or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

auth.mdindex.mdjsonrpc.mdmcp-client.mdmcp-protocol.mdmcp-server.mdmcp-transports.mdmcp-types.mdoauthex.md
tile.json

mcp-transports.mddocs/

MCP Transports

MCP transports enable communication between clients and servers over various channels. The SDK provides multiple built-in transport implementations.

Transport Interface

All transports implement the Transport interface.

import "github.com/modelcontextprotocol/go-sdk/mcp"

type Transport interface {
    Connect(ctx context.Context) (Connection, error)
}

Connection

The low-level connection interface returned by transports.

type Connection interface {
    Read(context.Context) (jsonrpc.Message, error)
    Write(context.Context, jsonrpc.Message) error
    Close() error
    SessionID() string
}

Methods:

  • Read: Reads the next message from the connection
  • Write: Writes a message to the connection (may be called concurrently)
  • Close: Closes the connection (may be called multiple times concurrently)
  • SessionID: Returns the session ID for this connection

ErrConnectionClosed

Error returned when sending to a closed connection.

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

Standard I/O Transports

StdioTransport

Communicates over stdin/stdout using newline-delimited JSON.

type StdioTransport struct{}

Usage:

transport := &mcp.StdioTransport{}
err := server.Run(ctx, transport)

Use cases:

  • Command-line tools
  • Simple server applications
  • Process-based communication

IOTransport

Communicates over custom readers and writers using newline-delimited JSON.

type IOTransport struct {
    Reader io.ReadCloser
    Writer io.WriteCloser
}

Example:

transport := &mcp.IOTransport{
    Reader: customReader,
    Writer: customWriter,
}
conn, err := transport.Connect(ctx)

Use cases:

  • Custom I/O streams
  • Network sockets
  • File-based communication

Command Transport

CommandTransport

Runs a command as a subprocess and communicates with it over stdin/stdout.

type CommandTransport struct {
    Command           *exec.Cmd
    TerminateDuration time.Duration
}

Fields:

  • Command: The command to execute
  • TerminateDuration: Time to wait after closing stdin before sending SIGTERM (default: 5s)

Example:

import "os/exec"

transport := &mcp.CommandTransport{
    Command: exec.Command("path/to/mcp-server"),
}
session, err := client.Connect(ctx, transport, nil)

Shutdown behavior:

  1. Closes stdin to the subprocess
  2. Waits TerminateDuration for graceful exit
  3. Sends SIGTERM if process hasn't exited
  4. Waits another TerminateDuration
  5. Sends SIGKILL as final resort

Use cases:

  • Connecting to external MCP servers
  • Process isolation
  • Language-agnostic server integration

In-Memory Transport

InMemoryTransport

Provides in-memory connections for testing and same-process communication.

type InMemoryTransport struct {
    // contains filtered or unexported fields
}

NewInMemoryTransports

Creates a pair of connected in-memory transports.

func NewInMemoryTransports() (*InMemoryTransport, *InMemoryTransport)

Returns: Two symmetrical transports connected to each other

Example:

serverTransport, clientTransport := mcp.NewInMemoryTransports()

// Connect server first
serverSession, err := server.Connect(ctx, serverTransport, nil)
if err != nil {
    log.Fatal(err)
}

// Then connect client
clientSession, err := client.Connect(ctx, clientTransport, nil)
if err != nil {
    log.Fatal(err)
}

Use cases:

  • Unit testing
  • Integration testing
  • Same-process client-server communication
  • Benchmarking

HTTP Transports (Server-Sent Events)

SSEHandler

Server-side handler for SSE-based MCP sessions (2024-11-05 spec).

func NewSSEHandler(
    getServer func(request *http.Request) *Server,
    opts *SSEOptions,
) *SSEHandler

Parameters:

  • getServer: Function that returns a Server for each new request (or reuses existing)
  • opts: Optional configuration

Example:

server := mcp.NewServer(&mcp.Implementation{Name: "my-server"}, nil)

handler := mcp.NewSSEHandler(func(req *http.Request) *mcp.Server {
    return server
}, nil)

http.Handle("/sse", handler)
log.Fatal(http.ListenAndServe(":8080", nil))

SSEOptions

Configuration for SSEHandler.

type SSEOptions struct{}

Currently empty, reserved for future options.

SSEServerTransport

Low-level SSE server transport (typically managed by SSEHandler).

type SSEServerTransport struct {
    Endpoint string
    Response http.ResponseWriter
}

Fields:

  • Endpoint: Session endpoint where client can POST messages
  • Response: Hanging response body for the GET request

Methods:

func (t *SSEServerTransport) Connect(context.Context) (Connection, error)
func (t *SSEServerTransport) ServeHTTP(w http.ResponseWriter, req *http.Request)

SSEClientTransport

Client-side SSE transport.

type SSEClientTransport struct {
    Endpoint   string
    HTTPClient *http.Client
}

Fields:

  • Endpoint: The SSE endpoint to connect to
  • HTTPClient: HTTP client for making requests (optional)

Example:

transport := &mcp.SSEClientTransport{
    Endpoint: "http://localhost:8080/sse",
}
session, err := client.Connect(ctx, transport, nil)

How SSE transport works:

  1. Client initiates with GET request accepting text/event-stream
  2. Server responds with 'endpoint' event containing session endpoint
  3. Server sends messages as SSE 'message' events
  4. Client POSTs messages to the session endpoint

Use cases:

  • Web-based MCP servers
  • Long-lived HTTP connections
  • Server-to-client push notifications

HTTP Transports (Streamable)

StreamableHTTPHandler

Server-side handler for streamable MCP sessions (2025-03-26 spec).

func NewStreamableHTTPHandler(
    getServer func(*http.Request) *Server,
    opts *StreamableHTTPOptions,
) *StreamableHTTPHandler

Example:

handler := mcp.NewStreamableHTTPHandler(
    func(req *http.Request) *mcp.Server {
        return server
    },
    &mcp.StreamableHTTPOptions{
        EventStore:     eventStore,
        SessionTimeout: 5 * time.Minute,
    },
)

http.Handle("/mcp", handler)

StreamableHTTPOptions

Configuration for StreamableHTTPHandler.

type StreamableHTTPOptions struct {
    Stateless      bool
    JSONResponse   bool
    Logger         *slog.Logger
    EventStore     EventStore
    SessionTimeout time.Duration
}

Fields:

  • Stateless: If true, server doesn't validate session IDs and uses temporary sessions
  • JSONResponse: Return application/json instead of text/event-stream
  • Logger: Logger for server activity (nil disables logging)
  • EventStore: Enables stream resumption by persisting events
  • SessionTimeout: Automatically close idle sessions after this duration (0 disables)

StreamableServerTransport

Low-level streamable server transport.

type StreamableServerTransport struct {
    SessionID  string
    Stateless  bool
    EventStore EventStore
}

Fields:

  • SessionID: The ID of this session
  • Stateless: Whether the session is stateless
  • EventStore: Optional event store for stream resumption

Methods:

func (t *StreamableServerTransport) Connect(ctx context.Context) (Connection, error)
func (t *StreamableServerTransport) ServeHTTP(w http.ResponseWriter, req *http.Request)

StreamableClientTransport

Client-side streamable HTTP transport.

type StreamableClientTransport struct {
    Endpoint   string
    HTTPClient *http.Client
    MaxRetries int
}

Fields:

  • Endpoint: The HTTP endpoint to connect to
  • HTTPClient: HTTP client for requests (optional)
  • MaxRetries: Maximum reconnection attempts before giving up (default: 5)

Example:

transport := &mcp.StreamableClientTransport{
    Endpoint:   "http://localhost:8080/mcp",
    MaxRetries: 10,
}
session, err := client.Connect(ctx, transport, nil)

Features:

  • Automatic reconnection on connection loss
  • Stream resumption with EventStore
  • Session state preservation

Use cases:

  • Modern web-based MCP servers
  • Fault-tolerant connections
  • Session persistence across network interruptions

Event Store (Stream Resumption)

EventStore

Interface for persisting and replaying SSE stream data.

type EventStore interface {
    Open(_ context.Context, sessionID, streamID string) error
    Append(_ context.Context, sessionID, streamID string, data []byte) error
    After(_ context.Context, sessionID, streamID string, index int) iter.Seq2[[]byte, error]
    SessionClosed(_ context.Context, sessionID string) error
}

Methods:

  • Open: Called when a new stream is created
  • Append: Appends data for an outgoing event to the stream
  • After: Returns an iterator over data after a given index
  • SessionClosed: Called when a session is finished

All methods must be safe for concurrent use.

MemoryEventStore

In-memory EventStore implementation.

func NewMemoryEventStore(opts *MemoryEventStoreOptions) *MemoryEventStore

Methods:

func (m *MemoryEventStore) MaxBytes() int
func (m *MemoryEventStore) SetMaxBytes(n int)
func (m *MemoryEventStore) After(
    _ context.Context,
    sessionID, streamID string,
    index int,
) iter.Seq2[[]byte, error]
func (m *MemoryEventStore) Append(
    _ context.Context,
    sessionID, streamID string,
    data []byte,
) error
func (m *MemoryEventStore) Open(
    _ context.Context,
    sessionID, streamID string,
) error
func (m *MemoryEventStore) SessionClosed(
    _ context.Context,
    sessionID string,
) error

MemoryEventStoreOptions

Configuration for MemoryEventStore.

type MemoryEventStoreOptions struct{}

Currently empty, reserved for future options.

ErrEventsPurged

Error returned when requested events are no longer available.

var ErrEventsPurged = errors.New("events purged")

Example:

store := mcp.NewMemoryEventStore(nil)

handler := mcp.NewStreamableHTTPHandler(
    getServer,
    &mcp.StreamableHTTPOptions{
        EventStore: store,
    },
)

SSE Event Types

Event

Represents a server-sent event.

type Event struct {
    Name string
    ID   string
    Data []byte
}

Fields:

  • Name: The "event" field
  • ID: The "id" field
  • Data: The "data" field

Methods:

func (e Event) Empty() bool

Returns whether the event is empty.

Logging Transport

LoggingTransport

Wraps another transport and logs all JSON-RPC messages.

type LoggingTransport struct {
    Transport Transport
    Writer    io.Writer
}

Example:

import "os"

transport := &mcp.LoggingTransport{
    Transport: &mcp.StdioTransport{},
    Writer:    os.Stderr,
}

Use cases:

  • Debugging transport issues
  • Protocol analysis
  • Development and testing

Custom Transports

You can implement custom transports by satisfying the Transport interface. The transport must return a Connection that handles reading and writing JSON-RPC messages.

Example custom transport:

type MyTransport struct {
    // custom fields
}

func (t *MyTransport) Connect(ctx context.Context) (mcp.Connection, error) {
    // Create your connection implementation
    return &myConnection{}, nil
}

type myConnection struct {
    // connection state
}

func (c *myConnection) Read(ctx context.Context) (jsonrpc.Message, error) {
    // Read next message
}

func (c *myConnection) Write(ctx context.Context, msg jsonrpc.Message) error {
    // Write message
}

func (c *myConnection) Close() error {
    // Clean up resources
}

func (c *myConnection) SessionID() string {
    // Return session identifier
}

Transport Selection Guidelines

TransportUse CaseProsCons
StdioTransportCLI tools, simple serversSimple, language-agnosticSingle connection only
CommandTransportExternal serversProcess isolation, clean shutdownSubprocess overhead
InMemoryTransportTestingFast, no I/O overheadSame-process only
SSEClientTransport/SSEHandlerWeb applications (legacy)HTTP-based, firewall-friendlyOlder spec
StreamableClientTransport/StreamableHTTPHandlerModern web appsResumable, fault-tolerantMore complex
IOTransportCustom I/OFlexibleRequires custom setup