Skip to main content
Glama
wenyue

OpenClaw MCP Proxy

by wenyue

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}

Related MCP server: MCP Host RPC Bridge

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 initialize via mcpSessionId

The stdio transport is implemented as a local proxy process in front of the HTTP MCP endpoint. The actual tool execution path is unchanged:

  1. The app registers a session over HTTP.

  2. The app connects the WebSocket bridge.

  3. The stdio process stores initialize.params.mcpSessionId and proxies MCP traffic to POST /v1/mcp with header MCP-Session-Id.

  4. 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_TOKEN Used by:

    • POST /v1/chat/sessions

    • DELETE /v1/chat/sessions/{session_id}

    • WS /v1/chat/sessions/{session_id}/bridge

  • OPENCLAW_PROXY_OPENCLAW_TOKEN Used by:

    • /v1/mcp/...

Important:

  • If OPENCLAW_PROXY_APP_TOKEN is empty, app-facing endpoints accept requests without authentication.

  • If OPENCLAW_PROXY_OPENCLAW_TOKEN is empty, MCP-facing endpoints accept requests without authentication.

Do not leave either token empty outside local development.

WebSocket close codes:

  • 4401: invalid app token

  • 4404: unknown session_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

  1. The app creates a session and sends its available tool definitions.

  2. The proxy stores the session in memory.

  3. OpenClaw calls the session MCP endpoint.

  4. The proxy dynamically builds a FastMCP server for that session and tool set.

  5. When OpenClaw invokes a tool, the proxy sends invoke_tool over the WebSocket bridge.

  6. The app executes the tool locally and sends invoke_result.

  7. 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:

    • Authorization

    • MCP-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.

F
license - not found
-
quality - not tested
D
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

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/wenyue/openclaw_mcp_proxy'

If you have feedback or need assistance with the MCP directory API, please join our Discord server