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

Index

Examples

Variables

var ErrConnectionClosed = errors.New("connection closed")

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

type AudioContent struct {
	Data     string
	MimeType string
}

AudioContent contains base64-encoded audio data.

func (AudioContent) ToWire

func (c AudioContent) ToWire() protocol.Content

type BlobResource

type BlobResource struct {
	URI      string
	MimeType string
	Blob     string
}

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

func (c *Client) 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 (*Client) Connect

func (c *Client) Connect(ctx context.Context, t Transport, opts *ConnectionOptions) (err error)

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

func (c *Client) ListPrompts(ctx context.Context) ([]protocol.Prompt, error)

ListPrompts lists prompts that are currently available on the server.

func (*Client) ListTools

func (c *Client) ListTools(ctx context.Context) ([]protocol.Tool, error)

ListTools lists tools that are currently available on the server.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping makes an MCP "ping" request to the server.

func (*Client) Wait

func (c *Client) Wait() error

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

type Content interface {
	ToWire() protocol.Content
}

Content is the union of supported content types: TextContent, ImageContent, AudioContent, and ResourceContent.

ToWire converts content to its jsonrpc2 wire format.

func ContentFromWireContent

func ContentFromWireContent(c protocol.Content) Content

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

type ImageContent struct {
	Data     string
	MimeType string
}

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

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 Resource interface {
	ToWire() protocol.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

Example

Code:play 

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)

}

Output:

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.

Example

Code:play 

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()

}

Output:

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

func (s *Server) AddPrompts(prompts ...*Prompt)

AddPrompts adds the given prompts to the server.

TODO(rfindley): notify connected clients of any changes.

func (*Server) AddTools

func (s *Server) AddTools(tools ...*Tool)

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

func (s *Server) Run(ctx context.Context, t Transport, opts *ConnectionOptions) error

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

type Stream interface {
	jsonrpc2.Reader
	jsonrpc2.Writer
	io.Closer
}

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

type TextResource struct {
	URI      string
	MimeType string
	Text     string
}

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

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

PathSynopsis
internal/mcp/examples
internal/mcp/examples/hello
internal/mcp/examples/sse
internal/mcp/internal
internal/mcp/internal/protocolThe protocol package contains types that define the MCP protocol.
internal/mcp/internal/util
internal/mcp/jsonschemaPackage 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.