stdio wrapper¶
mcp-svid-stdio starts a local stdio MCP server with a short-lived access token instead of a static key in its environment.
Usage¶
Example, as an MCP host config entry:
{
"command": "mcp-svid-stdio",
"args": [
"--resource", "http://notes-a:8101/mcp", "--scope", "notes:read",
"--trusted-issuer", "http://authz:8100",
"--allow-http", "--allow-private-network", "--", "my-stdio-server"
]
}
--allow-http and --allow-private-network are needed only because this example uses lab cluster service names over plain http. Without them the wrapper accepts only https URLs that resolve to public addresses, and refuses anything else with a url_refused event on stderr and exit code 2.
The child must read the token from MCP_ACCESS_TOKEN_FILE before each upstream call.
Behaviour¶
- Fetches an access token for
--resourcewith the wrapper's own JWT-SVID (same flow as the agent, see Architecture). - Writes it to
tokenin a private temp dir (mcp-svid-*), mode 0600, replaced atomically. - Starts the child with
MCP_ACCESS_TOKEN_FILEset to that path. Any inheritedMCP_ACCESS_TOKENis removed. - stdin and stdout are inherited, so the MCP stdio stream flows directly between host and child.
- Rewrites the file
--refresh-marginseconds (default 60) before expiry. Inside the margin it retries every 0.5 to 5 seconds. - Forwards SIGINT and SIGTERM to the child.
- On exit, deletes the token file and the temp dir.
Fail closed¶
If refresh keeps failing until the token expires, the wrapper:
- Deletes the token file.
- Sends the child SIGTERM, then SIGKILL if it is still running 5 seconds later.
- Exits with code 75 (
EX_TEMPFAIL).
If the first token fetch fails, the child is never started. Otherwise the wrapper exits with the child's exit code.
--export-token-env¶
Also sets MCP_ACCESS_TOKEN to the first token. A process environment cannot be changed from outside, so the child lives at most one token lifetime: when the exported token expires, the wrapper terminates the child (SIGKILL after the same 5 second grace) and exits with code 75. The MCP host then starts it again, and the new child gets a fresh token. The token file is still written and refreshed in this mode.
| Property | Token file (default) | --export-token-env |
|---|---|---|
| Visible to | Owner UID via file mode 0600 | Same UID via the process environment |
| Inherited by grandchildren | Only the path | The value |
| Refreshed | Yes | No. The child is stopped at the token expiry instead |
| Child lifetime | Until it exits or refresh fails | At most one token lifetime (300s) |
Grandchildren that detach from the child are not stopped and keep the expired value. Use this mode only for children that cannot read a file.
Status¶
Minimal. Children must re-read MCP_ACCESS_TOKEN_FILE per upstream call.