OpenClaw MCP Proxy
Exposes app-registered tools as an MCP server for OpenClaw, forwarding actual tool execution back to the app over a WebSocket bridge.
README
OpenClaw MCP Proxy
OpenClaw MCP Proxy is a small FastAPI + FastMCP service that exposes app-registered tools as an MCP server for OpenClaw, while forwarding actual tool execution back to the app over a WebSocket bridge.
It has two responsibilities:
- Manage chat-scoped proxy sessions over HTTP and WebSocket.
- Expose the registered tool set as MCP over either stateless HTTP or stdio.
Architecture
sequenceDiagram
participant AppClient
participant ProxyServer
participant OpenClawClient
AppClient->>ProxyServer: POST /v1/chat/sessions
ProxyServer-->>AppClient: mcpSessionId, bridge_url, mcp_url
AppClient->>ProxyServer: WS /v1/chat/sessions/{session_id}/bridge
OpenClawClient->>ProxyServer: POST /v1/mcp/{session_id}
ProxyServer->>AppClient: invoke_tool
AppClient-->>ProxyServer: invoke_result
ProxyServer-->>OpenClawClient: MCP tool result
AppClient->>ProxyServer: DELETE /v1/chat/sessions/{session_id}
Endpoints
POST /v1/chat/sessions
Creates a session and returns the bridge and MCP endpoints for that session.
Request body:
{
"device_id": "device-1",
"device_name": "desktop",
"app_version": "1.0.0",
"chat_id": "chat-1",
"tools": [
{
"name": "echo_text",
"path": "/tools/echo_text",
"description": "Echo text.",
"input_schema": {
"type": "object",
"properties": {
"text": {
"type": "string"
}
}
}
}
]
}
Response body:
{
"mcpSessionId": "session-id",
"bridge_url": "ws://127.0.0.1:8000/v1/chat/sessions/session-id/bridge",
"mcp_url": "http://127.0.0.1:8000/v1/mcp/session-id"
}
DELETE /v1/chat/sessions/{session_id}
Deletes a session.
Response body:
{
"ok": true
}
WS /v1/chat/sessions/{session_id}/bridge
Connects the app-side execution bridge for a registered session.
Bridge messages:
- Proxy -> app:
invoke_tool - App -> proxy:
invoke_result - Proxy -> app:
ping - App -> proxy:
pong
Proxy -> app:
{
"type": "invoke_tool",
"mcpSessionId": "session-id",
"request_id": "session-id:1",
"tool_name": "echo_text",
"arguments": {
"text": "hello"
}
}
App -> proxy:
{
"type": "invoke_result",
"mcpSessionId": "session-id",
"request_id": "session-id:1",
"ok": true,
"content": {
"echoed_text": "hello"
}
}
POST /v1/mcp/{session_id}
Exposes the registered tools for a specific session as a stateless HTTP MCP endpoint.
This is the simplest way to connect OpenClaw to a specific registered session.
POST /v1/mcp/ with MCP-Session-Id
The MCP endpoint also supports header-based session routing:
- Header:
MCP-Session-Id: <session_id>
This is useful when the MCP client configuration prefers a stable URL and injects the session ID through headers.
MCP Transports
The proxy now supports two MCP-facing transports:
- HTTP: multi-session, routed by path or
MCP-Session-Id - stdio: single-session, bound during MCP
initializeviamcpSessionId
The stdio transport is implemented as a local proxy process in front of the HTTP MCP endpoint. The actual tool execution path is unchanged:
- The app registers a session over HTTP.
- The app connects the WebSocket bridge.
- The stdio process stores
initialize.params.mcpSessionIdand proxies MCP traffic toPOST /v1/mcpwith headerMCP-Session-Id. - The HTTP proxy forwards tool execution to the app over the existing bridge.
GET /health
Returns plain text ok.
Authentication
The proxy uses two independent bearer tokens:
-
OPENCLAW_PROXY_APP_TOKENUsed by:POST /v1/chat/sessionsDELETE /v1/chat/sessions/{session_id}WS /v1/chat/sessions/{session_id}/bridge
-
OPENCLAW_PROXY_OPENCLAW_TOKENUsed by:/v1/mcp/...
Important:
- If
OPENCLAW_PROXY_APP_TOKENis empty, app-facing endpoints accept requests without authentication. - If
OPENCLAW_PROXY_OPENCLAW_TOKENis empty, MCP-facing endpoints accept requests without authentication.
Do not leave either token empty outside local development.
WebSocket close codes:
4401: invalid app token4404: unknownsession_id
Configuration
Environment variables:
| Variable | Default | Description |
|---|---|---|
OPENCLAW_PROXY_APP_TOKEN |
"" |
Bearer token for app registration and bridge endpoints. |
OPENCLAW_PROXY_OPENCLAW_TOKEN |
"" |
Bearer token for MCP requests from OpenClaw. |
OPENCLAW_PROXY_SERVER_URL |
http://127.0.0.1:8000 |
Base URL used by the stdio proxy process to reach the HTTP proxy. |
OPENCLAW_PROXY_SESSION_TTL_SECONDS |
300 |
Session time-to-live in seconds. |
OPENCLAW_PROXY_TOOL_TIMEOUT_SECONDS |
120 |
Tool call timeout in seconds. |
Example .env:
OPENCLAW_PROXY_APP_TOKEN=replace-me
OPENCLAW_PROXY_OPENCLAW_TOKEN=replace-me
OPENCLAW_PROXY_SERVER_URL=http://127.0.0.1:8000
OPENCLAW_PROXY_SESSION_TTL_SECONDS=300
OPENCLAW_PROXY_TOOL_TIMEOUT_SECONDS=120
Run Locally
Requirements
- Python 3.11+ recommended
pip
Install dependencies
pip install -r requirements.txt
Start the server
uvicorn app.main:app --host 0.0.0.0 --port 8000
Start the stdio MCP proxy
After creating a session and connecting the app bridge, you can expose that session over stdio:
python -m app.stdio_main
Optional flags:
python -m app.stdio_main \
--proxy-base-url http://127.0.0.1:8000
The stdio client must send mcpSessionId in initialize.params, for example:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "your-client",
"version": "1.0.0"
},
"mcpSessionId": "<session_id>"
}
}
Check health
curl http://127.0.0.1:8000/health
Expected output:
ok
OpenClaw MCP Configuration
Header-routed example:
{
"mcpServers": {
"otakuroom-chat-mcp": {
"transport": "http",
"url": "https://your-proxy-host.example.com/v1/mcp",
"headers": {
"Authorization": "Bearer ${OPENCLAW_PROXY_OPENCLAW_TOKEN}",
"MCP-Session-Id": "${SESSION_ID}"
}
}
}
}
You can also connect directly to the session-specific URL returned by session creation, for example:
https://your-proxy-host.example.com/v1/mcp/<session_id>
Stdio example:
{
"mcpServers": {
"otakuroom-chat-mcp": {
"transport": "stdio",
"command": "python",
"args": [
"-m",
"app.stdio_main"
],
"env": {
"OPENCLAW_PROXY_SERVER_URL": "http://127.0.0.1:8000",
"OPENCLAW_PROXY_OPENCLAW_TOKEN": "${OPENCLAW_PROXY_OPENCLAW_TOKEN}"
}
}
}
}
How Tool Forwarding Works
- The app creates a session and sends its available tool definitions.
- The proxy stores the session in memory.
- OpenClaw calls the session MCP endpoint.
- The proxy dynamically builds a FastMCP server for that session and tool set.
- When OpenClaw invokes a tool, the proxy sends
invoke_toolover the WebSocket bridge. - The app executes the tool locally and sends
invoke_result. - The proxy returns the tool result to the MCP caller.
Testing
Run the proxy integration tests:
python -m unittest tests.test_proxy_integration
Current coverage includes:
- session-specific MCP routing via
mcp_url - header-based MCP routing via
MCP-Session-Id - normal WebSocket bridge disconnect without error-level logging
- shared MCP server construction and stdio proxy bootstrap behavior
Operational Notes
-
Sessions are stored in memory only. The proxy is not currently designed for stateless multi-instance deployment without sticky routing or shared session state.
-
Tool calls require an active bridge connection. If the session exists but the bridge is disconnected, tool calls fail with
Bridge is not connected. -
Sessions expire automatically. A background cleanup loop runs every 15 seconds and removes expired sessions.
-
Registered tool names must be unique within a session.
-
Reverse proxies must support WebSocket upgrade and must forward:
AuthorizationMCP-Session-Id
-
HTTP MCP is served directly from the in-process session registry.
-
stdio MCP runs as a separate proxy process and forwards to the HTTP MCP endpoint.
-
Tool schemas are registered dynamically from the provided
input_schema. Only trusted app clients should be allowed to register tool definitions.
Limitations
- No persistent session storage.
- No built-in rate limiting.
- No container or deployment manifests are included in this directory.
- Audit logging is plain application logging, not a full security audit pipeline.
Recommended Servers
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.
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.
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.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
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.
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.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.