Build a fresh MCP server and transport per client session
One instance per session stops responses from going to the wrong client.
Before: shared server
- One McpServer shared by all HTTP clients
- Responses matched by JSON-RPC id only
- Ids start at 0, so collisions happen
After: one server per session
- New McpServer per client session
- New transport per client session
- SDK rejects second connect() on shared instance
Why it matters
Your MCP server answers AI clients' tool calls over HTTP; if you share one server or transport across clients, one client can get another client's responses and notifications (GHSA-jm63-cq47-j5jp (opens external site)). SDK clients number requests from 0, so JSON-RPC ids collide, and messages are matched by id alone. That is how the MCP TypeScript server shared-transport bug (opens external site) mixed up traffic between clients.
Steps
- Upgrade to @modelcontextprotocol/server 2.3.0 or later. The patched SDK refuses to be shared and rejects a second connect() with
ALREADY_CONNECTED. - Create a fresh McpServer instance for each client session. Do not keep a global one.
- Create a fresh transport for that session and connect it to the new server.
- Dispose both when the session ends, so nothing gets reused by the next client.
- Run a test with two clients connected at the same time and confirm each one only gets its own responses.
Common mistakes
- Reusing one McpServer but creating a new transport per request. The SDK still rejects a second connect(), because the server instance itself is the shared thing.
- Assuming JSON-RPC ids are unique across clients. They start from 0, so two clients will both send id 0, 1, 2 and collide.
- Only upgrading the package without changing how you build instances. The new version fails loudly, but you still need per-session instances to actually serve multiple clients.
Checklist
0 of 6 done