Stdio-to-HTTP gateway — connects MCP clients to remote HTTP MCP servers
Project description
mcp-stdio
English | 日本語
Stdio-to-HTTP gateway — connects MCP clients to remote HTTP MCP servers.
Overview
MCP clients like Claude Desktop and Claude Code see mcp-stdio as a locally running self-hosted MCP server, while it relays all requests to a remote MCP server with support for various authentication methods:
flowchart BT
A[Claude<br>Desktop/Code] <-- stdio --> B(mcp-stdio)
B <== "<b>HTTPS</b><br>Streamable HTTP / SSE<br>Bearer Token<br>Header<br>OAuth" ==> C[Remote<br>MCP Server]
B -. "OAuth 2.1<br>(PKCE)" .-> D[Authorization<br>Server]
D -. callback .-> B
style B fill:#4a5,stroke:#333,color:#fff
Bearer tokens, custom headers, and OAuth 2.1 credentials are forwarded to the remote server.
Features
- Both MCP transports supported — Streamable HTTP (current spec, default) and SSE (MCP 2024-11-05 legacy), selectable with
--transport. SSE parser follows the WHATWG Server-Sent Events spec. - OAuth 2.1 client — built-in authorization code flow with PKCE, dynamic client registration, token refresh, and secure token persistence. Implements the full MCP authorization spec at the section level:
- RFC 9728 Protected Resource Metadata
- §3 discovery of authorization servers via
/.well-known/oauth-protected-resource - §3.1 path-aware well-known URL construction for path-based reverse-proxy deployments, with host-root fallback
- §3.3
resourcefield validation — warn on mismatch, continue
- §3 discovery of authorization servers via
- RFC 8414 Authorization Server Metadata
- §3 well-known URL construction, including path insertion for issuers with path components
- §3
issuervalidation — warn on mismatch, continue
- RFC 8707 Resource Indicators
- §2
resourceparameter in authorization, token exchange, and refresh requests
- §2
- RFC 7636 PKCE
- §4.1–4.2 S256
code_challenge_methodwith a 96-charcode_verifier
- §4.1–4.2 S256
- RFC 7591 Dynamic Client Registration
- §3 client registration request (public client with
token_endpoint_auth_method: none) - §3.2.1
client_secret_expires_athandling — auto re-register on expiry
- §3 client registration request (public client with
- RFC 6750 Bearer Token usage
- §2.1
Authorization: Bearer <token>request header
- §2.1
- RFC 9728 Protected Resource Metadata
- Retry with backoff — retries up to 3 times on connection errors
- Streaming resilience — streams SSE responses in real time; auto-reconnects on mid-stream disconnect
- Session recovery — resets MCP session ID on 404 and retries
- Token refresh on 401 — automatically refreshes expired OAuth tokens mid-session
- Bearer token auth — via
--bearer-tokenflag orMCP_BEARER_TOKENenv var - Custom headers — pass any header with
-H/--header - Graceful shutdown — handles SIGTERM/SIGINT
- Proxy support — respects
HTTP_PROXY,HTTPS_PROXY,NO_PROXYenv vars via httpx - Minimal dependencies — only httpx; OAuth uses stdlib only
Install
pip install mcp-stdio
Or with uv:
uv tool install mcp-stdio
Or run directly without installing:
uvx mcp-stdio https://your-server.example.com:8080/mcp
Or with Homebrew:
brew install shigechika/tap/mcp-stdio
Quick Start
mcp-stdio https://your-server.example.com:8080/mcp
With Bearer token authentication:
# Recommended: use env var (token is hidden from `ps`)
MCP_BEARER_TOKEN=YOUR_TOKEN mcp-stdio https://your-server.example.com:8080/mcp
# Or pass directly (token is visible in `ps` output)
mcp-stdio https://your-server.example.com:8080/mcp --bearer-token YOUR_TOKEN
With custom headers:
mcp-stdio https://your-server.example.com:8080/mcp --header "X-API-Key: YOUR_KEY"
With OAuth 2.1 authentication (for servers that require it):
mcp-stdio --oauth https://your-server.example.com:8080/mcp
# With a pre-registered client ID (skips dynamic registration)
mcp-stdio --oauth --client-id YOUR_CLIENT_ID https://your-server.example.com:8080/mcp
For legacy MCP servers using the 2024-11-05 SSE transport:
mcp-stdio --transport sse https://your-server.example.com:8080/sse
Check connectivity before use:
mcp-stdio --check https://your-server.example.com:8080/mcp
Claude Desktop Configuration
Add to claude_desktop_config.json:
{
"mcpServers": {
"my-remote-server": {
"command": "mcp-stdio",
"args": ["https://your-server.example.com:8080/mcp"],
"env": {
"MCP_BEARER_TOKEN": "YOUR_TOKEN"
}
}
}
}
Config file locations:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Claude Code Configuration
claude mcp add my-remote-server \
-e MCP_BEARER_TOKEN=YOUR_TOKEN \
-- mcp-stdio https://your-server.example.com:8080/mcp
Usage
mcp-stdio [OPTIONS] URL
Arguments:
URL Remote MCP server URL
Options:
--bearer-token TOKEN Bearer token (or set MCP_BEARER_TOKEN env var)
--oauth Enable OAuth 2.1 authentication
--client-id ID Pre-registered OAuth client ID (or set MCP_OAUTH_CLIENT_ID)
--oauth-scope SCOPE OAuth scope to request
-H, --header 'Key: Value' Custom header (can be repeated)
--transport {streamable-http,sse}
Transport type (default: streamable-http)
--timeout-connect SEC Connection timeout (default: 10)
--timeout-read SEC Read timeout (default: 120)
--check Check connection and exit
-V, --version Show version
-h, --help Show help
Workarounds
Claude Code
Works around known issues in Claude Code's HTTP transport:
- Bearer token not sent — Claude Code ignores
Authorizationheader on tool calls (#28293, #33817) - Missing Accept header — servers return 406, misinterpreted as auth failure (#42470)
- OAuth fallback loop — Claude Code enters OAuth discovery even when not needed (#34008, #39271)
- Session lost after disconnect — mcp-stdio recovers MCP sessions automatically on 404 (#34498, #38631)
- OAuth scope omitted — Claude Code sends no
scopeparameter in authorization requests, causing strict OAuth servers to reject the flow (#4540); mcp-stdio sends scopes via--oauth-scope - Proxy settings ignored — Claude Code does not respect
NO_PROXY(#34804); mcp-stdio inherits proxy settings from httpx
mcp-remote
- OAuth discovery fails for auth server with path — mcp-remote does not implement the RFC 8414 §3 path insertion rule, causing OAuth metadata discovery to fail when the authorization server URL contains a path component (e.g. multi-tenant or realm-based servers) (mcp-remote#207); mcp-stdio constructs the correct well-known metadata URL.
- OAuth discovery fails for MCP server behind path-based reverse proxy — when an MCP server is mounted under a sub-path (e.g. Tailscale serve, nginx
location /mcp/), Protected Resource Metadata must be fetched at/.well-known/oauth-protected-resource/{path}per RFC 9728 §3.1, not at the host root (mcp-remote#249); mcp-stdio tries the path-aware URL first and falls back to host-root for compatibility.
Windows
- CRLF translation on stdio — Python's default
TextIOWrapperrewrites\nto\r\non Windows, corrupting the NDJSON wire format used by MCP. mcp-stdio reconfiguressys.stdin/sys.stdoutto bare LF mode so messages stay spec-compliant regardless of host OS (cf. modelcontextprotocol/python-sdk#2433 for the same class of bug instdio_server).
How It Works
- If
--oauthis set, obtains an access token (cached → refresh → browser flow) - Reads JSON-RPC messages from stdin (sent by Claude Desktop/Code)
- Relays them over HTTPS to the remote MCP server
- Parses responses and writes them to stdout
- On 401, refreshes the OAuth token and retries
Transport details:
- Streamable HTTP (default) — each stdin message is a single POST; session state is tracked via the
Mcp-Session-Idheader and re-initialized automatically on 404. - SSE (MCP 2024-11-05 legacy) — a persistent
GETstream delivers responses and the initialendpointevent containing the POST URL; the stream auto-reconnects on disconnect.
OAuth tokens are stored in ~/.config/mcp-stdio/tokens.json (permissions 0600).
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_stdio-0.4.5.tar.gz.
File metadata
- Download URL: mcp_stdio-0.4.5.tar.gz
- Upload date:
- Size: 51.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29a931eb4174f4d1ad21c6f1e9f029f4bc44dbac9e0b526db853e34cbfd9727f
|
|
| MD5 |
c92cfe94eb86a3fddf02c49f79105cc4
|
|
| BLAKE2b-256 |
476a490c70459636a851d7de3ade48184cb712876701c74bbdc0cfc686302eee
|
Provenance
The following attestation bundles were made for mcp_stdio-0.4.5.tar.gz:
Publisher:
release.yml on shigechika/mcp-stdio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_stdio-0.4.5.tar.gz -
Subject digest:
29a931eb4174f4d1ad21c6f1e9f029f4bc44dbac9e0b526db853e34cbfd9727f - Sigstore transparency entry: 1307870146
- Sigstore integration time:
-
Permalink:
shigechika/mcp-stdio@8456f60dc631a756bcd0f5f312c7129dc031f4cc -
Branch / Tag:
refs/tags/v0.4.5 - Owner: https://github.com/shigechika
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8456f60dc631a756bcd0f5f312c7129dc031f4cc -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcp_stdio-0.4.5-py3-none-any.whl.
File metadata
- Download URL: mcp_stdio-0.4.5-py3-none-any.whl
- Upload date:
- Size: 21.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63c69a4247e3a91696daddc8f4ddaa540bba7f3747038cdeefc40aaeea6c9257
|
|
| MD5 |
7483f9efc2f5185287a393535dd12111
|
|
| BLAKE2b-256 |
2dc3535666fe3e57c5c3f2a991ca0b8764c051128fa3f90f5cf60a0b8929663f
|
Provenance
The following attestation bundles were made for mcp_stdio-0.4.5-py3-none-any.whl:
Publisher:
release.yml on shigechika/mcp-stdio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_stdio-0.4.5-py3-none-any.whl -
Subject digest:
63c69a4247e3a91696daddc8f4ddaa540bba7f3747038cdeefc40aaeea6c9257 - Sigstore transparency entry: 1307870294
- Sigstore integration time:
-
Permalink:
shigechika/mcp-stdio@8456f60dc631a756bcd0f5f312c7129dc031f4cc -
Branch / Tag:
refs/tags/v0.4.5 - Owner: https://github.com/shigechika
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8456f60dc631a756bcd0f5f312c7129dc031f4cc -
Trigger Event:
push
-
Statement type: