mcp

package
v0.8.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package mcp implements MCP (Model Context Protocol) client support, allowing Thane to connect to external MCP servers and expose their tools to the agent loop and delegates.

MCP uses JSON-RPC 2.0 over two transports: stdio (subprocess) and streamable HTTP. The client discovers tools via tools/list and invokes them via tools/call. Discovered tools are bridged into Thane's tool registry so they appear as native tools to the LLM.

This implementation covers the client/host side only — Thane does not act as an MCP server.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BridgeTools

func BridgeTools(ctx context.Context, client *Client, serverName string, registry *tools.Registry, include, exclude []string, logger *slog.Logger) (int, error)

BridgeTools discovers tools from an MCP client and registers them on the given tool registry. Tool names are namespaced as "mcp_{serverName}_{toolName}" to avoid collisions with native tools.

The include and exclude lists control which MCP tools are bridged:

  • If include is non-empty, only tools whose MCP names appear in it are registered.
  • If exclude is non-empty, tools whose MCP names appear in it are skipped.
  • If both are empty, all tools are registered.

BridgeTools returns the number of tools registered.

func ToolName

func ToolName(serverName, mcpToolName string) string

ToolName generates a namespaced Thane tool name from an MCP server name and tool name. Both components are sanitized to contain only lowercase alphanumeric characters and underscores.

Types

type Client

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

Client connects to a single MCP server and provides typed access to the MCP protocol operations (initialize, tools/list, tools/call).

func NewClient

func NewClient(name string, transport Transport, logger *slog.Logger) *Client

NewClient creates an MCP client for the given server. The transport determines how messages are delivered (stdio or HTTP).

func (*Client) CallTool

func (c *Client) CallTool(ctx context.Context, name string, args map[string]any) (string, error)

CallTool invokes a tool by name with the given arguments. The result is extracted from the response content blocks as a single string. Non-text content blocks are described inline (e.g., "image").

func (*Client) Close

func (c *Client) Close() error

Close shuts down the client and its transport.

func (*Client) Initialize

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

Initialize performs the MCP handshake: sends an initialize request and then the notifications/initialized notification.

func (*Client) ListTools

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

ListTools calls tools/list and returns the available tool definitions. Results are cached; subsequent calls return the cached list.

func (*Client) Name

func (c *Client) Name() string

Name returns the server name this client is connected to.

func (*Client) Ping

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

Ping checks whether the MCP server is responsive. Used by connwatch for health monitoring.

type ContentBlock

type ContentBlock struct {
	Type string `json:"type"`
	Text string `json:"text,omitempty"`
}

ContentBlock is a single content item in a tools/call response.

type HTTPConfig

type HTTPConfig struct {
	// URL is the MCP server endpoint.
	URL string

	// Headers are additional HTTP headers sent with every request
	// (e.g., Authorization).
	Headers map[string]string

	// Logger is the structured logger for transport diagnostics.
	Logger *slog.Logger
}

HTTPConfig configures an HTTP MCP transport that communicates with a remote MCP server over streamable HTTP (JSON-RPC over POST).

type HTTPTransport

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

HTTPTransport communicates with an MCP server over streamable HTTP. Each JSON-RPC request is sent as an HTTP POST; the response comes back in the response body.

func NewHTTPTransport

func NewHTTPTransport(cfg HTTPConfig) *HTTPTransport

NewHTTPTransport creates an HTTP transport for the given config. The underlying HTTP client is constructed via httpkit.

func (*HTTPTransport) Close

func (t *HTTPTransport) Close() error

Close is a no-op for HTTP transports. The underlying HTTP client manages its own connection pool via httpkit.

func (*HTTPTransport) Notify

func (t *HTTPTransport) Notify(ctx context.Context, notif *Notification) error

Notify sends a JSON-RPC notification via HTTP POST. No response content is expected, but the HTTP response status is checked.

func (*HTTPTransport) Send

func (t *HTTPTransport) Send(ctx context.Context, req *Request) (*Response, error)

Send sends a JSON-RPC request via HTTP POST and returns the response.

type Notification

type Notification struct {
	JSONRPC string `json:"jsonrpc"`
	Method  string `json:"method"`
	Params  any    `json:"params,omitempty"`
}

Notification is a JSON-RPC 2.0 notification (no ID, no response expected).

func NewNotification

func NewNotification(method string, params any) *Notification

NewNotification creates a JSON-RPC 2.0 notification.

type RPCError

type RPCError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    any    `json:"data,omitempty"`
}

RPCError is a JSON-RPC 2.0 error object.

func (*RPCError) Error

func (e *RPCError) Error() string

Error implements the error interface for RPCError.

type Request

type Request struct {
	JSONRPC string `json:"jsonrpc"`
	ID      int64  `json:"id"`
	Method  string `json:"method"`
	Params  any    `json:"params,omitempty"`
}

Request is a JSON-RPC 2.0 request message.

func NewRequest

func NewRequest(id int64, method string, params any) *Request

NewRequest creates a JSON-RPC 2.0 request with the given method and params.

type Response

type Response struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      int64           `json:"id"`
	Result  json.RawMessage `json:"result,omitempty"`
	Error   *RPCError       `json:"error,omitempty"`
}

Response is a JSON-RPC 2.0 response message. Exactly one of Result or Error is non-nil in a well-formed response.

type StdioConfig

type StdioConfig struct {
	// Command is the executable to run.
	Command string

	// Args are command-line arguments passed to the executable.
	Args []string

	// Env are additional environment variables for the subprocess
	// (format: "KEY=VALUE"). These are appended to the current
	// process environment.
	Env []string

	// Logger is the structured logger for transport diagnostics.
	Logger *slog.Logger
}

StdioConfig configures a stdio MCP transport that communicates with a subprocess over stdin/stdout using newline-delimited JSON-RPC.

type StdioTransport

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

StdioTransport communicates with an MCP server running as a subprocess. JSON-RPC messages are newline-delimited on stdin/stdout. Access is serialized by a channel-based semaphore so that callers whose context expires while waiting do not kill the subprocess.

func NewStdioTransport

func NewStdioTransport(cfg StdioConfig) *StdioTransport

NewStdioTransport creates a stdio transport for the given config. The subprocess is not started until the first Send or Notify call.

func (*StdioTransport) Close

func (t *StdioTransport) Close() error

Close terminates the subprocess and releases resources. It blocks until the semaphore is available (matching the previous mutex behavior) because shutdown must wait for in-flight operations.

func (*StdioTransport) Notify

func (t *StdioTransport) Notify(ctx context.Context, notif *Notification) error

Notify sends a JSON-RPC notification over stdin. No response is expected.

func (*StdioTransport) Send

func (t *StdioTransport) Send(ctx context.Context, req *Request) (*Response, error)

Send sends a JSON-RPC request over stdin and reads the response from stdout. The semaphore serializes access since stdio is inherently sequential. If the caller's context expires while waiting for the semaphore, Send returns immediately without touching the subprocess. The read is performed in a goroutine so that context cancellation can interrupt a blocking read.

type ToolDefinition

type ToolDefinition struct {
	Name        string         `json:"name"`
	Description string         `json:"description"`
	InputSchema map[string]any `json:"inputSchema"`
}

ToolDefinition is an MCP tool as returned by tools/list.

type Transport

type Transport interface {
	// Send sends a JSON-RPC request and returns the response.
	// The transport handles framing, encoding, and correlation.
	Send(ctx context.Context, req *Request) (*Response, error)

	// Notify sends a JSON-RPC notification (no response expected).
	Notify(ctx context.Context, notif *Notification) error

	// Close shuts down the transport and releases resources.
	// For stdio transports this terminates the subprocess.
	Close() error
}

Transport is the interface for MCP server communication. Implementations handle the details of sending JSON-RPC requests and receiving responses over a specific transport (stdio or HTTP).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL