package mcp
import "golang.org/x/tools/internal/mcp"
TODO: consider passing Transport to NewClient and merging {Connection,Client}Options
The mcp package provides an SDK for writing model context protocol clients and servers. It is a work-in-progress. As of writing, it is a prototype to explore the design space of client/server transport and binding.
To get started, create either a Client or Server, and connect it to a peer using a Transport. The diagram below illustrates how this works:
Client Server ⇅ (jsonrpc2) ⇅ Client Transport ⇄ Server Transport ⇄ ClientConnection
A Client is an MCP client, which can be configured with various client capabilities. Clients may be connected to a Server instance using the Client.Connect method.
Similarly, a Server is an MCP server, which can be configured with various server capabilities. Servers may be connected to one or more Client instances using the Server.Connect method, which creates a ClientConnection.
A Transport connects a bidirectional Stream of jsonrpc2 messages. In practice, transports in the MCP spec are are either client transports or server transports. For example, the [StdIOTransport] is a server transport that communicates over stdin/stdout, and its counterpart is a CommandTransport that communicates with a subprocess over its stdin/stdout.
Some transports may hide more complicated details, such as an SSEClientTransport, which reads messages via server-sent events on a hanging GET request, and writes them to a POST endpoint. Users of this SDK may define their own custom Transports by implementing the Transport interface.
Here's an example that creates a client that talks to an MCP server running as a sidecar process:
import "golang.org/x/tools/internal/mcp" ... // Create a new client, with no features. client := mcp.NewClient("mcp-client", "v1.0.0", nil) // Connect to a server over stdin/stdout transport := mcp.NewCommandTransport(exec.Command("myserver")) if err := client.Connect(ctx, transport, nil); err != nil { log.Fatal(err) } // Call a tool on the server. content, err := client.CallTool(ctx, "greet", map[string]any{"name": "you"})
Here is an example of the corresponding server, connected over stdin/stdout:
import "golang.org/x/tools/internal/mcp" ... // Create a server with a single tool. server := mcp.NewServer("greeter", "v1.0.0", nil) server.AddTool(mcp.MakeTool("greet", "say hi", SayHi)) // Run the server over stdin/stdout, until the client diconnects _ = server.Run(ctx, mcp.NewStdIOTransport(), nil)
TODO
- Support all content types.
- Support pagination.
- Support completion.
- Support oauth.
- Support all client/server operations.
- Pass the client connection in the context.
- Support streamable HTTP transport.
- Support multiple versions of the spec.
- Implement full JSON schema support, with both client-side and server-side validation.
Index ¶
- Variables
- func NewLocalTransport() (*IOTransport, *IOTransport)
- type AudioContent
- type BlobResource
- type Client
- func NewClient(name, version string, opts *ClientOptions) *Client
- func (c *Client) CallTool(ctx context.Context, name string, args map[string]any) (_ *protocol.CallToolResult, err error)
- func (c *Client) Close() error
- func (c *Client) Connect(ctx context.Context, t Transport, opts *ConnectionOptions) (err error)
- func (c *Client) GetPrompt(ctx context.Context, name string, args map[string]string) (*protocol.GetPromptResult, error)
- func (c *Client) ListPrompts(ctx context.Context) ([]protocol.Prompt, error)
- func (c *Client) ListTools(ctx context.Context) ([]protocol.Tool, error)
- func (c *Client) Ping(ctx context.Context) error
- func (c *Client) Wait() error
- type ClientConnection
- func (cc *ClientConnection) Close() error
- func (cc *ClientConnection) Ping(ctx context.Context) error
- func (cc *ClientConnection) Wait() error
- type ClientOptions
- type CommandTransport
- func NewCommandTransport(cmd *exec.Cmd) *CommandTransport
- func (t *CommandTransport) Connect(ctx context.Context) (Stream, error)
- type ConnectionOptions
- type Content
- type IOTransport
- func NewStdIOTransport() *IOTransport
- func (t *IOTransport) Connect(context.Context) (Stream, error)
- type ImageContent
- type Prompt
- type PromptHandler
- type PromptOption
- type Resource
- type ResourceContent
- type SSEClientTransport
- func NewSSEClientTransport(baseURL string) *SSEClientTransport
- func (c *SSEClientTransport) Connect(ctx context.Context) (Stream, error)
- type SSEHandler
- func NewSSEHandler(getServer func(request *http.Request) *Server) *SSEHandler
- func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
- type SchemaOption
- func Description(desc string) SchemaOption
- func Enum(values ...any) SchemaOption
- func Property(name string, opts ...SchemaOption) SchemaOption
- func Required(v bool) SchemaOption
- func Schema(schema *jsonschema.Schema) SchemaOption
- type Server
- func NewServer(name, version string, opts *ServerOptions) *Server
- func (s *Server) AddPrompts(prompts ...*Prompt)
- func (s *Server) AddTools(tools ...*Tool)
- func (s *Server) Clients() iter.Seq[*ClientConnection]
- func (s *Server) Connect(ctx context.Context, t Transport, opts *ConnectionOptions) (*ClientConnection, error)
- func (s *Server) Run(ctx context.Context, t Transport, opts *ConnectionOptions) error
- type ServerOptions
- type Stream
- type TextContent
- type TextResource
- type Tool
- type ToolHandler
- type ToolOption
- type Transport
Examples ¶
Variables ¶
ErrConnectionClosed is returned when sending a message to a connection that is closed or in the process of closing.
Functions ¶
func NewLocalTransport ¶
func NewLocalTransport() (*IOTransport, *IOTransport)
NewLocalTransport returns two in-memory transports that connect to each other, for testing purposes.
Types ¶
type AudioContent ¶
AudioContent contains base64-encoded audio data.
func (AudioContent) ToWire ¶
func (c AudioContent) ToWire() protocol.Content
type BlobResource ¶
func (BlobResource) ToWire ¶
func (r BlobResource) ToWire() protocol.Resource
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
A Client is an MCP client, which may be connected to an MCP server using the Client.Connect method.
func NewClient ¶
func NewClient(name, version string, opts *ClientOptions) *Client
NewClient creates a new Client.
Use Client.Connect to connect it to an MCP server.
If non-nil, the provided options configure the Client.
func (*Client) CallTool ¶
func (c *Client) CallTool(ctx context.Context, name string, args map[string]any) (_ *protocol.CallToolResult, err error)
CallTool calls the tool with the given name and arguments.
TODO(jba): make the following true: If the provided arguments do not conform to the schema for the given tool, the call fails.
func (*Client) Close ¶
Close performs a graceful close of the connection, preventing new requests from being handled, and waiting for ongoing requests to return. Close then terminates the connection.
func (*Client) Connect ¶
Connect connects the MCP client over the given transport and initializes an MCP session.
Typically, it is the responsibility of the client to close the connection when it is no longer needed. However, if the connection is closed by the server, calls or notifications will return an error wrapping ErrConnectionClosed.
func (*Client) GetPrompt ¶
func (c *Client) GetPrompt(ctx context.Context, name string, args map[string]string) (*protocol.GetPromptResult, error)
GetPrompt gets a prompt from the server.
func (*Client) ListPrompts ¶
ListPrompts lists prompts that are currently available on the server.
func (*Client) ListTools ¶
ListTools lists tools that are currently available on the server.
func (*Client) Ping ¶
Ping makes an MCP "ping" request to the server.
func (*Client) Wait ¶
Wait waits for the connection to be closed by the server. Generally, clients should be responsible for closing the connection.
type ClientConnection ¶
type ClientConnection struct {
// contains filtered or unexported fields
}
A ClientConnection is a connection with an MCP client.
It handles messages from the client, and can be used to send messages to the client. Create a connection by calling Server.Connect.
func (*ClientConnection) Close ¶
func (cc *ClientConnection) Close() error
Close performs a graceful close of the connection, preventing new requests from being handled, and waiting for ongoing requests to return. Close then terminates the connection.
func (*ClientConnection) Ping ¶
func (cc *ClientConnection) Ping(ctx context.Context) error
Ping makes an MCP "ping" request to the client.
func (*ClientConnection) Wait ¶
func (cc *ClientConnection) Wait() error
Wait waits for the connection to be closed by the client.
type ClientOptions ¶
type ClientOptions struct{}
ClientOptions configures the behavior of the client.
type CommandTransport ¶
type CommandTransport struct {
// contains filtered or unexported fields
}
A CommandTransport is a Transport that runs a command and communicates with it over stdin/stdout, using newline-delimited JSON.
func NewCommandTransport ¶
func NewCommandTransport(cmd *exec.Cmd) *CommandTransport
NewCommandTransport returns a CommandTransport that runs the given command and communicates with it over stdin/stdout.
The resulting transport takes ownership of the command, starting it during CommandTransport.Connect, and stopping it when the connection is closed.
func (*CommandTransport) Connect ¶
func (t *CommandTransport) Connect(ctx context.Context) (Stream, error)
Connect starts the command, and connects to it over stdin/stdout.
type ConnectionOptions ¶
type ConnectionOptions struct { SessionID string // if set, the session ID Logger io.Writer // if set, write RPC logs }
ConnectionOptions configures the behavior of an individual client<->server connection.
type Content ¶
Content is the union of supported content types: TextContent, ImageContent, AudioContent, and ResourceContent.
ToWire converts content to its jsonrpc2 wire format.
func ContentFromWireContent ¶
ContentFromWireContent converts content from the jsonrpc2 wire format to a typed Content value.
type IOTransport ¶
type IOTransport struct {
// contains filtered or unexported fields
}
An IOTransport is a Transport that communicates using newline-delimited JSON over an io.ReadWriteCloser.
func NewStdIOTransport ¶
func NewStdIOTransport() *IOTransport
NewStdIOTransport constructs a transport that communicates over stdin/stdout.
func (*IOTransport) Connect ¶
func (t *IOTransport) Connect(context.Context) (Stream, error)
type ImageContent ¶
ImageContent contains base64-encoded image data.
func (ImageContent) ToWire ¶
func (c ImageContent) ToWire() protocol.Content
type Prompt ¶
type Prompt struct { Definition protocol.Prompt Handler PromptHandler }
A Prompt is a prompt definition bound to a prompt handler.
func MakePrompt ¶
func MakePrompt[TReq any](name, description string, handler func(context.Context, *ClientConnection, TReq) (*protocol.GetPromptResult, error), opts ...PromptOption) *Prompt
MakePrompt is a helper to use reflection to create a prompt for the given handler.
The arguments for the prompt are extracted from the request type for the handler. The handler request type must be a struct consisting only of fields of type string or *string. The argument names for the resulting prompt definition correspond to the JSON names of the request fields, and any fields that are not marked "omitempty" are considered required.
type PromptHandler ¶
type PromptHandler func(context.Context, *ClientConnection, map[string]string) (*protocol.GetPromptResult, error)
A PromptHandler handles a call to prompts/get.
type PromptOption ¶
type PromptOption interface {
// contains filtered or unexported methods
}
A PromptOption configures the behavior of a Prompt.
func Argument ¶
func Argument(name string, opts ...SchemaOption) PromptOption
Argument configures the 'schema' of a prompt argument. If the argument does not exist, it is added.
Since prompt arguments are not a full JSON schema, Argument only accepts Required and Description, and panics when encountering any other option.
type Resource ¶
type ResourceContent ¶
type ResourceContent struct { Resource Resource }
ResourceContent contains embedded resources.
func (ResourceContent) ToWire ¶
func (r ResourceContent) ToWire() protocol.Content
type SSEClientTransport ¶
type SSEClientTransport struct {
// contains filtered or unexported fields
}
An SSEClientTransport is a Transport that can communicate with an MCP endpoint serving the SSE transport defined by the 2024-11-05 version of the spec.
https://modelcontextprotocol.io/specification/2024-11-05/basic/transports
func NewSSEClientTransport ¶
func NewSSEClientTransport(baseURL string) *SSEClientTransport
NewSSEClientTransport returns a new client transport that connects to the SSE server at the provided URL.
NewSSEClientTransport panics if the given URL is invalid.
func (*SSEClientTransport) Connect ¶
func (c *SSEClientTransport) Connect(ctx context.Context) (Stream, error)
Connect connects through the client endpoint.
type SSEHandler ¶
type SSEHandler struct {
// contains filtered or unexported fields
}
SSEHandler is an http.Handler that serves SSE-based MCP sessions as defined by the 2024-11-05 version of the MCP protocol:
https://modelcontextprotocol.io/specification/2024-11-05/basic/transports
Code:play
Output:Example¶
package main
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
"golang.org/x/tools/internal/mcp"
)
type AddParams struct {
X, Y int
}
func Add(ctx context.Context, cc *mcp.ClientConnection, params *AddParams) ([]mcp.Content, error) {
return []mcp.Content{
mcp.TextContent{Text: fmt.Sprintf("%d", params.X+params.Y)},
}, nil
}
func main() {
server := mcp.NewServer("adder", "v0.0.1", nil)
server.AddTools(mcp.MakeTool("add", "add two numbers", Add))
handler := mcp.NewSSEHandler(func(*http.Request) *mcp.Server { return server })
httpServer := httptest.NewServer(handler)
defer httpServer.Close()
ctx := context.Background()
transport := mcp.NewSSEClientTransport(httpServer.URL)
client := mcp.NewClient("test", "v1.0.0", nil)
if err := client.Connect(ctx, transport, nil); err != nil {
log.Fatal(err)
}
defer client.Close()
res, err := client.CallTool(ctx, "add", map[string]any{"x": 1, "y": 2})
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Content[0].Text)
}
3
func NewSSEHandler ¶
func NewSSEHandler(getServer func(request *http.Request) *Server) *SSEHandler
NewSSEHandler returns a new SSEHandler that is ready to serve HTTP.
The getServer function is used to bind created servers for new sessions. It is OK for getServer to return the same server multiple times.
func (*SSEHandler) ServeHTTP ¶
func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
type SchemaOption ¶
type SchemaOption interface {
// contains filtered or unexported methods
}
A SchemaOption configures a jsonschema.Schema.
func Description ¶
func Description(desc string) SchemaOption
Description sets the provided schema description.
func Enum ¶
func Enum(values ...any) SchemaOption
Enum sets the provided values as the "enum" value of the schema.
func Property ¶
func Property(name string, opts ...SchemaOption) SchemaOption
Property configures the schema for the property of the given name. If there is no such property in the schema, it is created.
func Required ¶
func Required(v bool) SchemaOption
Required sets whether the associated property is required. It is only valid when used in a Property option: using Required outside of Property panics.
func Schema ¶
func Schema(schema *jsonschema.Schema) SchemaOption
Schema overrides the inferred schema with a shallow copy of the given schema.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
A Server is an instance of an MCP server.
Servers expose server-side MCP features, which can serve one or more MCP
sessions by using [Server.Start] or Server.Run.
Code:play
Output:Example¶
package main
import (
"context"
"fmt"
"log"
"golang.org/x/tools/internal/mcp"
)
type SayHiParams struct {
Name string `json:"name" mcp:"the name to say hi to"`
}
func SayHi(ctx context.Context, cc *mcp.ClientConnection, params *SayHiParams) ([]mcp.Content, error) {
return []mcp.Content{
mcp.TextContent{Text: "Hi " + params.Name},
}, nil
}
func main() {
ctx := context.Background()
clientTransport, serverTransport := mcp.NewLocalTransport()
server := mcp.NewServer("greeter", "v0.0.1", nil)
server.AddTools(mcp.MakeTool("greet", "say hi", SayHi))
clientConnection, err := server.Connect(ctx, serverTransport, nil)
if err != nil {
log.Fatal(err)
}
client := mcp.NewClient("client", "v0.0.1", nil)
if err := client.Connect(ctx, clientTransport, nil); err != nil {
log.Fatal(err)
}
res, err := client.CallTool(ctx, "greet", map[string]any{"name": "user"})
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Content[0].Text)
client.Close()
clientConnection.Wait()
}
Hi user
func NewServer ¶
func NewServer(name, version string, opts *ServerOptions) *Server
NewServer creates a new MCP server. The resulting server has no features: add features using Server.AddTools. (TODO: support more features).
The server can be connected to one or more MCP clients using [Server.Start] or Server.Run.
If non-nil, the provided options is used to configure the server.
func (*Server) AddPrompts ¶
AddPrompts adds the given prompts to the server.
TODO(rfindley): notify connected clients of any changes.
func (*Server) AddTools ¶
AddTools adds the given tools to the server.
TODO(rfindley): notify connected clients of any changes.
func (*Server) Clients ¶
func (s *Server) Clients() iter.Seq[*ClientConnection]
Clients returns an iterator that yields the current set of client connections.
func (*Server) Connect ¶
func (s *Server) Connect(ctx context.Context, t Transport, opts *ConnectionOptions) (*ClientConnection, error)
Connect connects the MCP server over the given transport and starts handling messages.
It returns a connection object that may be used to terminate the connection (with [Connection.Close]), or await client termination (with [Connection.Wait]).
func (*Server) Run ¶
Run runs the server over the given transport, which must be persistent.
Run blocks until the client terminates the connection.
type ServerOptions ¶
type ServerOptions struct { Instructions string }
ServerOptions is used to configure behavior of the server.
type Stream ¶
A Stream is an abstract bidirectional jsonrpc2 Stream. It is used by [connect] to establish a jsonrpc2.Connection.
type TextContent ¶
type TextContent struct { Text string }
TextContent is a textual content.
func (TextContent) ToWire ¶
func (c TextContent) ToWire() protocol.Content
type TextResource ¶
func (TextResource) ToWire ¶
func (r TextResource) ToWire() protocol.Resource
type Tool ¶
type Tool struct { Definition protocol.Tool Handler ToolHandler }
A Tool is a tool definition that is bound to a tool handler.
func MakeTool ¶
func MakeTool[TReq any](name, description string, handler func(context.Context, *ClientConnection, TReq) ([]Content, error), opts ...ToolOption) *Tool
MakeTool is a helper to make a tool using reflection on the given handler.
If provided, variadic ToolOption values may be used to customize the tool.
The input schema for the tool is extracted from the request type for the handler, and used to unmmarshal and validate requests to the handler. This schema may be customized using the Input option.
The handler request type must translate to a valid schema, as documented by jsonschema.ForType; otherwise, MakeTool panics.
TODO: just have the handler return a CallToolResult: returning []Content is going to be inconsistent with other server features.
type ToolHandler ¶
type ToolHandler func(context.Context, *ClientConnection, map[string]json.RawMessage) (*protocol.CallToolResult, error)
A ToolHandler handles a call to tools/call.
type ToolOption ¶
type ToolOption interface {
// contains filtered or unexported methods
}
A ToolOption configures the behavior of a Tool.
func Input ¶
func Input(opts ...SchemaOption) ToolOption
Input applies the provided SchemaOption configuration to the tool's input schema.
type Transport ¶
type Transport interface { // Connect returns the logical stream. // // It is called exactly once by [Connect]. Connect(ctx context.Context) (Stream, error) }
A Transport is used to create a bidirectional connection between MCP client and server.
Transports should be used for at most one call to Server.Connect or Client.Connect.
Source Files ¶
client.go cmd.go content.go mcp.go prompt.go server.go sse.go tool.go transport.go util.go
Directories ¶
Path | Synopsis |
---|---|
internal/mcp/examples | |
internal/mcp/examples/hello | |
internal/mcp/examples/sse | |
internal/mcp/internal | |
internal/mcp/internal/protocol | The protocol package contains types that define the MCP protocol. |
internal/mcp/internal/util | |
internal/mcp/jsonschema | Package jsonschema is an implementation of the JSON Schema specification: https://json-schema.org. |
- Version
- v0.33.0 (latest)
- Published
- May 5, 2025
- Platform
- linux/amd64
- Imports
- 25 packages
- Last checked
- 1 hour ago –
Tools for package owners.