Mcp Stdio — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Mcp Stdio (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<!-- mcp-name: io.github.shigechika/mcp-stdio -->
English | 日本語
Stdio-to-HTTP gateway — connects MCP clients to remote HTTP MCP servers.
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:#fffBearer tokens, custom headers, and OAuth 2.1 credentials are forwarded to the remote server.
--transport. SSE parser follows the WHATWG Server-Sent Events spec./.well-known/oauth-protected-resourceresource field validation — warn on mismatch, continueWWW-Authenticate: Bearer resource_metadata= hint — probes the server before discovery so servers that publish PRM at a non-standard URL are found without well-known path guessingissuer validation — reject a cross-origin issuer (AS mix-up guard), warn on a same-origin mismatch (trailing slash / path / case) and continueresource parameter in authorization, token exchange, and refresh requestscode_challenge_method with an 86-char code_verifierresource indicator (RFC 8707)authorization_pending / slow_down (interval +=5 s) / expired_token / access_denied handlingurn:ietf:params:oauth:grant-type:device_code in grant_types (RFC 7591 §2)token_endpoint_auth_method chosen from token_endpoint_auth_methods_supported in AS metadata (prefers none → client_secret_post → client_secret_basic)client_secret_expires_at handling — auto re-register on expiryclient_secret_basic: Authorization: Basic header with percent-encoded credentials (applied to code exchange, token refresh, and Device Authorization Grant polling)Authorization: Bearer <token> request headerRetry-After (delta-seconds or HTTP-date) up to a 60-second cap on both 429 (Too Many Requests) and 503 (Service Unavailable) — the two spec-sanctioned Retry-After carriers (RFC 9110 §10.2.3) — then surfaces the status so the client can decide (cf. modelcontextprotocol/typescript-sdk#1892)nextCursor for tools/list / resources/list / resources/templates/list / prompts/list and merges the pages into one response, so clients that drop pages beyond the first still see the full list (cf. anthropics/claude-code#39586)U+2028 / U+2029 (legal in JSON, but JavaScript line terminators) in upstream responses so clients that treat them as line breaks cannot mis-frame the output; lossless (cf. modelcontextprotocol/typescript-sdk#2155)tools/call request whose arguments is null to {} so strict servers that reject the null form accept the call; on by default, opt out with --no-normalize-arguments (cf. modelcontextprotocol/typescript-sdk#2012)notifications/cancelled on stdin and drops any late upstream response carrying one of those ids before it reaches the client, per the MCP cancellation spec; on by default (60 s TTL), opt out with --no-cancel-filter (cf. anthropics/claude-code#51073)protocolVersion from the initialize response and injects MCP-Protocol-Version on every subsequent Streamable HTTP request (MCP spec rev 2025-06-18); servers that enforce the header would otherwise reject post-initialize requests with 400 Bad RequestBearer error="insufficient_scope" challenge, re-authorizes for the union of the granted and required scopes (RFC 9470 / MCP step-up; cf. anthropics/claude-code#44652)--bearer-token flag or MCP_BEARER_TOKEN env var-H / --headerHTTP_PROXY, HTTPS_PROXY, NO_PROXY env vars via httpxpip install mcp-stdioOr with uv:
uv tool install mcp-stdioOr run directly without installing:
uvx mcp-stdio https://your-server.example.com:8080/mcpOr with Homebrew:
brew install shigechika/tap/mcp-stdiomcp-stdio https://your-server.example.com:8080/mcpWith 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_TOKENWith 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/mcpWith OAuth 2.1 Device Authorization Grant (RFC 8628, for headless/SSH environments):
mcp-stdio --oauth-device https://your-server.example.com:8080/mcpFor legacy MCP servers using the 2024-11-05 SSE transport:
mcp-stdio --transport sse https://your-server.example.com:8080/sseCheck connectivity before use:
mcp-stdio --check https://your-server.example.com:8080/mcp
# For an SSE server, pass --transport sse so --check runs the legacy
# GET/endpoint/POST handshake instead of a Streamable HTTP probe:
mcp-stdio --check --transport sse https://your-server.example.com:8080/sseAdd 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:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json~/.config/Claude/claude_desktop_config.jsonclaude mcp add my-remote-server \
-e MCP_BEARER_TOKEN=YOUR_TOKEN \
-- mcp-stdio https://your-server.example.com:8080/mcpmcp-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 (browser flow)
--oauth-device Enable OAuth 2.1 Device Authorization Grant (RFC 8628, headless)
--client-id ID Pre-registered OAuth client ID (or set MCP_OAUTH_CLIENT_ID)
--oauth-scope SCOPE OAuth scope to request
--oauth-refresh-leeway SECONDS
Proactively refresh tokens this many seconds before
expiry (default: 60, or MCP_OAUTH_REFRESH_LEEWAY)
--oauth-timeout SECONDS
Seconds to wait for the interactive OAuth flow (browser
callback / device-code confirmation) before giving up
(default: 120; OAuth only)
--no-resource-indicator
Omit the RFC 8707 resource parameter from all OAuth
requests. Required for AS that reject it, such as
Microsoft Entra ID v2 with api:// scopes (AADSTS9010010).
Persisted in the token store so proactive refreshes
and step-up flows stay consistent
-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)
--sse-read-timeout SEC Idle read timeout on the SSE GET stream
(default: 300; 0 disables; SSE transport only)
--no-tcp-keepalive Disable TCP keepalive on the HTTP socket
--no-cancel-filter Disable the cancel-aware response filter (drops late
responses for ids cancelled via notifications/cancelled)
--no-normalize-arguments
Disable rewriting a tools/call request's
arguments:null to {} before forwarding
--check Check connection and exit
-V, --version Show version
-h, --help Show helpRun mcp-stdio --help for the full per-flag detail (platform notes and issue references are more verbose than this table).
serve modeThe default mode bridges stdio → HTTP (client side). The serve subcommand is the mirror image — HTTP → stdio — exposing a local stdio MCP server as a Streamable HTTP MCP endpoint so clients that cannot spawn it locally can reach it over the network:
flowchart BT
A["MCP client<br>Claude Code / Desktop<br>(or mcp-stdio --oauth)"]
B("mcp-stdio serve<br><b>HTTP → stdio</b> gateway<br>auth: none / static token /<br>embedded OAuth 2.1 AS")
C["local stdio<br>MCP server"]
A <== "Streamable HTTP<br>Bearer / OAuth 2.1 (PKCE)" ==> B
B <-- "stdio (spawned child)" --> CThis is the mirror of the client-side diagram at the top: there mcp-stdio is stdio → HTTP; here it is HTTP → stdio.
mcp-stdio serve --port 8080 -- python -m my_mcp_serverThen point any MCP client (including mcp-stdio itself) at it:
mcp-stdio --check http://127.0.0.1:8080/mcphttp.server) — adds no runtime dependency.plus a GET SSE channel for server-initiated messages.
--auth-token / MCP_STDIO_SERVE_TOKEN) — acts as an OAuthResource Server: MCP requests require Authorization: Bearer <token>, and a 401 advertises RFC 9728 Protected Resource Metadata at /.well-known/oauth-protected-resource.
--enable-oauth) — a minimal OAuth 2.1 AuthorizationServer (PKCE auth-code, RFC 7591 dynamic client registration, refresh, opaque in-memory tokens, stdlib only). The mcp-stdio client's --oauth flow then works against the gateway.
Static-token example (token via env so it is not visible in ps):
MCP_STDIO_SERVE_TOKEN=your-secret mcp-stdio serve --port 8080 -- python -m my_mcp_server
mcp-stdio --bearer-token your-secret --check http://127.0.0.1:8080/mcpEmbedded-OAuth example. User authentication is delegated to a fronting reverse proxy that asserts the logged-in user via a header (--trusted-user-header, only trusted behind a proxy that strips client copies). --dev-user is an insecure loopback-only shortcut for local testing:
mcp-stdio serve --enable-oauth --public-url http://127.0.0.1:8080 \
--dev-user alice --port 8080 -- python -m my_mcp_server
mcp-stdio --oauth http://127.0.0.1:8080/mcpOptions: --host (default 127.0.0.1), --port (default 8080), --path (default /mcp), --auth-token TOKEN (or MCP_STDIO_SERVE_TOKEN, preferred); and for the embedded AS: --enable-oauth, --public-url URL (pins the issuer; recommended behind a proxy), --trusted-user-header HEADER, --dev-user USER (insecure, testing only), --access-token-ttl SECONDS. In-memory tokens mean a restart invalidates issued tokens (the client re-runs --oauth). The backend command follows the options (an optional -- separator is supported).
See WORKAROUNDS.md for known issues in Claude Code, mcp-remote, the MCP SDKs, and Windows that mcp-stdio addresses.
--oauth (browser) or --oauth-device (headless, RFC 8628) is set, obtains an access token (cached → refresh → browser/device flow)--bearer-token / -H auth the 401 is surfaced to the clientTransport details:
Mcp-Session-Id header and re-initialized automatically on 404. The negotiated MCP-Protocol-Version header is sent on every post-initialize request (spec rev 2025-06-18).GET stream delivers responses and the initial endpoint event containing the POST URL; the stream auto-reconnects on disconnect.OAuth tokens are stored in ~/.config/mcp-stdio/tokens.json (permissions 0600).
MIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.