pi-modal-mcp
Provides tools to run serverless compute on Modal, including parallel model execution and headless browser screenshots.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pi-modal-mcpbrowse example.com and show me the screenshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 app: FastAPI REST endpoints and a Modal-hosted MCP-over-HTTP server (stateless streamable HTTP). Deploys Playwright for screenshots. |
| Stdio MCP shim. Bridges stdio-only MCP clients (e.g. pi) to the Modal REST endpoints. Returns screenshots as MCP image content. |
| Pi extension: a native MCP runtime for pi. Reads |
| Example pi MCP config. |
Related MCP server: Modal MCP Server
Tools exposed
Tool | Does |
| Health-check the Modal frontend. |
| Fan out N parallel CPU workers on Modal. Returns JSON: concurrent count, elapsed seconds, per-worker results. |
| Open a URL in headless Chromium inside a Modal container. Returns a PNG screenshot (MCP image content). |
| Run a prompt across N parallel OSS model workers on Modal GPUs (a model swarm). Returns JSON: |
Deploy the Modal app
Requires the Modal CLI authenticated.
cd modal-frontend
modal deploy app.pyYou'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())
PYpi (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.
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 installAdd
~/.pi/agent/mcp.json(replace workspace + URL):
{
"mcpServers": {
"modal": {
"url": "https://YOUR-WORKSPACE--pi-frontend-mcp-web.modal.run/mcp",
"transport": "streamable-http"
}
}
}Restart pi (or
/reload), then/mcp listto seemcp_modal_modal_ping,mcp_modal_modal_models,mcp_modal_modal_browsetagged[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:
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-mcpAdd
~/.pi/agent/mcp.jsonusing thecommandform instead ofurl:
{
"mcpServers": {
"modal": {
"command": "modal-mcp",
"args": [],
"env": {
"MODAL_FRONTEND": "https://YOUR-WORKSPACE--pi-frontend-web.modal.run"
}
}
}
}/mcp listshows 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/ideModels 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
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/salus-ryan/pi-modal-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server