Skip to content

Spike the MCP 2026-07-28 modern server on Restlet (gate 0) - #1662

Merged
jlouvel merged 2 commits into
3.0from
spike/mcp-2026-07-28
Nov 7, 2026
Merged

jlouvel merged 2 commits into
3.0from
spike/mcp-2026-07-28

Conversation

@jlouvel

@jlouvel jlouvel commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

Gate 0 for MCP revision 2026-07-28 (#1640), the revision Ikanos speaks today. Test-only, apart from the SDK version.

SDK. lib-mcp-version moves from 2.1.0 to 2.2.0-M2 (2026-11-02), the first Java SDK line with a 2026-07-28 server: io.modelcontextprotocol.modern, a stateless server with a transport-neutral handle(context, request). It is a milestone, and its modern API is marked preview until 3.0. The classic API that McpServerAdapter uses is unchanged: the existing MCP tests pass on M2, the session spike included.

Spike. McpModernSpikeTestCase puts the SDK's modern McpServer, with one tool, behind a test-only Restlet that does what the SDK's HttpServletMcpTransport does: POST only, JSON content type, Mcp-Method / MCP-Protocol-Version / Mcp-Name checked against the body (base64 values included), 202 for notifications, JSON replies, errors mapped to their HTTP status, and streaming replies over core SSE (EventStreamRepresentation). A JDK HttpClient sends requests as the revision requires (the Java SDK has no modern client yet):

  1. server/discover advertises ["2026-07-28"], the tools capability, resultType: complete and _meta serverInfo.
  2. tools/list returns the tool with ttlMs and cacheScope; tools/call works with a plain and a base64 Mcp-Name.
  3. Errors: a header mismatch is 400 / -32020, a 2025-11-25 request is 400 / -32022 with data.supported, an unknown method 404 / -32601.
  4. Legacy traffic: GET is 405, a notification 202, a 2025-11-25 initialize 400 / -32602.
  5. A request without _meta client capabilities is refused with 400 / -32602.

Findings against Ikanos' implementation of the revision:

  • Ikanos' MCP client sends only the protocol version in _meta; the SDK requires the client capabilities too, as the revision does, so Ikanos' client can't call an SDK-based server until it sends them (empty is enough).
  • Ikanos answers a legacy initialize with -32022; the SDK with -32602. Both refuse it.
  • Ikanos answers notifications with -32601 / 404; the SDK, as the revision says, with 202.

mvn -pl org.restlet.ext.mcp verify: 42 tests, coverage and SpotBugs pass.

🤖 Generated with Claude Code

Gate 0 for MCP 2026-07-28 (#1640): the MCP SDK 2.2.0-M2 modern
stateless server behind a test-only Restlet transport that mirrors the
SDK's servlet transport: POST only, header checks against the body,
JSON replies, errors mapped to their HTTP status, streaming replies over
core SSE. Requests are shaped as the revision requires: server/discover,
tools/list and tools/call with plain and base64 Mcp-Name, header,
version and method errors, legacy GET, notification and initialize.

The SDK moves to 2.2.0-M2, a milestone whose modern API is a preview;
the classic API ext.mcp uses is unchanged and its tests pass.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@jlouvel
jlouvel requested a balanced review from Copilot November 7, 2026 11:59
@jlouvel jlouvel self-assigned this Nov 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The tests do not exercise the modern SDK’s streaming response path over Restlet, leaving SSE content type, notification ordering, final response ID, and stream completion unverified.

1 open issue
What changed in this PR

Adds a gate-0 spike for hosting the MCP 2026-07-28 modern stateless server on Restlet, supporting the R6 transport investigation. The transport remains test-only; the SDK upgrade affects the production extension.

Changes:

  • Upgrades the MCP Java SDK from 2.1.0 to 2.2.0-M2.
  • Adds HTTP tests for discovery, tool calls, protocol errors, legacy traffic, and required client capabilities.
  • Implements a test-only Restlet transport with header validation, JSON replies, and an SSE response path.
File Description
pom.xml Updates the shared MCP SDK version to 2.2.0-M2.
org.restlet.ext.mcp/​src/​test/​java/​org/​restlet/​ext/​mcp/​McpModernSpikeTestCase.java Adds the modern-server transport spike and HTTP interoperability tests.

Review effort: Balanced

A tool reporting progress before its result is answered on an SSE
stream: the progress notification first, then the result answering the
request, then the end of the stream.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@sonarqubecloud

sonarqubecloud Bot commented Nov 7, 2026

Copy link
Copy Markdown

@jlouvel
jlouvel merged commit 6ce2c99 into 3.0 Nov 7, 2026
3 checks passed
@jlouvel
jlouvel deleted the spike/mcp-2026-07-28 branch November 7, 2026 12:48
jlouvel added a commit that referenced this pull request Nov 7, 2026
McpServerAdapter now also serves MCP revision 2026-07-28 on the same
endpoint: a request whose MCP-Protocol-Version header names it goes to
the MCP SDK's modern stateless server (mcp-core 2.2.0-M2), any other
request keeps the 2025-11-25 path unchanged.

- The tools, resources, templates and prompts registered on the adapter
  are served to both revisions, bridged through JSON between the two
  SDK schemas; getModernTools() adds tools on the modern types, served
  to 2026-07-28 clients only, for input_required and streamed progress.
- The interceptors wrap each 2026-07-28 request and its final result or
  error; progress streamed before the result passes without them.
- The Origin allow-list, message size, call limit, request timeout,
  stop and peer disconnect apply to both revisions; the tool filters
  apply to 2026-07-28 listings, modern tools included.
- A streamed reply goes over core SSE through a bounded queue, with
  heartbeats; leaving it early, on a timeout, a disconnect or a stop,
  cancels the SDK's stream and ends the client's with an error
  answering the request.
- Mcp-Param headers are passed to the SDK, which validates x-mcp-header
  arguments against them.
- input_required state is sealed bound to the authenticated user;
  setRequestStateKey() shares the key between instances.

McpRequestContext reports the revision of its request, and
McpProtocol.MODERN_VERSION names 2026-07-28. Not yet for 2026-07-28:
stdio, subscriptions/listen, modern resources and prompts, the client.
The test-only spike of #1662 is replaced by McpModernServerTestCase.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.

2 participants