Commit graph go-sdk/mcp
Author SHA1 Message Date
Yaroslav
bc72835f62
mcp: fix potential nil-pointer dereference on message send (#1115) 2026-07-27 17:20:53 +02:00
George McCarron
e761950d97
mcp: avoid double-copy of payload in writeEvent (#1106)
`writeEvent` built the SSE frame with `fmt.Fprintf(&b, "data: %s\n\n",
string(evt.Data))`, which copies the payload into a fresh string and
then again into the buffer, growing it via repeated `bytes.growSlice`
doublings. For large MCP responses (e.g. ~162KB `tools/list`) under a
burst of concurrent writes this ~3x amplifies allocations and peak heap.

Write the payload directly into a pre-grown buffer instead. Output
framing is byte-identical. Benchmarks (162KB payload): 517KB->172KB per
op, 9->4 allocs/op, ~3x faster.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Yaroslav <yarolegovich@gmail.com>
2026-07-24 10:07:06 +02:00
Jan Steinke
2781b8f7e3
mcp: derive Mcp-Protocol-Version header from the outgoing message (#1107)
`streamableClientConn.setMCPHeaders` sets `Mcp-Protocol-Version` only
from `c.initializedResult`, which is populated exclusively through the
unexported `clientConnection.sessionUpdated` hook. `Client.Connect`
reaches that hook via a type assertion on the `Connection` returned by
the `Transport`:

```go
  if hc, ok := cs.mcpConn.(clientConnection); ok {
      hc.sessionUpdated(cs.state)
  }
```

That assertion silently fails whenever the `Connection` is wrapped by
another type that exposes only the exported `Connection` interface.
`c.initializedResult` then stays `nil` for the life of the session, and
every `SEP-2575` (>= `2026-07-28`) request sent through that connection
is missing the header. Servers that validate the header per spec reject
the request with `400 Bad Request`, closing the connection.

Every SEP-2575 request already carries its own `_meta.protocolVersion`
field via `injectRequestMeta`. `setMCPHeaders` now reads the protocol
version from the outgoing message first, falling back to
`c.initializedResult` and then the request context.

This is currently breaking the GitHub MCP with the 1.7-pre releases of
this module.

Fixes #1109

Co-authored-by: eu.anthropic.claude-sonnet-5 via Crush <charmcrush@users.noreply.github.com>
2026-07-24 09:21:59 +02:00
Guglielmo Colombo
827f90ba0c
mcp: allow opt-in to cancel handler ctx on aborted POST (#1099)
Fixes #1093
2026-07-17 13:40:39 +02:00
Guglielmo Colombo
5cb8339210
mcp: update return meta in DiscoverResult (SEP-2575) (#1097)
This PR implements the latest changes introduced by
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3002
2026-07-16 16:10:12 +02:00
Guglielmo Colombo
8baa4ccebe
mcp: add return type to subscriptions/listen (#1088)
This PR adds the expected return type to `subscriptions/listen` rpc
2026-07-15 14:37:19 +02:00
Guglielmo Colombo
9576afc114
mcp: wrap unmarshalParams with jsonrpc error (#1087)
Fixes #976
2026-07-14 14:26:18 +00:00
Guglielmo Colombo
7fde7d3452
mcp: reject calls to methodDiscover for <20260728 requests (#1084)
This PR adds a gate for requests towards methodDiscover if it is coming
from a client that does not support the 20260728 protocol version
2026-07-14 12:13:40 +02:00
Guglielmo Colombo
c79a30ae0a
mcp: add param check for CompleteResult (#1080)
Fixes #1071
2026-07-13 12:14:21 +00:00
Yashas Gunderia
dd79ca3d44
mcp: include resultType on new-protocol responses (#1060)
## Summary

- Add `resultType: "complete"` to non-MRTR server result responses for
2026-07-28 requests.
- Cover `server/discover`, list methods, and completion responses, and
update expected conformance/example output.

## Why

Fixes #1032. The 2026-07-28 schema requires `resultType` on result
objects, but only the MRTR-capable results were setting it.

## Validation

- `go test ./mcp -run
'Test(ServerSessionHandle|CompleteResult|ClientConnectDiscover|InMemory_E2E_Discover)'
-count=1` — passed\n- `go test ./mcp -count=1` — passed\n- `go test
./...` — passed\n- `go vet ./...` — passed

---------

Co-authored-by: ychampion <ychampion@users.noreply.github.com>
Co-authored-by: Guglielmo Colombo <guglielmoc@google.com>
2026-07-13 11:51:19 +00:00
Guglielmo Colombo
40f034322f
mcp: infer elicit mode from ElicitParams (#1078)
Fixes #1072
2026-07-13 11:49:15 +02:00
Guglielmo Colombo
ce393acb95
mcp: do not ApplyDefault when res.Content==nil (#1069)
Fixes #1062
2026-07-10 11:26:29 +02:00
Guglielmo Colombo
deecf8a432
mcp: block server initiated requests (SEP-2322) (#1057)
This PR explicitly blocks server initiated requests in server.go
2026-07-08 15:17:41 +02:00
Guglielmo Colombo
7f67c851d1
mcp: enforce body size limit in Stremable connection (#1055)
This PR enforces a body size limit on Streamable connection to prevent
OOM attacks
2026-07-08 10:34:41 +02:00
Guglielmo Colombo
6de85ec3ed
mcp: do not enforce TTL on cached tool (#1053)
This PR removes the TTL enforcing on the cached tools, when used to
generate the http-parameters for CallTool, according to updated
[spec](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2972)

> Clients **MUST** construct `Mcp-Param-*` headers using the most
recently obtained `inputSchema` for the tool.
2026-07-07 13:43:10 +02:00
Guglielmo Colombo
d651e2d2e1
mcp: make NotificationSubscriptions a mandatory field (#1050)
Fixes #1037
2026-07-07 11:39:18 +02:00
Guglielmo Colombo
ec564f9ccb
mcp: cap negotiated protocolVersion in legacy initialize to protocolVersion20251125 (#1051)
Fixes #1033
2026-07-06 15:40:27 +00:00
Guglielmo Colombo
224a240875
mcp: do not exclude Notifications from carrying InitializeParams in Meta (#1049)
Fixes #1043
2026-07-06 17:10:26 +02:00
Yaroslav
ede1894174
fix: extra wrapper for input response map (#1045)
fixes #1036
2026-07-02 09:22:05 +02:00
Guglielmo Colombo
65ece59643
mcp: Allow registration of custom JSON-RPC methods (#956)
## Description

This PR introduces support for custom (non-standard) JSON-RPC methods in
the MCP Go SDK.
This feature enables servers to handle arbitrary JSON-RPC methods and
clients to invoke them, all while maintaining full type safety and
integrating seamlessly with the SDK's existing middleware and session
management.

- Server-Side Registration: Added AddReceivingCustomMethod to allow
servers to register handlers for custom methods. Incoming requests are
automatically unmarshaled into user-defined parameter structs.
- Client-Side Calling: Added AddSendingCustomMethod which returns a
strongly-typed caller function that clients can use to invoke custom
methods and receive strongly-typed results.
- Helper Structs: Provided ParamsBase and ResultBase for users to embed
in their custom structs. This allows them to easily satisfy the SDK's
internal Params and Result interfaces.

Fixes #954
2026-06-25 23:13:17 +02:00
Guglielmo Colombo
a817f61412
mcp: add Cacheable fields to DiscoverResult (#1022)
This PR add the Cacheable fields to the DiscoverResult, as it was added
later
(8e4c2322ca)
2026-06-24 14:08:43 +02:00
Guglielmo Colombo
7f4aa4a0ce
mcp: add 2026-07-28 to the supported protocol versions (#1020)
This PR adds the protocol version `2026-07-28` to the list of supported
protocol versions and fixes legacy tests hardcoding the legacy protocol
version for those use cases.
2026-06-24 12:02:56 +02:00
Guglielmo Colombo
b9e6fc5a66
mcp: add documentation for new protocol version (#1019)
Add documentation for new protocol version in the `internal/docs`
2026-06-23 17:07:38 +02:00
Guglielmo Colombo
01847b35b3
mcp: refactor notification of subscribed sessions (#1018)
This PR improves the notification of subscribed sessions removing
duplicated part
2026-06-23 09:50:33 +00:00
Guglielmo Colombo
b6649db4f9
mcp: Deprecate roots, sampling and logging (SEP-2577) (#1017)
Fixes #1013
2026-06-23 11:11:08 +02:00
Guglielmo Colombo
cd7d80c591
mcp: Implement subscriptions/listen rpc (SEP-2575) (#1007)
Fixes #966
2026-06-22 18:57:36 +02:00
Guglielmo Colombo
3486f6bcaf
mco: update JSON-RPC error codes to align with updated MCP specification (#1016)
This PR updates the error codes to align with the updated specifications
in
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2907

ErrServerClosing and ErrClientClosing are reverted to their 1.6.0
version codes, as they do not overlap anymore with the newly introduced
error codes.
2026-06-22 10:27:31 +02:00
Guglielmo Colombo
17029489ff
mcp: bump protocol version from 2026-06-30 to 2026-07-28 (#1015)
The new official date for the protocol version has been moved to
'2026-07-28'. Update all the references in the code of the old version.
2026-06-22 09:53:04 +02:00
Guglielmo Colombo
b85574f685
mcp: Enable legacy initialize fallback on any error (#1014)
To guarantee a better compatibility with legacy server, enable the
fallback to the legacy initialize rpc in case of any error returned by
the server, in case of `server/discover` request.
2026-06-18 15:52:11 +02:00
Guglielmo Colombo
6333aa7c63
mcp: add ttl for list results (SEP-2549) (#1008)
Fixes #994
2026-06-18 15:20:21 +02:00
Guglielmo Colombo
71ffcb412a
mcp: add MCPGPDEBUG for opt-in Content-Type check (#1012)
Copy of existing
[PR](https://github.com/modelcontextprotocol/go-sdk/pull/972) patching
1.6.0 version
2026-06-17 11:41:35 +02:00
Guglielmo Colombo
96074c9918
fix: prevent duplicate in-flight request IDs (#1011)
Fixes #1004
2026-06-16 14:13:52 +00:00
Guglielmo Colombo
79e1a13dcf
mcp: tool.InputSchema and tool.OutputSchema validation (SEP-2106) (#1009)
Fixes #990
2026-06-16 13:55:47 +02:00
Guglielmo Colombo
91c010f664
mcp: fix http-standardization (SEP-2243) (#1010)
Fixes #905
2026-06-16 09:20:53 +00:00
Piyush Bag
bcbfe0ce36
fix(jsonrpc2): decode requests when method key is present (#1000)
## Summary

Fixes #976.

`DecodeMessage` used `msg.Method != ""` to classify messages. A wire
payload with `"method":""` was decoded as a **response**, so stdio
servers dropped it without a correlated JSON-RPC error.

## Approach

Decode into a `wireDecode` struct whose `method` field is
`json.RawMessage`. Treat the message as a **request** when the `method`
key is **present on the wire** (including `""`), which matches JSON-RPC
semantics.

This revision:

- Uses a **single JSON parse** per message (dedicated decode struct, no
secondary fields-map unmarshal)
- Documents why `json.RawMessage` is used for `method`
- Adds regression coverage so normal responses and id-only payloads
without a `method` key stay on the response path

## Test plan

- [x] `go test ./internal/jsonrpc2/... -v`
- [x] `go test ./mcp/... -run TestIOConnRead_EmptyMethod -v`
- [x] `go test ./... -count=1`
- [x] `go test -race ./internal/jsonrpc2/... -count=1`
- [x] Server conformance (`npx @modelcontextprotocol/conformance server
--url http://127.0.0.1:3000/mcp`) — 40 passed, 0 failed
- [x] Client conformance (`./scripts/client-conformance.sh`) — 217
passed, 0 failed

## Scope note

This PR addresses the primary repro in #976 (empty `method` with valid
`id`). Other cases listed in the issue (`id: null`, structurally invalid
envelopes) are unchanged.

Co-authored-by: Guglielmo Colombo <guglielmoc@google.com>
2026-06-16 09:57:18 +02:00
Guglielmo Colombo
4dc99b48e1
mcp: Remove resumability and introduce MissingRequiredClientCapability error data (#1005)
Fixes #966
2026-06-15 09:47:42 +02:00
Guglielmo Colombo
88c58c3006
mcp: remove outdated comment (#1003) 2026-06-10 16:13:27 +02:00
Guglielmo Colombo
dd978160ab
mcp: Implement server-side support for discover method (SEP-2575) (#987)
## Summary
Part 3 of the SEP-2575 ("Make MCP Stateless") implementation. Builds on
PR #975 which landed the client-side discover/fallback flow and the
per-request `_meta` plumbing. This PR adds the **server-side**
counterparts:

- `server/discover` handler (replaces the
stub),ProtocolVersionSupporter`
- transport hook for per-transport version filtering,
- transport-agnostic version validation and method-removal enforcement
in `ServerSession.handle`,
- HTTP-level wire compliance for SEP-2575 error codes/status codes,
- bug fix in `internal/jsonrpc2`,`processResult` with an `MCPGODEBUG`
opt-out for backward compatibility.
2026-06-08 17:52:10 +02:00
Guglielmo Colombo
00d3642840
mcp: add support for logging level (SEP-2575) (#997)
## Description

This PR adds the support for logging feature in meta.

Fixes #966
2026-06-08 15:56:38 +02:00
Guglielmo Colombo
d9714c61f1
mcp: Implement retry on advised supportedVersions in UnsupportedProtocolVersion error (#989)
## Description

This PR introduces a retry mechanism for the discover method according
to SEP-2575 (Issue #966)
2026-06-08 15:09:07 +02:00
Guglielmo Colombo
c60a318d22
mcp: Implement support for SEP-2575 on client side (#975)
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
2026-06-02 14:17:01 +02:00
Yufeng He
6d2bbff7d8
fix: add implementation description metadata (#981)
## Summary
- add the optional `description` field to `mcp.Implementation`
- keep the field omitted when empty
- cover JSON marshal/unmarshal behavior with a focused regression test

Fixes #977.

## To verify
- `go test ./mcp -run TestImplementationDescriptionJSON -count=1`
- `go test ./mcp -run TestServerRequest_PerRequestAccessors -count=1`
- `go test ./mcp -count=1`
- `go test ./...`
- `git diff --check`

Co-authored-by: Guglielmo Colombo <guglielmoc@google.com>
2026-05-31 10:35:46 +02:00
Tomas Dabašinskas
8805aa85f7
mcp: add configurable keepalive failure threshold (#982)
mcp: add configurable keepalive failure threshold

Introduce `KeepAliveFailureThreshold` option in both `ClientOptions` and
`ServerOptions` to control how many consecutive keepalive ping failures
are tolerated before closing the session.

This aligns with the MCP spec's guidance that "multiple failed pings MAY
trigger a connection reset," allowing operators to tune resilience
against transient network hiccups without immediately tearing down
otherwise healthy sessions.

A threshold of 0 or 1 (the default) closes on the first failure,
preserving existing behavior. Higher values let isolated misses pass
while still closing the session once consecutive failures reach the
threshold. A successful ping resets the counter.

Tolerated failures are logged at WARN level; the final failure that
closes the session is logged at ERROR level.

This is rework of #979.
2026-05-31 10:25:49 +02:00
Yaroslav
189a85ad92
feat: multi-round-trip request implementation (SEP-2322) (#950)
### Context

Design (`design/mrtr.md`) and implementation proposal for Multi
Round-Trip Requests (MRTR) per
[SEP-2322](de6d76fba3/seps/2322-MRTR.md).

### Changes

- Introduce `InputRequest` and `InputResponse` sealed interfaces with
corresponding `InputRequestMap` and `InputResponseMap` types for custom
map JSON codec implementation.
- Extend `CallToolParams`, `GetPromptParams`, and `ReadResourceParams`
with `InputResponses`, `RequestState` and an unexported `resultType`
("complete" or "input_required") for retry round-trips. The type is set
by the SDK based on input requests presence.
- Add client-side MRTR middleware enabled by default that automatically
fulfills input requests and retries.
- Added MRTROptions on ClientOptions to allow disabling the middleware
and configuring the number of retries.
- Add server-side MRTR middleware for backward compatibility:
transparently bridges input requests to direct
Elicit/CreateMessage/ListRoots calls for older clients
2026-05-29 09:29:34 +02:00
Guglielmo Colombo
4cbdd6a514
mcp: Implement stateless server (SEP-2275) (#965)
## Description

This PR lays the foundational server-side groundwork for the `>=
2026-06-30` sessionless and stateless feature introduced by
[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575)
and SEP-2567, tracked in
[design/stateless.md](614460a225/design/stateless.md).

### SEP-2575: Stateless MCP

*   **Per-request protocol detection in `ServerSession.handle()`**
Unmarshal `_meta` from the raw JSON-RPC params determines whether each
request follows the new protocol.

*   **Per-request typed accessors on `ServerRequest[P]`**
    ```go
    func (r *ServerRequest[P]) ProtocolVersion() string
    func (r *ServerRequest[P]) ClientInfo() *Implementation
    func (r *ServerRequest[P]) ClientCapabilities() *ClientCapabilities
    ```

* **Reject client->server `initialize`, `initialized` and `ping` for
new-protocol requests**

*   **Per-request `_meta` field name constants**
Three constants for the wire-protocol field names
(`MetaKeyProtocolVersion`, `MetaKeyClientInfo`,
`MetaKeyClientCapabilities`)

* **Stop synthesizing fake `InitializeParams` for new-protocol
requests**

Fixes: #966
2026-05-26 14:25:51 +00:00
Pavel Bazin
c044cdb734
fix: do not omitempty ReadOnlyHint in ToolAnnotations (#908)
`ReadOnlyHint` is a `bool` with omitempty, so the zero value (false) is
indistinguishable from unset, and **drops out** of marshaled JSON.

The current behavior causes an issue with the OpenAI MCP app submission
because they require explicit hints.

Consumers that explicitly set `ReadOnlyHint: false` on write tools lose
the field on the wire. Removing `omitempty` ensures `false` is always
serialized, which matches the MCP spec default.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Maciej Kisiel <mkisiel@google.com>
Co-authored-by: guglielmoc <guglielmoc@google.com>
2026-05-25 15:52:15 +02:00
Yufeng He
bed83e104b
fix: reject duplicate initialize requests (#962)
## Summary
- reject a second `initialize` request on an already initialized server
session
- keep the original `ServerSession.InitializeParams()` instead of
replacing it with later client parameters
- add a raw JSON-RPC regression test for the duplicate-initialize path

Fixes #961.

## To verify
- `go test ./mcp -run TestServerRejectsDuplicateInitialize -count=1`
- `go test ./mcp -count=1`
- `go test ./...`

---------

Co-authored-by: guglielmoc <guglielmoc@google.com>
2026-05-25 15:15:26 +02:00
Maciej Kisiel
1253d17add
mcp: do not call DELETE for sessionless & doc adjustments (#960) 2026-05-15 21:47:34 +02:00
Maciej Kisiel
8eb54632ad
mcp: remove session header handling in stateless mode (#952) 2026-05-15 09:51:14 +02:00
Maciej Kisiel
9f5e89fea2
mcp: refactor streamable handler control flow (#949) 2026-05-08 14:29:01 +02:00