Commit graph go-sdk/mcp/server.go
Author SHA1 Message Date
Robert Findley
62d815922f
mcp: minor cleanup of some TODOs (#332)
Do a pass through TODOs to delete or address minor TODOs.
2025-08-20 12:55:19 -04:00
Shusaku Yasoda
719f68d0bf
improve error handling for tools and server methods (#311)
- 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
2025-08-20 12:31:11 -04:00
Rob Findley
0eb03e0d76 mcp: factor out reusable functions from TestStreamableServerTransport
The next CL will test stateless and distributable server transport
configurations, using the HTTP testing strategy of
TestStreamableServerTransport.
2025-08-20 09:59:52 -04:00
cryo
732b97fdaf
mcp: add syntax and scheme validation to AddResourceTemplate (#253)
Add template validation and scheme check in `AddResourceTemplate`.
2025-08-19 17:43:26 -04:00
Rob Findley
3db848abec mcp: implement a concurrency model for calls
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
2025-08-19 11:21:02 -04:00
cryo
112ca4e3b1 mcp: Ensure keepalive goroutine is started exactly once 2025-08-19 09:46:54 -04:00
Jonathan Amsterdam
52734fd414
mcp: rename logging symbols (#321)
Fixes #279.
2025-08-19 07:49:56 -04:00
Matt L
75f9999590
feat(mcp): export initialized result in client session (#320)
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>
2025-08-18 14:49:02 -04:00
Kamdyn Shaeffer
16f2857700
mcp/tool: duplicate tools should not error (#295)
This CL causes the dup to fail.
2025-08-14 13:38:31 -04:00
Rob Findley
bb6dadecca mcp: fix cancellation for HTTP transport
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.
2025-08-14 11:32:51 -04:00
Jonathan Amsterdam
6e03217c83
mcp: introduce Requests (#267)
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.
2025-08-12 17:49:50 -04:00
Robert Findley
dae88535ba
mcp: support stateless streamable sessions (#277)
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
2025-08-11 16:43:46 -04:00
Jonathan Amsterdam
cccc086518 mcp: clarify Server.Run use
Make it clear that it's not needed for an HTTP server.
2025-08-09 15:59:26 -04:00
Rob Findley
5ab63feefa mcp: don't mark the server sesion as initialized prematurely
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
2025-08-07 14:59:36 -04:00
Rob Findley
4608401cc4 mcp: simplify ServerSession.initialize
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
2025-08-07 14:59:36 -04:00
Jim Clark
cb17593a5d
update Subscribe/Unsubscribe handlers in ServerOpts (#231)
## 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.
2025-08-04 14:46:49 -04:00
Sam Thanawalla
faaf77dc05
mcp/server: advertise completions only if installed (#213)
Previously, completions would always be advertised as a capability even
if the CompletionHandler was not installed by the server. This CL fixes
that.
2025-08-04 10:12:01 -04:00
cryo
0cde9623d3
mcp: fix comments (#221)
### change:
Fix typos in some comments.
2025-08-01 16:20:55 -04:00
Robert Findley
b34ba2149d
mcp: handle bad or missing params (#210)
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
2025-07-31 10:57:59 -04:00
Robert Findley
9f48a04971
mcp: remove unused functions (cleanup) (#207)
Remove a few functions that were flagged by gopls as unused. We can
always add them back if necessary.
2025-07-30 14:59:47 -04:00
Robert Findley
64493be392
mcp: reject requests with bad IDs (#202)
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 #194
Fixes #197
2025-07-30 12:26:40 -04:00
Sam Thanawalla
2b6f7b5185
mcp/server: add initial capability server option (#182)
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.
2025-07-29 05:20:08 -04:00
Koichi Shiraishi
619bc41581
internal/jsonrpc2,mcp: fix typos (#183)
- add links to doc strings
- use correct symbol and package names
2025-07-28 12:18:03 -04:00
Jonathan Amsterdam
8dd9a819bb
mcp: panic if AddTool method is given a nil InputSchema (#157)
The spec requires an input schema for every tool.
2025-07-23 16:02:00 -04:00
Sam Thanawalla
94b88a26e0
mcp/server: fix nil PingParams in server.Ping (#163)
Use OrZero in case PingParams is nil to avoid typed nil.

Fixes: #162
2025-07-23 15:40:57 -04:00
Sam Thanawalla
bcbb31f072
mcp: add resource subscriptions (#138)
This CL adds the ability for clients to subscribe and receive updates
for resources as described in
https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions

Fixes: #23
2025-07-23 15:23:50 -04:00
Jonathan Amsterdam
ea6162ca1c
mcp: incorporate EventStore into StreamableServerTransport (#156)
Use the EventStore interface to implement resumption on the server side.
2025-07-23 13:42:50 -04:00
Jonathan Amsterdam
78a66a438a
README for v0.2.0 (#118)
Preliminary readme for v0.2.0.

We will make a GH "release" with the release notes.
2025-07-11 08:08:14 -04:00
Jonathan Amsterdam
6c6243c0b0
mcp: NewClient and NewServer take Implementation (#113)
Change the name and version arguments to NewClient and NewServer to a
`*Implementation`, to future-proof against the spec.

Fixes #109.
2025-07-10 16:57:38 -04:00
Jonathan Amsterdam
b4febf129b
mcp: advertise a capability if and only if added (#93)
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.
2025-07-10 15:52:11 -04:00
Jonathan Amsterdam
bfa5e30cd1
jsonrpc: package with JSON-RPC symbols (#117)
Move the aliases to the internal/jsonrpc2 package into their own
package.

Fixes #115.
2025-07-10 14:33:23 -04:00
Jonathan Amsterdam
c037ba51d2
mcp: negotiate protocol version (#112)
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.
2025-07-10 11:06:55 -04:00
Chris Hoff
a1a3510315
mcp/server: make Run return on context cancel (#111)
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.
2025-07-10 10:07:25 -04:00
Jonathan Amsterdam
aebd244981
mcp: new API for features (#88)
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.
2025-07-07 14:54:52 -04:00
Jonathan Amsterdam
9b6327b3b7
mcp: add Session.ID (#67)
Support retrieving the session ID from client and server sessions.

Fixes #65.
2025-07-01 13:49:23 -04:00
Sam Thanawalla
e1b1cd0072
mcp: implement completion (#55)
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
-->
2025-07-01 13:09:15 -04:00
Robert Jackson
c47dbcd7b2
mcp: Implement KeepAlive for client and server
Implement KeepAlive features from the design doc.

Fixes #24.
2025-06-27 08:24:05 -04:00
Jonathan Amsterdam
92859ef391
mcp: rename LoggingMessage to Log (#42)
Use a verb for this method name.
2025-06-25 16:52:37 -04:00
Robert Findley
204b59483b
mcp,design: revert 'content' back to an interface type (#29)
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.
2025-06-25 13:09:05 -04:00
Jonathan Amsterdam
3da831b0c9
mcp: move to 2025-06-18 schema (#8)
* 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
2025-06-25 09:48:33 -04:00
Rob Findley
4012cc3d2e internal/mcp: use JSONRPC aliases consistently
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>
2025-06-19 06:55:37 -07:00
Rob Findley
927070053a internal/mcp: avoid JSON nulls on the wire
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.

Fixes golang/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>
2025-06-18 12:32:33 -07:00
Rob Findley
5ae2a9f222 internal/mcp: update protocol versions
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>
2025-06-18 08:11:16 -07:00
Rob Findley
9453d6bf6c internal/mcp: rename NewXXX->NewServerXXX
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>
2025-06-17 17:54:58 -07:00
Rob Findley
d2f2f87bbe internal/mcp: implement streamable HTTP transport
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>
2025-06-17 17:54:33 -07:00
Sam Thanawalla
11b17f5858 internal/mcp: add NotifyProgress
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>
2025-06-12 09:59:05 -07:00
Jonathan Amsterdam
6a6c44171c internal/mcp: apply JSON schema defaults
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>
2025-06-10 08:07:54 -07:00
Jonathan Amsterdam
f211cc8e4a internal/mcp: reorganize the tool API, keeping generics
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>
2025-06-10 04:57:48 -07:00
Jonathan Amsterdam
c1524fe934 internal/mcp: implement resource templates
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>
2025-06-09 10:59:01 -07:00
Jonathan Amsterdam
d9a7859c3b internal/mcp/internal/util: add Wrapf
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>
2025-06-09 08:52:39 -07:00