Borrowing it
Nothing to install: this file belongs to shigechika/mcp-stdio. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.
curl -O https://raw.githubusercontent.com/shigechika/mcp-stdio/main/CLAUDE.mdgit clone --depth 1 https://github.com/shigechika/mcp-stdioWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/instructions/shigechika/mcp-stdio/claude-md)<a href="https://agentmods.dev/instructions/shigechika/mcp-stdio/claude-md"><img src="https://agentmods.dev/badge/instructions/shigechika/mcp-stdio/claude-md/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/instructions/shigechika/mcp-stdio/claude-md"><img src="https://agentmods.dev/badge/instructions/shigechika/mcp-stdio/claude-md.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.04060 | $0.04060 |
| Opus 5.5 | $0.01624 | $0.01624 |
| Sonnet 5.5 | $0.00812 | $0.00812 |
| Haiku 4.5 | $0.00406 | $0.00406 |
Grade A, and why
mcp-stdio CLAUDE.md scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 20d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 66 lines — stays where its author put it; the contents beside it link to each section on GitHub.
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Language Policy (Public Repository)
- Code comments, commit messages, documentation, and PR descriptions: English
- README.md in English; README.ja.md in Japanese
Build & Test
# Setup
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# Run all tests
pytest tests/ -v
# Run a single test file or class
pytest tests/test_relay.py -v
pytest tests/test_relay.py::TestWriteLine -v
# Integration harness against python-sdk v2, the 2026-07-28 reference peer
# (#367). Real localhost HTTP and a real relay subprocess, so it is a
# SEPARATE directory the unit gate never walks. Needs the extra; without it
# a conftest guard skips collection.
pip install -e ".[dev,integration]"
pytest tests_integration/ -v
# Build package
pip install build && python -m build
Uses hatchling as the build backend (build-backend = "hatchling.build" in pyproject.toml). Version is defined in src/mcp_stdio/__init__.py (__version__).
Architecture
A gateway between stdio JSON-RPC framing and MCP's HTTP transports, in both directions:
- relay (the original job,
relay.py) — the client side (stdin/stdout in, HTTP out): translates a local stdio MCP host to a remote Streamable HTTP or legacy SSE server. - serve (
server.py,mcp-stdio serve) — the mirror image, the server side (HTTP in, stdio out): publishes a locally-spawned stdio MCP server as a Streamable HTTP endpoint.
Only runtime dependency is httpx (the serve path is stdlib-only).
The substantive modules under src/mcp_stdio/:
relay.py— Two transport implementations sharing stdin/stdout plumbing (file name kept for import compatibility):run()— Streamable HTTP transport (MCP current spec, default). Reads JSON-RPC from stdin line-by-line, streams POST to the remote URL via httpx, parses JSON or SSE responses, writes to stdout. On the modern era (2026-07-28) a dedicated daemon reader thread owns stdin and feeds a FIFO queue, so anotifications/cancelledcan abort the matching in-flight POST by closing its response stream; the legacy era keeps the literal synchronous stdin loop and spawns none of the modern era's threads (stdin reader, listen/resource streams). OAuth machinery is era-independent, though:_start_proactive_refresh()and the--oauth-eagercold-start daemon are both started unconditionally, before the era branch, so either can put a daemon thread on the legacy era too when OAuth is configured. A stdin line whoseparams._metaalready carries theprotocolVersionkey comes from a modern stdio client (#446): its_metais not re-injected, it skips the MRTR bridge, and itssubscriptions/listenruns on its own thread (_ClientListens/_client_listen_loop) so it never blocks the single-dispatch consumer.x-mcp-header→Mcp-Param-*(#459,--mcp-param-headers:moderndefault = modern era only;alwaysalso on a legacy session, the opt-in exception to the legacy freeze that GitHub's hosted server needs): a run()-scoped_ToolHeaderCache(own lock; invalidated bytools/list_changedfrom any stream, including the listen threads) learns from the client'stools/listanswers and drops tools with invalid annotations,_prepare_headersmirrors the arguments, and a-32020correlated to the call's id re-lists once (_PARAM_ID_PREFIX, never on stdout) and retries once; MRTR continuations reuse the opening call's declarations. Handles retry with backoff (3 attempts; after a post-send transport error only_REPLAY_SAFE_METHODSare replayed, nevertools/call, #444), session ID tracking (Mcp-Session-Idheader), 404-based session recovery, and 401-based token refresh. When that refresh fails because the grant is DEAD (_RefreshOutcome.dead, recorded by cli's refresher inrefresh_state),_Reauthorizer(#471, both transports and the MRTR 401 arm) starts the interactive flow on a daemon thread (the same_build_cold_start_logincallable--oauth-eageruses; decided underrefresh_lock, run outside it; one at a time; 60 s cooldown after a failure) and the line gets-32002— it is never re-dispatched inside the rung. The rung passes theAuthorizationthe 401'd request actually carried (None if it carried none; MRTR records it per retry intxn["sent_authorization"]): if the shared headers already hold another value nothing starts and the client just retries. cli's_build_reauth_loginfirst adopts a stored token that differs from the rejected one (no sign-in, refresh token or not), else takestoken_store.reauth_lock(per normalised server key; waits up to--oauth-timeout+ 30 s for a sibling, then re-checks the store) and signs in, rejecting a cached token only while it still renders to that value (ensure_token(reject_access_token=)).--no-oauth-reauthopts out.run_sse()— SSE transport (MCP 2024-11-05 legacy). Spawns a daemon reader thread that maintains a long-livedGET /sseconnection, parsesendpoint/messageevents per the WHATWG SSE spec, and resolves the POST endpoint URL (possibly relative). The main thread reads stdin and POSTs to that endpoint. Auto-reconnects on stream disconnect, synthesizing a-32000error for every request whose reply was still in flight on the dropped stream (tracked in_SseState.pending, drained by_drain_pending; cancelled ids are skipped).- Both paths enforce the MCP cancellation spec's receiver-side SHOULD (and shield the client from canceller-side bugs) via a shared
_CancelTracker+_emitgate: ids seen innotifications/cancelledon stdin are tracked with a 60 s TTL, and any late JSON-RPC response for a tracked id is dropped before it reaches stdout. Disable with--no-cancel-filter. - Signal handlers (
signal.signal) are set from the main thread only — both transports now run daemon threads (run_sse's SSE reader;run()'s modern-era listen/resource streams and stdin reader;run()'s OAuth proactive-refresh and cold-start daemons, on either era), so pytest tests must driverun()andrun_ssefrom the main thread.
cli.py— argparse-based CLI. Builds headers, resolvesMCP_BEARER_TOKEN/MCP_OAUTH_CLIENT_IDenv vars, runs the OAuth flow before relay if--oauthor--oauth-deviceis set, and dispatches torun()orrun_sse()based on--transport.oauth.py— OAuth 2.1 client: RFC 9728/8414 discovery, RFC 7591 dynamic client registration, RFC 7636 PKCE, RFC 8707 resource indicators, authorization code flow with localhost callback server, RFC 8628 device authorization grant, RFC 9470 step-up authorization, token exchange and refresh.token_store.py— Token persistence in~/.config/mcp-stdio/tokens.json(0o600). Stores per-server-URL tokens with client credentials and endpoint URLs for refresh. Migrates legacy~/.mcp-stdio/tokens on first read. Two lock files:_store_lock(blocking, NOT re-entrant) around each save/delete, andrefresh_lock(bounded 30 s wait, then unlocked with a warning) aroundoauth._refresh_cached_token_ex's load → exchange → save so concurrent relay processes never spend the same rotating refresh token (#454);delete_token(expected_refresh_token=...)is compare-and-delete.server.py— themcp-stdio servereverse gateway (dispatched fromcli.pywhenargv[1] == "serve"). Dual-era since #270 Phase 3: one endpoint answers both revisions, and_request_era()classifies each POST body conservatively — modern only on positive evidence (params._metacarries theprotocolVersionKEY, or the method isserver/discover); everything else falls through to the untouched legacy path.- Legacy path (unchanged, AC2). One backend stdio child per MCP session (
SessionRegistry, keyed onMcp-Session-Id) over a stdlibhttp.serverStreamable HTTP endpoint: session minted oninitialize, 400 sessionless, 404 on an unknown id, DELETE to terminate, GET SSE for server-initiated messages. Pinned byte-for-byte bytests_integration/test_serve_legacy_pin.py, which every Phase 3 PR had to keep green with zero diffs. One opt-in exception:--drop-client-capability(#466) removesroots/elicitation/samplingfrom a legacyinitialize'sparams.capabilitiesbefore the child sees it (_drop_client_capabilities), for clients like claude.ai that declarerootsbut never answerroots/list; off is byte-identical. - Modern path (2026-07-28). A request-plane validation ladder (
_validate_modern; first failure wins, in python-sdk v2's order — the header rungs run BEFORE the unsupported-version rung): required_meta→-32602;MCP-Protocol-Version/Mcp-Method/Mcp-Nameagreement, the last sentinel-decoded via relay's_decode_mcp_name→-32020; unsupported version →-32022withdata.supported. Notifications are exempt from the ladder entirely (O9)._dispatch_modernthen serves the request statelessly from aModernBackendPoolchild, keyed on the authenticated principal and NOT on a session (one shared child under no-auth or a static token, one per OAuth user), with the gateway performing theinitialize+notifications/initializedhandshake the modern wire omits and caching the result.server/discoveris synthesised locally and never forwarded (a legacy child would answer-32601); every modern result is stampedresultType: "complete", the six cacheable ops additionally getttlMs(--cache-ttl-ms, default 60000) /cacheScope: "private", and every result carries the child'sserverInfounder_meta. Client ids are remapped to a mintedmcp-stdio/serve/id so concurrent stateless clients sharing one child cannot collide.subscriptions/listenis SERVED by serve itself, never forwarded: SCOPE is the listChanged trio (_LISTEN_FILTER_METHODS, #374) plusresourceSubscriptions(#381, detailed below), honor-all on the three booleans, attach-BEFORE-ack, ack as frame 1 with the honored subset atparams.notificationsand the id atparams._meta[subscriptionId](both nestings are load-bearing — a top-level echo is silently ignored by a compliant client). Every frame is stamped with the subscription id.BackendProcessfans notifications out to attached_ListenStreams (filtering on the reader thread, bounded 1024-deep queue per stream, ≤4 streams per pooled child →-32603/503 pre-ack). Endings: gateway shutdown → terminalresultType: "complete"frame then close (signal_end(graceful=True)+ a boundeddrain_listeners); child death or backlog overflow → abrupt close with NO terminal frame; NEVER a server-sentnotifications/cancelled(the v2 client settles that as LOST). First ending wins. #381 added the fourth field,resourceSubscriptions: honoring is entirely LOCAL (child's advertisedresources.subscribevia_child_supports_resource_subscribe, then sanitize + dedup + cap at_LISTEN_MAX_RESOURCE_SUBSCRIPTIONS=256with truncate-and-honor), so the ack ships BEFORE anyresources/subscribeis driven — the drive runs on a background daemon thread and can never stall the ack or the pump.notifications/resources/updatedgets its OWN routing branch (never folded into_LISTEN_FORWARDED_METHODS, which would make any non-empty URI list match every URI and leak across streams); matching is exact string equality, no normalization. URIs are refcounted per child inBackendProcess._resource_refsunder a dedicated_sub_lockHELD ACROSS the send (order_sub_lock->_lock, never reversed): subscribe on the first reference, unsubscribe on the last, ids from the existing_mint_modern_id()._ListenStream.torn_downcloses the async-drive-vs-sync-release race. Failure is reply-then-degrade (log once per URI per stream via_ListenStream.subscribe_failure_logged, #388 review, keep honored)._UNDELIVERABLE_NOTIFICATION_FLAGSstill listsresources.subscribeas the DEFAULT, lifted per-child by_synthesize_discover_result'skeep=on the same predicate the ack uses. O16 is closed by construction, zero production code:notifications/messageis never in any listen-forward set, serve's modern face has no other streaming channel to gate, and SEP-2577 deprecated the feature. Pool lifecycle (#376): entries carry aholdscheckout refcount (taken byget_or_create, released in_dispatch_modern'sfinally) which — together withhas_pendingand the PENDING check — forms the single_reapable_lockedpredicate shared by cap-eviction and themodern-pool-reaperidle thread (--modern-idle-ttl, 0 = off);holdsis also #374's attach seam.--modern-onlyrefuses legacy callers after the auth gate (GET/DELETE 405 +Allow, legacyinitialize→-32022).--accept-claimless-resource-read(#469, opt-in) is the one exception to D5's positive-evidence rule: aresources/readrequest with noMcp-Session-Id, noMCP-Protocol-Versionand no_metaprotocol version (the Claude iOS MCP App read) gets the claim filled in by_claimless_resource_readand goes to_dispatch_modernwithout_validate_modern(whose version rungs are exactly what it lacks), but any routing header it does send must still agree with the body (_validate_claimless_routing_headers,-32020). A partial claim is not promoted: a_metaversion alone is modern and meets the full ladder; a version header alone stays legacy (D5 reads the body) and gets the sessionless 400. - Auth is optional, layered, and applies to both eras: open by default,
--auth-token(or theMCP_STDIO_SERVE_TOKENenv var, preferred so the token isn't exposed inps) for a static bearer, or--enable-oauthfor an embedded OAuth 2.1 authorization server with optional--token-storepersistence. Clients come from DCR or, opt-in, from Client ID Metadata Documents (#463):--allow-client-id-urlallowlists exact URLs, and only those are ever fetched — at/authorize, by_ClientMetadataCache(never under_OAuthProvider._lock; one flight per URL, and waiters behind a failed fetch take its outcome instead of fetching again), through_fetch_client_metadata(stdlibhttp.client, every resolved address must be public — IPv6 that embeds IPv4 is judged by the IPv4 — connection pinned to a vetted address, no redirects, 200 only, 5 KB cap, a truncated body is a transport failure, one deadline enforced by a watchdog that shuts the socket down). The document'sredirect_urisare the registration (--allow-redirect-uridoes not apply); a transport failure may fall back to the last validated copy for 24 h, a validation failure never does. These clients live in memory only — codes and grants already carry theclient_idstring; the token endpoint only re-checks that a URL-shapedclient_idis still allowlisted (_client_still_allowed). A failed fetch is not retried for 30 s (_retry_after), 404/410 is a withdrawal, andclient_id_metadata_document_supportedis NEVER advertised: it would switch every CIMD-capable client off DCR onto its own non-allowlisted URL (claude.ai's No sign-in mode sends its URL without checking the flag). Every request'sOriginis checked first (_reject_bad_origin, #449): absent passes, an http(s) loopback origin (localhost,*.localhost, 127/8,::1) / the--public-urlorigin / an exact--allow-originentry (any scheme, e.g.chrome-extension://) passes, anything else (includingnull) gets 403 and the connection is closed before the body is read — never derived fromHost, which a DNS-rebinding request controls. IncomingHost/X-Forwarded-Hostvalues are sanitized against_HOST_ALLOWEDbefore they reach theWWW-Authenticatechallenge / metadata responses. Stdlib only — adds no runtime dependency.
- Legacy path (unchanged, AC2). One backend stdio child per MCP session (
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 20d ago Changed · +836 tokens per session 9a04deb41922
- 21d ago Changed · +455 tokens per session 6410b04566c5
- 1mo ago First seen · 66 lines · 2,769 tokens per session scan A 0a3457f531de
mcp-stdio CLAUDE.md is an instructions file published in the GitHub repository shigechika/mcp-stdio (9 stars, last pushed yesterday), licensed MIT. It adds 4,060 tokens to every session, about $0.0162 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other instructions, from other repositories
vscode buildNext.instructions.md
Working notes and architecture documentation for the new esbuild-based build system in build/next. Use when making changes to the new build pipeline (transpile/bundle commands, NLS plugin, source-map handling, resource copying, or self-hosting watch tasks).
next.js AGENTS.md
AGENTS.md instructions for vercel/next.js, covering next.js development guide, codebase structure, monorepo overview, core package: packages/next and other important packages.
vscode oss-third-party-notices.instructions.md
Instructions for microsoft/vscode, covering vs code oss third-party-notices pipeline, architecture, pipeline flow in ci, cache eligibility and rollout and applying the notice (cutover).
langchain AGENTS.md
AGENTS.md instructions for langchain-ai/langchain, covering global development guidelines for the langchain monorepo, corridor security analysis, project architecture and context, monorepo structure and development tools & commands.
vscode copilot-instructions.md
Copilot instructions for microsoft/vscode, covering vs code copilot instructions, project overview, root folders, core architecture (src/ folder) and built-in extensions (extensions/ folder).
deno copilot-instructions.md
Copilot instructions for denoland/deno, covering deno development guide for github copilot, network access, high level overview, key directories and key files to understand first.