Bridge stdio MCP clients

Problem: Claude Desktop, Cursor, and Zed launch MCP servers as subprocesses and speak the stdio variant of MCP — newline-framed JSON-RPC over stdin/stdout. mcpgw is an HTTP server. You need a bridge.

Solution: ship the mcpgw stdio subcommand on the client machine. It speaks stdio to the parent app and HTTPS to the gateway.

Recipe — Claude Desktop

  1. Install the mcpgw binary on the user’s laptop. Either pull it from the releases page or brew install mcpgw once available.

  2. Add an entry to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "filesystem-via-mcpgw": {
      "command": "mcpgw",
      "args": [
        "stdio",
        "--upstream=https://mcpgw.internal.acme.com:7332"
      ]
    }
  }
}
  1. Restart Claude Desktop. The next tool call routes through your gateway and gets policy-checked, traced, and audited.

Recipe — Cursor

~/.cursor/mcp.json:

{
  "mcpServers": {
    "git-via-mcpgw": {
      "command": "mcpgw",
      "args": ["stdio", "--upstream=https://mcpgw.internal.acme.com:7332"]
    }
  }
}

Recipe — Zed

In Zed settings.json:

"context_servers": {
  "mcpgw-corp": {
    "command": {
      "path": "mcpgw",
      "args": ["stdio", "--upstream=https://mcpgw.internal.acme.com:7332"]
    }
  }
}

How the bridge works

[Claude Desktop] --stdin/stdout--> [mcpgw stdio] --HTTP POST--> [mcpgw HTTP] --upstream--> [MCP server]

The bridge reads newline-delimited JSON-RPC frames from stdin, POSTs each one to <upstream>/mcp with the right Content-Type and a stable Mcp-Session-Id (generated once per bridge process), reads the response, and emits it back on stdout.

Spans on the gateway side carry mcp.transport = stdio-bridge so you can distinguish stdio-originated calls from native HTTP clients in Datadog.

Pitfalls

  • Pass the base URL, not /mcp. The /mcp path is appended automatically by the bridge. Pass https://mcpgw.internal.acme.com:7332, not https://mcpgw.internal.acme.com:7332/mcp.
  • TLS verification is on by default. If your gateway uses a private CA, set --ca-file=/path/to/corp-ca.pem (v1.0+) or distribute the cert via the OS trust store.
  • One bridge process per MCP server entry. The session id is shared across all calls in that bridge, so per-session rate-limits scope to the desktop client. To get per-tab rate-limits, fork the upstream MCP server registration so each client app uses a distinct entry.
  • The bridge does not buffer. If the gateway is unreachable, the bridge surfaces the connection error to the client app, which typically displays “MCP server failed to start.” Use the Datadog mcp.error.kind = upstream_unreachable filter to triage.