MCP Remote Transport¶
Module: bernstein.mcp.remote_transport Class: StreamableHTTPTransport
The MCP remote transport exposes Bernstein's MCP server over HTTP using the streamable HTTP transport spec. This allows remote MCP clients (Claude Desktop, other agents, CI systems) to interact with a Bernstein instance over the network -- including deployment on Cloudflare Workers via a Python worker.
Configuration¶
RemoteMCPConfig dataclass fields:
| Field | Type | Default | Description |
|---|---|---|---|
host | str | "0.0.0.0" | Bind host |
port | int | 8053 | Bind port |
path | str | "/mcp" | URL path for MCP endpoint |
auth_type | str | "none" | Authentication: "none", "bearer", or "oauth" |
auth_token | str | "" | Bearer token (when auth_type="bearer") |
cors_origins | list[str] | ["*"] | CORS allowed origins |
max_sessions | int | 100 | Maximum concurrent MCP sessions |
session_timeout_seconds | int | 3600 | Session expiry (1 hour) |
Available tools¶
The remote transport exposes these MCP tools (same as the local MCP server):
| Tool | Description | Required args |
|---|---|---|
bernstein_health | Liveness check | None |
bernstein_run | Start an orchestration run | goal |
bernstein_status | Task count summary | None |
bernstein_tasks | List tasks (optional status filter) | None |
bernstein_cost | Cost summary (total + per-role) | None |
bernstein_stop | Graceful shutdown | None |
bernstein_approve | Approve a pending task | task_id |
bernstein_create_subtask | Create a subtask | parent_task_id, goal |
Starting the server¶
Python API¶
from bernstein.mcp.remote_transport import RemoteMCPConfig, run_remote
# Start with defaults (binds to 0.0.0.0:8053)
run_remote()
# Custom configuration
run_remote(
server_url="http://127.0.0.1:8052", # Bernstein task server
host="0.0.0.0",
port=8053,
)
ASGI application¶
For deployment with any ASGI server (uvicorn, hypercorn, Cloudflare Python workers):
from bernstein.mcp.remote_transport import RemoteMCPConfig, create_asgi_app
config = RemoteMCPConfig(
port=8053,
auth_type="bearer",
auth_token="my-secret-token",
cors_origins=["https://myapp.example.com"],
max_sessions=50,
)
app = create_asgi_app(
server_url="http://127.0.0.1:8052",
config=config,
)
# Run with uvicorn
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8053)
HTTP protocol¶
The transport implements the MCP streamable HTTP transport spec:
| Method | Path | Purpose |
|---|---|---|
| POST | /mcp | JSON-RPC 2.0 request/notification (single or batch) |
| GET | /mcp | SSE stream endpoint (stub, returns 501) |
| DELETE | /mcp | Close an MCP session |
| OPTIONS | /mcp | CORS preflight |
Headers¶
| Header | Direction | Description |
|---|---|---|
mcp-session-id | Both | Session identifier (returned on first POST, send on subsequent requests) |
Authorization | Request | Bearer <token> when auth_type="bearer" |
Content-Type | Both | application/json |
Session lifecycle¶
- First POST creates a new session and returns
mcp-session-idin the response headers. - Subsequent requests include the session ID header to maintain state.
- DELETE with the session ID closes the session.
- Sessions expire after
session_timeout_seconds(default 1 hour) of inactivity. - Expired sessions are pruned automatically on each request.
JSON-RPC methods¶
| Method | Description |
|---|---|
initialize | Return server info and capabilities |
tools/list | List available Bernstein tools |
tools/call | Execute a tool by name |
ping | Liveness check |
notifications/initialized | Client notification (no-op) |
Example request¶
# Initialize session
curl -X POST http://localhost:8053/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
# List tools (include session ID from previous response)
curl -X POST http://localhost:8053/mcp \
-H "Content-Type: application/json" \
-H "mcp-session-id: SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}'
# Run a task
curl -X POST http://localhost:8053/mcp \
-H "Content-Type: application/json" \
-H "mcp-session-id: SESSION_ID" \
-d '{
"jsonrpc":"2.0",
"method":"tools/call",
"params":{
"name":"bernstein_run",
"arguments":{"goal":"Add input validation","role":"backend"}
},
"id":3
}'
Authentication¶
| Mode | Config | Behavior |
|---|---|---|
none | auth_type="none" | No authentication (default, for local development) |
bearer | auth_type="bearer", auth_token="secret" | Validates Authorization: Bearer secret header |
Production deployment
Always use auth_type="bearer" with a strong token when exposing the MCP server over the network. The "none" mode is only safe for local development.
CORS configuration¶
By default, all origins are allowed (["*"]). For production, restrict to your application domains:
config = RemoteMCPConfig(
auth_type="bearer",
auth_token="secret",
cors_origins=["https://myapp.example.com", "https://admin.example.com"],
)
CORS headers exposed: mcp-session-id.
Deployment on Cloudflare Workers¶
The ASGI app can be deployed as a Cloudflare Python worker:
# worker.py
from bernstein.mcp.remote_transport import RemoteMCPConfig, create_asgi_app
config = RemoteMCPConfig(
auth_type="bearer",
auth_token="YOUR_SECRET",
max_sessions=100,
)
app = create_asgi_app(
server_url="https://your-bernstein-server.example.com:8052",
config=config,
)
This lets MCP clients connect to your Bernstein instance from anywhere with Cloudflare's global edge network handling TLS and routing.