Commit graph

543 commits

Author SHA1 Message Date
Robert Findley
411d5a049a
mcp: switch icon theme to named string type (#733) v1.2.0 v1.2.0-pre.2
To be consistent with logging level, use a named string type for icon
themes. This improves readability / discoverability, and is more
consistent.

Updates #552
For #725
2025-12-19 16:44:10 -05:00
Jonathan Hefner
76e6854375
docs: add GitHub Pages redirect to latest release documentation (#702)
**Context:** I am working on getting documentation up for each MCP SDK
at `https://modelcontextprotocol.github.io/*-sdk/`. I realize the Go
ecosystem has its own idioms for generating and hosting documentation,
so I am proposing we make https://modelcontextprotocol.github.io/go-sdk/
redirect to the latest tag of
https://github.com/modelcontextprotocol/go-sdk/blob/v1.1.0/docs/README.md.

---

Adds a redirect page at https://modelcontextprotocol.github.io/go-sdk/
that automatically redirects visitors to the `docs/README.md` of the
latest release tag. Uses Jekyll templating with
`site.github.latest_release` to dynamically resolve the current release
version at build time.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 15:21:03 -08:00
Robert Findley
875d1d30c2
mcp: don't break the streamable client connection for transient errors (#723) v1.2.0-pre.1
When POST requests in the streamableClientConn return a transient error,
return this error to the caller rather than permanently breaking the
connection.

This is achieved by using the special sentinel ErrRejected error to the
jsonrpc2 layer. In doing so, the change revealed a pre-existing bug:
ErrRejected had the same code as ErrConnectionClosing, and
jsonrpc2.WireError implements errors.Is, so the two sentinel values
could be conflated. This is fixed by using a new internal code.

There's more to do for #683: we should also retry transient errors in
handleSSE.

For #683
2025-12-12 13:49:41 -05:00
Nikola Petrov
e009bacfcb
oauthex: fix content type check in getJSON (#721)
The content type header contains full mimetype string which might
contain parameters. The getJSON function doesn't account for this and so
some responses fail to parse although they are perfectly acceptable. For
example
```
curl -vv 'https://github.com/.well-known/oauth-authorization-server/login/oauth'
```
returns a content type header with the value
```
content-type: application/json; charset=utf-8
```
which is perfectly valid but fails in the current logic.
2025-12-12 09:44:26 -05:00
Robert Findley
3430e2242e
mcp: add Capabilities fields to ServerOptions and ClientOptions (#713)
This allows users to configure default capabilities, disable defaults,
or suppress listChanged notifications by setting ListChanged: false.

Key changes:
- Add ServerOptions.Capabilities and ClientOptions.Capabilities fields.
- Merge user-provided capabilities with dynamically-added ones (tools,
  prompts, resources, sampling, elicitation).
- Check ListChanged before sending list-changed notifications.
- Deprecate HasPrompts, HasResources, HasTools on ServerOptions.
- Remove unreleased ElicitationModes field from ClientOptions.
- Add clone methods to capability structs using shallowClone helper.
- Add synctest-based tests for notification behavior (go1.25).
- Add TestClientCapabilitiesOverWire and TestServerCapabilitiesOverWire
- Document the new Capabilities API in docs/

Updates #706
2025-12-11 20:17:46 -05:00
Robert Findley
bae0929820
mcp: address review comments on streamable cleanup (#716)
Follow up on some post-submit comments from jba.
2025-12-11 15:16:04 -05:00
Robert Findley
b3399e6730
mcp: use args struct for CloseSSEStream (#718)
Change CloseSSEStream from func(time.Duration) to
func(CloseSSEStreamArgs) for forward compatibility, allowing new fields
to be added without breaking existing callers.
2025-12-11 15:13:38 -05:00
Robert Findley
1a964ae23d
mcp: debounce server change notifications (#717)
Debounce and batch notifications for changes in server feature sets
(adding or removing tools, prompts, resources, or resource templates).

This PR handles server-side change notifications only. We could do the
same for client-side notifications (e.g. roots changed), but at the
moment we don't need to.

Fixes #649.
2025-12-11 15:11:32 -05:00
Robert Findley
a5e369ed12
mcp: fix broken client root capabilities (#698)
To address #607, add ClientCapabilities.RootsV2, and populate it when
constructing sending and receiving InitializeParams.

Fixes #607
2025-12-11 10:16:56 -05:00
Rob Findley
307e32c2b3 oauthex: validate URL schemes in auth server metadata and DCR
Use URL scheme validation for remaining URL fields in auth
datastructures (AuthServerMeta and ClientRegistrationMetadata), to
prevent XSS attacks.

By comparison, the typescript SDK doesn't validate
introspection_endpoint, and I don't know why. Otherwise the
implementations align.

Fixes #526
2025-12-11 10:09:43 -05:00
Rob Findley
6f6e196c27 mcp: fix stray log.Printf in notifySessions
I encountered these logs, and they were distracting and noisy. We
shouldn't log to stderr unless configured by the user. Thread through
the logger.

Also, use ensureLogger in the streamable client to simplify call sites.

Updates #708
Updates #684
2025-12-10 18:15:54 -05:00
John Howard
b012d0824e client: allow re-using connections in more cases
I am seeing a bug where connections with a Streamable HTTP client are
not reused at all. This makes performance terrible, since each request
establishes a new TCP connection.

I was able to root cause this down to behavior of the `processStream`
function. This sets up a bufio.NewScanner, and waits to get data. Once
we get a message, we abort and *close the connection*.

At this point, there are two paths:
* The bufio reader read the *full* response body to EOF, and then we
  closed. This case is fine; we can re-use the idle connection.
* The bufio reader *did not* real the full response body. It may have
  read the entire actual data that *would be sent*, but since its
streaming happened to not yet be delivered. In this case, we call
`body.Close()` before an EOF, which causes the HTTP client to not
attempt to re-use the connection.

In my case, the server I am using reliable sends the response over 2 TCP
packets (one with the event, and the other with the closure of the
`chunked` encoding (`0`)). This causes the body to never be fully read.

This PR fixes that case by unconditionally reading the full body before
we close the connection. With this change, I am able to reliably re-use
connections for future requests.
2025-12-10 17:06:20 -05:00
Rob Findley
6848e36ef0 mcp: finish cleanup notes in streamable.go
Address remaining TODO(cleanup) comments in streamable.go: eliminate a
pointless context cancellation, and simplify forCall logic.
2025-12-10 16:25:38 -05:00
Rob Findley
e69fd7ba25 mcp: simplify stream state management in streamable transport
Replace closure-based deliver and closeLocked fields with explicit
state:
- pendingJSONMessages: signals JSON mode and collects messages
- w: indicates stream is claimed by HTTP request
- done: signals stream completion (non-nil implies w is non-nil)
- lastIdx, supportsPrimeClose, logger: moved from closures to fields

Add stream methods to consolidate logic:
- close: sends close event and closes done channel
- release: releases stream from HTTP request for resumption
- deliverLocked: writes/stores messages, handles request accounting

Factor out hangResponse to document HTTP response lifecycle.

Inline writeEvent to eliminate confusing pointer-based index
management.
2025-12-10 13:28:25 -05:00
Markus Kusano
dd5a8ff77b mcp: clarify documentation for the streamable transports
After a deep dive with the team, document areas of the codebase
identified as unclear. For now, this is a documentation-only commit (apart
from one switch of jsonrpc2.Request.ID.IsValid->Request.IsCall). Special
TODO(cleanup) comments are added for additional code changes in
follow-up commits.

Also, include high level doc comments for server and client transports,
in new streamable_server.go and streamable_client.go. Eventually, the
server and client transport logic should be migrated to these files, as
streamable.go has gotten too large. However, we can do that at a future
date, to minimize diff.
2025-12-10 10:46:10 -05:00
Rob Findley
b8c21e9fc0 mcp: add lastEventIDHeader for streamable implementation
Use a constant, to be consistent with other headers.
2025-12-10 10:46:10 -05:00
Robert Findley
afe8888129
examples: improve example for listfeatures (#701)
Use an example from the Go SDK, rather than something that requires
node.js.

Fixes #700
2025-12-10 10:26:22 -05:00
Robert Findley
d1c06cb748
internal/docs: document UserID for session hijacking prevention (#697)
Update our Session Hijacking mitigation documentation to describe the
new TokenInfo.UserID field and how the streamable transport uses it to
bind sessions to users.

Fixes #571
2025-12-08 15:25:34 -05:00
Robert Findley
87c81260e2
mcp: gate prime and close events on protocol version 2025-11-25 (#696)
The prime and close SSE events (SEP-1699) were added in protocol version
2025-11-25. Only send these events when the client negotiates that
version or later.

- In servePOST, extract protocol version from InitializeParams for
initialize requests, otherwise use the Mcp-Protocol-Version header
- In serveGET/acquireStream, read protocol version from header
- Only set closeLocked callback when prime/close is supported
- Add unexported protocolVersion field to ClientSessionOptions for
testing

Fixes #686
2025-12-08 15:24:41 -05:00
Eliya Sadan
d6d6edd6d4
auth: add OAuth 2.0 Protected Resource Metadata handler
This change adds support for RFC 9728 (OAuth 2.0 Protected Resource Metadata)
by introducing a `ProtectedResourceMetadataHandler`.

The handler includes built-in CORS support with `Access-Control-Allow-Origin: *`
by default, as OAuth metadata is public information meant for client discovery.

Documentation includes examples for using custom CORS policies with
popular middleware libraries (github.com/rs/cors and github.com/jub0bs/cors).

The implementation follows RFC 9728 §3.1 for OAuth 2.0 Authorization Server
Metadata discovery, enabling clients to discover protected resource capabilities
and authentication requirements.
2025-12-08 14:54:52 -05:00
Robert Findley
18cd63599d
auth, mcp: add UserID to TokenInfo for session hijacking prevention (#695)
Add a UserID field to auth.TokenInfo that TokenVerifiers can populate
from JWT "sub" claims or token introspection. The streamable HTTP
transport uses this to bind sessions to users, rejecting requests where
the user ID doesn't match the session's original user.

Fixes #589
2025-12-08 14:32:33 -05:00
Robert Findley
6c16aa60a6
scripts: add conformance test runner (#694)
Add a script to run the official MCP conformance tests against the SDK's
conformance server. The script supports saving results to a custom
directory (--result_dir) and running against a local checkout of the
conformance repo (--conformance_repo).

Document the script in CONTRIBUTING.md.

For #650
2025-12-08 13:03:17 -05:00
Robert Findley
7b8f83fa1b
.github: add permissions to the nightly workflow (#690)
This is best practice, and I'd missed it while adding the nightly
vulncheck workflow.
2025-12-08 12:58:02 -05:00
Robert Findley
3b42db997c
examples: add a server for conformance testing (#681)
Add a server example for the new conformance test suite.

Passes all current conformance tests.

For #650
2025-12-08 10:32:21 -05:00
Robert Findley
4c52f37649
SECURITY.md: add a security policy (#682)
Consistent with other SDKs (typescript, python, csharp), add a
SECURITY.md file citing Anthropic's overarching security policy.

This is not specialized to the Go SDK, but seems better than not having
a policy.
2025-12-05 16:00:32 -05:00
Robert Findley
272e0cd4f5
mcp: better handling for streamable context cancellation (#677)
After walking through our handling of streamable client context
cancellation (due to encountering a shutdown deadlock), I think I've
settled on a more coherent strategy for handling call cancellation:

- In our call handler, retire the request if the call exits due to
cancellation: the caller will never see the actual result anyway.
- In connectSSE, use the actual request context (the same context used
in Write) for the client request, so that it terminates when the context
is cancelled. Thread through the initialization context for the
standalone SSE request.

Also, a couple minor improvements:
- Use a detached context for the background context of the client
connection. We want to preserve context values (see #513), but it is not
right to cancel the connection after Connect has already returned, if
the context times out.
- Don't use Last-Event-ID != "" as the signal for whether the connectSSE
call is initial: if the standalone SSE stream disconnects without an
event ID, we'll still reconnect it, and don't want to do so without a
delay.

+ tests, updating the streamable client connection test harness to
accomodate the new aspects being exercised.

Fixes #662
2025-12-03 12:26:50 -05:00
Robert Findley
8adc1e3a3d
CONTRIBUTING.md: add a dependency update policy, and nightly vulncheck (#678)
Add a section the our CONTRIBUTING.md describing when and how
dependencies should be updated, and the criteria for adding a new
dependency.

Also, add a nightly workflow to run vulncheck.

Fixes #635
2025-12-03 11:07:05 -05:00
Robert Findley
6a87ca8d62
CONTRIBUTING.md: defer to the blanket antitrust policy (#661)
Defer to the model context protocol's blanket antitrust policy, rather
than maintain an ad-hoc antitrust policy.


https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/ANTITRUST.md

Fixes #651
2025-12-03 10:55:24 -05:00
Markus Kusano
5928940d5f
mcp/mcp_test: tests for elicit content validation (#676)
This adds a simple schema and checks that the content returned by an
elicitation handler is validated against the schema. Previously, we had
no test coverage checking if the content was validated (i.e., we would
see no test failures if we removed content validation against the
schema).

The bulk of the actual validation logic is handled by the jsonschema
library so adding comprehensive tests covering different schema-features
is redundant, we simply need to see that some validation is happening.

See https://github.com/modelcontextprotocol/go-sdk/issues/625 for more
details on the motivation of this change.

Fixes #625

---------

Co-authored-by: Markus Kusano <kusano@google.com>
2025-12-03 10:12:07 -05:00
Robert Findley
623780125c
mcp: support SSE polling and server disconnects (SEP-1699) (#663)
This CL implements support for SEP-1699, adding the following new API:

- Event.Retry corresponds to the 'retry' field of a server sent event.
This is used to signal client retry behavior.
- RequestExtra.CloseStream is set by the streamable transport to allow
closing a stream.

The streamable server transport is updated to set CloseStream for calls,
allowing server operations or middleware to close the underlying stream.
If the configured 'reconnectAfter' delay is set, a 'retry' message is
sent prior to terminating the stream.

The streamable client transport is updated to read the configured delay.

Fixes #630
2025-12-01 16:21:37 -05:00
isfzhang
1bec3c60a0
fix: handle Windows CRLF in MCP client(#664) (#665)
This change updates the MCP client stdio JSON decoder to correctly
handle
both Unix (`\n`) and Windows (`\r\n`) line endings. 

Fixes #664

Co-authored-by: qysz <i_zf@qq.com>
2025-12-01 12:16:39 -05:00
Robert Findley
2ce44d45e9
all: expose JSON-RPC error codes, and support URLElicitationRequired errors (#655)
Expose the jsonrpc.Error type to allow access to underlying JSON-RPC
error codes. Also, expose common JSON-RPC error codes in the jsonrpc
package, and MCP error codes in the mcp package.

Also, implement support for the MCP URL elicitation required error
(-32042), enabling servers to request out-of-band user authorization and
clients to automatically handle these requests with retry logic.

Server-side:
- Add CodeURLElicitationRequired constant
- Add URLElicitationRequiredError() constructor.

Client-side:
- Add urlElicitationMiddleware to intercept URLElicitationRequired
  errors and retry calls.
- Update callElicitationCompleteHandler to signal waiting operations.
- Fix capability advertisement to support both form and URL modes.

Fixes #452
Fixes #623
2025-12-01 11:29:17 -05:00
Robert Findley
96385fde3c
docs: document non-pointer receiver for AudioContent (#660)
AudioContent should have had a non-pointer receiver, to be consistent
with other content types. Add this to our log of rough edges to
reconsider for v2.

Fixes #641
2025-11-26 10:27:32 -05:00
Robert Findley
21fb03dd1a
mcp: support url mode elicitation (#646)
Add initial support for URL mode elicitation, by introducing the new
types, as well as both server and client-side validation.

A follow-up CL will add support for ErrURLElicitationRequired.

For #623
2025-11-23 12:58:28 -05:00
Markus Kusano
d9263f7e47
mcp: support elicitation defaults (#644)
Fixes #617

---------

Co-authored-by: Markus Kusano <kusano@google.com>
2025-11-21 16:15:21 -05:00
Robert Findley
1943780255
mcp: validate tool names (#640)
Implement SEP 986, enforcing restrictions on tool names. Since we're
already at v1 we couldn't turn this into a panic, so use an error log
instead. This is consistent with the typescript SDK. A note is left in
our 'rough edges' doc to panic in v2.

Fixes #621
2025-11-19 17:01:50 -05:00
Raphael MANSUY
9ef2b2742e
Fix: Skip non-message SSE events in processStream (#637)
Fixes #636

## Problem
The StreamableClientTransport tries to JSON-decode ALL SSE events,
including ping events sent by servers for keep-alive purposes. This
causes errors like 'invalid character 'p' looking for beginning of
value' when encountering non-JSON event data.

## Solution
Modified processStream to check evt.Name and skip events that are not
'message' events (or unnamed events, which default to 'message' per SSE
spec).

## Changes
- Added event name check in processStream before attempting JSON decode
- Added test case for ping event filtering
- Added test for scanning multiple events including ping events

## Testing
- All existing tests pass
- New tests verify ping events are properly filtered
- Tested with DeepWiki MCP server which sends ping events
2025-11-13 20:48:23 -05:00
Suraj Bobade
faddd764aa
Implement SEP-973 (#570)
mcp/protocol: Implement SEP-973

- Define Icon structure, which includes source, mimeType and sizes.
- sizes is any array of strings. refer
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1531
- Support setting websiteUrl, icons for mcp.Implementation
- Support setting icons for mcp.Prompt
- Support setting icons for mcp.Tool
- Support setting icons for mcp.Resource

Fixes #552
2025-11-12 16:52:44 -05:00
Spring_MT
35dfcf21c9
examples: Fix SSE streaming issue by moving logging from HTTP to MCP middlewarre (#614)
In `examples/http`, previous HTTP-level logging middleware blocked SSE
streaming because `handler.ServeHTTP()` does not return until the
connection closes for GET requests (SSE streams).
This prevented response headers from being sent to the client.

Changes:
- Replace HTTP-level logging handler with MCP middleware pattern
- Implement logging at the MCP protocol layer using mcp.Middleware
- Add middleware to server using AddReceivingMiddleware()
- Simplify main.go by removing HTTP handler wrapping

This allows SSE streams to work properly while still providing detailed
logging for all MCP protocol-level method calls.

Fixes #632
2025-11-11 11:56:52 -05:00
Xie Zhihao
d297272705
mcp: relax SSE connection response handling in non-strict mode (#611)
Some MCP servers do not support SSE, but when receiving a request, they
return 400 Bad Request or 404 Not Found instead of the standard 405
Method Not Allowed. The TypeScript and Python SDK ignore this error,
while the Go SDK terminates the session. This patch addresses the issue
in the non-strict mode.

Fixes #610

---------

Signed-off-by: Xie Zhihao <zhihao.xie@bytedance.com>
2025-11-03 10:12:28 -05:00
Robert Findley
32d84d8421
docs: document known rough edges (#609)
Start keeping a log of rough edges we've discovered post v1.0.0, so that
they're discoverable (along with their workarounds), and so that we can
fix them in v2.
2025-10-29 10:57:45 -04:00
Ruturaj Dattatray Kadam
72afbc91bd
auth: change OAuthHandler to take http Request and Response (#603) v1.1.0 v1.1.0-pre.2
Change OAuthHandler signature from func(context.Context,
OAuthHandlerArgs) to func(req *http.Request, res *http.Response).

- Remove OAuthHandlerArgs struct
- Update HTTPTransport to pass req and resp to handler
- Update tests to use new signature
- Handler can now call oauthex.GetProtectedResourceMetadataFromHeader
with proper validation against request URL

This change fixes an impedance mismatch between OAuthHandler and the
protected resource metadata functions of the oauthex package. The new
signature allows handlers to properly validate resource metadata against
the request URL, as required by RFC 9728.

Fixes #600
2025-10-29 10:08:40 -04:00
Robert Findley
d256a9c109
mcp: don't persist failed streamable sessions (#605)
If a stateful streamable session fails to initialize, it is unusable.
Avoid allocating resources by closing the session immediately.

Also:
- Fix a bug where InitializeParams is not guarded with its mutex.
- Fix a resource leak where sessions are persisted with session id "",
even though they are unaddressable.
- Add a relevant benchmark, and update tests.

Fixes #578
2025-10-27 16:29:16 -04:00
Robert Findley
ae6bda692b
mcp: establish the streamable client standalone SSE stream in Connect (#604)
When Connect returns, client should be guaranteed that the streamable
SSE stream is connected.

Fixes #583
2025-10-27 14:03:22 -04:00
Robert Findley
80abbe6171
docs: document support for resumability and redelivery (#606)
Add missing documentation on resumability and redelivery in the
streamable transport.

Indirectly, also update stale transcluded examples. Example changes
weren't causing CI failure as we only trigger the docs check on changes
to the raw docs.
2025-10-27 14:00:58 -04:00
Robert Findley
1a907bcd6f
auth: clone the client request body before roundtripping (#597) v1.1.0-pre.1
RoundTrippers may read and close the body, so be careful to clone before
roundtripping during client oauth, as the request may be issued multiple
times.

Fixes #590
2025-10-23 09:29:53 -04:00
Robert Findley
f01e7faaf5
mcp: add StreamableHTTPOptions.SessionTimeout (#594)
Add a timeout option for the streamable HTTP handler that automatically
cleans up idle sessions.

Also, fix a bug in the streamable client, where we hang on a request
even though the client can never get a response (because the HTTP
request terminated without a response or Last-Event-Id).

Fixes #499
2025-10-23 09:17:20 -04:00
Robert Findley
a5dae3e054
.github: fix staticcheck linting (#599)
Update the test.yml lint job to run linting with Go 1.25, and use the
ambient Go command to run staticcheck. This seems to fix a mysterious
bug where staticcheck was failing, presumably in the Go installation
step. Using the ambient Go command resulted in staticcheck failures,
since some symbols are detected as unused at Go 1.23 due to build tags.
Upgrading the Go version for this job avoids those errors.

Also, use a pinned version of staticcheck (as recommended), to avoid
future failures when new versions are released.
2025-10-22 14:34:51 -04:00
Robert Findley
cfa7a515a9
mcp: add StreamableHTTPOptions.EventStore (#593)
Allow users to enable streamable replay by setting a non-nil event
store.

Updates #587
2025-10-20 14:58:24 -04:00
Robert Findley
8aee8d39bd
mcp: clean up stream metadata after completion (#592)
Address longstanding TODOs to clean up stream metadata after streams are
complete:

- Interpret a missing stream as a complete stream.
- Remove the request->stream mapping when the request completes. Any
writes after that point will fail as there can be no recipient.

Tested using examples/client/loadtest, and updating
TestStreamableTransports to check in-band and out-of-band behavior.
2025-10-20 14:57:56 -04:00