Implementing an MCP Server From Scratch — Five Things the Guide Skips
The MCP server *official guide* gets you to PoC. The *production deployment* that follows hits five things the guide doesn't cover — JSON-RPC translation, per-tool authorization, error semantics, lifecycle, isolation.
If you've implemented an MCP server, the official guide takes you through tool definitions → server boot → connection verification. After that, the path to production hits five things the guide doesn't cover.
This post is the field notes for those five.
1 — The JSON-RPC translation traps
MCP runs on JSON-RPC 2.0. The guide assumes you're using JSON-RPC. Our internal RPC was gRPC. We needed a translation layer, and the details of that layer matter.
Most-frequent breakage:
- Streaming responses — JSON-RPC assumes single response. MCP fakes streaming via progress notifications. Doesn't map cleanly to gRPC streaming
- Cancellation — client cancel must stop progress + clean up. JSON-RPC has no native cancel — needs a separate cancel notification
- Binary data — JSON requires base64. Large binaries (images, files) should ride separate transport
2 — Authorization branches at the tool level, not the server
The guide assumes a server exposes all tools to all clients. In practice, one server exposes partial tools to clients with different permissions.
Fix: per-call evaluation of (client, tool, args). Our graph permission model applies directly. → Permission model on a graph
Receive call →
Verify client identity →
Is the tool call within client's permission? →
Are the args within client's scope? →
ExecuteWithout this branching inside the server, every call shares one permission — security risk.
3 — Error semantics — JSON-RPC codes + MCP meaning
JSON-RPC standard error codes (-32600 to -32099) + additional MCP-defined errors + your domain errors.
Trap — JSON-RPC errors are standard, but MCP-domain errors have ambiguous representation.
Our answer:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000, // JSON-RPC server-defined error
"message": "Authorization failed",
"data": {
"type": "mcp.authorization.denied", // our semantic
"tool": "deploy.production",
"reason": "missing scope: prod.deploy",
"audit_id": "audit-xyz" // for audit trail
}
}
}Domain-error meaning sits in data. Clients use it to show the user a precise message.
4 — Server lifecycle
The guide says initialize → use → terminate. In practice, connections drop and reconnect frequently. Clients assume state survives; servers assume stateless. Conflict.
Fix: separate session store on the server. On client reconnect, restore by session ID. The session holds current tool permissions / in-progress work / context cache.
Default session expiry — 30-minute idle. Infinite while active.
5 — Isolation — one client doesn't affect another
Multiple clients use one server concurrently. While one is in a long-running tool call, others' fast calls must not block.
The guide doesn't address concurrency.
Our answer:
- Separate worker pools per client
- A client's long call only blocks that client's next call
- Global resources (DB connection, external API) get separate rate limits
Without this isolation, one user's heavy request escalates into total service degradation.
What we learned from the five
An MCP server that doesn't address all five runs fine in PoC, then incidents hit 1–3 months into production. The pattern is what we saw — permission leaks, error illegibility, lost sessions, broken isolation.
The MCP server official guide is a get-started guide, not a production guide.
Before you go to production
If you're implementing an MCP server or building MCP-based agent infrastructure, hard-coding explicit answers to even two or three of the five questions above avoids 3–6 months of rework later. Running fine in PoC proves nothing — the incidents arrive 1–3 months into production.
Related posts
When a Product Manager Ships Code, Who Owns the Outage?
In organizations where product managers write code with AI and several agents work at once, who checks what before a change reaches production? A role design for verification, approval, and recovery that is independent of the author, grounded in NIST SSDF, SLSA provenance, and the Google SRE postmortem culture.
John Baek
An Eclipse Plugin for the Agent Era — Task Context Was Already the Problem 20 Years Ago
The problem Mylyn set out to solve in the mid-2000s is the agent context problem. What changed is that the thing reading that context is no longer only a person.
Yeongsang Kim
A VS Code Extension for the Agent Era — What Developers Look At Now
Once writing code got cheap, a developer's time moved to judging and approving. Here is why those jobs cannot live outside the editor, and the choices behind the CollabOps VS Code extension.
Seungbaek Lee