Skip to content

mcp: Implement support for SEP-2575 on client side#975

Open
guglielmo-san wants to merge 48 commits into
mainfrom
guglielmoc/SEP-2575_Stateless_MCP_part2
Open

mcp: Implement support for SEP-2575 on client side#975
guglielmo-san wants to merge 48 commits into
mainfrom
guglielmoc/SEP-2575_Stateless_MCP_part2

Conversation

@guglielmo-san
Copy link
Copy Markdown
Contributor

@guglielmo-san guglielmo-san commented May 26, 2026

Implements the client half of the SEP-2575 / 2026-06-30 protocol. This CL is client-only; server-side server/discover is still a MethodNotFound stub.

Changes

  • server/discover probe in Client.Connect() (client.go). When the caller opts into protocolVersion >= 2026-06-30, the client probes the server with server/discover before falling back to the legacy initialize
    handshake.
  • Per-request _meta injection (shared.go, injectRequestMeta). For>= 2026-06-30 sessions every outgoing request gets the SEP-2575 triple (protocolVersion, clientInfo, clientCapabilities).
  • Server-side fix: ServerSession.handle no longer pre-populates state.InitializeParams from a server/discover request's _meta, so a subsequent fallback initialize is not rejected as a duplicate.

Fallback rules

Client falls back to the legacy initialize handshake when discover returns:

  • MethodNotFound (-32601),
  • UnsupportedProtocolVersionError (-32004),
  • an HTTP Bad Request (substring-matched on the error message, to interop
    with pre-2026-06-30 servers).

Fixes #966

…t stateless protocol to stateless HTTP servers
…protocol version checking in server and tests
…rt headers and conditional SSE stream initialization
…ization, and correct session metadata mapping
…version propagation in client and transport layers
@guglielmo-san guglielmo-san marked this pull request as ready for review May 27, 2026 09:04
@guglielmo-san guglielmo-san changed the title mcp: Implement support for methodDiscover on client side mcp: Implement support for SEP-2275 on client side May 27, 2026
@yarolegovich yarolegovich changed the title mcp: Implement support for SEP-2275 on client side mcp: Implement support for SEP-2575 on client side May 27, 2026
Comment thread mcp/client.go Outdated
Comment thread mcp/client.go Outdated
if errors.As(err, &werr) && (werr.Code == jsonrpc.CodeMethodNotFound || werr.Code == CodeUnsupportedProtocolVersion) {
return nil, true, nil
}
if strings.Contains(err.Error(), "Bad Request") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this is quite unreliable.
maybe we can use other jsonrpc codes like 32600 invalid request. maybe introduce internal error errNotFound and add http-transport logic for %w-ing it into the error when status code is 404, add a check here

Comment thread mcp/streamable.go Outdated
Comment thread internal/jsonrpc2/wire.go
ErrUnknown = NewError(-32001, "unknown error")
// ErrServerClosing is returned for calls that arrive while the server is closing.
ErrServerClosing = NewError(-32004, "server is closing")
ErrServerClosing = NewError(-32006, "server is closing")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

oh, that's not nice . SDK claimed error codes which are now also used in the spec.

ErrClientClosing = NewError(-32003, "client is closing")

will now mean MISSING_REQUIRED_CLIENT_CAPABILITY.

for the server side we can do mcgdebug for returning -32004 when server is closing for a session with and old protocol version.
I guess we need to handle it in internal/jsonrpc2/wire.go is-check looking not just at the code but at the message as well 😞

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am not sure this is needed. The ErrClientClosing and ErrServerClosing are never sent over the wire and the error code is never returned to the calling function. Are only used internally in the client / server implementation.

Comment thread internal/jsonrpc2/conn.go
// For cancelled or rejected requests, we don't set the writeErr (which would
// break the connection). They can just be returned to the caller.
if err != nil && ctx.Err() == nil && !errors.Is(err, ErrRejected) {
if err != nil && ctx.Err() == nil && !errors.Is(err, ErrRejected) && !errors.Is(err, ErrUnsupportedProtocolVersion) && !errors.Is(err, ErrMethodNotFound) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if any server implementation close a connection on their side in case of an unknown method request

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In this case it will not pass through this path. The server will send a request from the SSE stream, and the client will respond with a new response that will eventually contain the error. But that will be a new POST Response

Comment thread mcp/client.go Outdated
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.

Implement SEP-2575: Make MCP Stateless

2 participants