Commit graph go-sdk/mcp/tool.go
Author SHA1 Message Date
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
beed2f0677
mcp: small changes to CallTool structs (#60)
- Use `any` for CallToolResult.StructuredContent.

- Change the non-generic structs into aliases for the generic ones.
2025-06-30 13:47:24 -04:00
Jonathan Amsterdam
1373ddf905
mcp: add a TODO (#31) 2025-06-25 13:19:35 -04:00
Robert Findley
5aabc33c9b
all: minor cleanup and README improvements (#30)
Clean up some inaccurate comments, and update the README to strengthen
warnings about the current status.
2025-06-25 13:12:39 -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
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
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
a07ce11b37 internal/mcp: validate tool input schemas
A tool now validates its input with its InputSchema.

Change schema inference to allow explicit nulls for fields of
pointer type.

We assume the schema has no external references. For example, the
following schema cannot be handled:

  {
    "$ref": "https://example.com/other.json"
  }

Schemas with internal references, like to a "$defs", are fine.

Change-Id: I6ee7c18c2c5cb609df0b22a66da986f7ea64bbe4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/670676
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
2025-06-04 07:51:59 -07:00
Rob Findley
04ca8ac03b internal/mcp: generic handling of CallToolParams
Make Tool APIs future-proof by pushing generics into CallToolParams, and
using CallToolParams throughout. This has several advantages:

- We no longer need the awkward CallToolOptions type, which is almost
  but not quite like CallToolParams.
- NewTool no longer needs to define its own handler type: it accepts a
  ToolHandler[TArgs]. This also means its signature is future-proof.

Additionally, provide a `CallTool` helper (the analog of NewTool) to
serve as a more strongly typed variant of `ClientSession.CallTool`.

+ design, protocol generation

Change-Id: I80172a25bc50734dae84a541aa4776ed9161694e
Reviewed-on: https://go-review.googlesource.com/c/tools/+/676495
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-06-02 07:45:36 -07:00
Rob Findley
7eadde0a23 internal/mcp/design: further clean-up
Do a pass through the design doc, adding a bit more clean-up and
commentary.

Additionally, update ServerTool and ServerPrompt to be consistent with
the design.

Change-Id: I1b75c4690d86fe8946d512cb36a1fc2938b3c883
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672576
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Sam Thanawalla <samthanawalla@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-05-14 14:28:07 -07:00
Rob Findley
ac828d5a82 internal/mcp: rename ServerConnection->ServerSession
Bring the Server implementation up to date with the spec by renaming
ServerConnection to ServerSession. Also update variable names, which
were in various states of disarray from the multiple renamings of this
type.

Change-Id: I4aec883db6d0500fb91e6daa51b702614877cf8a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672655
Auto-Submit: Robert Findley <rfindley@google.com>
TryBot-Bypass: Robert Findley <rfindley@google.com>
Commit-Queue: Robert Findley <rfindley@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
2025-05-14 10:10:28 -07:00
Jonathan Amsterdam
bbd253ee4c internal/mcp: use RawMessage for tool args
Change the type of CallToolParams.Arguments to json.RawMessage.

Change-Id: Ief16ef261b9f41566a1a16efc60a9382a8d414eb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672615
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
2025-05-14 06:23:29 -07:00
Jonathan Amsterdam
6394485a3d internal/mcp: change CallTool signature
CallTool takes a tool name, arguments, and an options struct.

Also, pass the params to ToolHandler.

Update the design doc accordingly.

Change-Id: I21b7995b607bea976ad708ebb6ac0716018f39cb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672596
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-05-14 06:23:21 -07:00
Jonathan Amsterdam
02fa1b3ea6 internal/mcp: pointerize all the things
Use pointers for the protocol's struct types, to future-proof against
them getting large.

Change-Id: I55b204080a41c8140539697ba264e502e912e613
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672575
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-05-14 06:22:56 -07:00
Rob Findley
dac5be2c50 internal/mcp: simplify content
Now that the protocol package is merged into the mcp package, clean up
the higher level 'Content' union types, in favor of types constructors.

Change-Id: I37bedb0ff0a296eef799ba65c37ca7f94ee1dbbe
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672415
Reviewed-by: Jonathan Amsterdam <jba@google.com>
TryBot-Bypass: Jonathan Amsterdam <jba@google.com>
2025-05-13 15:03:25 -07:00
Rob Findley
4f6510b9ae internal/mcp: merge the protocol package into mcp
In accordance with the updated design, merge the protocol package into
the mcp package. To do so, rename protocol.Content to WireContent and
protocol.ResourceContents to WireResource.

Also, remove some stray logging in readResource.

Change-Id: I76f61ce8d67dd3ac520ef2e1959ade0a0785a480
Reviewed-on: https://go-review.googlesource.com/c/tools/+/672375
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
2025-05-13 14:43:46 -07:00
Rob Findley
347a1a0078 internal/mcp: rename ClientConnection to ServerConnection
It's too confusing that you send server requests through the Client, and
send client requests through the ClientConnection. Rename
ClientConnection to ServerConnection, so that the types on the
server side of the control diagram start with 'Server'.

Change-Id: Idfd27af464a9296a2341cd23b2075cd9d0eb6b45
Reviewed-on: https://go-review.googlesource.com/c/tools/+/670538
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Robert Findley <rfindley@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
2025-05-07 10:17:38 -07:00
Jonathan Amsterdam
e0e304e51e internal/mcp: rename Make* to New*
Change-Id: I8d3d2ca125b7c24dd265937c4fe910ea823ab811
Reviewed-on: https://go-review.googlesource.com/c/tools/+/670537
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-05-07 09:32:55 -07:00
Rob Findley
8efb54691d internal/mcp/protocol: move out of mcp/internal, as it's used in the API
The generated protocol package is part of the SDK API, so it shouldn't
be internal.

Change-Id: I5306af48019b1599707b939b348eb6ae4f766ca9
Reviewed-on: https://go-review.googlesource.com/c/tools/+/670356
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
2025-05-06 10:18:38 -07:00
Jonathan Amsterdam
15e0c9ef02 internal/mcp: move jsonschema out of mcp/internal
The jsonschema package is part of of the API of the mcp package,
so it should not be internal.

Change-Id: I9520797837329fc2cda09c2f46ec4d48d031b9d3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/669996
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
2025-05-05 13:17:44 -07:00
Rob Findley
bf608eeeae internal/mcp: clean up handling of content
Add support for all content types, and formalize the conversion of
content to and from the wire format (as a discriminated union).

Change-Id: I93678ce98c02176a524d2c82425fb1267ad68bf0
Reviewed-on: https://go-review.googlesource.com/c/tools/+/669135
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
2025-05-01 19:15:30 -07:00
Rob Findley
af4d138732 internal/mcp: support prompts
Add support for 'prompts/list' and 'prompts/get', and registering
prompts on the server using AddPrompts. Add a 'MakePrompt' helper to
construct prompts from a prompt handler using reflection.

Change-Id: I479cb9c9b99313cca99640c1f5ea1939363759e6
Reviewed-on: https://go-review.googlesource.com/c/tools/+/669015
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
2025-05-01 18:43:44 -07:00
Rob Findley
e082a340be internal/mcp: add tool and schema options
Implement variadic options for building tools and schemas, to allow
easier customization of tool input schemas.

Also, make fields required, unless they are marked as "omitempty".

Change-Id: I7a29258fae3ec5e7ea4906ed30ed6750979de962
Reviewed-on: https://go-review.googlesource.com/c/tools/+/668955
Reviewed-by: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-05-01 18:41:25 -07:00
Jonathan Amsterdam
3434e57007 internal/mcp/internal/jsonschema: schema definition
The first of several CLs providing JSON Schema validation.

Replace the existing Schema type with one that has all the keywords
of the most current version of the JSON Schema spec, called 2020-12.

The 2020-12 spec can be represented type-safely in Go with one exception:
the "type" keyword can be either a string or a []string. To handle this
safely, both Type and Types fields are defined. Custom
JSONMarshal/Unmarshal methods handle the conversion. We need the
unmarshal anyway because "true" and "false" are valid schemas.

Unfortunately, the MCP spec uses the older "draft7" version of JSON
Schema, but the two are close enough for code generation to work.
I confirmed that the protocol generator produces the identical output.

Change-Id: I44f6ea2f3a3f8498979946f69dfb7f50afa1acad
Reviewed-on: https://go-review.googlesource.com/c/tools/+/667855
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
2025-04-25 08:33:53 -07:00
Rob Findley
fe938f6eb7 internal/mcp: implement ping, and test request interleaving
Also validate that requests observe the lifecycle rules defined in the
spec.

Change-Id: I302282f81e053e76926e0bb295f7dbf8d526f02d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/667575
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Commit-Queue: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
TryBot-Bypass: Robert Findley <rfindley@google.com>
2025-04-23 19:15:29 -07:00
Rob Findley
34cc770852 internal/mcp: an MCP SDK prototype
This CL contains an minimal prototype of an MCP SDK, using the
"new" jsonrpc2_v2 package (similar to x/exp/jsonrpc2).

Much is still yet to do, but this initial version addressed the
following aspects:

- Support for newline delimited JSONRPC2 framing, and message logging.
- A generated protocol package, containing type definitions to be used
  in transport.
- A minimal jsonschema package to be used for both reading the MCP spec,
  and for serving Tool input schemas.
- A transport abstraction, and two transport implementations: stdio, and
  local (for testing).
- Client and Server types, to be configured with features and then
  connected using their Connect methods, which return (respectively) a
  ServerConnection and ClientConnection object.
- A minimal binding API for tools.

A catalog of things not yet done is in doc.go, but we should review this
CL eagerly, as it contains the fundamental building blocks of an
eventual SDK.

It is the intention that this package is more-or-less standalone, as it
may eventually be carved out into a separate repository. As such, its
only dependency within x/tools is jsonrpc2_v2, and the only change
required to that package is to expose a callback when the connection is
closed.

Change-Id: Ib66018961014f85a8884d56ab721d5642c98443c
Reviewed-on: https://go-review.googlesource.com/c/tools/+/667036
Reviewed-by: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2025-04-22 14:37:47 -07:00