Problem
mcp-stdio's serve mode is a great way to publish an existing stdio MCP server over HTTP, but it doesn't help with writing that stdio server in the first place. Most small MCP servers reach for mcp.server.fastmcp.FastMCP for that job, which means they inherit a real risk: a major-version bump of the mcp SDK removed mcp.server.fastmcp outright, breaking every FastMCP-based server on the machine in one shot (this actually happened to a fleet of stdio servers I run behind mcp-stdio serve — a hard version pin was the only quick fix).
mcp-stdio itself dodges this entirely (zero dependency on the mcp package, just httpx), which got me wondering whether the same philosophy could extend one layer down — to the servers serve wraps.
What I measured
I audited three of my own public stdio MCP servers (zapi-mcp, keycloak-mcp, junos-mcp — 6/30/24 tools, 601/3155/2991 lines) to see how much of FastMCP they actually use. The answer: almost nothing beyond two things —
@mcp.tool() — JSON Schema generation from type hints + docstring
mcp.run(transport="stdio") — the stdio JSON-RPC loop (initialize/tools/list/tools/call dispatch + error translation)
None of the three touch Context injection, resources, prompts, or lifespan hooks. That's a much smaller surface than I expected, which makes a from-scratch replacement (probably 300–500 lines, using e.g. pydantic.TypeAdapter for schema generation) look feasible.
The question
I don't think this belongs inside mcp-stdio — "one small package, one runtime dependency, two jobs" is exactly why I reach for it, and bolting a server framework on would blur that. But I'd be curious whether:
- you've seen this need from other
serve users,
- there's prior art you'd point to instead of reinventing it, and
- if a companion library did exist, whether you'd want
serve's docs to mention it (or keep them strictly transport-agnostic).
No urgency either way — mostly looking for a second opinion before sinking time into a PoC.
Problem
mcp-stdio's
servemode is a great way to publish an existing stdio MCP server over HTTP, but it doesn't help with writing that stdio server in the first place. Most small MCP servers reach formcp.server.fastmcp.FastMCPfor that job, which means they inherit a real risk: a major-version bump of themcpSDK removedmcp.server.fastmcpoutright, breaking every FastMCP-based server on the machine in one shot (this actually happened to a fleet of stdio servers I run behindmcp-stdio serve— a hard version pin was the only quick fix).mcp-stdio itself dodges this entirely (zero dependency on the
mcppackage, justhttpx), which got me wondering whether the same philosophy could extend one layer down — to the serversservewraps.What I measured
I audited three of my own public stdio MCP servers (zapi-mcp, keycloak-mcp, junos-mcp — 6/30/24 tools, 601/3155/2991 lines) to see how much of FastMCP they actually use. The answer: almost nothing beyond two things —
@mcp.tool()— JSON Schema generation from type hints + docstringmcp.run(transport="stdio")— the stdio JSON-RPC loop (initialize/tools/list/tools/call dispatch + error translation)None of the three touch Context injection, resources, prompts, or lifespan hooks. That's a much smaller surface than I expected, which makes a from-scratch replacement (probably 300–500 lines, using e.g.
pydantic.TypeAdapterfor schema generation) look feasible.The question
I don't think this belongs inside mcp-stdio — "one small package, one runtime dependency, two jobs" is exactly why I reach for it, and bolting a server framework on would blur that. But I'd be curious whether:
serveusers,serve's docs to mention it (or keep them strictly transport-agnostic).No urgency either way — mostly looking for a second opinion before sinking time into a PoC.