pi-modal-mcp

pi-modal-mcp

Enables MCP-aware agents to drive Modal serverless compute, including GPU workers and headless Chromium for web browsing with screenshots.

Category
Visit Server

README

pi-modal-mcp

Drive Modal serverless compute (GPU workers + headless Chromium) from any MCP-aware agent. Zero local dependencies for the remote path; a tiny stdio shim for stdio-only clients like pi.

Three pieces, one system:

agent (pi / Claude Desktop / Cursor / your Linux box)
  │
  │  MCP (stdio shim OR streamable HTTP)
  ▼
Modal frontend  ── FastAPI + MCP-over-HTTP
  │  (.remote.aio fan-out)
  ├─▶ run_model containers   (CPU workers, parallel)
  └─▶ browse_page container  (Playwright + Chromium → PNG)

What's inside

Path What
modal-frontend/app.py Modal app: FastAPI REST endpoints and a Modal-hosted MCP-over-HTTP server (stateless streamable HTTP). Deploys Playwright for screenshots.
modal-mcp/modal_mcp.py Stdio MCP shim. Bridges stdio-only MCP clients (e.g. pi) to the Modal REST endpoints. Returns screenshots as MCP image content.
mcp-runtime/index.ts Pi extension: a native MCP runtime for pi. Reads ~/.pi/agent/mcp.json, spawns stdio MCP servers, registers their tools as pi tools.
mcp-runtime/mcp.json.example Example pi MCP config.

Tools exposed

Tool Does
modal_ping Health-check the Modal frontend.
modal_models Fan out N parallel CPU workers on Modal. Returns JSON: concurrent count, elapsed seconds, per-worker results.
modal_browse Open a URL in headless Chromium inside a Modal container. Returns a PNG screenshot (MCP image content).
modal_swarm Run a prompt across N parallel OSS model workers on Modal GPUs (a model swarm). Returns JSON: {concurrent, elapsed, results:[{model, completion, elapsed}]}. Models are HuggingFace IDs (default Salesforce/codegen-350M-mono), cached in a shared Modal Volume.

Deploy the Modal app

Requires the Modal CLI authenticated.

cd modal-frontend
modal deploy app.py

You'll get two URLs:

web:      https://YOUR-WORKSPACE--pi-frontend-web.modal.run       (REST: /api/*)
mcp_web:  https://YOUR-WORKSPACE--pi-frontend-mcp-web.modal.run/mcp  (MCP streamable HTTP)

Why stateless?

Modal load-balances each HTTP request across containers, so stateful MCP sessions (which require session affinity) break. The app sets stateless_http=True and disables DNS-rebinding host checks so any host can reach it. For a private deployment, tighten transport_security.allowed_hosts.

Use it

Remote MCP client (Claude Desktop / Cursor / your Linux box)

{
  "mcpServers": {
    "modal": {
      "url": "https://YOUR-WORKSPACE--pi-frontend-mcp-web.modal.run/mcp"
    }
  }
}

Or the mcp Python client:

pip install mcp
python3 - <<'PY'
import asyncio
from mcp.client.streamable_http import streamablehttp_client
from mcp.client.session import ClientSession
async def main():
    async with streamablehttp_client("https://YOUR-WORKSPACE--pi-frontend-mcp-web.modal.run/mcp") as (r,w,_):
        async with ClientSession(r,w) as s:
            await s.initialize()
            print([t.name for t in (await s.list_tools()).tools])
            res = await s.call_tool("modal_browse", {"url": "example.com"})
            print([getattr(c,'type',None) for c in res.content])
asyncio.run(main())
PY

pi (native remote transport, no shim)

The mcp-runtime extension now speaks the remote (streamable-HTTP) MCP transport directly, so pi can hit the Modal-hosted MCP server with zero local component.

  1. Install the extension:
mkdir -p ~/.pi/agent/extensions/mcp-runtime
cp mcp-runtime/index.ts mcp-runtime/package.json ~/.pi/agent/extensions/mcp-runtime/
cd ~/.pi/agent/extensions/mcp-runtime && npm install
  1. Add ~/.pi/agent/mcp.json (replace workspace + URL):
{
  "mcpServers": {
    "modal": {
      "url": "https://YOUR-WORKSPACE--pi-frontend-mcp-web.modal.run/mcp",
      "transport": "streamable-http"
    }
  }
}
  1. Restart pi (or /reload), then /mcp list to see mcp_modal_modal_ping, mcp_modal_modal_models, mcp_modal_modal_browse tagged [remote].

pi (stdio fallback) via the shim

For MCP servers that only expose a stdio interface (or for air-gapped use), the modal-mcp shim still works:

  1. Install the shim on PATH:
cp modal-mcp/run.sh /usr/local/bin/modal-mcp   # or anywhere on PATH
chmod +x /usr/local/bin/modal-mcp
  1. Add ~/.pi/agent/mcp.json using the command form instead of url:
{
  "mcpServers": {
    "modal": {
      "command": "modal-mcp",
      "args": [],
      "env": {
        "MODAL_FRONTEND": "https://YOUR-WORKSPACE--pi-frontend-web.modal.run"
      }
    }
  }
}
  1. /mcp list shows the tools tagged [stdio].

Why stateless + 405 GET?

Modal load-balances each HTTP request across containers, so stateful MCP sessions (which require session affinity) break. The app sets stateless_http=True and disables DNS-rebinding host checks so any host can reach it.

A second subtlety: the MCP Node SDK's streamable-HTTP client, on start(), first tries GET /mcp to open a listening SSE stream; if the server returns 200 and holds it open, the client blocks waiting for events that a stateless server never delivers. A stateless server has no stream to offer, so the app wraps the MCP ASGI app in a middleware that returns 405 for GET /mcp, telling strict clients to skip the GET stream and use POST-inline responses. This makes the endpoint compatible with the Node SDK, the Python SDK, Claude Desktop, and Cursor alike.

For a private deployment, tighten transport_security.allowed_hosts.

Transports

The pi mcp-runtime extension supports both backends from one config:

  • stdio — { "command": "...", "args": [...] } spawns a local process.
  • remote — { "url": "https://...", "transport": "streamable-http" } talks to a remote MCP-over-HTTP server directly. "transport": "sse" selects the legacy SSE client. Optional "headers": { ... } for auth.

Remote transport means pi needs zero local component for cloud-hosted MCP servers — no shim, no npx/Python process to spawn.

AI-native IDE (model swarm)

The app serves a web IDE at /ide on the web URL: a Monaco editor whose "Run swarm" button fans the current buffer across N parallel OSS model workers on Modal GPUs and shows each completion in a side panel. This is the self-hosted, OSS-brain equivalent of a cloud coding agent — local UI, remote GPUs, no API keys.

https://YOUR-WORKSPACE--pi-frontend-web.modal.run/ide

Models default to Salesforce/codegen-350M-mono (small, fast, public) and are cached in a shared Modal Volume so cold starts after the first only pay the model-load cost. Pass any HuggingFace ID in the models field; gated models need a secrets=[modal.Secret.from_name("huggingface-secret")] on llm_worker.

How many models can I run simultaneously?

Modal scales each function horizontally — there's no fixed concurrency cap. You can fan out hundreds of concurrent .remote() calls; Modal spins up containers on demand. What actually bounds you:

  • Concurrent containers quota per workspace (free tiers are low; extra calls queue, they don't fail).
  • GPU availability for gpu=... functions.
  • Cold starts — first container of a function takes a few seconds; warm containers are ~instant.
  • Your fan-out shape — asyncio.gather(*[fn.remote.aio(x) for x in items]) issues all calls concurrently.

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured