Skip to content

feat(server): adopt MCP 2026-07-28 stateless spec over HTTP - #432

Merged
davidwkeith merged 2 commits into
mainfrom
feat/mcp-2026-stateless
Aug 10, 2026
Merged

feat(server): adopt MCP 2026-07-28 stateless spec over HTTP#432
davidwkeith merged 2 commits into
mainfrom
feat/mcp-2026-stateless

Conversation

@davidwkeith

Copy link
Copy Markdown
Contributor

Summary

  • Migrates the MCP server to the v2 TypeScript SDK (@modelcontextprotocol/server + @modelcontextprotocol/node, explicit zod@^4.2) and adopts the MCP 2026-07-28 stateless spec on the HTTP path: createMcpHandler serves the modern protocol (_meta envelope, Mcp-Method/Mcp-Name headers, resultType, cache hints) and its built-in legacy: 'stateless' fallback keeps answering 2025-era Streamable HTTP traffic — including the initialize handshake the shipped Anglesite-app MCPClient (pinned 2024-11-05) sends — from the same buildServer factory, per-request, with no session minted. The hand-rolled Mcp-Session-Id session map is gone.
  • Tool registrations move from v1 server.tool() to v2 registerTool() with explicit z.object() input schemas; stdio stays on the same server via the v2 stdio transport (verified to still negotiate 2024-11-05 with the app's raw JSON-RPC handshake).
  • The v1 SDK stays as a devDependency so the old client remains exercised in tests for the drain window; @modelcontextprotocol/client v2 covers the modern era.

Paired PR check

  • This change is self-contained to the plugin (skills / hooks / template / docs / MCP server with no consumer-visible contract change).
  • This change needs a paired PR in Anglesite/Anglesite-app (MCP message schema, template fields the app reads, hook surface, anything the native app embeds or shells out to). Link it here: Adopt MCP 2026-07-28 stateless spec (sidecar first, then app client) Anglesite#1277 (app PR to follow — bump protocolVersion, drop the initialize/session plumbing from MCPClient/HTTPTransport, re-vendor the container image)

Backward compatible by design: the legacy fallback means the current app keeps working against this server before the app PR lands, so this can ship first in a tagged release per the two-repo flow.

Test plan

  • npx vitest run test/mcp-http-transport.test.js — 4 tests: v1-SDK client (drain-window regression), raw 2024-11-05 wire mirroring the app's HTTPTransport (asserts no Mcp-Session-Id is minted), raw 2026-07-28 stateless request with the _meta envelope (asserts resultType: "complete"), v2-SDK client
  • npx vitest run tests/mcp-server.test.ts — 11 stdio tests pass unchanged (raw JSON-RPC initialize pinned to 2024-11-05)
  • npm test — 149/150 files pass; the one failing file (tests/build-agent-skills.test.ts, 56 SKILL.md drift assertions) also fails on clean main and is unrelated
  • App-side e2e against this checkout: ANGLESITE_PLUGIN_PATH=<this worktree> swift test --filter "AppliesEditEndToEnd|MCPClientHTTPEndToEnd" — real Swift MCPClient/HTTPTransport pass over stdio and HTTP

Notes

  • Deprecated-feature audit per the issue: the server uses none of Roots, Sampling, Logging, or elicitation — nothing to migrate there.
  • Legacy-leg behavior change: session-less GET/DELETE on /mcp now answer 405 (previously 400). The app only sends DELETE when it holds a session id, which a stateless server never mints, so no consumer is affected.

🤖 Generated with Claude Code

Migrate the MCP server from @modelcontextprotocol/sdk v1 to the v2 SDK
(@modelcontextprotocol/server + /node, zod 4 declared explicitly):

- http-server.mjs: replace the hand-rolled session map with
  createMcpHandler + toNodeHandler. The modern leg serves 2026-07-28
  stateless requests (_meta envelope, Mcp-Method/Mcp-Name headers,
  resultType, cache hints); the built-in legacy: 'stateless' fallback
  answers 2025-era traffic — including the initialize handshake the
  shipped Anglesite-app MCPClient (pinned 2024-11-05) sends — from the
  same buildServer factory, per-request, with no session minted.
- index-tools.mjs: server.tool() -> registerTool() with explicit
  z.object() input schemas; v2 import paths for McpServer and stdio.
- tests: keep the v1-SDK client test as drain-window regression
  coverage, add raw 2024-11-05 wire, raw 2026-07-28 stateless, and
  v2-SDK client tests.

Verified against the app's real Swift client: AppliesEditEndToEndTests
and MCPClientHTTPEndToEndTests pass with ANGLESITE_PLUGIN_PATH at this
checkout (stdio + HTTP).

Part of Anglesite/Anglesite#1277 (sidecar half of the paired PRs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The update skill bundles the root package.json as a reference file, so
the @modelcontextprotocol/sdk -> server/node + zod dependency change
must be re-exported (agent-skills-export CI gate).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@davidwkeith
davidwkeith merged commit 9069dcb into main Aug 10, 2026
4 checks passed
@davidwkeith
davidwkeith deleted the feat/mcp-2026-stateless branch August 10, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant