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) {
return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{mcp.NewTextContent("Hi " + params.Name)},
Content: []*mcp.ContentBlock{mcp.NewTextContent("Hi " + params.Name)},
}, 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) {
return &mcp.CallToolResultFor[struct{}]{
Content: []*mcp.Content{
Content: []*mcp.ContentBlock{
mcp.NewTextContent("Hi " + params.Name),
},
}, 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) {
return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{
Content: []*mcp.ContentBlock{
mcp.NewTextContent("Hi " + params.Name),
},
}, 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) {
return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{mcp.NewTextContent("Hi " + params.Name)},
Content: []*mcp.ContentBlock{mcp.NewTextContent("Hi " + params.Name)},
}, nil
}

View file

@ -70,7 +70,7 @@ func TestCmdTransport(t *testing.T) {
log.Fatal(err)
}
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 != "" {
t.Errorf("greet returned unexpected content (-want +got):\n%s", diff)

View file

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

View file

@ -14,7 +14,7 @@ import (
func TestContent(t *testing.T) {
tests := []struct {
in *mcp.Content
in *mcp.ContentBlock
want string // json serialization
}{
{mcp.NewTextContent("hello"), `{"type":"text","text":"hello"}`},
@ -27,13 +27,13 @@ func TestContent(t *testing.T) {
`{"type":"audio","mimeType":"audio/wav","data":"YTFiMmMz"}`,
},
{
mcp.NewResourceContent(
mcp.NewResourceContents(
mcp.NewTextResourceContents("file://foo", "text", "abc"),
),
`{"type":"resource","resource":{"uri":"file://foo","mimeType":"text","text":"abc"}}`,
},
{
mcp.NewResourceContent(
mcp.NewResourceContents(
mcp.NewBlobResourceContents("file://foo", "image/png", []byte("a1b2c3")),
),
`{"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 != "" {
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 {
t.Fatal(err)
}

View file

@ -23,7 +23,9 @@ func Example_progressMiddleware() {
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) {
params.GetMeta().ProgressToken = nextProgressToken.Add(1)
if rp, ok := params.(mcp.RequestParams); ok {
rp.SetProgressToken(nextProgressToken.Add(1))
}
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) {
return &CallToolResultFor[any]{
Content: []*Content{
Content: []*ContentBlock{
NewTextContent("Hi " + params.Name),
},
}, 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 {
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) {
@ -195,7 +195,7 @@ func TestEndToEnd(t *testing.T) {
t.Fatal(err)
}
wantHi := &CallToolResult{
Content: []*Content{{Type: "text", Text: "hi user"}},
Content: []*ContentBlock{{Type: "text", Text: "hi user"}},
}
if diff := cmp.Diff(wantHi, gotHi); diff != "" {
t.Errorf("tools/call 'greet' mismatch (-want +got):\n%s", diff)
@ -212,7 +212,7 @@ func TestEndToEnd(t *testing.T) {
}
wantFail := &CallToolResult{
IsError: true,
Content: []*Content{{Type: "text", Text: errTestFailure.Error()}},
Content: []*ContentBlock{{Type: "text", Text: errTestFailure.Error()}},
}
if diff := cmp.Diff(wantFail, gotFail); diff != "" {
t.Errorf("tools/call 'fail' mismatch (-want +got):\n%s", diff)

View file

@ -4,6 +4,12 @@
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 (
"github.com/modelcontextprotocol/go-sdk/jsonschema"
)
@ -16,6 +22,13 @@ type Annotations struct {
// It can include multiple entries to indicate content useful for multiple
// audiences (e.g., `["user", "assistant"]`).
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.
//
// A value of 1 means "most important," and indicates that the data is
@ -27,63 +40,78 @@ type Annotations struct {
type CallToolParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
Arguments any `json:"arguments,omitempty"`
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 {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
Arguments In `json:"arguments,omitempty"`
Name string `json:"name"`
}
func (x *CallToolParamsFor[In]) GetMeta() *Meta { return &x.Meta }
// 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 {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Content []*Content `json:"content"`
Meta `json:"_meta,omitempty"`
// 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.
//
// 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"`
// 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 {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Content []*Content `json:"content"`
Meta `json:"_meta,omitempty"`
// 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.
//
// 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"`
// 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 {
// This property is reserved by the protocol to allow clients and servers to
// 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
// logged or presented to the user.
Reason string `json:"reason,omitempty"`
@ -94,7 +122,8 @@ type CancelledParams struct {
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
// 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"`
// Present if the client supports sampling from an LLM.
Sampling *SamplingCapabilities `json:"sampling,omitempty"`
// Present if the client supports elicitation from the server.
Elicitation *ElicitationCapabilities `json:"elicitation,omitempty"`
}
type CreateMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// caller), to be attached to the prompt. The client MAY ignore this request.
IncludeContext string `json:"includeContext,omitempty"`
@ -135,7 +166,8 @@ type CreateMessageParams struct {
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 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 {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Content *Content `json:"content"`
Meta `json:"_meta,omitempty"`
Content any `json:"content"`
// The name of the model that generated the message.
Model string `json:"model"`
Role Role `json:"role"`
@ -153,36 +185,33 @@ type CreateMessageResult struct {
StopReason string `json:"stopReason,omitempty"`
}
func (x *CreateMessageResult) GetMeta() *Meta { return &x.Meta }
type GetPromptParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
// Arguments to use for templating the prompt.
Arguments map[string]string `json:"arguments,omitempty"`
// The name of the prompt or prompt template.
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.
type GetPromptResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
// An optional description for the prompt.
Description string `json:"description,omitempty"`
Messages []*PromptMessage `json:"messages"`
}
func (x *GetPromptResult) GetMeta() *Meta { return &x.Meta }
type InitializeParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
Capabilities *ClientCapabilities `json:"capabilities"`
ClientInfo *implementation `json:"clientInfo"`
// The latest version of the Model Context Protocol that the client supports.
@ -190,14 +219,15 @@ type InitializeParams struct {
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
// response.
type InitializeResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
Capabilities *serverCapabilities `json:"capabilities"`
// Instructions describing how to use the server and its features.
//
@ -212,101 +242,101 @@ type InitializeResult struct {
ServerInfo *implementation `json:"serverInfo"`
}
func (x *InitializeResult) GetMeta() *Meta { return &x.Meta }
type InitializedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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 {
// This property is reserved by the protocol to allow clients and servers to
// 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,
// the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"`
}
func (x *ListPromptsParams) GetMeta() *Meta { return &x.Meta }
func (x *ListPromptsParams) cursorPtr() *string { return &x.Cursor }
func (x *ListPromptsParams) GetProgressToken() any { return getProgressToken(x) }
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.
type ListPromptsResult struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
Prompts []*Prompt `json:"prompts"`
}
func (x *ListPromptsResult) GetMeta() *Meta { return &x.Meta }
func (x *ListPromptsResult) nextCursorPtr() *string { return &x.NextCursor }
type ListResourceTemplatesParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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,
// the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"`
}
func (x *ListResourceTemplatesParams) GetMeta() *Meta { return &x.Meta }
func (x *ListResourceTemplatesParams) cursorPtr() *string { return &x.Cursor }
func (x *ListResourceTemplatesParams) GetProgressToken() any { return getProgressToken(x) }
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.
type ListResourceTemplatesResult struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
ResourceTemplates []*ResourceTemplate `json:"resourceTemplates"`
}
func (x *ListResourceTemplatesResult) GetMeta() *Meta { return &x.Meta }
func (x *ListResourceTemplatesResult) nextCursorPtr() *string { return &x.NextCursor }
type ListResourcesParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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,
// the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"`
}
func (x *ListResourcesParams) GetMeta() *Meta { return &x.Meta }
func (x *ListResourcesParams) cursorPtr() *string { return &x.Cursor }
func (x *ListResourcesParams) GetProgressToken() any { return getProgressToken(x) }
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.
type ListResourcesResult struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
Resources []*Resource `json:"resources"`
}
func (x *ListResourcesResult) GetMeta() *Meta { return &x.Meta }
func (x *ListResourcesResult) nextCursorPtr() *string { return &x.NextCursor }
type ListRootsParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// 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 {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
Roots []*Root `json:"roots"`
}
func (x *ListRootsResult) GetMeta() *Meta { return &x.Meta }
type ListToolsParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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,
// the server should return results starting after this cursor.
Cursor string `json:"cursor,omitempty"`
}
func (x *ListToolsParams) GetMeta() *Meta { return &x.Meta }
func (x *ListToolsParams) cursorPtr() *string { return &x.Cursor }
func (x *ListToolsParams) GetProgressToken() any { return getProgressToken(x) }
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.
type ListToolsResult struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
Tools []*Tool `json:"tools"`
}
func (x *ListToolsResult) GetMeta() *Meta { return &x.Meta }
func (x *ListToolsResult) nextCursorPtr() *string { return &x.NextCursor }
// The severity of a log message.
@ -355,7 +383,7 @@ type LoggingLevel string
type LoggingMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// serializable type is allowed here.
Data any `json:"data"`
@ -365,7 +393,8 @@ type LoggingMessageParams struct {
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.
//
@ -422,15 +451,16 @@ type ModelPreferences struct {
type PingParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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 {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
// An optional message describing the current progress.
Message string `json:"message,omitempty"`
// 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"`
}
func (x *ProgressNotificationParams) GetMeta() *Meta { return &x.Meta }
// A prompt or prompt template that the server offers.
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.
Arguments []*PromptArgument `json:"arguments,omitempty"`
// An optional description of what this prompt provides
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"`
// 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.
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.
Description string `json:"description,omitempty"`
// The name of the argument.
Name string `json:"name"`
// Whether this argument must be provided.
Required bool `json:"required,omitempty"`
}
@ -468,43 +507,46 @@ type PromptArgument struct {
type PromptListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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.
//
// This is similar to `SamplingMessage`, but also supports the embedding of
// resources from the MCP server.
type PromptMessage struct {
Content *Content `json:"content"`
Role Role `json:"role"`
Content *ContentBlock `json:"content"`
Role Role `json:"role"`
}
type ReadResourceParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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 server how to interpret it.
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.
type ReadResourceResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta Meta `json:"_meta,omitempty"`
Meta `json:"_meta,omitempty"`
Contents []*ResourceContents `json:"contents"`
}
func (x *ReadResourceResult) GetMeta() *Meta { return &x.Meta }
// A known resource that the server is capable of reading.
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.
Annotations *Annotations `json:"annotations,omitempty"`
// A description of what this resource represents.
@ -514,9 +556,8 @@ type Resource struct {
Description string `json:"description,omitempty"`
// The MIME type of this resource, if known.
MIMEType string `json:"mimeType,omitempty"`
// A human-readable name for this resource.
//
// This can be used by clients to populate UI elements.
// 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"`
// The size of the raw resource content, in bytes (i.e., before base64 encoding
// 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
// usage.
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.
URI string `json:"uri"`
}
@ -531,13 +579,17 @@ type Resource struct {
type ResourceListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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.
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.
Annotations *Annotations `json:"annotations,omitempty"`
// 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
// included if all resources matching this template have the same type.
MIMEType string `json:"mimeType,omitempty"`
// A human-readable name for the type of resource this template refers to.
//
// This can be used by clients to populate UI elements.
// 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.
//
// 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
// URIs.
URITemplate string `json:"uriTemplate"`
@ -562,6 +620,9 @@ type Role string
// Represents a root directory or file that the server can operate on.
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
// identifier for the root, which may be useful for display purposes or for
// referencing the root in other parts of the application.
@ -575,35 +636,45 @@ type Root struct {
type RootsListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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{}
// ElicitationCapabilities describes the capabilities for elicitation.
type ElicitationCapabilities struct{}
// Describes a message issued to or received from an LLM API.
type SamplingMessage struct {
Content *Content `json:"content"`
Role Role `json:"role"`
Content any `json:"content"`
Role Role `json:"role"`
}
type SetLevelParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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
// server should send all logs at this level and higher (i.e., more severe) to
// the client as notifications/message.
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.
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.
//
// Display name precedence order is: title, annotations.title, then name.
Annotations *ToolAnnotations `json:"annotations,omitempty"`
// A human-readable description of the tool.
//
@ -612,8 +683,17 @@ type Tool struct {
Description string `json:"description,omitempty"`
// A JSON Schema object defining the expected parameters for the tool.
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"`
// 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.
@ -656,14 +736,25 @@ type ToolAnnotations struct {
type ToolListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// 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 {
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"`
}
@ -713,6 +804,7 @@ const (
notificationCancelled = "notifications/cancelled"
methodComplete = "completion/complete"
methodCreateMessage = "sampling/createMessage"
methodElicit = "elicitation/create"
methodGetPrompt = "prompts/get"
methodInitialize = "initialize"
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
}
// TODO: uncomment when output schemas drop.
// if st.Tool.OutputSchema != nil {
// st.outputResolved, err := st.Tool.OutputSchema.Resolve(&jsonschema.ResolveOptions{ValidateDefaults: true})
// 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) {
return &mcp.CallToolResultFor[any]{
Content: []*mcp.Content{
Content: []*mcp.ContentBlock{
mcp.NewTextContent("Hi " + params.Arguments.Name),
},
}, nil

View file

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

View file

@ -9,67 +9,8 @@ import (
"encoding/json"
"strings"
"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.
func TestNewServerToolValidate(t *testing.T) {
// 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) {
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
}

View file

@ -53,7 +53,7 @@ func TestSSEServer(t *testing.T) {
t.Fatal(err)
}
wantHi := &CallToolResult{
Content: []*Content{{Type: "text", Text: "hi user"}},
Content: []*ContentBlock{{Type: "text", Text: "hi user"}},
}
if diff := cmp.Diff(wantHi, gotHi); 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.
want := &CallToolResult{
Content: []*Content{{Type: "text", Text: "hi streamy"}},
Content: []*ContentBlock{{Type: "text", Text: "hi streamy"}},
}
if diff := cmp.Diff(want, got); 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.
if err != nil {
return &CallToolResult{
Content: []*Content{NewTextContent(err.Error())},
Content: []*ContentBlock{NewTextContent(err.Error())},
IsError: true,
}, nil
}