Index Agentica

Bridge stdio and remote MCP servers: mcp-remote, Supergateway, mcp-proxy and mcpo

Put a local stdio MCP server on HTTP so remote agents can reach it, or plug a remote server into a client that only speaks stdio. Covers mcp-remote, Supergateway, mcp-proxy and mcpo: which direction each one bridges, exact commands, how to lock the endpoint down, and two dependency breakages we hit.

Type
Guide
Author
Agentica Author
Published
Last verified
Difficulty
intermediate
Time
30 min

Prerequisites

MCP has two standard transports. stdio: the client starts the server as a child process and talks over stdin/stdout. Streamable HTTP (and the older SSE transport): the server is a web endpoint that any client on the network can reach. Many useful servers still ship stdio only, and a few clients still only launch stdio servers. A bridge translates between the two, so you don't have to rewrite either side.

Which direction do you need?

You haveYou wantUse
A stdio server on your machineRemote agents, a cloud IDE or a hosted client to call it over HTTPSupergateway --stdio or mcp-proxy server mode
A remote MCP URL (possibly OAuth-protected)A client that only launches stdio serversmcp-remote, or Supergateway / mcp-proxy client mode
Any MCP serverPlain REST with an OpenAPI schema (Open WebUI, OpenAPI tool callers, curl)mcpo
flowchart LR
  subgraph expose[Expose a stdio server]
    S1[stdio server] -- stdin/stdout --> G[Supergateway / mcp-proxy] -- Streamable HTTP or SSE --> RC((remote client))
  end
  subgraph consume[Use a remote server from a stdio client]
    LC((stdio-only client)) -- stdin/stdout --> R[mcp-remote] -- HTTPS + OAuth --> RS[remote MCP server]
  end
  subgraph rest[REST instead of MCP]
    S2[any MCP server] --> O[mcpo] -- OpenAPI / REST --> T((OpenAPI tool caller))
  end
Mermaid diagram (source shown; not rendered client-side)

The four bridges at a glance

mcp-remoteSupergatewaymcp-proxymcpo
Version we ran (2026-10-25)0.15.2 (npm)4.2.1 (npm)0.13.0 (PyPI, Python ≥3.10)0.0.20 (PyPI, Python ≥3.11)
stdio → networknoSSE, WebSocket or Streamable HTTPSSE and Streamable HTTP on one portREST + OpenAPI (not MCP)
network → stdioyes (HTTP first, SSE fallback by default)yes (--sse / --streamableHttp)yes (SSE, or --transport=streamablehttp)n/a
OAuth to the upstream serverfull browser flow, tokens in ~/.mcp-authstatic bearer token (--oauth2Bearer) or headersOAuth2 client credentials, basic/digest, headersOAuth 2.1 with dynamic client registration (Streamable HTTP upstreams)
Auth for your endpointn/a (local process)--apiKey / --apiKeyFilenone documented--api-key
Default listen addressn/aevery interface127.0.0.1, random port0.0.0.0:8000, CORS *
Several serversone per process--config with an mcpServers file, or several combined on one URL--named-server / --named-server-config at /servers/<name>/--config (Claude Desktop format), one route per server, --hot-reload
LicenseMITMITMITMIT

Versions are the latest on npm and PyPI on 2026-10-25. Defaults come from each README, except mcpo's listen address and CORS default, which come from its CLI source and matched what mcpo logged when we started it.

1. Expose a stdio server over Streamable HTTP (Supergateway)

Supergateway has the most complete server mode. The command below wraps the reference filesystem server (from the MCP reference servers), binds to localhost, requires a key and exposes only two read tools:

export MCP_API_KEY="$(openssl rand -hex 24)"
npx -y supergateway@4.2.1 \
  --stdio "npx -y @modelcontextprotocol/server-filesystem /srv/shared" \
  --outputTransport streamableHttp \
  --host 127.0.0.1 --port 8000 \
  --apiKey "$MCP_API_KEY" \
  --tools list_directory --tools read_text_file

The endpoint is http://127.0.0.1:8000/mcp. When we ran this on 2026-10-25:

Useful flags from the README:

2. Use a remote server from a stdio-only client (mcp-remote)

Most current clients (Claude Code, Cursor, Codex CLI) connect to remote servers natively. Check that first: the guide Connect an agent to a remote MCP server covers it, and its README says mcp-remote is meant to be removed once your client supports remote, authorized servers. For a client that only launches commands, add mcp-remote as the command:

{
  "mcpServers": {
    "remote-example": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://remote.mcp.server/mcp"]
    }
  }
}

What the README documents:

Round trip we ran. We pointed mcp-remote 0.15.2 at the Supergateway endpoint from step 1 (in --stateful mode, with --allow-http because it was on localhost and --header "Authorization:Bearer <key>"). Then we piped initialize and tools/list into its stdin. The filesystem server's answers came back on stdout: stdio → HTTP → stdio, with no code written.

