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
This commit is contained in:
Jonathan Amsterdam 2025-06-25 09:48:33 -04:00 • committed by GitHub
commit 3da831b0c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 372 additions and 249 deletions

View file

@ -94,7 +94,7 @@ type HiParams struct {
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[HiParams]) (*mcp.CallToolResultFor[any], error) { func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[HiParams]) (*mcp.CallToolResultFor[any], error) {
return &mcp.CallToolResultFor[any]{ return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{mcp.NewTextContent("Hi " + params.Name)}, Content: []*mcp.ContentBlock{mcp.NewTextContent("Hi " + params.Name)},
}, nil }, nil
} }

View file

@ -24,7 +24,7 @@ type HiArgs struct {
func SayHi(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[HiArgs]) (*mcp.CallToolResultFor[struct{}], error) { func SayHi(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[HiArgs]) (*mcp.CallToolResultFor[struct{}], error) {
return &mcp.CallToolResultFor[struct{}]{ return &mcp.CallToolResultFor[struct{}]{
Content: []*mcp.Content{ Content: []*mcp.ContentBlock{
mcp.NewTextContent("Hi " + params.Name), mcp.NewTextContent("Hi " + params.Name),
}, },
}, nil }, nil

View file

@ -21,7 +21,7 @@ type SayHiParams struct {
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[SayHiParams]) (*mcp.CallToolResultFor[any], error) { func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[SayHiParams]) (*mcp.CallToolResultFor[any], error) {
return &mcp.CallToolResultFor[any]{ return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{ Content: []*mcp.ContentBlock{
mcp.NewTextContent("Hi " + params.Name), mcp.NewTextContent("Hi " + params.Name),
}, },
}, nil }, nil

View file

@ -18,7 +18,7 @@ type HiParams struct {
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[HiParams]) (*mcp.CallToolResultFor[any], error) { func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[HiParams]) (*mcp.CallToolResultFor[any], error) {
return &mcp.CallToolResultFor[any]{ return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{mcp.NewTextContent("Hi " + params.Name)}, Content: []*mcp.ContentBlock{mcp.NewTextContent("Hi " + params.Name)},
}, nil }, nil
} }

View file

@ -70,7 +70,7 @@ func TestCmdTransport(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
want := &mcp.CallToolResult{ want := &mcp.CallToolResult{
Content: []*mcp.Content{{Type: "text", Text: "Hi user"}}, Content: []*mcp.ContentBlock{{Type: "text", Text: "Hi user"}},
} }
if diff := cmp.Diff(want, got); diff != "" { if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("greet returned unexpected content (-want +got):\n%s", diff) t.Errorf("greet returned unexpected content (-want +got):\n%s", diff)

View file

@ -10,58 +10,67 @@ import (
"fmt" "fmt"
) )
// Content is the wire format for content. // A ContentBlock is one of a TextContent, ImageContent, AudioContent
// It represents the protocol types TextContent, ImageContent, AudioContent // ResourceLink, or EmbeddedResource.
// and EmbeddedResource. // Use [NewTextContent], [NewImageContent], [NewAudioContent], [NewResourceLink]
// Use [NewTextContent], [NewImageContent], [NewAudioContent] or [NewResourceContent] // or [NewResourceContents] to create one.
// to create one.
// //
// The Type field must be one of "text", "image", "audio" or "resource". The // The Type field must be one of "text", "image", "audio", "resource_link" or "resource".
// constructors above populate this field appropriately. // The constructors above populate this field appropriately.
// Although at most one of Text, Data, and Resource should be non-zero, consumers of Content // Although at most one of Text, Data, ResourceLink and Resource should be non-zero,
// use the Type field to determine which value to use; values in the other fields are ignored. // consumers of ContentBlock use the Type field to determine which value to use;
type Content struct { // values in the other fields are ignored.
Type string `json:"type"` // TODO(jba,rfindley): rethink this type. Each kind (text, image, etc.) should have its own
Text string `json:"text,omitempty"` // meta and annotations, otherwise they're duplicated for Resource and ResourceContents.
MIMEType string `json:"mimeType,omitempty"` type ContentBlock struct {
Data []byte `json:"data,omitempty"` Meta map[string]any `json:"_meta,omitempty"`
Resource *ResourceContents `json:"resource,omitempty"` Type string `json:"type"`
Annotations *Annotations `json:"annotations,omitempty"` Text string `json:"text,omitempty"`
MIMEType string `json:"mimeType,omitempty"`
Data []byte `json:"data,omitempty"`
ResourceLink *Resource `json:"resource_link,omitempty"`
Resource *ResourceContents `json:"resource,omitempty"`
Annotations *Annotations `json:"annotations,omitempty"`
} }
func (c *Content) UnmarshalJSON(data []byte) error { func (c *ContentBlock) UnmarshalJSON(data []byte) error {
type wireContent Content // for naive unmarshaling type wireContent ContentBlock // for naive unmarshaling
var c2 wireContent var c2 wireContent
if err := json.Unmarshal(data, &c2); err != nil { if err := json.Unmarshal(data, &c2); err != nil {
return err return err
} }
switch c2.Type { switch c2.Type {
case "text", "image", "audio", "resource": case "text", "image", "audio", "resource", "resource_link":
default: default:
return fmt.Errorf("unrecognized content type %s", c.Type) return fmt.Errorf("unrecognized content type %s", c.Type)
} }
*c = Content(c2) *c = ContentBlock(c2)
return nil return nil
} }
// NewTextContent creates a [Content] with text. // NewTextContent creates a [ContentBlock] with text.
func NewTextContent(text string) *Content { func NewTextContent(text string) *ContentBlock {
return &Content{Type: "text", Text: text} return &ContentBlock{Type: "text", Text: text}
} }
// NewImageContent creates a [Content] with image data. // NewImageContent creates a [ContentBlock] with image data.
func NewImageContent(data []byte, mimeType string) *Content { func NewImageContent(data []byte, mimeType string) *ContentBlock {
return &Content{Type: "image", Data: data, MIMEType: mimeType} return &ContentBlock{Type: "image", Data: data, MIMEType: mimeType}
} }
// NewAudioContent creates a [Content] with audio data. // NewAudioContent creates a [ContentBlock] with audio data.
func NewAudioContent(data []byte, mimeType string) *Content { func NewAudioContent(data []byte, mimeType string) *ContentBlock {
return &Content{Type: "audio", Data: data, MIMEType: mimeType} return &ContentBlock{Type: "audio", Data: data, MIMEType: mimeType}
} }
// NewResourceContent creates a [Content] with an embedded resource. // NewResourceLink creates a [ContentBlock] with a [Resource].
func NewResourceContent(resource *ResourceContents) *Content { func NewResourceLink(r *Resource) *ContentBlock {
return &Content{Type: "resource", Resource: resource} return &ContentBlock{Type: "resource_link", ResourceLink: r}
}
// NewResourceContents creates a [ContentBlock] with an embedded resource (a [ResourceContents]).
func NewResourceContents(rc *ResourceContents) *ContentBlock {
return &ContentBlock{Type: "resource", Resource: rc}
} }
// ResourceContents represents the union of the spec's {Text,Blob}ResourceContents types. // ResourceContents represents the union of the spec's {Text,Blob}ResourceContents types.
@ -71,10 +80,11 @@ func NewResourceContent(resource *ResourceContents) *Content {
// A ResourceContents is either a TextResourceContents or a BlobResourceContents. // A ResourceContents is either a TextResourceContents or a BlobResourceContents.
// Use [NewTextResourceContents] or [NextBlobResourceContents] to create one. // Use [NewTextResourceContents] or [NextBlobResourceContents] to create one.
type ResourceContents struct { type ResourceContents struct {
URI string `json:"uri"` // resource location; must not be empty Meta map[string]any `json:"_meta,omitempty"`
MIMEType string `json:"mimeType,omitempty"` URI string `json:"uri"` // resource location; must not be empty
Text string `json:"text"` MIMEType string `json:"mimeType,omitempty"`
Blob []byte `json:"blob,omitempty"` // if nil, then text; else blob Text string `json:"text"`
Blob []byte `json:"blob,omitempty"` // if nil, then text; else blob
} }
func (r ResourceContents) MarshalJSON() ([]byte, error) { func (r ResourceContents) MarshalJSON() ([]byte, error) {

View file

@ -14,7 +14,7 @@ import (
func TestContent(t *testing.T) { func TestContent(t *testing.T) {
tests := []struct { tests := []struct {
in *mcp.Content in *mcp.ContentBlock
want string // json serialization want string // json serialization
}{ }{
{mcp.NewTextContent("hello"), `{"type":"text","text":"hello"}`}, {mcp.NewTextContent("hello"), `{"type":"text","text":"hello"}`},
@ -27,13 +27,13 @@ func TestContent(t *testing.T) {
`{"type":"audio","mimeType":"audio/wav","data":"YTFiMmMz"}`, `{"type":"audio","mimeType":"audio/wav","data":"YTFiMmMz"}`,
}, },
{ {
mcp.NewResourceContent( mcp.NewResourceContents(
mcp.NewTextResourceContents("file://foo", "text", "abc"), mcp.NewTextResourceContents("file://foo", "text", "abc"),
), ),
`{"type":"resource","resource":{"uri":"file://foo","mimeType":"text","text":"abc"}}`, `{"type":"resource","resource":{"uri":"file://foo","mimeType":"text","text":"abc"}}`,
}, },
{ {
mcp.NewResourceContent( mcp.NewResourceContents(
mcp.NewBlobResourceContents("file://foo", "image/png", []byte("a1b2c3")), mcp.NewBlobResourceContents("file://foo", "image/png", []byte("a1b2c3")),
), ),
`{"type":"resource","resource":{"uri":"file://foo","mimeType":"image/png","blob":"YTFiMmMz"}}`, `{"type":"resource","resource":{"uri":"file://foo","mimeType":"image/png","blob":"YTFiMmMz"}}`,
@ -48,7 +48,7 @@ func TestContent(t *testing.T) {
if diff := cmp.Diff(test.want, string(got)); diff != "" { if diff := cmp.Diff(test.want, string(got)); diff != "" {
t.Errorf("json.Marshal(%v) mismatch (-want +got):\n%s", test.in, diff) t.Errorf("json.Marshal(%v) mismatch (-want +got):\n%s", test.in, diff)
} }
var out *mcp.Content var out *mcp.ContentBlock
if err := json.Unmarshal(got, &out); err != nil { if err := json.Unmarshal(got, &out); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -23,7 +23,9 @@ func Example_progressMiddleware() {
func addProgressToken[S mcp.Session](h mcp.MethodHandler[S]) mcp.MethodHandler[S] { func addProgressToken[S mcp.Session](h mcp.MethodHandler[S]) mcp.MethodHandler[S] {
return func(ctx context.Context, s S, method string, params mcp.Params) (result mcp.Result, err error) { return func(ctx context.Context, s S, method string, params mcp.Params) (result mcp.Result, err error) {
params.GetMeta().ProgressToken = nextProgressToken.Add(1) if rp, ok := params.(mcp.RequestParams); ok {
rp.SetProgressToken(nextProgressToken.Add(1))
}
return h(ctx, s, method, params) return h(ctx, s, method, params)
} }
} }

View file

@ -20,7 +20,7 @@ type SayHiParams struct {
func SayHi(ctx context.Context, cc *ServerSession, params *CallToolParamsFor[SayHiParams]) (*CallToolResultFor[any], error) { func SayHi(ctx context.Context, cc *ServerSession, params *CallToolParamsFor[SayHiParams]) (*CallToolResultFor[any], error) {
return &CallToolResultFor[any]{ return &CallToolResultFor[any]{
Content: []*Content{ Content: []*ContentBlock{
NewTextContent("Hi " + params.Name), NewTextContent("Hi " + params.Name),
}, },
}, nil }, nil

View file

@ -34,7 +34,7 @@ func sayHi(ctx context.Context, ss *ServerSession, params *CallToolParamsFor[hiP
if err := ss.Ping(ctx, nil); err != nil { if err := ss.Ping(ctx, nil); err != nil {
return nil, fmt.Errorf("ping failed: %v", err) return nil, fmt.Errorf("ping failed: %v", err)
} }
return &CallToolResultFor[any]{Content: []*Content{NewTextContent("hi " + params.Arguments.Name)}}, nil return &CallToolResultFor[any]{Content: []*ContentBlock{NewTextContent("hi " + params.Arguments.Name)}}, nil
} }
func TestEndToEnd(t *testing.T) { func TestEndToEnd(t *testing.T) {
@ -195,7 +195,7 @@ func TestEndToEnd(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
wantHi := &CallToolResult{ wantHi := &CallToolResult{
Content: []*Content{{Type: "text", Text: "hi user"}}, Content: []*ContentBlock{{Type: "text", Text: "hi user"}},
} }
if diff := cmp.Diff(wantHi, gotHi); diff != "" { if diff := cmp.Diff(wantHi, gotHi); diff != "" {
t.Errorf("tools/call 'greet' mismatch (-want +got):\n%s", diff) t.Errorf("tools/call 'greet' mismatch (-want +got):\n%s", diff)
@ -212,7 +212,7 @@ func TestEndToEnd(t *testing.T) {
} }
wantFail := &CallToolResult{ wantFail := &CallToolResult{
IsError: true, IsError: true,
Content: []*Content{{Type: "text", Text: errTestFailure.Error()}}, Content: []*ContentBlock{{Type: "text", Text: errTestFailure.Error()}},
} }
if diff := cmp.Diff(wantFail, gotFail); diff != "" { if diff := cmp.Diff(wantFail, gotFail); diff != "" {
t.Errorf("tools/call 'fail' mismatch (-want +got):\n%s", diff) t.Errorf("tools/call 'fail' mismatch (-want +got):\n%s", diff)

View file

@ -4,6 +4,12 @@
package mcp package mcp
// Protocol types for version 2025-06-18.
// To see the schema changes from the previous version, run:
//
// prefix=https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/refs/heads/main/schema
// sdiff -l <(curl $prefix/2025-03-26/schema.ts) <(curl $prefix/2025/06-18/schema.ts)
import ( import (
"github.com/modelcontextprotocol/go-sdk/jsonschema" "github.com/modelcontextprotocol/go-sdk/jsonschema"
) )
@ -16,6 +22,13 @@ type Annotations struct {
// It can include multiple entries to indicate content useful for multiple // It can include multiple entries to indicate content useful for multiple
// audiences (e.g., `["user", "assistant"]`). // audiences (e.g., `["user", "assistant"]`).
Audience []Role `json:"audience,omitempty"` Audience []Role `json:"audience,omitempty"`
// The moment the resource was last modified, as an ISO 8601 formatted string.
//
// Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z").
//
// Examples: last activity timestamp in an open file, timestamp when the
// resource was attached, etc.
LastModified string `json:"lastModified,omitempty"`
// Describes how important this data is for operating the server. // Describes how important this data is for operating the server.
// //
// A value of 1 means "most important," and indicates that the data is // A value of 1 means "most important," and indicates that the data is
@ -27,63 +40,78 @@ type Annotations struct {
type CallToolParams struct { type CallToolParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Arguments any `json:"arguments,omitempty"` Arguments any `json:"arguments,omitempty"`
Name string `json:"name"` Name string `json:"name"`
} }
func (x *CallToolParams) GetMeta() *Meta { return &x.Meta } func (x *CallToolParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CallToolParams) SetProgressToken(t any) { setProgressToken(x, t) }
type CallToolParamsFor[In any] struct { type CallToolParamsFor[In any] struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Arguments In `json:"arguments,omitempty"` Arguments In `json:"arguments,omitempty"`
Name string `json:"name"` Name string `json:"name"`
} }
func (x *CallToolParamsFor[In]) GetMeta() *Meta { return &x.Meta }
// The server's response to a tool call. // The server's response to a tool call.
//
// Any errors that originate from the tool SHOULD be reported inside the result
// object, with `isError` set to true, _not_ as an MCP protocol-level error
// response. Otherwise, the LLM would not be able to see that an error occurred
// and self-correct.
//
// However, any errors in _finding_ the tool, an error indicating that the
// server does not support tool calls, or any other exceptional conditions,
// should be reported as an MCP error response.
type CallToolResult struct { type CallToolResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Content []*Content `json:"content"` // A list of content objects that represent the unstructured result of the tool
// call.
Content []*ContentBlock `json:"content"`
// Whether the tool call ended in an error. // Whether the tool call ended in an error.
// //
// If not set, this is assumed to be false (the call was successful). // If not set, this is assumed to be false (the call was successful).
//
// Any errors that originate from the tool SHOULD be reported inside the result
// object, with `isError` set to true, _not_ as an MCP protocol-level error
// response. Otherwise, the LLM would not be able to see that an error occurred
// and self-correct.
//
// However, any errors in _finding_ the tool, an error indicating that the
// server does not support tool calls, or any other exceptional conditions,
// should be reported as an MCP error response.
IsError bool `json:"isError,omitempty"` IsError bool `json:"isError,omitempty"`
// An optional JSON object that represents the structured result of the tool
// call.
// TODO(jba,rfindley): should this be any?
StructuredContent map[string]any `json:"structuredContent,omitempty"`
} }
func (x *CallToolResult) GetMeta() *Meta { return &x.Meta }
type CallToolResultFor[Out any] struct { type CallToolResultFor[Out any] struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Content []*Content `json:"content"` // A list of content objects that represent the unstructured result of the tool
// call.
Content []*ContentBlock `json:"content"`
// Whether the tool call ended in an error. // Whether the tool call ended in an error.
// //
// If not set, this is assumed to be false (the call was successful). // If not set, this is assumed to be false (the call was successful).
//
// Any errors that originate from the tool SHOULD be reported inside the result
// object, with `isError` set to true, not as an MCP protocol-level error
// response. Otherwise, the LLM would not be able to see that an error occurred
// and self-correct.
//
// However, any errors in finding the tool, an error indicating that the
// server does not support tool calls, or any other exceptional conditions,
// should be reported as an MCP error response.
IsError bool `json:"isError,omitempty"` IsError bool `json:"isError,omitempty"`
// An optional JSON object that represents the structured result of the tool
// call.
StructuredContent Out `json:"structuredContent,omitempty"`
} }
func (x *CallToolResultFor[Out]) GetMeta() *Meta { return &x.Meta }
type CancelledParams struct { type CancelledParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An optional string describing the reason for the cancellation. This MAY be // An optional string describing the reason for the cancellation. This MAY be
// logged or presented to the user. // logged or presented to the user.
Reason string `json:"reason,omitempty"` Reason string `json:"reason,omitempty"`
@ -94,7 +122,8 @@ type CancelledParams struct {
RequestID any `json:"requestId"` RequestID any `json:"requestId"`
} }
func (x *CancelledParams) GetMeta() *Meta { return &x.Meta } func (x *CancelledParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CancelledParams) SetProgressToken(t any) { setProgressToken(x, t) }
// Capabilities a client may support. Known capabilities are defined here, in // Capabilities a client may support. Known capabilities are defined here, in
// this schema, but this is not a closed set: any client can define its own, // this schema, but this is not a closed set: any client can define its own,
@ -109,12 +138,14 @@ type ClientCapabilities struct {
} `json:"roots,omitempty"` } `json:"roots,omitempty"`
// Present if the client supports sampling from an LLM. // Present if the client supports sampling from an LLM.
Sampling *SamplingCapabilities `json:"sampling,omitempty"` Sampling *SamplingCapabilities `json:"sampling,omitempty"`
// Present if the client supports elicitation from the server.
Elicitation *ElicitationCapabilities `json:"elicitation,omitempty"`
} }
type CreateMessageParams struct { type CreateMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// A request to include context from one or more MCP servers (including the // A request to include context from one or more MCP servers (including the
// caller), to be attached to the prompt. The client MAY ignore this request. // caller), to be attached to the prompt. The client MAY ignore this request.
IncludeContext string `json:"includeContext,omitempty"` IncludeContext string `json:"includeContext,omitempty"`
@ -135,7 +166,8 @@ type CreateMessageParams struct {
Temperature float64 `json:"temperature,omitempty"` Temperature float64 `json:"temperature,omitempty"`
} }
func (x *CreateMessageParams) GetMeta() *Meta { return &x.Meta } func (x *CreateMessageParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CreateMessageParams) SetProgressToken(t any) { setProgressToken(x, t) }
// The client's response to a sampling/create_message request from the server. // The client's response to a sampling/create_message request from the server.
// The client should inform the user before returning the sampled message, to // The client should inform the user before returning the sampled message, to
@ -144,8 +176,8 @@ func (x *CreateMessageParams) GetMeta() *Meta { return &x.Meta }
type CreateMessageResult struct { type CreateMessageResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Content *Content `json:"content"` Content any `json:"content"`
// The name of the model that generated the message. // The name of the model that generated the message.
Model string `json:"model"` Model string `json:"model"`
Role Role `json:"role"` Role Role `json:"role"`
@ -153,36 +185,33 @@ type CreateMessageResult struct {
StopReason string `json:"stopReason,omitempty"` StopReason string `json:"stopReason,omitempty"`
} }
func (x *CreateMessageResult) GetMeta() *Meta { return &x.Meta }
type GetPromptParams struct { type GetPromptParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// Arguments to use for templating the prompt. // Arguments to use for templating the prompt.
Arguments map[string]string `json:"arguments,omitempty"` Arguments map[string]string `json:"arguments,omitempty"`
// The name of the prompt or prompt template. // The name of the prompt or prompt template.
Name string `json:"name"` Name string `json:"name"`
} }
func (x *GetPromptParams) GetMeta() *Meta { return &x.Meta } func (x *GetPromptParams) GetProgressToken() any { return getProgressToken(x) }
func (x *GetPromptParams) SetProgressToken(t any) { setProgressToken(x, t) }
// The server's response to a prompts/get request from the client. // The server's response to a prompts/get request from the client.
type GetPromptResult struct { type GetPromptResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An optional description for the prompt. // An optional description for the prompt.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
Messages []*PromptMessage `json:"messages"` Messages []*PromptMessage `json:"messages"`
} }
func (x *GetPromptResult) GetMeta() *Meta { return &x.Meta }
type InitializeParams struct { type InitializeParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Capabilities *ClientCapabilities `json:"capabilities"` Capabilities *ClientCapabilities `json:"capabilities"`
ClientInfo *implementation `json:"clientInfo"` ClientInfo *implementation `json:"clientInfo"`
// The latest version of the Model Context Protocol that the client supports. // The latest version of the Model Context Protocol that the client supports.
@ -190,14 +219,15 @@ type InitializeParams struct {
ProtocolVersion string `json:"protocolVersion"` ProtocolVersion string `json:"protocolVersion"`
} }
func (x *InitializeParams) GetMeta() *Meta { return &x.Meta } func (x *InitializeParams) GetProgressToken() any { return getProgressToken(x) }
func (x *InitializeParams) SetProgressToken(t any) { setProgressToken(x, t) }
// After receiving an initialize request from the client, the server sends this // After receiving an initialize request from the client, the server sends this
// response. // response.
type InitializeResult struct { type InitializeResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Capabilities *serverCapabilities `json:"capabilities"` Capabilities *serverCapabilities `json:"capabilities"`
// Instructions describing how to use the server and its features. // Instructions describing how to use the server and its features.
// //
@ -212,101 +242,101 @@ type InitializeResult struct {
ServerInfo *implementation `json:"serverInfo"` ServerInfo *implementation `json:"serverInfo"`
} }
func (x *InitializeResult) GetMeta() *Meta { return &x.Meta }
type InitializedParams struct { type InitializedParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *InitializedParams) GetMeta() *Meta { return &x.Meta } func (x *InitializedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *InitializedParams) SetProgressToken(t any) { setProgressToken(x, t) }
type ListPromptsParams struct { type ListPromptsParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the current pagination position. If provided, // An opaque token representing the current pagination position. If provided,
// the server should return results starting after this cursor. // the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"` Cursor string `json:"cursor,omitempty"`
} }
func (x *ListPromptsParams) GetMeta() *Meta { return &x.Meta } func (x *ListPromptsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListPromptsParams) cursorPtr() *string { return &x.Cursor } func (x *ListPromptsParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListPromptsParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a prompts/list request from the client. // The server's response to a prompts/list request from the client.
type ListPromptsResult struct { type ListPromptsResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the pagination position after the last returned // An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available. // result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"` NextCursor string `json:"nextCursor,omitempty"`
Prompts []*Prompt `json:"prompts"` Prompts []*Prompt `json:"prompts"`
} }
func (x *ListPromptsResult) GetMeta() *Meta { return &x.Meta }
func (x *ListPromptsResult) nextCursorPtr() *string { return &x.NextCursor } func (x *ListPromptsResult) nextCursorPtr() *string { return &x.NextCursor }
type ListResourceTemplatesParams struct { type ListResourceTemplatesParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the current pagination position. If provided, // An opaque token representing the current pagination position. If provided,
// the server should return results starting after this cursor. // the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"` Cursor string `json:"cursor,omitempty"`
} }
func (x *ListResourceTemplatesParams) GetMeta() *Meta { return &x.Meta } func (x *ListResourceTemplatesParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListResourceTemplatesParams) cursorPtr() *string { return &x.Cursor } func (x *ListResourceTemplatesParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListResourceTemplatesParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a resources/templates/list request from the client. // The server's response to a resources/templates/list request from the client.
type ListResourceTemplatesResult struct { type ListResourceTemplatesResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the pagination position after the last returned // An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available. // result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"` NextCursor string `json:"nextCursor,omitempty"`
ResourceTemplates []*ResourceTemplate `json:"resourceTemplates"` ResourceTemplates []*ResourceTemplate `json:"resourceTemplates"`
} }
func (x *ListResourceTemplatesResult) GetMeta() *Meta { return &x.Meta }
func (x *ListResourceTemplatesResult) nextCursorPtr() *string { return &x.NextCursor } func (x *ListResourceTemplatesResult) nextCursorPtr() *string { return &x.NextCursor }
type ListResourcesParams struct { type ListResourcesParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the current pagination position. If provided, // An opaque token representing the current pagination position. If provided,
// the server should return results starting after this cursor. // the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"` Cursor string `json:"cursor,omitempty"`
} }
func (x *ListResourcesParams) GetMeta() *Meta { return &x.Meta } func (x *ListResourcesParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListResourcesParams) cursorPtr() *string { return &x.Cursor } func (x *ListResourcesParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListResourcesParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a resources/list request from the client. // The server's response to a resources/list request from the client.
type ListResourcesResult struct { type ListResourcesResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the pagination position after the last returned // An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available. // result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"` NextCursor string `json:"nextCursor,omitempty"`
Resources []*Resource `json:"resources"` Resources []*Resource `json:"resources"`
} }
func (x *ListResourcesResult) GetMeta() *Meta { return &x.Meta }
func (x *ListResourcesResult) nextCursorPtr() *string { return &x.NextCursor } func (x *ListResourcesResult) nextCursorPtr() *string { return &x.NextCursor }
type ListRootsParams struct { type ListRootsParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *ListRootsParams) GetMeta() *Meta { return &x.Meta } func (x *ListRootsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListRootsParams) SetProgressToken(t any) { setProgressToken(x, t) }
// The client's response to a roots/list request from the server. This result // The client's response to a roots/list request from the server. This result
// contains an array of Root objects, each representing a root directory or file // contains an array of Root objects, each representing a root directory or file
@ -314,36 +344,34 @@ func (x *ListRootsParams) GetMeta() *Meta { return &x.Meta }
type ListRootsResult struct { type ListRootsResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Roots []*Root `json:"roots"` Roots []*Root `json:"roots"`
} }
func (x *ListRootsResult) GetMeta() *Meta { return &x.Meta }
type ListToolsParams struct { type ListToolsParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the current pagination position. If provided, // An opaque token representing the current pagination position. If provided,
// the server should return results starting after this cursor. // the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"` Cursor string `json:"cursor,omitempty"`
} }
func (x *ListToolsParams) GetMeta() *Meta { return &x.Meta } func (x *ListToolsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListToolsParams) cursorPtr() *string { return &x.Cursor } func (x *ListToolsParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListToolsParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a tools/list request from the client. // The server's response to a tools/list request from the client.
type ListToolsResult struct { type ListToolsResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An opaque token representing the pagination position after the last returned // An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available. // result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"` NextCursor string `json:"nextCursor,omitempty"`
Tools []*Tool `json:"tools"` Tools []*Tool `json:"tools"`
} }
func (x *ListToolsResult) GetMeta() *Meta { return &x.Meta }
func (x *ListToolsResult) nextCursorPtr() *string { return &x.NextCursor } func (x *ListToolsResult) nextCursorPtr() *string { return &x.NextCursor }
// The severity of a log message. // The severity of a log message.
@ -355,7 +383,7 @@ type LoggingLevel string
type LoggingMessageParams struct { type LoggingMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// The data to be logged, such as a string message or an object. Any JSON // The data to be logged, such as a string message or an object. Any JSON
// serializable type is allowed here. // serializable type is allowed here.
Data any `json:"data"` Data any `json:"data"`
@ -365,7 +393,8 @@ type LoggingMessageParams struct {
Logger string `json:"logger,omitempty"` Logger string `json:"logger,omitempty"`
} }
func (x *LoggingMessageParams) GetMeta() *Meta { return &x.Meta } func (x *LoggingMessageParams) GetProgressToken() any { return getProgressToken(x) }
func (x *LoggingMessageParams) SetProgressToken(t any) { setProgressToken(x, t) }
// Hints to use for model selection. // Hints to use for model selection.
// //
@ -422,15 +451,16 @@ type ModelPreferences struct {
type PingParams struct { type PingParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *PingParams) GetMeta() *Meta { return &x.Meta } func (x *PingParams) GetProgressToken() any { return getProgressToken(x) }
func (x *PingParams) SetProgressToken(t any) { setProgressToken(x, t) }
type ProgressNotificationParams struct { type ProgressNotificationParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// An optional message describing the current progress. // An optional message describing the current progress.
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
// The progress thus far. This should increase every time progress is made, even // The progress thus far. This should increase every time progress is made, even
@ -443,24 +473,33 @@ type ProgressNotificationParams struct {
Total float64 `json:"total,omitempty"` Total float64 `json:"total,omitempty"`
} }
func (x *ProgressNotificationParams) GetMeta() *Meta { return &x.Meta }
// A prompt or prompt template that the server offers. // A prompt or prompt template that the server offers.
type Prompt struct { type Prompt struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
// usage.
Meta `json:"_meta,omitempty"`
// A list of arguments to use for templating the prompt. // A list of arguments to use for templating the prompt.
Arguments []*PromptArgument `json:"arguments,omitempty"` Arguments []*PromptArgument `json:"arguments,omitempty"`
// An optional description of what this prompt provides // An optional description of what this prompt provides
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// The name of the prompt or prompt template. // Intended for programmatic or logical use, but used as a display name in past
// specs or fallback (if title isn't present).
Name string `json:"name"` Name string `json:"name"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
Title string `json:"title,omitempty"`
} }
// Describes an argument that a prompt can accept. // Describes an argument that a prompt can accept.
type PromptArgument struct { type PromptArgument struct {
// Intended for programmatic or logical use, but used as a display name in past
// specs or fallback (if title isn't present).
Name string `json:"name"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
Title string `json:"title,omitempty"`
// A human-readable description of the argument. // A human-readable description of the argument.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// The name of the argument.
Name string `json:"name"`
// Whether this argument must be provided. // Whether this argument must be provided.
Required bool `json:"required,omitempty"` Required bool `json:"required,omitempty"`
} }
@ -468,43 +507,46 @@ type PromptArgument struct {
type PromptListChangedParams struct { type PromptListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *PromptListChangedParams) GetMeta() *Meta { return &x.Meta } func (x *PromptListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *PromptListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
// Describes a message returned as part of a prompt. // Describes a message returned as part of a prompt.
// //
// This is similar to `SamplingMessage`, but also supports the embedding of // This is similar to `SamplingMessage`, but also supports the embedding of
// resources from the MCP server. // resources from the MCP server.
type PromptMessage struct { type PromptMessage struct {
Content *Content `json:"content"` Content *ContentBlock `json:"content"`
Role Role `json:"role"` Role Role `json:"role"`
} }
type ReadResourceParams struct { type ReadResourceParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// The URI of the resource to read. The URI can use any protocol; it is up to // The URI of the resource to read. The URI can use any protocol; it is up to
// the server how to interpret it. // the server how to interpret it.
URI string `json:"uri"` URI string `json:"uri"`
} }
func (x *ReadResourceParams) GetMeta() *Meta { return &x.Meta } func (x *ReadResourceParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ReadResourceParams) SetProgressToken(t any) { setProgressToken(x, t) }
// The server's response to a resources/read request from the client. // The server's response to a resources/read request from the client.
type ReadResourceResult struct { type ReadResourceResult struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
Contents []*ResourceContents `json:"contents"` Contents []*ResourceContents `json:"contents"`
} }
func (x *ReadResourceResult) GetMeta() *Meta { return &x.Meta }
// A known resource that the server is capable of reading. // A known resource that the server is capable of reading.
type Resource struct { type Resource struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
// usage.
Meta `json:"_meta,omitempty"`
// Optional annotations for the client. // Optional annotations for the client.
Annotations *Annotations `json:"annotations,omitempty"` Annotations *Annotations `json:"annotations,omitempty"`
// A description of what this resource represents. // A description of what this resource represents.
@ -514,9 +556,8 @@ type Resource struct {
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// The MIME type of this resource, if known. // The MIME type of this resource, if known.
MIMEType string `json:"mimeType,omitempty"` MIMEType string `json:"mimeType,omitempty"`
// A human-readable name for this resource. // Intended for programmatic or logical use, but used as a display name in past
// // specs or fallback (if title isn't present).
// This can be used by clients to populate UI elements.
Name string `json:"name"` Name string `json:"name"`
// The size of the raw resource content, in bytes (i.e., before base64 encoding // The size of the raw resource content, in bytes (i.e., before base64 encoding
// or any tokenization), if known. // or any tokenization), if known.
@ -524,6 +565,13 @@ type Resource struct {
// This can be used by Hosts to display file sizes and estimate context window // This can be used by Hosts to display file sizes and estimate context window
// usage. // usage.
Size int64 `json:"size,omitempty"` Size int64 `json:"size,omitempty"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
//
// If not provided, the name should be used for display (except for Tool, where
// `annotations.title` should be given precedence over using `name`, if
// present).
Title string `json:"title,omitempty"`
// The URI of this resource. // The URI of this resource.
URI string `json:"uri"` URI string `json:"uri"`
} }
@ -531,13 +579,17 @@ type Resource struct {
type ResourceListChangedParams struct { type ResourceListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *ResourceListChangedParams) GetMeta() *Meta { return &x.Meta } func (x *ResourceListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ResourceListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
// A template description for resources available on the server. // A template description for resources available on the server.
type ResourceTemplate struct { type ResourceTemplate struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
// usage.
Meta `json:"_meta,omitempty"`
// Optional annotations for the client. // Optional annotations for the client.
Annotations *Annotations `json:"annotations,omitempty"` Annotations *Annotations `json:"annotations,omitempty"`
// A description of what this template is for. // A description of what this template is for.
@ -548,10 +600,16 @@ type ResourceTemplate struct {
// The MIME type for all resources that match this template. This should only be // The MIME type for all resources that match this template. This should only be
// included if all resources matching this template have the same type. // included if all resources matching this template have the same type.
MIMEType string `json:"mimeType,omitempty"` MIMEType string `json:"mimeType,omitempty"`
// A human-readable name for the type of resource this template refers to. // Intended for programmatic or logical use, but used as a display name in past
// // specs or fallback (if title isn't present).
// This can be used by clients to populate UI elements.
Name string `json:"name"` Name string `json:"name"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
//
// If not provided, the name should be used for display (except for Tool, where
// `annotations.title` should be given precedence over using `name`, if
// present).
Title string `json:"title,omitempty"`
// A URI template (according to RFC 6570) that can be used to construct resource // A URI template (according to RFC 6570) that can be used to construct resource
// URIs. // URIs.
URITemplate string `json:"uriTemplate"` URITemplate string `json:"uriTemplate"`
@ -562,6 +620,9 @@ type Role string
// Represents a root directory or file that the server can operate on. // Represents a root directory or file that the server can operate on.
type Root struct { type Root struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
// usage.
Meta `json:"_meta,omitempty"`
// An optional name for the root. This can be used to provide a human-readable // An optional name for the root. This can be used to provide a human-readable
// identifier for the root, which may be useful for display purposes or for // identifier for the root, which may be useful for display purposes or for
// referencing the root in other parts of the application. // referencing the root in other parts of the application.
@ -575,35 +636,45 @@ type Root struct {
type RootsListChangedParams struct { type RootsListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *RootsListChangedParams) GetMeta() *Meta { return &x.Meta } func (x *RootsListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *RootsListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
// Present if the client supports sampling from an LLM. // SamplingCapabilities describes the capabilities for sampling.
type SamplingCapabilities struct{} type SamplingCapabilities struct{}
// ElicitationCapabilities describes the capabilities for elicitation.
type ElicitationCapabilities struct{}
// Describes a message issued to or received from an LLM API. // Describes a message issued to or received from an LLM API.
type SamplingMessage struct { type SamplingMessage struct {
Content *Content `json:"content"` Content any `json:"content"`
Role Role `json:"role"` Role Role `json:"role"`
} }
type SetLevelParams struct { type SetLevelParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
// The level of logging that the client wants to receive from the server. The // The level of logging that the client wants to receive from the server. The
// server should send all logs at this level and higher (i.e., more severe) to // server should send all logs at this level and higher (i.e., more severe) to
// the client as notifications/message. // the client as notifications/message.
Level LoggingLevel `json:"level"` Level LoggingLevel `json:"level"`
} }
func (x *SetLevelParams) GetMeta() *Meta { return &x.Meta } func (x *SetLevelParams) GetProgressToken() any { return getProgressToken(x) }
func (x *SetLevelParams) SetProgressToken(t any) { setProgressToken(x, t) }
// Definition for a tool the client can call. // Definition for a tool the client can call.
type Tool struct { type Tool struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
// usage.
Meta `json:"_meta,omitempty"`
// Optional additional tool information. // Optional additional tool information.
//
// Display name precedence order is: title, annotations.title, then name.
Annotations *ToolAnnotations `json:"annotations,omitempty"` Annotations *ToolAnnotations `json:"annotations,omitempty"`
// A human-readable description of the tool. // A human-readable description of the tool.
// //
@ -612,8 +683,17 @@ type Tool struct {
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// A JSON Schema object defining the expected parameters for the tool. // A JSON Schema object defining the expected parameters for the tool.
InputSchema *jsonschema.Schema `json:"inputSchema"` InputSchema *jsonschema.Schema `json:"inputSchema"`
// The name of the tool. // Intended for programmatic or logical use, but used as a display name in past
// specs or fallback (if title isn't present).
Name string `json:"name"` Name string `json:"name"`
// An optional JSON Schema object defining the structure of the tool's output
// returned in the structuredContent field of a CallToolResult.
OutputSchema *jsonschema.Schema `json:"outputSchema,omitempty"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
// If not provided, Annotations.Title should be used for display if present,
// otherwise Name.
Title string `json:"title,omitempty"`
} }
// Additional properties describing a Tool to clients. // Additional properties describing a Tool to clients.
@ -656,14 +736,25 @@ type ToolAnnotations struct {
type ToolListChangedParams struct { type ToolListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to // This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses. // attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"` Meta `json:"_meta,omitempty"`
} }
func (x *ToolListChangedParams) GetMeta() *Meta { return &x.Meta } func (x *ToolListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ToolListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
// Describes the name and version of an MCP implementation. // TODO(jba): add CompleteRequest and related types.
// TODO(jba): add ElicitRequest and related types.
// Describes the name and version of an MCP implementation, with an optional
// title for UI representation.
type implementation struct { type implementation struct {
Name string `json:"name"` // Intended for programmatic or logical use, but used as a display name in past
// specs or fallback (if title isn't present).
Name string `json:"name"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
Title string `json:"title,omitempty"`
Version string `json:"version"` Version string `json:"version"`
} }
@ -713,6 +804,7 @@ const (
notificationCancelled = "notifications/cancelled" notificationCancelled = "notifications/cancelled"
methodComplete = "completion/complete" methodComplete = "completion/complete"
methodCreateMessage = "sampling/createMessage" methodCreateMessage = "sampling/createMessage"
methodElicit = "elicitation/create"
methodGetPrompt = "prompts/get" methodGetPrompt = "prompts/get"
methodInitialize = "initialize" methodInitialize = "initialize"
notificationInitialized = "notifications/initialized" notificationInitialized = "notifications/initialized"

69
mcp/protocol_test.go Normal file
View file

@ -0,0 +1,69 @@
// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package mcp
import (
"encoding/json"
"maps"
"testing"
)
func TestParamsMeta(t *testing.T) {
// Verify some properties of the Meta field of Params structs.
// We use CallToolParams for the test, but the Meta setup of all params types
// is identical so they should all behave the same.
toJSON := func(x any) string {
data, err := json.Marshal(x)
if err != nil {
t.Fatal(err)
}
return string(data)
}
meta := map[string]any{"m": 1}
// You can set the embedded Meta field to a literal map.
p := &CallToolParams{
Meta: meta,
Name: "name",
}
// The Meta field marshals properly when it's present.
if g, w := toJSON(p), `{"_meta":{"m":1},"name":"name"}`; g != w {
t.Errorf("got %s, want %s", g, w)
}
// ... and when it's absent.
p2 := &CallToolParams{Name: "n"}
if g, w := toJSON(p2), `{"name":"n"}`; g != w {
t.Errorf("got %s, want %s", g, w)
}
// The GetMeta and SetMeta functions work as expected.
if g := p.GetMeta(); !maps.Equal(g, meta) {
t.Errorf("got %+v, want %+v", g, meta)
}
meta2 := map[string]any{"x": 2}
p.SetMeta(meta2)
if g := p.GetMeta(); !maps.Equal(g, meta2) {
t.Errorf("got %+v, want %+v", g, meta2)
}
// The GetProgressToken and SetProgressToken methods work as expected.
if g := p.GetProgressToken(); g != nil {
t.Errorf("got %v, want nil", g)
}
p.SetProgressToken("t")
if g := p.GetProgressToken(); g != "t" {
t.Errorf("got %v, want `t`", g)
}
// You can set a progress token to an int, int32 or int64.
p.SetProgressToken(int(1))
p.SetProgressToken(int32(1))
p.SetProgressToken(int64(1))
}

View file

@ -146,7 +146,6 @@ func (s *Server) addToolsErr(tools ...*ServerTool) error {
st.inputResolved = r st.inputResolved = r
} }
// TODO: uncomment when output schemas drop.
// if st.Tool.OutputSchema != nil { // if st.Tool.OutputSchema != nil {
// st.outputResolved, err := st.Tool.OutputSchema.Resolve(&jsonschema.ResolveOptions{ValidateDefaults: true}) // st.outputResolved, err := st.Tool.OutputSchema.Resolve(&jsonschema.ResolveOptions{ValidateDefaults: true})
// if err != nil { // if err != nil {

View file

@ -18,7 +18,7 @@ type SayHiParams struct {
func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[SayHiParams]) (*mcp.CallToolResultFor[any], error) { func SayHi(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[SayHiParams]) (*mcp.CallToolResultFor[any], error) {
return &mcp.CallToolResultFor[any]{ return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{ Content: []*mcp.ContentBlock{
mcp.NewTextContent("Hi " + params.Arguments.Name), mcp.NewTextContent("Hi " + params.Arguments.Name),
}, },
}, nil }, nil

View file

@ -242,51 +242,62 @@ func notifySessions[S Session](sessions []S, method string, params Params) {
} }
} }
type Meta struct { type Meta map[string]any
Data map[string]any `json:",omitempty"`
// For params, the progress token can be nil, a string or an integer. func (m Meta) GetMeta() map[string]any { return m }
// It should be nil for results. func (m *Meta) SetMeta(x map[string]any) { *m = x }
ProgressToken any `json:"progressToken,omitempty"`
const progressTokenKey = "progressToken"
func getProgressToken(p Params) any {
return p.GetMeta()[progressTokenKey]
} }
type metaSansMethods Meta // avoid infinite recursion during marshaling func setProgressToken(p Params, pt any) {
switch pt.(type) {
func (m Meta) MarshalJSON() ([]byte, error) { // Support int32 and int64 for atomic.IntNN.
if p := m.ProgressToken; p != nil { case int, int32, int64, string:
if k := reflect.ValueOf(p).Kind(); k != reflect.Int && k != reflect.String { default:
return nil, fmt.Errorf("bad type %T for Meta.ProgressToken: must be int or string", p) panic(fmt.Sprintf("progress token %v is of type %[1]T, not int or string", pt))
}
} }
// If ProgressToken is nil, accept Data["progressToken"]. We can't call marshalStructWithMap m := p.GetMeta()
// in that case because it will complain about duplicate fields. (We'd have to if m == nil {
// make it much smarter to avoid that; not worth it.) m = map[string]any{}
if m.ProgressToken == nil && len(m.Data) > 0 {
return json.Marshal(m.Data)
} }
return marshalStructWithMap((*metaSansMethods)(&m), "Data") m[progressTokenKey] = pt
}
func (m *Meta) UnmarshalJSON(data []byte) error {
return unmarshalStructWithMap(data, (*metaSansMethods)(m), "Data")
} }
// Params is a parameter (input) type for an MCP call or notification. // Params is a parameter (input) type for an MCP call or notification.
type Params interface { type Params interface {
// Returns a pointer to the params's Meta field. GetMeta() map[string]any
GetMeta() *Meta SetMeta(map[string]any)
}
// RequestParams is a parameter (input) type for an MCP request.
type RequestParams interface {
Params
// GetProgressToken returns the progress token from the params' Meta field, or nil
// if there is none.
GetProgressToken() any
// SetProgressToken sets the given progress token into the params' Meta field.
// It panics if its argument is not an int or a string.
SetProgressToken(any)
} }
// Result is a result of an MCP call. // Result is a result of an MCP call.
type Result interface { type Result interface {
// Returns a pointer to the result's Meta field. GetMeta() map[string]any
GetMeta() *Meta SetMeta(map[string]any)
} }
// emptyResult is returned by methods that have no result, like ping. // emptyResult is returned by methods that have no result, like ping.
// Those methods cannot return nil, because jsonrpc2 cannot handle nils. // Those methods cannot return nil, because jsonrpc2 cannot handle nils.
type emptyResult struct{} type emptyResult struct{}
func (*emptyResult) GetMeta() *Meta { panic("should never be called") } func (*emptyResult) GetMeta() map[string]any { panic("should never be called") }
func (*emptyResult) SetMeta(map[string]any) { panic("should never be called") }
type listParams interface { type listParams interface {
// Returns a pointer to the param's Cursor field. // Returns a pointer to the param's Cursor field.

View file

@ -9,67 +9,8 @@ import (
"encoding/json" "encoding/json"
"strings" "strings"
"testing" "testing"
"github.com/google/go-cmp/cmp"
) )
func TestMetaMarshal(t *testing.T) {
// Verify that Meta values round-trip.
for _, meta := range []Meta{
{Data: nil, ProgressToken: nil},
{Data: nil, ProgressToken: "p"},
{Data: map[string]any{"d": true}, ProgressToken: nil},
{Data: map[string]any{"d": true}, ProgressToken: "p"},
} {
got := roundTrip(t, meta)
if !cmp.Equal(got, meta) {
t.Errorf("\ngot %#v\nwant %#v", got, meta)
}
}
// Check errors.
for _, tt := range []struct {
meta Meta
want string
}{
{
Meta{Data: map[string]any{"progressToken": "p"}, ProgressToken: 1},
"duplicate",
},
{
Meta{ProgressToken: true},
"bad type",
},
} {
_, err := json.Marshal(tt.meta)
if err == nil || !strings.Contains(err.Error(), tt.want) {
t.Errorf("%+v: got %v, want error containing %q", tt.meta, err, tt.want)
}
}
// Accept progressToken in map if the field is nil.
// It will unmarshal by populating ProgressToken.
meta := Meta{Data: map[string]any{"progressToken": "p"}}
got := roundTrip(t, meta)
want := Meta{ProgressToken: "p"}
if !cmp.Equal(got, want) {
t.Errorf("got %+v, want %+v", got, want)
}
}
func roundTrip[T any](t *testing.T, v T) T {
t.Helper()
bytes, err := json.Marshal(v)
if err != nil {
t.Fatal(err)
}
var res T
if err := json.Unmarshal(bytes, &res); err != nil {
t.Fatal(err)
}
return res
}
// TODO(jba): this shouldn't be in this file, but tool_test.go doesn't have access to unexported symbols. // TODO(jba): this shouldn't be in this file, but tool_test.go doesn't have access to unexported symbols.
func TestNewServerToolValidate(t *testing.T) { func TestNewServerToolValidate(t *testing.T) {
// Check that the tool returned from NewServerTool properly validates its input schema. // Check that the tool returned from NewServerTool properly validates its input schema.

View file

@ -20,7 +20,7 @@ type AddParams struct {
func Add(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[AddParams]) (*mcp.CallToolResultFor[any], error) { func Add(ctx context.Context, cc *mcp.ServerSession, params *mcp.CallToolParamsFor[AddParams]) (*mcp.CallToolResultFor[any], error) {
return &mcp.CallToolResultFor[any]{ return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{mcp.NewTextContent(fmt.Sprintf("%d", params.Arguments.X+params.Arguments.Y))}, Content: []*mcp.ContentBlock{mcp.NewTextContent(fmt.Sprintf("%d", params.Arguments.X+params.Arguments.Y))},
}, nil }, nil
} }

View file

@ -53,7 +53,7 @@ func TestSSEServer(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
wantHi := &CallToolResult{ wantHi := &CallToolResult{
Content: []*Content{{Type: "text", Text: "hi user"}}, Content: []*ContentBlock{{Type: "text", Text: "hi user"}},
} }
if diff := cmp.Diff(wantHi, gotHi); diff != "" { if diff := cmp.Diff(wantHi, gotHi); diff != "" {
t.Errorf("tools/call 'greet' mismatch (-want +got):\n%s", diff) t.Errorf("tools/call 'greet' mismatch (-want +got):\n%s", diff)

View file

@ -82,7 +82,7 @@ func TestStreamableTransports(t *testing.T) {
// 5. Verify that the correct response is received. // 5. Verify that the correct response is received.
want := &CallToolResult{ want := &CallToolResult{
Content: []*Content{{Type: "text", Text: "hi streamy"}}, Content: []*ContentBlock{{Type: "text", Text: "hi streamy"}},
} }
if diff := cmp.Diff(want, got); diff != "" { if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("CallTool() returned unexpected content (-want +got):\n%s", diff) t.Errorf("CallTool() returned unexpected content (-want +got):\n%s", diff)
@ -583,4 +583,3 @@ func TestEventID(t *testing.T) {
}) })
} }
} }

View file

@ -132,7 +132,7 @@ func newRawHandler(st *ServerTool) rawToolHandler {
// rather than returned as jsonrpc2 server errors. // rather than returned as jsonrpc2 server errors.
if err != nil { if err != nil {
return &CallToolResult{ return &CallToolResult{
Content: []*Content{NewTextContent(err.Error())}, Content: []*ContentBlock{NewTextContent(err.Error())},
IsError: true, IsError: true,
}, nil }, nil
} }