GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add a modern client for MCP 2026-07-28 by chemicL · Pull Request #1325 · modelcontextprotocol/java-sdk

Conversation

@chemicL

@chemicL chemicL commented Nov 10, 2026

Copy link
Copy Markdown
Member

The latest protocol revision introduced a stateless incarnation of the protocol. It requires no initialization handshake or session management, and it doesn't allow server-to-client requests.

An instance of the modern client is meant to stand for one user. It does no I/O when built and can share its transport with other clients, so an application that handles authorization creates one per user over a single HTTP transport. Identity isn't passed to client methods; the caller's McpTransportContext reaches the transport's request customizer and authorization error handler. The tool catalog is therefore that user's view of the server. The client also uses it for x-mcp-header mirroring.

Clients are built with McpClient.async(transport) or McpClient.sync(transport), and each operation goes through an immutable request spec, e.g. client.tool("create_issue").arguments(args).call(). Timeouts, progress, _meta and elicitation handlers are set on the builder and can be overridden per call on the spec.

The client takes care of what the revision requires:

  • the _meta block with version and capabilities on every request
  • version renegotiation
  • the multi round-trip loop for input_required results (with callOnce() for callers that run it themselves)
  • the Mcp-* and Mcp-Param-* headers, with one retry on -32020
  • subscriptions/listen streams that report which parts of the filter the server doesn't honour

A round timeout bounds each exchange but not the time a user spends answering; a call timeout is optional.

The sync client runs the loop and its handlers on the caller's thread.

Transports: Streamable HTTP on the JDK HttpClient, and stdio. Sampling, roots, logging and extensions are left out for now.

On the server side, the HTTP and stdio wire constants are shared with the client, input requests are typed by method and mode, and the listen filter is open so features can honour extension fields. InputResponses.get and RequestStateCodec.open return null instead of an empty Optional.

A conformance client in conformance-tests/client-modern passes the non-auth 2026-07-28 client scenarios.

Part of #1011

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@chemicL
Add a modern client for MCP 2026-07-28
637d995
The latest protocol revision introduced a stateless incarnation of the
protocol. It requires no initialization handshake or session
management, and it doesn't allow server-to-client requests.

An instance of the modern client is meant to stand for one user. It
does no I/O when built and can share its transport with other clients,
so an application that handles authorization creates one per user over
a single HTTP transport. Identity isn't passed to client methods; the
caller's McpTransportContext reaches the transport's request customizer
and authorization error handler. The tool catalog is therefore that
user's view of the server. The client also uses it for x-mcp-header
mirroring.

Clients are built with McpClient.async(transport) or
McpClient.sync(transport), and each operation goes through an immutable
request spec, e.g. client.tool("create_issue").arguments(args).call().
Timeouts, progress, _meta and elicitation handlers are set on the
builder and can be overridden per call on the spec.

The client takes care of what the revision requires:
- the _meta block with version and capabilities on every request
- version renegotiation
- the multi round-trip loop for input_required results (with callOnce()
  for callers that run it themselves)
- the Mcp-* and Mcp-Param-* headers, with one retry on -32020
- subscriptions/listen streams that report which parts of the filter
  the server doesn't honour

A round timeout bounds each exchange but not the time a user spends
answering; a call timeout is optional.

The sync client runs the loop and its handlers on the caller's thread.

Transports: Streamable HTTP on the JDK HttpClient, and stdio. Sampling,
roots, logging and extensions are left out for now.

On the server side, the HTTP and stdio wire constants are shared with
the client, input requests are typed by method and mode, and the listen
filter is open so features can honour extension fields.
InputResponses.get and RequestStateCodec.open return null instead of an
empty Optional.

A conformance client in conformance-tests/client-modern passes the
non-auth 2026-07-28 client scenarios.

Signed-off-by: Dariusz Jedrzejczyk <[email protected]>
@chemicL chemicL added this to the 2.2.0-M3 milestone Nov 10, 2026
@chemicL chemicL added enhancement New feature or request area/client labels Nov 10, 2026
@chemicL chemicL mentioned this pull request Nov 10, 2026
SEP-2575: Make MCP Stateless #1011
Open
1 of 5 tasks
@chemicL
Polish the modern client's tool listing, failures and HTTP hooks
b58d21c
- listTools() asked the server for every page on each call. The client
  now keeps the listing for its ttlMs and returns it while it's fresh.
  listTools() returns a spec: list() serves the kept listing, and
  skipCache() always asks the server. A listen stream that reports tool
  changes drops the kept listing.
- The client's own failures (missing input handler, too many input
  rounds, invalid result, lost response, timeout, lost listen stream,
  HTTP error status) now extend McpClientException. Errors the server
  answered remain McpException, so catching the two covers every
  failure of a call.
- McpHttpRequestCustomizer.fromSync ran the customizer on whichever
  thread sent the request, sometimes the caller's and sometimes an HTTP
  client thread. It now runs on boundedElastic, as the authorization
  error handler's fromSync does, so a customizer may block, for example
  to fetch a token. Hooks get the call's identity only from the
  McpTransportContext, on every attempt.
- McpHttpRequest and McpHttpResponseInfo can now be created outside the
  SDK, with McpHttpRequest.builder(...) and McpHttpResponseInfo.of(...),
  so a custom HTTP transport can call the request customizers and the
  authorization error handler.

Signed-off-by: Dariusz Jedrzejczyk <[email protected]>
@HanselIdes

HanselIdes commented Nov 10, 2026

Copy link
Copy Markdown

Thanks for the modern client. We maintain a downstream MCP client connector on top of this SDK and plan to adopt 2026-07-28, so we have two questions about scope and timing.

1. Fallback to the initialize handshake. The compatibility matrix in the spec says a modern-only client fails against a server that still requires initialize. Most deployed servers will stay on the old protocol for a while. In the changed files I found the server/discover cache and the UnsupportedProtocolVersion handling, but no probe or fallback path. Is a dual-era client in scope for this PR, planned as a follow-up, or left to callers to combine from the 2.x client and this one? If it is a follow-up, which issue tracks it? The closest issue I found is #1203, which covers dual-era servers.

2. Release timing. The PR is in milestone 2.2.0-M3. Will the modern client ship in that milestone? Is there an expected date for a non-milestone release that includes it? The roadmap says the SDK implements new revisions within six months of the spec, which is about the end of January 2027. We need to know whether to plan around that date.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@HanselIdes HanselIdes mentioned this pull request Nov 10, 2026
MCP Client: support MCP specification 2026-07-28 (stateless protocol) camunda/connectors#10344
Open
tzolov
tzolov previously approved these changes Nov 12, 2026
View reviewed changes

@tzolov tzolov left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I like the design, but given the time constraints, I can't give it the thoughtful review it deserves.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@tzolov
Merge branch 'main' into modern-client
b9dd1af
@tzolov
tzolov dismissed their stale review via b9dd1af November 12, 2026 12:29
tzolov
tzolov approved these changes Nov 12, 2026
View reviewed changes

@tzolov tzolov left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

conflict resolution is fine

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@tzolov
tzolov merged commit c531bb8 into main Nov 12, 2026
33 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@tzolov
tzolov deleted the modern-client branch November 12, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@tzolov tzolov tzolov approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

area/client enhancement New feature or request

Projects

None yet

Milestone

2.2.0-M3

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@chemicL @HanselIdes @tzolov
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.