3. The Python alternative (mcp-proxy)

mcp-proxy does both directions in one Python tool. To expose a server:

uv tool install mcp-proxy        # or: pipx install mcp-proxy
mcp-proxy --port 8080 -- npx -y @modelcontextprotocol/server-filesystem /srv/shared

On 2026-10-25, version 0.13.0 listened on 127.0.0.1 and served both transports from the same port: Streamable HTTP at /mcp (it answered initialize with an mcp-session-id) and SSE at /sse. It also had a /status JSON endpoint. Pass --stateless for stateless Streamable HTTP. To use a remote server from a stdio client, give it the URL instead of a command: mcp-proxy --transport=streamablehttp https://host/mcp, with API_ACCESS_TOKEN or --headers, OAuth2 client credentials (--client-id, --client-secret, --token-url) or basic/digest auth.

Caveat: the README documents no authentication for the endpoint mcp-proxy serves. Keep it on 127.0.0.1 (the default) or put an authenticating reverse proxy in front of it. Don't bind it to 0.0.0.0 on an open network.

4. MCP as REST (mcpo)

mcpo isn't an MCP bridge. It turns each MCP tool into a REST endpoint with a generated OpenAPI schema and docs at /docs, for tools that speak OpenAPI rather than MCP (it comes from the Open WebUI project). Upstreams can be stdio, SSE or Streamable HTTP, and --config serves several servers at /<name>.

What we hit on 2026-10-25. The README command uvx mcpo ... failed at startup in two different ways, because mcpo 0.0.20 only sets lower bounds on its dependencies (mcp>=1.17.0, fastapi>=0.115.12):

  1. uv resolved mcp 2.3.0, and mcpo crashed with ImportError: cannot import name 'streamablehttp_client'. Open issue #303 tracks this.
  2. After pinning mcp<2, it crashed again with TypeError: FastAPI.__init__() got an unexpected keyword argument 'ssl_certfile' (FastAPI 0.162.0 had been resolved).

This pin worked:

uvx --with "mcp<2" --with "fastapi<0.130" mcpo@0.0.20 \
  --host 127.0.0.1 --port 8000 --api-key "$MCP_API_KEY" \
  -- npx -y @modelcontextprotocol/server-filesystem /srv/shared

We picked <0.130 as a known-good bound and didn't track down the exact FastAPI release that breaks it. With the pin, a request without the key got 401. POST /read_text_file with Authorization: Bearer <key> returned the file. /openapi.json listed one path per filesystem tool, including write_file, edit_file and move_file, so use disabledTools in a config file to hide the ones you don't want exposed. Note that mcpo binds to 0.0.0.0 with CORS * by default, so always pass --host 127.0.0.1 and --api-key unless you really mean to serve the whole network. The README says "Python 3.8+", but PyPI lists Requires-Python >=3.11.

Lock it down before you expose anything

A bridge turns a process that only you could start into a network service. The MCP transport spec says servers must validate the Origin header (to stop DNS-rebinding attacks from web pages) and should bind only to localhost when running locally. Bridges sit outside your server, so these checks are on you:

  1. Bind to 127.0.0.1 (--host) and publish through a reverse proxy or tunnel that terminates HTTPS. Supergateway's README says to use HTTPS so keys aren't sent in clear text.
  2. Require a key (Supergateway --apiKey, mcpo --api-key). For per-user access, audit logs and policy, put a real gateway in front instead. The MCP gateways comparison covers Docker MCP Gateway and ToolHive, and LiteLLM's MCP gateway also accepts stdio servers. For OAuth on your own server, see Add OAuth to your MCP server.
  3. Expose the fewest tools you can (Supergateway --tools, mcpo disabledTools). A filesystem or shell server reachable over HTTP is remote code execution waiting to happen. Scope its directory, and consider running it in a container or sandbox (see Run untrusted code in a sandbox).
  4. Leave CORS off unless a browser client needs it, and then list origins explicitly. mcpo's default of * is the one to override.
  5. Pin versions (supergateway@4.2.1, mcp-remote@0.15.2, mcpo@0.0.20). Unpinned npx/uvx runs fetch whatever is newest, and the mcpo breakage above shows that a dependency's major release can break a bridge overnight.
  6. Test the endpoint before giving it to an agent: MCP Inspector connects to Streamable HTTP and SSE URLs. The guide Test your MCP server has a checklist.

Choosing quickly

To find stdio servers worth bridging, or a hosted server that makes the bridge unnecessary, search Index Agentica with the pick-an-mcp-server skill.

Directory entries in this guide

Related

Sources

Machine-readable