Add a benchmark using the streamable HTTP handler, and a more realistic input/output signature. Also expose this handler as an example (both a go example and a server in the examples/ directory).
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
Add a new benchmark measuring the append and purge performance of the
MemoryEventStore. This benchmark revealed that the store is orders of
magnitude slower than it should be due to conservative validation
(hugely so: 300KB/s vs 568MB/s). Turn off this validation by default.
For #190
Add a framework for feature documentation, and start populating it with
our SDK documentation.
This framework is as follows:
- internal/docs/**.src.md is the markdown source for the docs/
directory.
- The x/example/internal/cmd/weave tool is used to compile these docs to
the top-level docs, supporting both linked code samples and generated
tables of contents.
- The readme-check workflow is updated to check these docs as well.
- The structure of these docs follows the MCP spec.
- Wherever possible, example code is linked from actual Go documentation
examples, so that it is testable.
Some minor modifications to the weave tool were made to support this
framework.
Additionally, partially fill out this documentation with content on
base protocol and client features, as well as troubleshooting help.
Along the way, a bug was encountered that our LoggingTransport was not
concurrency safe. This is fixed with a mutex.
Fixes https://github.com/modelcontextprotocol/go-sdk/issues/466
Fixes https://github.com/modelcontextprotocol/go-sdk/issues/409
Updates https://github.com/modelcontextprotocol/go-sdk/issues/442
At 7s, this test was 70% of our test execution time on my computer.
Speed it up by mutating the defaultTerminateDuration for the purposes of
the test.
Also update our test workflow to use go1.25, now that it's out.
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
Simplify the readme generation to just use go:generate, no longer
depending on Make or bash.
Subsequent CLs will generate more documentation in a similar manner.
For #442
Previously, the error message received from ClientSession.Wait would
only report the closeErr, which would often be nil even if the client
transport was broken. Wait should return the reason the session
terminated, if abnormal.
I'm not sure of the exact semantics of this, but surely returning nil is
less useful than returning a meaningful non-nil error. We can refine our
handling of errors once we have more feedback.
Also add a test for client termination on HTTP server shutdown,
described in #265. This should work as long as (1) the session is
stateful (with a hanging GET), or (2) the session is stateless but the
client has a keepalive ping.
Also: don't send DELETE if the session was terminated with 404; +test.
Fixes#265
In #272, we made transports open structs and deprecated their
constructors. However, we left the constructors in place to allow go:fix
directives to facilitate migration.
Now let's remove the constructors before cutting the release.
Fixes#305
Make the process termination timeout configurable instead of using a
hardcoded 5-second delay. This allows applications to customize the
termination behavior based on their specific needs.
Fixes#322.
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
The streamable client connection can break for a variety of reasons,
asynchronously to the client's request. Decorate these failures with
additional context to clarify why they occurred.
Add a test for the failure message of #393.
Fixes#393
Use a fake streamable server to facilitate testing client behavior.
For this commit, just update the existing test (moved to a new file for
isolation). Subsequent CLs will add more tests.
Improve one client error message that occurred while debuging tests.
For #393
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.
During initialization, the default logging level is set to info allowing
servers to emit logs immediately without waiting for a client to set a
log level.
The updated example shows how to send a notification in the context of
the request.
Fixes#387
The condition sessionID == "" was not quite right for disallowing GET
requests. Since we decided to differentiate "stateless" vs "sessionless"
servers, we need to disallow GET requests for both.
For #393
Exporting StreamableHTTPOptions.JSONResponse is helpful for some users behind proxies that don't work well with text/event-stream.
For #211
Co-authored-by: ccpro10 <co1797249167@gmail.com>
This CL utilizes the event store to write outgoing messages and removes
the unbounded outgoing data structure.
It also adds a new interface [EventStore.Open]
For #190
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
Add to the middleware example to show how to wrap a ToolHandler.
This middleware is very close to, but not the same as, wrapping a
ToolHandler directly. The only difference is that the middleware wraps
Server.callTool, which looks up the tool by name in the server's list
and then calls the handler. That lookup (plus other intervening
middleware, of course) is all that distinguishes this way of wrapping
from a more direct wrapping.
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.