This implements [SEP-1303](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1303).
Input validation errors (missing required fields, wrong types) during
tool calls
are now returned as `CallToolResult` with `IsError=true` instead of
JSON-RPC
`-32602` errors. This allows LLMs to see the validation error and
self-correct,
per the MCP spec.
The existing pattern for handler-returned errors (lines 347-350 in
server.go)
already converts regular errors to tool results with `IsError=true`.
This change
applies the same pattern to argument schema validation and unmarshal
errors,
resolving the `TODO(#450)` in the code.
Thanks to @iwyrkore for filing the issue and proposing the approach, and
@findleyr for the cross-SDK analysis in the discussion.
Fixes#450
Co-authored-by: Maciej Kisiel <mkisiel@google.com>
1. (non-test) Don't queue notifications if there are no connected
sessions.
2. Change `reconnectInitialDelay` to be atomic, as it is modified in
tests.
3. Protect map access with mutex in `TestServerTransportCleanup`.
As reported in
https://github.com/modelcontextprotocol/go-sdk/issues/805, case
insensitive unmarshaling can pose security issues. This change adjusts
all non-test and non-example unmarshaling to use a case sensitive mode.
This introduces a new external dependency
`github.com/segmentio/encoding`.
Summary
Add support for tool use within sampling requests, as described in the
MCP 2025-11-25 spec's sampling.tools capability.
New types
Content types:
- ToolUseContent — represents a tool invocation request from the
assistant
- ToolResultContent — represents the result of a tool invocation, with
nested []Content for the result blocks
Capability types:
- SamplingCapabilities gains Tools and Context sub-fields
- SamplingToolsCapabilities, SamplingContextCapabilities
Tool-enabled sampling (parallel tool calls):
- CreateMessageWithToolsParams with SamplingMessageV2 (supports array
content)
- CreateMessageWithToolsResult (supports array content)
- ToolChoice — controls tool invocation mode (auto, required, none)
- ServerSession.CreateMessageWithTools
- ClientOptions.CreateMessageWithToolsHandler
Design
Following the TypeScript SDK's pattern, tool-enabled sampling uses
separate types from basic sampling to avoid breaking the existing API.
The basic CreateMessage/CreateMessageResult path
is unchanged.
Both paths share the same wire method (sampling/createMessage) and go
through the method info table. The table uses the broader
CreateMessageWithToolsResult type internally;
CreateMessage downconverts (erroring if multiple content blocks are
returned). This is documented as a rough edge to unify in v2.
Setting CreateMessageWithToolsHandler automatically infers the
sampling.tools capability. It is a panic to set both
CreateMessageHandler and CreateMessageWithToolsHandler.
References
-
https://modelcontextprotocol.io/specification/2025-11-25/client/sampling
- TypeScript SDK: CreateMessageResultWithToolsSchema /
CreateMessageRequestParamsWithTools
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Address TODOs in code requiring go 1.24 as minimum version
mcp/logging.go: use slog.DiscardHandler, over local implementation
mcp/util.go: use rand.Text, over local implementation
Fixes#772
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.
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
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#452Fixes#623
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
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
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
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
This PR fixes goroutine leaks in all unit tests.
To find the leaks I integrated https://github.com/uber-go/goleak and I
suggest to keep using it to catch any future regressions.
I used the folowing script to more easily find individual tests which
were leaking goroutines:
```
for t in $(go test -run=Nothing -list=. ./mcp | grep -v ok); do go test ./mcp -run="$t" > /dev/null && echo -n . || echo -e "\nDetected leak: $t"; done
```
mcp/server.go: implement server‑side logging
- Thread a *slog.Logger through server paths to improve debuggability
- Introduce no‑op discard handler + ensureLogger so loggers are never
nil
- Use ensured loggers in Server
- address todo comments related to adding logging support
All tests are passing and no functionality should change with this PR
Fixes https://github.com/modelcontextprotocol/go-sdk/issues/170
As discussed at length in
https://github.com/modelcontextprotocol/go-sdk/issues/518, coupling our
schema fields to
jsonschema.Schema limits our user's ability to use a different schema
package, and makes it impossible for our client to talk to some
backends.
This CL relaxes the type of `*jsonschema.Schema` fields to be of type
`any`, which is a breaking change but is unlikely to affect most server
code. (It *is* a nontrivial change for clients).
Fixes https://github.com/modelcontextprotocol/go-sdk/issues/518
Recently, I refactored to fix validation and default application for
structured output. However, I used the wrong byte slice for the
unstructured output. Fix it to use the same bytes as structured output,
with a test.
Fixes#475
Our validation logic was avoiding double-unmarshalling as much as
possible, by parsing before validation and validating the Go type.
This only works if the Go type has the same structure as its JSON
representation, which may not be the case in the presence of types with
custom MarshalJSON or UnmarshalJSON methods (such as time.Time).
But even if the Go type doesn't use any custom marshalling, validation
is broken, because we can't differentiate zero values from missing
values.
Bite the bullet and use double-unmarshalling for both input and output
schemas. Coincidentally, this fixes three bugs:
- We were accepting case-insensitive JSON keys, since we parsed first,
even though they should have been rejected. A number of tests were
wrong.
- Defaults were overriding present-yet-zero values, as noted in an
incorrect test case.
- When "arguments" was missing, validation wasn't performed, no defaults
were applied, and unmarshalling failed even if all properties were
optional.
First unmarshalling to map[string]any allows us to fix all these bugs.
Unfortunately, it means a 3x increase in the number of reflection
operations (we need to unmarshal, apply defaults and validate,
re-marshal with the defaults, and then unmarshal into the Go type).
However, this is not likely to be a significant overhead, and we can
always optimize in the future.
Update github.com/google/jsonschema-go to pick up necessary improvements
supporting this change.
Additionally, fix the error codes for invalid tool parameters, to be
consistent with other SDKs (Invalid Params: -32602).
Fixes#447Fixes#449
Updates #450
Add example/server/toolschemas, which demonstrates various ways to
customize tool schemas, and illustrates the differences between
ToolHandler and ToolHandlerFor.
Fixes#385Fixes#386
For #368
Upon a closer reading of the spec, it is OK for the server to response
to client requests before it has received notifications/initialized (as
long as it has received initialize). This effectively rolls back the fix
from #225.
Some hooks are left for enforcing strictness around server->client
requests prior to initialized. These will be revisited in subsequent
CLs.
For #395
toolForErr was ignoring the output schema if the output type was any.
That neglected the case where the user provided their own output schema.
Fixes#371.
remove checks for URI scheme; nothing in the spec requires one
# Background
When adding resource templates, we are currently doing checks for
schemes on absolute uris. It is still common for MCP servers to use
custom uris that would not pass these checks. For example, if the
official GitHub MCP server were to use this sdk, it would show failures
like:
```
"repo://{owner}/{repo}/contents{/path*}": parse "repo://{owner}/{repo}/contents{/path*}": invalid character "{" in host name
"repo://{owner}/{repo}/refs/heads/{branch}/contents{/path*}": parse "repo://{owner}/{repo}/refs/heads/{branch}/contents{/path*}": invalid character "{" in host name
"repo://{owner}/{repo}/sha/{sha}/contents{/path*}": parse "repo://{owner}/{repo}/sha/{sha}/contents{/path*}": invalid character "{" in host name
invalid resource template uri "repo://{owner}/{repo}/refs/pull/{prNumber}/head/contents{/path*}": parse "repo://{owner}/{repo}/refs/pull/{prNumber}/head/contents{/path*}": invalid character "{" in host name
"repo://{owner}/{repo}/refs/tags/{tag}/contents{/path*}": parse "repo://{owner}/{repo}/refs/tags/{tag}/contents{/path*}": invalid character "{" in host name
```
The wikipedia MCP would also show problems with missing schemes.
```
"/search/{query}": <nil>
"/article/{title}": <nil>
"/summary/{title}": <nil>
"/summary/{title}/query/{query}/length/{max_length}": <nil>
"/summary/{title}/section/{section_title}/length/{max_length}": <nil>
"/sections/{title}": <nil>
"/links/{title}": <nil>
"/facts/{title}/topic/{topic_within_article}/count/{count}": <nil>
"/coordinates/{title}": <nil>
```
An onClose function is passed to the ServerSession and ClientSession to
help cleanup resources from the caller.
The onClose function will be executed as part of the ServerSession and
ClientSession closure.
Fixes#258
Our 'hello' example should be as simple as possible. On the other hand,
we should have an 'everything' example that exercises (almost)
everything we offer.
Using the everything example, I did some final testing using the
inspector. This turned up a couple rough edges related to JSON null that
I addressed by preferring empty slices.
For #33
The spec makes it clear that input schemas must have type "object".
Enforce that.
Allow "any" as an input argument type by special-casing it.
Fixes#283.