The emergence of advanced AI models has made it necessary to create standardized techniques for supplying them with real-time, external, or domain-specific data. A technical specification known as the Model Context Protocol (MCP) outlines the client-server communication necessary to provide this context. An MCP server, an application in charge of exposing specialized data sources like issues from Linear, design files from Figma, or repository code from GitHub, communicates with an MCP client (such as Gemini or GitHub Copilot). The LLM can perform tasks and reasoning that would be impossible with its base knowledge alone thanks to this client-server model. This fundamental feature of providing context to models was initially put forth in architectures such as Anthropic's Ask to Ask (A2A) method.1.
Despite the protocol's power, building a production-ready MCP server often encounters significant friction, particularly within the old classical TypeScript and Node.js ecosystem. The official SDK, while functional, adheres to an older architectural paradigm that clashes with the patterns established by modern meta-frameworks like Next.js, SolidStart, and SvelteKit. This friction creates unnecessary complexity, dependency bloat, and architectural limitations, which TMCP (TypeScript MCP) was created to resolve2.
The Modern Server Landscape and The Official SDK Gap
The modern JavaScript server ecosystem is overwhelmingly defined by a universal, standardized pattern: the application endpoint receives a Web Request object as input and returns a Web Response object as output. This structure is consistent across Bun, Cloudflare Workers, Dino, SvelteKit, and Next.js2.
However, the official MCP SDK does not adhere to this standardized pattern. Instead, it relies heavily on the legacy Node.js/Express request/response objects2. The core incompatibility stems from the difference in how the response is handled:
-
Modern Web Standard: Functions return a
Response
object. -
Official MCP SDK: Functions require the server to write to a passed-in
Node.js Response
object via methods likeres.status()
andres.json()
2.
This structural difference necessitates complex workarounds when attempting to deploy an MCP server within modern frameworks. Solutions like the node-fetch-server
or Vercel's proprietary MCP handler
library2 must be employed to act as translation layers. These handlers perform a labor-intensive conversion, collecting data written to a fake Node response object and then constructing an actual Web Response object to return to the caller. This introduces middleware overhead and unnecessary complexity.
Furthermore, the reliance on older architectural choices leads to significant dependency bloat2. The official SDK has a hard dependency on packages like:
express
express-rate-limit
cors
-
zod
v3 zod-to-json-schema
This forces developers using lighter or framework-agnostic runtimes to include an entire Express-based server stack in their dependency tree, even if they only need the core protocol logic. Critically, the SDK's dependency on zod-to-json-schema
locks the implementation into Zod v3, preventing users from upgrading to newer versions or utilizing alternative, potentially smaller, validation libraries like Valibot or Archtype2.
Building with TMCP: A Type-Safe and Modular Approach
TMCP's foundational insight is that the Model Context Protocol is, at its core, simply a JSON-RPC 2.0 server2. By stripping away the heavy Express and Node.js dependencies, TMCP replaces them with a minimal JSON-RPC library, focusing purely on method declaration and payload handling.
This architectural shift allows TMCP to deliver a consistently type-safe and highly flexible API. Unlike the official SDK, which uses positional arguments and different structures for various components2, TMCP uses a single, concise configuration object for defining all core protocol elements: tools, resources, and prompts.
The Consistent API Design
The following TypeScript snippets illustrate the clean, object-based, and type-safe API provided by TMCP:
// TMCP Tool Definition
server.addTool({
name: "getGreeting",
description: "Returns a friendly greeting message.",
// Consistent 'schema' property for validation/documentation
schema: TMCPAdapter.object({
name: TMCPAdapter.string(),
}),
implementation: ({ name }) => {
return { message: `Hello, ${name}!` };
}
});
// TMCP Dynamic Resource Template
server.addResourceTemplate({
name: "UserPosts",
description: "A list of recent posts for a given user.",
uri: "/users/{username}/posts", // Clean URI template
// Type-safe parameter definition
paramsSchema: TMCPAdapter.object({
username: TMCPAdapter.string()
}),
list: ({ username }) => {
// TMCP automatically infers and types 'username' from the schema
console.log(`Listing posts for: ${username}`);
return [{ title: "First Post", uri: `/users/${username}/posts/1` }];
},
complete: ({ param }) => {
// Used for parameter completion—API mirrored across templates and prompts
return [{ value: "paolo", description: "Paolo Ricciuti" }];
}
});
This design ensures that developers are not "surprised by the API"2; the core logic for schema definition and completion functions is identical regardless of whether a tool, a resource template, or a prompt is being configured.
Validation Library Agnostic
TMCP embraces the modern concept of standard schema interfaces, similar to libraries that unify validation output. It does not force a dependency on any specific validation library. Instead, it provides optional adapter packages:
-
@tmcp/adapter-zod
(allowing Zod v4+) @tmcp/adapter-valibot
@tmcp/adapter-archtype
-
@tmcp/adapter-effect
(16:15)
The chosen adapter handles the necessary conversion of the schema definition into the JSON Schema required by the Model Context Protocol, eliminating the hard dependency on zod-to-json-schema
and allowing the developer to use their preferred library for type-safe validation.
Additionally, TMCP handles complex elicitation responses internally. If an implementation requires an elicitation message, the developer simply uses their chosen validation schema, and TMCP automatically converts it to the required JSON Schema for the protocol, removing the need for manual, error-prone JSON schema typing2.
Behind the Scenes: Architectural Decoupling for Serverless Deployment
The primary architectural achievement of TMCP is the complete decoupling of the protocol's core logic from both the transport layer and session management.
1. Transport Agnosticism
Since the core is a simple JSON-RPC server, the transport mechanism is implemented via lightweight, optional adapter packages:
-
@tmcp/transport-stdio
: Installs only what is needed for a standard I/O server. -
@tmcp/transport-http
: Provides a dedicated handler for HTTP requests.
The HTTP transport handler is designed to only process routes relevant to the MCP server. If an incoming request does not concern the protocol, the handler returns null
, allowing the developer to easily implement a middleware pattern that either serves the MCP context or returns a standard web response (e.g., a website or a 404 error)2.
2. Async Local Storage for Session Isolation
The official SDK requires the developer to manually handle session instantiation and wire up the new server and transport for every new connection or session. This is burdensome.
TMCP abstracts session management using Async Local Storage (ALS). ALS is a Node.js mechanism that allows data (like session context) to be stored and retrieved asynchronously throughout the execution context of a single request, even across multiple asynchronous calls. Every new session is automatically isolated using ALS, ensuring that session data cannot leak or link between different simultaneous requests, providing robust and invisible session management out-of-the-box.
3. Solving the Serverless Notification Problem
One of the most significant deployment issues with the official SDK arises when attempting to distribute the server across multiple instances, particularly in a serverless environment. The MCP protocol requires a handle to the original request stream (typically a Server-Sent Events, or SSE, connection) to send asynchronous notifications back to the client. This stream cannot be easily maintained or replicated across multiple stateless serverless functions.
TMCP solves this with an abstracted Session Manager Pub/Sub pattern. It allows the server to decouple the notification generation from the active stream connection by using a persistent external store as a pub/sub channel:
@tmcp/session-manager-redis
@tmcp/session-manager-postgres
-
@tmcp/session-manager-durable-object
(for Cloudflare)
This architectural pattern ensures that notifications generated on one serverless instance can be routed via the persistent pub/sub channel back to the instance that is currently maintaining the client's SSE connection, finally enabling robust, distributed deployment of MCP servers.
My Thoughts
The creation of TMCP is a crucial demonstration of how community-driven development can provide essential refinements to nascent protocols. The library effectively addresses the two most pressing technical issues with the official SDK: the impedance mismatch with modern web architecture and the constraints imposed by rigid dependencies. By pivoting to a lightweight JSON-RPC core, TMCP has created an architecture that is inherently more testable, modular, and performant.
The structural differences between TMCP and the official SDK are so profound—especially concerning the fundamental handling of requests, responses, and dependencies—that the implementation is essentially a complete overhaul. As noted in the follow-up discussion, these differences strongly suggest that the official SDK will eventually require a V2 rewrite to adopt cleaner, more modern patterns and overcome these core structural limitations. Until that time, the clean, type-safe API, combined with modular transports and the innovative solution for serverless notification management, positions TMCP as the superior choice for professional developers seeking a reliable, maintainable foundation for their MCP projects.
Acknowledgements
Gratitude is extended to Paolo Ricciuti from Mainmatter for sharing this valuable technical work. Thank's to MCP Developers Summit for hosting the discussion TMCP: A Modern TypeScript Way to Build MCP Servers2. Finally, thank you to the broader MCP and AI community for driving the standards and tooling forward.
References
Anthropic A2A Documentation and Early LLM Protocol Specification
Top comments (4)
Intresting read!
Thanks Ma'am
Looks quite promising
Thanks Sir. Glad you liked it!!!