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.
This is needed so clients can modify tool schemas, and not merely to
wrap ToolHandlers.
(A consequence of returning a copy of Tool instead of modifying it.)
Replace all occurrences of ServerRequest[*CallToolParams] and other
concrete instantiations with CallToolRequest and the like.
Make the XXXRequest types aliases, to preserve the convenience of
generics for the internal machinery (see shared.go, for example.)
I will expand the aliases in a followup PR.
As reported in #199 and #200, the fact that we return a possibly "null"
schema for pointer types breaks various clients, which expect schemas to
be of type "object". This is an unfortunate footgun. For now, assume
that the user wants us to treat pointers equivalently to non-pointers.
If we want to change this behavior in the future, we can do so behind an
option.
+ a test
Also fix the handling of nil results in the case where the output schema
is non-nil: we must provide structured content in this case. (This was
causing the test to fail).
Fixes#199Fixes#200
Change the design of tool handlers by removing genericity from the common path.
- `ToolHandler` gets the args as a `json.RawMessage`. Using Server.AddTool does no unmarshaling or schema validation.
- `ToolHandlerFor`, installed with `AddTool`, are the only generic pieces.
TODO:
uncomment and fix some tests
This change adopts a clearer convention:
- any is used for fields where the structure is defined by the client or
server implementer.
- an named empty struct type is the place holder type to be defined by
the MCP spec in the future.
The "Experimental" fields in "ClientCapabilities" and
"ServerCapabilities" now use "map[string]any". This allows clients and
servers to negotiate custom capabilities that contain complex data,
rather than being restricted to a simple on/off flag.
The "Metadata" field in "CreateMessageParams" was also changed to "any"
to properly serve its purpose as a flexible container for server-defined
data.
This CL enables the server session to see what capabilities the client
has by introducing the InitializeParams() function.
This CL also adds a test to ensure ClientCapabilities is accurate.
Fixes#141
- Fix tool error handling to properly distinguish between protocol
errors and tool execution errors
- Return structured JSON-RPC errors directly for protocol-level issues
- Embed regular tool errors in CallToolResult as per MCP specification
- Improve server error responses for unknown prompts and tools
- Add comprehensive tests for both structured and regular error handling
If there is a TokenInfo in the request context of a
StreamableServerTransport, then propagate it through to the
ServerRequest that is passed to server methods like callTool.
Fixes#317.
A few problems with reconnection cropped up in the review of PR #307.
We should allow for the hanging GET to fail with StatusMethodNotAllowed.
This simply means that the server does not support sending notifications
or requests over the GET, which is allowed in the spec.
Also, we should fix the initial delay of the hanging GET request: it
should start with 0 delay. Fix the math for this and subsequent
attempts. Incidentally, this makes the tests take 3s on my machine, down
from 9s.
Also address some comments from #307.
Several improvements for the stateless streamable mode, plus support for
a 'distributed' (or rather, distributable) version of the stateless
server.
- Add a 'Stateless' option to StreamableHTTPOptions and
StreamableServerTransport, which controls stateless behavior.
GetSessionID may still return a non-empty session ID.
- Audit validation of stateless mode to allow requests with a session
id. Propagate this session ID to the temporary connection.
- Peek at requests to allow 'initialize' requests to go through to the
session, so that version negotiation can occur (FIXME: add tests).
Fixes#284
For #148
Implement the concurrency model described in #26: notifications are
synchronous, but calls are asynchronous (except for 'initialize'). To
achieve this, implement jsonrpc2.Async(ctx) to signal asynchronous
handling. This is simpler to use than returning ErrAsyncResponse and
calling Respond, and since this is an internal detail we don't need to
worry too much about whether it's idiomatic.
Add tests that verify both features, for both client and server.
Also:
- replace req.ID.IsValid with req.IsCall
- remove the methodHandler type as we can just use MethodHandler
Fixes#26
Export ServerCapabilities and related subtypes and update protocol,
server, and tests to use exported types. Add InitializeResult method on
ClientSession for accessing the initialize result from sessions.
Fixes: https://github.com/modelcontextprotocol/go-sdk/issues/166
Co-authored-by: Shashank Pachava <spachava753@gmail.com>
- Adds `go vet` call to the lint step in GA workflow.
- Enforces a compatible `go-version` with the minimum in the matrix for
the `test` step.
- Fixes some minor `.yml` formatting
Fixes#281
---
There's some discussion in #281 about adding
[staticcheck](https://staticcheck.dev/docs/) as well but when I ran it,
it found some hits (see below) that are presumably not severe, and I
wouldn't want to block deployments before getting some feedback from
maintainers.
```
internal/jsonrpc2/conn.go:695:4: this value of writeErr is never used (SA4006)
internal/jsonrpc2/conn.go:697:5: this value of err is never used (SA4006)
internal/jsonrpc2/conn.go:700:4: this value of err is never used (SA4006)
mcp/mcp_test.go:501:2: var resource3 is unused (U1000)
mcp/mcp_test.go:509:5: var embeddedResources is unused (U1000)
mcp/mcp_test.go:513:6: func handleEmbeddedResource is unused (U1000)
mcp/streamable.go:124:3: unnecessary assignment to the blank identifier (S1005)
mcp/streamable.go:291:2: field lastStreamID is unused (U1000)
mcp/streamable.go:293:2: field opts is unused (U1000)
mcp/streamable_test.go:542:29: argument ctx is overwritten before first use (SA4009)
```
Do a pass through the streamable client reconnection logic, and fix
several bugs.
- Establish the initial GET even if MaxRetries is 0 (#256). This was
broken because the GET bypasses the initial request and going straight
to the SSE GET reconnection logic.
- Release the stream ownership when POST requests exit.
- Don't reconnect POST requests if we've received the expected response.
- Move unexported reconnection config to constants. Otherwise it is too
hard to set ReconnectOptions (you have to use the DefaultOptions and
mutate).
Fixes#256