mcp

package
v0.0.1-alpha.2 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package mcp connects to Model Context Protocol servers and exposes their tools through the unchanged Tool port (change 0015, ADR-0010).

This package is the only place in OpenPlus that knows the MCP wire protocol: JSON-RPC 2.0 over either a stdio subprocess or streamable HTTP. Everything it hands the rest of the system is a neutral tool.Tool. It is written against the standard library only, so the build stays cgo-free.

Security: an MCP server is arbitrary code (stdio) or an arbitrary endpoint (http) chosen by the user's config. Its tools are registered like any other, so they pass the PolicyGate — that gate is the only in-process mitigation, and MCP tools must never bypass it.

Index

Constants

View Source
const ClientName = "openplus"

ClientName identifies OpenPlus to servers in the handshake.

View Source
const DefaultHTTPTimeout = 2 * time.Minute

DefaultHTTPTimeout bounds one streamable-HTTP call when the caller's context carries no deadline. A server that never answers must not hold a turn open forever.

View Source
const ProtocolVersion = "2025-06-18"

ProtocolVersion is the MCP revision this client speaks. A server that needs a different one says so in its initialize result; we report the mismatch rather than guessing at compatibility.

View Source
const ToolNameSeparator = "."

ToolNameSeparator joins a server name and its tool name. Namespacing is not cosmetic: two servers may both expose "search", and a permission rule is written against the full name.

View Source
const Version = "2.0"

Version is the JSON-RPC version every message carries.

Variables

This section is empty.

Functions

func DecodeFrame

func DecodeFrame(r *bufio.Reader, msg any) error

DecodeFrame reads one newline-delimited JSON message into msg, skipping blank padding lines. A malformed frame is an error rather than a zero value, so a caller cannot mistake garbage for an empty result.

func EncodeFrame

func EncodeFrame(w io.Writer, msg any) error

EncodeFrame writes one newline-delimited JSON message. Compact encoding matters: an embedded newline would split one message across two frames.

func NewHTTP

func NewHTTP(cfg HTTPConfig) *httpTransport

NewHTTP returns a Transport for a streamable-HTTP endpoint. Nothing is contacted until the first call, so this cannot fail.

func NewStdio

func NewStdio(ctx context.Context, cfg StdioConfig) (*stdioTransport, error)

NewStdio starts the configured subprocess and returns a Transport for it. A command that cannot start is an error here rather than at the first call, so a typo in config surfaces at assemble time.

The subprocess is stopped when ctx is cancelled or Close is called — whichever happens first. Cancelling ctx is the session-teardown path.

Types

type Client

type Client struct {
	// Name is the config key for this server; it prefixes its tool names and
	// appears in every error, so a failure points at a specific server.
	Name string
	// contains filtered or unexported fields
}

Client speaks MCP to one server.

func NewClient

func NewClient(name string, t Transport) *Client

NewClient wraps a Transport as an MCP client. The caller must call Initialize before listing or calling tools.

func (*Client) CallTool

func (c *Client) CallTool(ctx context.Context, name string, args json.RawMessage) (string, error)

CallTool invokes one tool and returns its content as text.

Two distinct failures both surface as errors: a JSON-RPC error (the call did not happen) and an isError result (the tool ran and reported failure). The loop needs to see both as failures, so neither is returned as ordinary output.

func (*Client) Close

func (c *Client) Close() error

Close shuts the transport down (killing a subprocess, closing a connection).

func (*Client) Initialize

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

Initialize performs the MCP handshake: an initialize request, then the initialized notification. The notification is only sent once the server has answered — sending it early would announce readiness we do not have.

func (*Client) ListTools

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

ListTools returns the server's advertised tools. It refuses before the handshake rather than sending a request the server is entitled to reject.

func (*Client) ServerInfo

func (c *Client) ServerInfo() string

ServerInfo reports the server's self-reported name and version, empty before the handshake.

func (*Client) Tools

func (c *Client) Tools(ctx context.Context) ([]tool.Tool, error)

Tools lists the server's tools and adapts them to the Tool port.

A tool whose schema cannot be translated fails the whole listing rather than being dropped: a user who configured a server expects its tools, and silently serving a subset hides the problem until the model tries to call the missing one.

type Error

type Error struct {
	Code    int             `json:"code"`
	Message string          `json:"message"`
	Data    json.RawMessage `json:"data,omitempty"`
}

Error is a JSON-RPC 2.0 error object.

func (*Error) Error

func (e *Error) Error() string

type HTTPConfig

type HTTPConfig struct {
	// URL is the MCP endpoint. Required.
	URL string
	// Headers are sent on every request (an Authorization header, typically).
	Headers map[string]string
	// Client overrides the HTTP client. Nil uses a default one.
	Client *http.Client
}

HTTPConfig describes a streamable-HTTP MCP endpoint.

type Request

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

Request is a JSON-RPC 2.0 request or notification. A notification has no ID and expects no response.

type Response

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

Response is a JSON-RPC 2.0 response. Exactly one of Result and Error is set.

type StdioConfig

type StdioConfig struct {
	// Command is the executable to run. Required.
	Command string
	// Args are its arguments.
	Args []string
	// Env is added to the child's environment as "K=V" entries. The parent's
	// environment is inherited, because these servers routinely need PATH, HOME
	// and a credential the user already exported.
	Env []string
	// Dir is the child's working directory. Empty means the parent's.
	Dir string
}

StdioConfig describes a subprocess MCP server.

type ToolDesc

type ToolDesc struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	InputSchema json.RawMessage `json:"inputSchema"`
}

ToolDesc is one tool a server advertises.

type Transport

type Transport interface {
	Call(ctx context.Context, method string, params json.RawMessage) (json.RawMessage, error)
	Notify(ctx context.Context, method string, params json.RawMessage) error
	Close() error
}

Transport carries JSON-RPC to one server. Call awaits a response; Notify sends a message that expects none. Both honor ctx: a hung server must never block a turn indefinitely.

Implementations: stdioTransport (subprocess) and httpTransport (streamable HTTP). The Client is transport-agnostic.

Jump to

Keyboard shortcuts

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