mcp-stdio-core -- JSON-RPC stdio Framing + Dispatch (Core)
September 5, 2026 ยท View on GitHub
Generated: 2026-08-24 / f3642fcda
OVERVIEW
The lowest-level core package: JSON-RPC 2.0 transport over stdio (line-mode and Content-Length framed), an event-loop server with idle timeout, response builders, and an isPlainRecord guard. Zero runtime/peer dependencies; imports nothing from the workspace, consumed by every MCP-layer package. Package: @oh-my-opencode/mcp-stdio-core.
KEY FILES (5 source, all flat in src/)
| File | Subpath export | Role |
|---|---|---|
types.ts | ./types | JsonRpcId/Error/Result/Response, McpToolDescriptor, TextContent, McpLifecycleLog |
record.ts | ./record | isPlainRecord(value) type guard |
responses.ts | ./responses | successResponse, errorResponse, jsonRpcId, messageFromError |
server.ts | ./server | runJsonRpcStdioServer(config): async-generator loop, idle timeout, McpRequestHandler, exits on terminal output errors |
transport.ts | ./transport | readStdioJsonRpcMessages (async gen), writeStdioJsonRpcResponse, dual framing |
CONSUMERS
lsp-core/src/mcp.ts(primary): LSP MCP server.ast-grep-mcp/src/mcp.ts: ast-grep MCP server.git-bash-mcp/src/mcp.ts: Git Bash MCP server.lsp-daemon/src/proxy.ts: stdio MCP proxy; also imports./recordfromdaemon-client.ts,request-routing.ts,ipc-protocol.ts.
NOTES
- Two framing modes:
"line"(\n-delimited) and"framed"(Content-Length:header per MCP spec); auto-detected by scanning the buffer prefix forcontent-length:. - Idle timeout uses
timer.unref(): the timeout never keeps the process alive. - Handler contract: return
undefinedto skip silently;onHandlerErrorcatches exceptions;parseErrorResponsecustomizes JSON parse errors. - Output writes are awaited; closed output stops the loop:
writeStdioJsonRpcResponseis async andwriteChunkremoves its one-shoterrorlistener after settle.writeResponsecatches terminal output errors (EPIPE,ERR_STREAM_DESTROYED,ERR_STREAM_WRITE_AFTER_END), logsoutput_error, and returns false so the read loop exits; non-terminal write errors still propagate. - Keep zero dependencies.
.jssuffix on relative imports (ESM). This is the floor of the package layering; it must stay leaf. - Parent:
packages/AGENTS.md.