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>
In #202, I added the checkRequest helper to validate incoming requests,
and invoked it in the stremable transports to preemptively reject
invalid HTTP requests, so that a jsonrpc error could be translated to an
HTTP error.
However, this introduced a bug: since cancellation was handled in the
jsonrpc2 layer, we never had to validate it in the mcp layer, and
therefore never added methodInfo. As a result, it was reported as an
invalid request in the http layer.
Add a test, and a fix. The simplest fix was to create stubs that are
placeholders for cancellation.
This was discovered in the course of investigating #285.
Handlers and client/server methods take a single request argument
combining the session and params. This slightly simplifies the signature
for handlers, since there is no longer an often-ignored session
argument.
But more importantly, it opens the door to adding more information in
requests, such as auth info and HTTP request headers.
For #243.
Support stateless streamable sessions by adding a GetSessionID function
to StreamableHTTPOptions. If GetSessionID returns "", the session is
stateless, and no validation is performed. This is implemented by
providing the session a trivial initialization state.
To implement this, some parts of #232 (distributed sessions) are copied
over, since they add an API for creating an already-initialized session.
In total, the following new API is added:
- StreamableHTTPOptions.GetSessionID
- ServerSessionOptions (a new parameter to Server.Connect)
- ServerSessionState
- ClientSessionOptions (a new parameter to Client.Connect, for symmetry)
For #10
Update ServerSession so that the session is not marked as initialized
until 'notifications/initialized' is actually received from the client.
Include a new test of this lifecycle strictness.
Fixes#225
Make the simplifications described in #222. I don't know why we
originally had such fine granularity of locking: perhaps we were going
to execute 'oninitialized' callbacks.
Also update the TODO with a bit more information about jsonrpc2
behavior.
Fixes#222
## Background
Since the Server has a map of ServersSessions->subscriptions, and takes
care of routing ResourceUpdate messages to ServerSessions, I think the
decision was made to leave *ServerSession out of the
SubscribeHandler/UnsubscribeHandler signatures. However, resource
subscriptions are not specific to the a particular client and this
information is kept private in the Session today.
## Proposal
Align the Subscribe/Unsubscribe handlers with the other two handlers
that are client specific (ProgressNotificationHandler, and
RootListChangeHanlder), and include *ServerSession in the signature.
It comes in practice because because a gateway server that needs to
forward subscriptions still needs this information. The routing logic in
Server is convenient and means that most servers won't need to know
which ServerSessions are subscribed. But I think there are still use
cases where the user will need to know.
Audit all cases where params must not be null, and enforce this using
methodInfo via a new methodFlags bitfield that parameterizes method
requirements. Write extensive conformance tests catching all the
(server-side) crashes that were possible.
We should go further and validate schema against the spec, but that is
more indirect, more complicated, and potentially slower. For now we
adopt this more explicit approach.
Still TODO in a subsequent CL: verify the client side of this with
client conformance tests.
Additionally, improve some error messages that were redundant or leaked
internal implementation details.
Fixes#195
Add an isRequest field to methodInfo, used it to reject non-notification
requests that lack a valid ID. Furthermore, lift this validation to the
transport layer for HTTP server transports, so that we can preemptively
reject bad HTTP requests.
Fixes#194Fixes#197
This CL adds an option for servers to advertise support for features
that have not been added yet. This includes Prompts, Tools, and
Resources as these could be dynamically added after initialization.
Fixes: #135.
If tools are added to a Server when Run is called, it will send
toolCapabilities to the client. Otherwise it won't. Ditto for prompts
and resources.
For #56.
Negotiate the protocol version properly, and set the header on HTTP
transports.
We follow the logic of the Typescript SDK.
- On initialization, the client sends the latest version it can support,
and accepts the version that the server returns if the client supports
it. If not, the connection fails.
- The server accepts the client's version unless it doesn't support it,
in which case it replies with its latest version.
Fixes#103.
Make `Server.Run` return when the provided context is canceled.
Add tests for when the `Run` context is cancelled and also for when the
server process receives a signal.
Fixes#107.
BREAKING CHANGE
Change the API for adding tools, prompts, resources and resource
templates to a server.
The ServerXXX types are gone along with the plural Add methods
(AddTools, AddPrompts etc.)
Instead there are single Add methods (AddTool, AddPrompt).
In addition, instead of NewServerTool, there is AddTool[In, Out].
Fixes#73.
This CL implements a completion handler for the server and a complete
method for the client.
Fixes: #12
<!-- Provide a brief summary of your changes -->
## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
This adds support for completion.
## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->
Added tests and an example.
## Breaking Changes
<!-- Will users need to update their code or configurations? -->
N/A
## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->
After some experience with the flattened version of Content, we see that
it can easily lead to incorrect usage and is a harder API to read.
Therefore, this CL changes back to a design similar to what we had prior
to https://go.dev/cl/672415, though opting to promote content
unmarshalling to the protocol types that use it, which leads to an
overall simpler api.
* mcp: move to 2025-06-18 schema
Add types and fields for the latest MCP schema.
The main challenge here was dealing with the presence of _meta fields
on many types, like Tool, Prompt and Resource.
- Distinguish between the _meta field of a request's params, which
includes a progress token, from the _meta field on other types,
which is simply a map.
- Redefine GetMeta to return a pointer to the map. We wanted to avoid
that, but I don't see a clean way to do so. An alternative would be
to have GetMeta return a map, and SetMeta to set it.
- Provide GetProgressToken for requests only (not notifications or other
types).
- Still to do: deal with the meta and annotation fields of ContentBlock,
which are currently duplicated for Resource and ResourceContents.
* Meta and progress token redesign
Use JSONRPCMessage, JSONRPCRequest, and JSONRPCResponse aliases
throughout the internal/mcp package, so that no jsonrpc2 names are
exposed in the public API.
Change-Id: Ibce794907538706448c694eafccf599a5892ab17
Reviewed-on: https://go-review.googlesource.com/c/tools/+/682796
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Add a test that checks for JSON null on the wire, and fix two categories
of bugs leading to null:
1. In many places, we could pass typed nil where we shouldn't have. Add
an orZero helper to avoid typed nills.
2. When listing roots, we should avoid nil.
Fixesgolang/go#74105
Change-Id: I061420487dbfcbf9016cb94b39bd72270e871c0e
Reviewed-on: https://go-review.googlesource.com/c/tools/+/682675
Reviewed-by: Sam Thanawalla <samthanawalla@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Update protocol versions to reflect that 2025-03-26 is supported, and
add server logic to negotiate the supported version with the client.
Update the client to set the protocol version, fixing what was probably
a spec violation.
+tests
Change-Id: I564b591b3daf018dd54f5c7e5d8f2d2b1e4ff502
Reviewed-on: https://go-review.googlesource.com/c/tools/+/682516
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Sam Thanawalla <samthanawalla@google.com>
The NewTool and NewPrompt constructors were unidiomatic, because they
returned a ServerTool and ServerPrompt, respectively, rather than a Tool
and Prompt. Rename to be consistent with the constructed object name.
Change-Id: Ife3f16f783368401f792660c4272e1bb5ae61638
Reviewed-on: https://go-review.googlesource.com/c/tools/+/682375
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Add an (almost) complete implementation of the streamable HTTP
transport, including:
- A StreamableHTTPHandler for serving sessions.
- A StreamableHTTPServerTransport that supports session resumption.
- A minimal StreamableHTTPClientTransport.
Additionally, include the following minor changes:
- Refactor SSE event reading to use an iterator.
- Start to to aliases for JSON-RPC types (incomplete)
- Fix handling for null tool arguments (again)
Still to do:
- The streamable client does not support retry/resumption, or the
side-channel GET requests.
- Support configurable session and event retention (garbage collection).
- Expose the HTTP client used for HTTP requests (for auth).
Change-Id: Ieba216ef901169b4660d601386fa0c7c7bb4c4b2
Reviewed-on: https://go-review.googlesource.com/c/tools/+/667515
Reviewed-by: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This CL adds a NotifyProgress function and a ProgressNotificationHandler
to enable progress sending and handling.
Subsequent CL's to follow to handle progress updates for other methods such as list or readresource.
Change-Id: Ifcc422e6f6231d7d773d5432c1cf64032d796709
Reviewed-on: https://go-review.googlesource.com/c/tools/+/681116
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Sam Thanawalla <samthanawalla@google.com>
Before validating a tool input, apply the defaults from the input
schema.
Change-Id: I23fae4087f898d51b3d1f0578d3203b954cb5f2d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/680395
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
CallToolParams.Arguments is any.
Clients can send whatever they want.
Tool authors who create their own ToolHandler (bypassing NewTool)
will receive the arguments as a map[string]any which has been
validated against the input schema.
Tool authors who call NewTool can choose the type that the arguments
unmarshal into.
There is no double-unmarshaling and no downcasting.
There is no way for tool authors to avoid the unmarshal, and no way to
avoid the validation unless the omit an input schema, which is probably
bad for LLMs. If tool authors want this optimization, we can provide
it later.
Change-Id: Ieb201e56c7fb8a23bb1a93b27e946630ec9e79ad
Reviewed-on: https://go-review.googlesource.com/c/tools/+/679595
TryBot-Bypass: Jonathan Amsterdam <jba@google.com>
Auto-Submit: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Provide support for resource templates on the client and server.
Adding, removing and listing resource templates looks just like those
operations on resources.
Although the spec provides no guidance on the unique ID for resource
templates, we follow most existing SDKs, as well as the parallel with
resources, and index on the URI template rather than the name.
As the spec recommends, the server verifies an incoming URI in a
ReadResource request against its list of resources and resource
templates, to make sure the URI came from one of them. The main
technical challenge here is the need to check that a URI template could
have produced a particular URI.
I wrote a very simplified version of this check. At some point
we should switch to github.com/yosida95/uritemplate/v3.
Change-Id: I1e34dd01c8f2171123c68c045ad62f5e85c05e7c
Reviewed-on: https://go-review.googlesource.com/c/tools/+/680158
Auto-Submit: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Add Wrapf, a function that helps with error wrapping.
Change-Id: I102695f75e4d217e09f828f4723cbfcbbe83f887
Reviewed-on: https://go-review.googlesource.com/c/tools/+/679177
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Sam Thanawalla <samthanawalla@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This CL simplifies the paginateList function in server.go to use a
generic helper for tools, resources, and prompts.
Change-Id: Ide0d2a90d715374280067e094d8870882e6bddfa
Reviewed-on: https://go-review.googlesource.com/c/tools/+/678055
Auto-Submit: Sam Thanawalla <samthanawalla@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Unexport our nice root-respecting local-filesystem resource handler.
It's unclear how roots should interact with a resource handler that
uses the local filesystem. All we know from the spec is that servers
should "respect root boundaries during operations," but it's not
clear how they can do that reliably if root changes are notifications,
meaning there is no causality between a client changing a root and then
asking the server for a file. (Maybe the server sees the new roots,
maybe it doesn't.)
The spec is loose about all this: it feels more like a sketch. No other
SDK seems to devote much to providing a local helper, and those that do
(Python) don't look at roots.
Change-Id: Ia4d9abb9bc1a6450e1fc8e607df5d7bc6aa227e3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/678855
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>