Repository navigation
Serve the 2026-07-28 MCP revision, on SDK v2 and zod 4 - #10
Merged
Merged
Conversation
The 2026-07-28 spec shipped as a stable release line under new package
names, not as a beta: @modelcontextprotocol/server 2.0.0 replaces the
monolithic @modelcontextprotocol/sdk. Previous note in this repo that it
was not production ready was reading the beta-era announcement.
WHAT A 2026-07-28 CLIENT NOW GETS, on both /mcp and /mcp/compact:
- no initialize handshake; every request stands alone with its protocol
version, client info and capabilities in _meta
- Mcp-Method and Mcp-Name header routing, so a gateway dispatches and
authorizes without parsing the body
- server/discover for capabilities and instructions in one call
- ttlMs and cacheScope on tools/list, prompts/list, resources/list and
server/discover. tools/list is cacheScope private, never public: it is
filtered per credential, so a shared cache would hand one key's
catalogue to another. 60s matches the scope cache behind it.
Legacy clients are untouched: createMcpHandler runs with
legacy: 'stateless', and an initialize on 2025-11-25, 2025-06-18 or older
negotiates exactly as before. Verified live against both eras on both
endpoints: same 31 and 15 tools, same bytes.
zod 3 to 4 came with it. The generated JSON Schema changed only by being
MORE precise: v1's converter silently dropped constraints on refined
strings (emitting {} for trimmed, length-bounded fields) and used
format: uuid where v2 emits the explicit pattern. Diffed all 31 input and
24 output schemas property by property before and after: no property,
required entry, or enum lost anywhere, money-path schemas byte-identical
in substance.
Express feeds the handler a rebuilt web Request because express.json()
has already drained the socket, and the response is streamed back rather
than buffered. CORS now allows Mcp-Method and Mcp-Name.
163 tests, 7 new covering the modern path end to end through
createMcpHandler: no-handshake tools/list, cache hints, server/discover,
compact discover, scope filtering, header-routed tools/call, and the
rejection when the routing header and body disagree.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The premise I got wrong
PR #9 deferred the 2026-07-28 revision because the announcement I read was the beta one. It shipped as a stable release line on 2026-07-28 under new package names:
@modelcontextprotocol/server2.0.0 replaces the monolithic@modelcontextprotocol/sdk. So this does it.What a 2026-07-28 client now gets, on
/mcpand/mcp/compactinitializehandshake. Every request stands alone, carrying its protocol version, client info and capabilities in_meta.Mcp-MethodandMcp-Nameheader routing, so a gateway can dispatch and authorize without parsing the body.server/discover: capabilities, instructions and supported versions in one call.ttlMsandcacheScopeontools/list,prompts/list,resources/listandserver/discover.tools/listisprivate, neverpublicbecause it is filtered per credential, so a shared cache would hand one key's catalogue to another. 60s matches the scope cache behind it.Legacy clients are untouched.
createMcpHandlerruns withlegacy: 'stateless', so aninitializeon 2025-11-25, 2025-06-18 or older negotiates exactly as before.zod 3 to 4
Required by the v2 SDK. The generated JSON Schema changed only by being more precise: v1's converter silently dropped constraints on refined strings (emitting
{}for trimmed, length-bounded fields), and usedformat: uuidwhere v2 emits the explicit pattern. I captured the full v1 catalogue first and diffed all 31 input schemas and 24 output schemas property by property. Nothing lost;place_orderandget_barsbyte-identical in substance.Plumbing
Express hands the handler a rebuilt web
Request, becauseexpress.json()has already drained the socket. The response is streamed back rather than buffered, and cancels the reader if the client hangs up. CORS allowsMcp-MethodandMcp-Name.zod-to-json-schemais gone: zod 4 converts natively, with the same target the SDK uses.Verification
163 tests, 7 new in
tests/modern-protocol.test.tsdrivingcreateMcpHandlerdirectly. Live over HTTP on both endpoints and both eras:/mcp/mcp/compactDeploy
Not git-triggered, and
--force-new-deploymentalone ships nothing: the task definition pins the image by digest. S3 zip, CodeBuild, register a new task-def revision with the new digest, update the service, then confirm the running tasks'imageDigest.