internal/mcp/protocol: move out of mcp/internal, as it's used in the API
The generated protocol package is part of the SDK API, so it shouldn't be internal. Change-Id: I5306af48019b1599707b939b348eb6ae4f766ca9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/670356 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
parent
5cc4e6ea54
commit
8efb54691d
16 changed files with 12 additions and 12 deletions
|
|
@ -12,7 +12,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
var httpAddr = flag.String("http", "", "if set, use SSE HTTP at this address, instead of stdin/stdout")
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
// A Client is an MCP client, which may be connected to an MCP server
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
const runAsServer = "_MCP_RUN_AS_SERVER"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package mcp
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
// Content is the union of supported content types: [TextContent],
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
func TestContent(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import (
|
|||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/jsonschema"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
type hiParams struct {
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import (
|
|||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/util"
|
||||
"github.com/modelcontextprotocol/go-sdk/jsonschema"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
// A PromptHandler handles a call to prompts/get.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
// testPromptHandler is used for type inference in TestMakePrompt.
|
||||
|
|
|
|||
42
mcp/protocol/content.go
Normal file
42
mcp/protocol/content.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// 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 protocol
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Content is the wire format for content, including all fields.
|
||||
type Content struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text,omitempty"`
|
||||
MIMEType string `json:"mimeType,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Resource *Resource `json:"resource,omitempty"`
|
||||
}
|
||||
|
||||
// Resource is the wire format for embedded resources, including all fields.
|
||||
type Resource struct {
|
||||
URI string `json:"uri,"`
|
||||
MIMEType string `json:"mimeType,omitempty"`
|
||||
Text string `json:"text"`
|
||||
Blob *string `json:"blob"` // blob is a pointer to distinguish empty from missing data
|
||||
}
|
||||
|
||||
func (c *Content) UnmarshalJSON(data []byte) error {
|
||||
type wireContent Content // for naive unmarshaling
|
||||
var c2 wireContent
|
||||
if err := json.Unmarshal(data, &c2); err != nil {
|
||||
return err
|
||||
}
|
||||
switch c2.Type {
|
||||
case "text", "image", "audio", "resource":
|
||||
default:
|
||||
return fmt.Errorf("unrecognized content type %s", c.Type)
|
||||
}
|
||||
*c = Content(c2)
|
||||
return nil
|
||||
}
|
||||
13
mcp/protocol/doc.go
Normal file
13
mcp/protocol/doc.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// 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.
|
||||
|
||||
//go:generate go run generate.go
|
||||
|
||||
// The protocol package contains types that define the MCP protocol.
|
||||
//
|
||||
// It is auto-generated from the MCP spec. Run go generate to update it.
|
||||
// The generated set of types is intended to be minimal, in the sense that we
|
||||
// only generate types that are actually used by the SDK. See generate.go for
|
||||
// instructions on how to generate more (or different) types.
|
||||
package protocol
|
||||
395
mcp/protocol/generate.go
Normal file
395
mcp/protocol/generate.go
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
// 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.
|
||||
|
||||
//go:build ignore
|
||||
|
||||
// This script generates protocol definitions in protocol.go from the MCP spec.
|
||||
//
|
||||
// Only the set of declarations configured by the [declarations] value are
|
||||
// generated.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/jsonschema"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/util"
|
||||
)
|
||||
|
||||
var schemaFile = flag.String("schema_file", "", "if set, use this file as the persistent schema file")
|
||||
|
||||
// A typeConfig defines a rewrite to perform to a (possibly nested) struct
|
||||
// field. In some cases, we may want to use an external type for the nested
|
||||
// struct field. In others, we may want to extract the type definition to a
|
||||
// name.
|
||||
type typeConfig struct {
|
||||
Name string // declaration name for the type
|
||||
Substitute string // type definition to substitute
|
||||
Fields config // individual field configuration, or nil
|
||||
}
|
||||
|
||||
type config map[string]*typeConfig
|
||||
|
||||
// declarations configures the set of declarations to write.
|
||||
//
|
||||
// Top level declarations are only created if they are configured with a
|
||||
// non-empty Name. Otherwise, they are discarded, though their fields may be
|
||||
// extracted to types if they have a nested field configuration.
|
||||
var declarations = config{
|
||||
"Annotations": {Name: "Annotations"},
|
||||
"CallToolRequest": {
|
||||
Fields: config{"Params": {Name: "CallToolParams"}},
|
||||
},
|
||||
"CallToolResult": {Name: "CallToolResult"},
|
||||
"CancelledNotification": {
|
||||
Fields: config{"Params": {Name: "CancelledParams"}},
|
||||
},
|
||||
"ClientCapabilities": {Name: "ClientCapabilities"},
|
||||
"GetPromptRequest": {
|
||||
Fields: config{"Params": {Name: "GetPromptParams"}},
|
||||
},
|
||||
"GetPromptResult": {Name: "GetPromptResult"},
|
||||
"Implementation": {Name: "Implementation"},
|
||||
"InitializeRequest": {
|
||||
Fields: config{"Params": {Name: "InitializeParams"}},
|
||||
},
|
||||
"InitializeResult": {Name: "InitializeResult"},
|
||||
"InitializedNotification": {
|
||||
Fields: config{"Params": {Name: "InitializedParams"}},
|
||||
},
|
||||
"ListPromptsRequest": {
|
||||
Fields: config{"Params": {Name: "ListPromptsParams"}},
|
||||
},
|
||||
"ListPromptsResult": {Name: "ListPromptsResult"},
|
||||
"ListToolsRequest": {
|
||||
Fields: config{"Params": {Name: "ListToolsParams"}},
|
||||
},
|
||||
"ListToolsResult": {Name: "ListToolsResult"},
|
||||
"Prompt": {Name: "Prompt"},
|
||||
"PromptMessage": {Name: "PromptMessage"},
|
||||
"PromptArgument": {Name: "PromptArgument"},
|
||||
"RequestId": {Substitute: "any"}, // null|number|string
|
||||
"Role": {Name: "Role"},
|
||||
"ServerCapabilities": {
|
||||
Name: "ServerCapabilities",
|
||||
Fields: config{
|
||||
"Prompts": {Name: "PromptCapabilities"},
|
||||
"Resources": {Name: "ResourceCapabilities"},
|
||||
"Tools": {Name: "ToolCapabilities"},
|
||||
},
|
||||
},
|
||||
"Tool": {
|
||||
Name: "Tool",
|
||||
Fields: config{"InputSchema": {Substitute: "*jsonschema.Schema"}},
|
||||
},
|
||||
"ToolAnnotations": {Name: "ToolAnnotations"},
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Load and unmarshal the schema.
|
||||
data, err := loadSchema(*schemaFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
schema := new(jsonschema.Schema)
|
||||
if err := json.Unmarshal(data, &schema); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Collect named types. Since we may create new type definitions while
|
||||
// writing types, we collect definitions and concatenate them later. This
|
||||
// also allows us to sort.
|
||||
named := make(map[string]*bytes.Buffer)
|
||||
for name, def := range util.Sorted(schema.Definitions) {
|
||||
config := declarations[name]
|
||||
if config == nil {
|
||||
continue
|
||||
}
|
||||
if err := writeDecl(*config, def, named); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
fmt.Fprintf(buf, `
|
||||
// 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.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/jsonschema"
|
||||
)
|
||||
`)
|
||||
|
||||
// Write out types.
|
||||
for _, b := range util.Sorted(named) {
|
||||
fmt.Fprintln(buf)
|
||||
fmt.Fprint(buf, b.String())
|
||||
}
|
||||
|
||||
formatted, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
log.Println(buf.String())
|
||||
log.Fatalf("failed to format: %v", err)
|
||||
}
|
||||
if err := os.WriteFile("protocol.go", formatted, 0666); err != nil {
|
||||
log.Fatalf("failed to write protocol.go: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func loadSchema(schemaFile string) (data []byte, err error) {
|
||||
const schemaURL = "https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/refs/heads/main/schema/2025-03-26/schema.json"
|
||||
|
||||
if schemaFile != "" {
|
||||
data, err = os.ReadFile(schemaFile)
|
||||
if os.IsNotExist(err) {
|
||||
data = nil
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("reading schema file %q: %v", schemaFile, err)
|
||||
}
|
||||
}
|
||||
if data == nil {
|
||||
resp, err := http.Get(schemaURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("downloading schema: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("downloading schema: %v", resp.Status)
|
||||
}
|
||||
data, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading schema body: %v", err)
|
||||
}
|
||||
if schemaFile != "" {
|
||||
if err := os.WriteFile(schemaFile, data, 0666); err != nil {
|
||||
return nil, fmt.Errorf("persisting schema: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func writeDecl(config typeConfig, def *jsonschema.Schema, named map[string]*bytes.Buffer) error {
|
||||
var w io.Writer = io.Discard
|
||||
if name := config.Name; name != "" {
|
||||
if _, ok := named[name]; ok {
|
||||
return nil
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
w = buf
|
||||
named[name] = buf
|
||||
if def.Description != "" {
|
||||
fmt.Fprintf(buf, "%s\n", toComment(def.Description))
|
||||
}
|
||||
fmt.Fprintf(buf, "type %s ", name)
|
||||
}
|
||||
if err := writeType(w, &config, def, named); err != nil {
|
||||
return err // Better error here?
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeType writes the type definition to the given writer.
|
||||
//
|
||||
// If path is non-empty, it is the path to the field using this type, for the
|
||||
// purpose of detecting field rewrites (see [fieldRewrite]).
|
||||
//
|
||||
// named is the in-progress collection of type definitions. New named types may
|
||||
// be added during writeType, if they are extracted from inner fields.
|
||||
func writeType(w io.Writer, config *typeConfig, def *jsonschema.Schema, named map[string]*bytes.Buffer) error {
|
||||
// Use type names for Named types.
|
||||
if name := strings.TrimPrefix(def.Ref, "#/definitions/"); name != "" {
|
||||
// TODO: this check is not quite right: we should really panic if the
|
||||
// definition is missing, *but only if w is not io.Discard*. That's not a
|
||||
// great API: see if we can do something more explicit than io.Discard.
|
||||
if cfg, ok := declarations[name]; ok {
|
||||
if cfg.Name == "" && cfg.Substitute == "" {
|
||||
panic(fmt.Sprintf("referenced type %q cannot be referred to (no name or substitution)", name))
|
||||
}
|
||||
if cfg.Substitute != "" {
|
||||
name = cfg.Substitute
|
||||
} else {
|
||||
name = cfg.Name
|
||||
}
|
||||
}
|
||||
w.Write([]byte(name))
|
||||
return nil
|
||||
}
|
||||
|
||||
// For types that explicitly allow additional properties, we can either
|
||||
// unmarshal them into a map[string]any, or delay unmarshalling with
|
||||
// json.RawMessage. For now, use json.RawMessage as it defers the choice.
|
||||
if def.Type == "object" && canHaveAdditionalProperties(def) {
|
||||
w.Write([]byte("map[string]"))
|
||||
return writeType(w, nil, def.AdditionalProperties, named)
|
||||
}
|
||||
|
||||
if def.Type == "" {
|
||||
// special case: recognize Content
|
||||
if slices.ContainsFunc(def.AnyOf, func(s *jsonschema.Schema) bool {
|
||||
return s.Ref == "#/definitions/TextContent"
|
||||
}) {
|
||||
fmt.Fprintf(w, "Content")
|
||||
} else {
|
||||
// E.g. union types.
|
||||
fmt.Fprintf(w, "json.RawMessage")
|
||||
}
|
||||
} else {
|
||||
switch def.Type {
|
||||
case "array":
|
||||
fmt.Fprintf(w, "[]")
|
||||
return writeType(w, nil, def.Items, named)
|
||||
|
||||
case "boolean":
|
||||
fmt.Fprintf(w, "bool")
|
||||
|
||||
case "integer":
|
||||
fmt.Fprintf(w, "int64")
|
||||
|
||||
// not handled: "null"
|
||||
|
||||
case "number":
|
||||
// We could use json.Number here; use float64 for simplicity.
|
||||
fmt.Fprintf(w, "float64")
|
||||
|
||||
case "object":
|
||||
fmt.Fprintf(w, "struct {\n")
|
||||
for name, fieldDef := range util.Sorted(def.Properties) {
|
||||
if fieldDef.Description != "" {
|
||||
fmt.Fprintf(w, "%s\n", toComment(fieldDef.Description))
|
||||
}
|
||||
export := exportName(name)
|
||||
fmt.Fprintf(w, "\t%s ", export)
|
||||
|
||||
required := slices.Contains(def.Required, name)
|
||||
|
||||
// If the field is not required, and is a struct type, indirect with a
|
||||
// pointer so that it can be empty as defined by encoding/json.
|
||||
//
|
||||
// TODO: use omitzero when available.
|
||||
needPointer := !required &&
|
||||
(strings.HasPrefix(fieldDef.Ref, "#/definitions/") ||
|
||||
fieldDef.Type == "object" && !canHaveAdditionalProperties(fieldDef))
|
||||
|
||||
if config != nil && config.Fields[export] != nil {
|
||||
r := config.Fields[export]
|
||||
if r.Substitute != "" {
|
||||
fmt.Fprintf(w, r.Substitute)
|
||||
} else {
|
||||
assert(r.Name != "", "missing ExtractTo")
|
||||
if err := writeDecl(*r, fieldDef, named); err != nil {
|
||||
return err
|
||||
}
|
||||
if needPointer {
|
||||
fmt.Fprintf(w, "*")
|
||||
}
|
||||
fmt.Fprintf(w, r.Name)
|
||||
}
|
||||
} else {
|
||||
if needPointer {
|
||||
fmt.Fprintf(w, "*")
|
||||
}
|
||||
if err := writeType(w, nil, fieldDef, named); err != nil {
|
||||
return fmt.Errorf("failed to write type for field %s: %v", export, err)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, " `json:\"%s", name)
|
||||
if !required {
|
||||
fmt.Fprint(w, ",omitempty")
|
||||
}
|
||||
fmt.Fprint(w, "\"`\n")
|
||||
}
|
||||
fmt.Fprintf(w, "}")
|
||||
|
||||
case "string":
|
||||
fmt.Fprintf(w, "string")
|
||||
|
||||
default:
|
||||
fmt.Fprintf(w, "any")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// toComment converts a JSON schema description to a Go comment.
|
||||
func toComment(description string) string {
|
||||
var (
|
||||
buf strings.Builder
|
||||
lineBuf strings.Builder
|
||||
)
|
||||
const wrapAt = 80
|
||||
for line := range strings.SplitSeq(description, "\n") {
|
||||
// Start a new paragraph, if the current is nonempty.
|
||||
if len(line) == 0 && lineBuf.Len() > 0 {
|
||||
buf.WriteString(lineBuf.String())
|
||||
lineBuf.Reset()
|
||||
buf.WriteString("\n//\n")
|
||||
continue
|
||||
}
|
||||
// Otherwise, fill in the current paragraph.
|
||||
for field := range strings.FieldsSeq(line) {
|
||||
if lineBuf.Len() > 0 && lineBuf.Len()+len(" ")+len(field) > wrapAt {
|
||||
buf.WriteString(lineBuf.String())
|
||||
buf.WriteRune('\n')
|
||||
lineBuf.Reset()
|
||||
}
|
||||
if lineBuf.Len() == 0 {
|
||||
lineBuf.WriteString("//")
|
||||
}
|
||||
lineBuf.WriteString(" ")
|
||||
lineBuf.WriteString(field)
|
||||
}
|
||||
}
|
||||
if lineBuf.Len() > 0 {
|
||||
buf.WriteString(lineBuf.String())
|
||||
}
|
||||
return strings.TrimRight(buf.String(), "\n")
|
||||
}
|
||||
|
||||
// The MCP spec improperly uses the absence of the additionalProperties keyword to
|
||||
// mean that additional properties are not allowed. In fact, it means just the opposite
|
||||
// (https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.6.5.6).
|
||||
// If the MCP spec wants to allow additional properties, it will write "true" or
|
||||
// an object explicitly.
|
||||
func canHaveAdditionalProperties(s *jsonschema.Schema) bool {
|
||||
ap := s.AdditionalProperties
|
||||
return ap != nil && !reflect.DeepEqual(ap, &jsonschema.Schema{Not: &jsonschema.Schema{}})
|
||||
}
|
||||
|
||||
// exportName returns an exported name for a Go symbol, based on the given name
|
||||
// in the JSON schema, removing leading underscores and capitalizing.
|
||||
func exportName(s string) string {
|
||||
if strings.HasPrefix(s, "_") {
|
||||
s = s[1:]
|
||||
}
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func assert(cond bool, msg string) {
|
||||
if !cond {
|
||||
panic(msg)
|
||||
}
|
||||
}
|
||||
290
mcp/protocol/protocol.go
Normal file
290
mcp/protocol/protocol.go
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
// 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.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/jsonschema"
|
||||
)
|
||||
|
||||
// Optional annotations for the client. The client can use annotations to inform
|
||||
// how objects are used or displayed
|
||||
type Annotations struct {
|
||||
// Describes who the intended customer of this object or data is.
|
||||
//
|
||||
// It can include multiple entries to indicate content useful for multiple
|
||||
// audiences (e.g., `["user", "assistant"]`).
|
||||
Audience []Role `json:"audience,omitempty"`
|
||||
// Describes how important this data is for operating the server.
|
||||
//
|
||||
// A value of 1 means "most important," and indicates that the data is
|
||||
// effectively required, while 0 means "least important," and indicates that the
|
||||
// data is entirely optional.
|
||||
Priority float64 `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
type CallToolParams struct {
|
||||
Arguments map[string]json.RawMessage `json:"arguments,omitempty"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// 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 result property is reserved by the protocol to allow clients and servers
|
||||
// to attach additional metadata to their responses.
|
||||
Meta map[string]json.RawMessage `json:"_meta,omitempty"`
|
||||
Content []Content `json:"content"`
|
||||
// Whether the tool call ended in an error.
|
||||
//
|
||||
// If not set, this is assumed to be false (the call was successful).
|
||||
IsError bool `json:"isError,omitempty"`
|
||||
}
|
||||
|
||||
type CancelledParams struct {
|
||||
// An optional string describing the reason for the cancellation. This MAY be
|
||||
// logged or presented to the user.
|
||||
Reason string `json:"reason,omitempty"`
|
||||
// The ID of the request to cancel.
|
||||
//
|
||||
// This MUST correspond to the ID of a request previously issued in the same
|
||||
// direction.
|
||||
RequestId any `json:"requestId"`
|
||||
}
|
||||
|
||||
// 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,
|
||||
// additional capabilities.
|
||||
type ClientCapabilities struct {
|
||||
// Experimental, non-standard capabilities that the client supports.
|
||||
Experimental map[string]map[string]json.RawMessage `json:"experimental,omitempty"`
|
||||
// Present if the client supports listing roots.
|
||||
Roots *struct {
|
||||
// Whether the client supports notifications for changes to the roots list.
|
||||
ListChanged bool `json:"listChanged,omitempty"`
|
||||
} `json:"roots,omitempty"`
|
||||
// Present if the client supports sampling from an LLM.
|
||||
Sampling map[string]json.RawMessage `json:"sampling,omitempty"`
|
||||
}
|
||||
|
||||
type GetPromptParams struct {
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// The server's response to a prompts/get request from the client.
|
||||
type GetPromptResult struct {
|
||||
// This result property is reserved by the protocol to allow clients and servers
|
||||
// to attach additional metadata to their responses.
|
||||
Meta map[string]json.RawMessage `json:"_meta,omitempty"`
|
||||
// An optional description for the prompt.
|
||||
Description string `json:"description,omitempty"`
|
||||
Messages []PromptMessage `json:"messages"`
|
||||
}
|
||||
|
||||
// Describes the name and version of an MCP implementation.
|
||||
type Implementation struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type InitializeParams struct {
|
||||
Capabilities ClientCapabilities `json:"capabilities"`
|
||||
ClientInfo Implementation `json:"clientInfo"`
|
||||
// The latest version of the Model Context Protocol that the client supports.
|
||||
// The client MAY decide to support older versions as well.
|
||||
ProtocolVersion string `json:"protocolVersion"`
|
||||
}
|
||||
|
||||
// After receiving an initialize request from the client, the server sends this
|
||||
// response.
|
||||
type InitializeResult struct {
|
||||
// This result property is reserved by the protocol to allow clients and servers
|
||||
// to attach additional metadata to their responses.
|
||||
Meta map[string]json.RawMessage `json:"_meta,omitempty"`
|
||||
Capabilities ServerCapabilities `json:"capabilities"`
|
||||
// Instructions describing how to use the server and its features.
|
||||
//
|
||||
// This can be used by clients to improve the LLM's understanding of available
|
||||
// tools, resources, etc. It can be thought of like a "hint" to the model. For
|
||||
// example, this information MAY be added to the system prompt.
|
||||
Instructions string `json:"instructions,omitempty"`
|
||||
// The version of the Model Context Protocol that the server wants to use. This
|
||||
// may not match the version that the client requested. If the client cannot
|
||||
// support this version, it MUST disconnect.
|
||||
ProtocolVersion string `json:"protocolVersion"`
|
||||
ServerInfo Implementation `json:"serverInfo"`
|
||||
}
|
||||
|
||||
type InitializedParams map[string]json.RawMessage
|
||||
|
||||
type ListPromptsParams struct {
|
||||
// An opaque token representing the current pagination position. If provided,
|
||||
// the server should return results starting after this cursor.
|
||||
Cursor string `json:"cursor,omitempty"`
|
||||
}
|
||||
|
||||
// The server's response to a prompts/list request from the client.
|
||||
type ListPromptsResult struct {
|
||||
// This result property is reserved by the protocol to allow clients and servers
|
||||
// to attach additional metadata to their responses.
|
||||
Meta map[string]json.RawMessage `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"`
|
||||
}
|
||||
|
||||
type ListToolsParams struct {
|
||||
// An opaque token representing the current pagination position. If provided,
|
||||
// the server should return results starting after this cursor.
|
||||
Cursor string `json:"cursor,omitempty"`
|
||||
}
|
||||
|
||||
// The server's response to a tools/list request from the client.
|
||||
type ListToolsResult struct {
|
||||
// This result property is reserved by the protocol to allow clients and servers
|
||||
// to attach additional metadata to their responses.
|
||||
Meta map[string]json.RawMessage `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"`
|
||||
}
|
||||
|
||||
// A prompt or prompt template that the server offers.
|
||||
type Prompt struct {
|
||||
// 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.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Describes an argument that a prompt can accept.
|
||||
type PromptArgument struct {
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Present if the server offers any prompt templates.
|
||||
type PromptCapabilities struct {
|
||||
// Whether this server supports notifications for changes to the prompt list.
|
||||
ListChanged bool `json:"listChanged,omitempty"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Present if the server offers any resources to read.
|
||||
type ResourceCapabilities struct {
|
||||
// Whether this server supports notifications for changes to the resource list.
|
||||
ListChanged bool `json:"listChanged,omitempty"`
|
||||
// Whether this server supports subscribing to resource updates.
|
||||
Subscribe bool `json:"subscribe,omitempty"`
|
||||
}
|
||||
|
||||
// The sender or recipient of messages and data in a conversation.
|
||||
type Role string
|
||||
|
||||
// Capabilities that a server may support. Known capabilities are defined here,
|
||||
// in this schema, but this is not a closed set: any server can define its own,
|
||||
// additional capabilities.
|
||||
type ServerCapabilities struct {
|
||||
// Present if the server supports argument autocompletion suggestions.
|
||||
Completions map[string]json.RawMessage `json:"completions,omitempty"`
|
||||
// Experimental, non-standard capabilities that the server supports.
|
||||
Experimental map[string]map[string]json.RawMessage `json:"experimental,omitempty"`
|
||||
// Present if the server supports sending log messages to the client.
|
||||
Logging map[string]json.RawMessage `json:"logging,omitempty"`
|
||||
// Present if the server offers any prompt templates.
|
||||
Prompts *PromptCapabilities `json:"prompts,omitempty"`
|
||||
// Present if the server offers any resources to read.
|
||||
Resources *ResourceCapabilities `json:"resources,omitempty"`
|
||||
// Present if the server offers any tools to call.
|
||||
Tools *ToolCapabilities `json:"tools,omitempty"`
|
||||
}
|
||||
|
||||
// Definition for a tool the client can call.
|
||||
type Tool struct {
|
||||
// Optional additional tool information.
|
||||
Annotations *ToolAnnotations `json:"annotations,omitempty"`
|
||||
// A human-readable description of the tool.
|
||||
//
|
||||
// This can be used by clients to improve the LLM's understanding of available
|
||||
// tools. It can be thought of like a "hint" to the model.
|
||||
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.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Additional properties describing a Tool to clients.
|
||||
//
|
||||
// NOTE: all properties in ToolAnnotations are **hints**. They are not
|
||||
// guaranteed to provide a faithful description of tool behavior (including
|
||||
// descriptive properties like `title`).
|
||||
//
|
||||
// Clients should never make tool use decisions based on ToolAnnotations
|
||||
// received from untrusted servers.
|
||||
type ToolAnnotations struct {
|
||||
// If true, the tool may perform destructive updates to its environment. If
|
||||
// false, the tool performs only additive updates.
|
||||
//
|
||||
// (This property is meaningful only when `readOnlyHint == false`)
|
||||
//
|
||||
// Default: true
|
||||
DestructiveHint bool `json:"destructiveHint,omitempty"`
|
||||
// If true, calling the tool repeatedly with the same arguments will have no
|
||||
// additional effect on the its environment.
|
||||
//
|
||||
// (This property is meaningful only when `readOnlyHint == false`)
|
||||
//
|
||||
// Default: false
|
||||
IdempotentHint bool `json:"idempotentHint,omitempty"`
|
||||
// If true, this tool may interact with an "open world" of external entities. If
|
||||
// false, the tool's domain of interaction is closed. For example, the world of
|
||||
// a web search tool is open, whereas that of a memory tool is not.
|
||||
//
|
||||
// Default: true
|
||||
OpenWorldHint bool `json:"openWorldHint,omitempty"`
|
||||
// If true, the tool does not modify its environment.
|
||||
//
|
||||
// Default: false
|
||||
ReadOnlyHint bool `json:"readOnlyHint,omitempty"`
|
||||
// A human-readable title for the tool.
|
||||
Title string `json:"title,omitempty"`
|
||||
}
|
||||
|
||||
// Present if the server offers any tools to call.
|
||||
type ToolCapabilities struct {
|
||||
// Whether this server supports notifications for changes to the tool list.
|
||||
ListChanged bool `json:"listChanged,omitempty"`
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
// A Server is an instance of an MCP server.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
func TestSSEServer(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import (
|
|||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/util"
|
||||
"github.com/modelcontextprotocol/go-sdk/jsonschema"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
)
|
||||
|
||||
// A ToolHandler handles a call to tools/call.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp/protocol"
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/xcontext"
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue