Documentation
¶
Overview ¶
Package mcp implements a stateless, streamable-HTTP Model Context Protocol server and upstream client. It is transport- and storage-agnostic: the gateway adapts its auth/store/registry into the ToolSource interface and drives the Server, so this package stays below the gateway layer. All protocol constants live in this file so reconciling a future spec revision is a one-file change.
Index ¶
Constants ¶
const ( ProtocolVersionLatest = "2025-06-18" ProtocolVersionLegacy = "2025-03-26" )
Protocol revisions Polaris speaks. Latest is preferred on negotiation; Legacy is accepted from older clients and used as the upstream-client fallback.
const ( MethodInitialize = "initialize" MethodPing = "ping" MethodToolsList = "tools/list" MethodToolsCall = "tools/call" MethodInitialized = "notifications/initialized" MethodCancelled = "notifications/cancelled" )
JSON-RPC method names (v1 surface: tools only).
const ( ErrCodeParse = -32700 ErrCodeInvalidRequest = -32600 ErrCodeMethodNotFound = -32601 ErrCodeInvalidParams = -32602 ErrCodeInternal = -32603 )
JSON-RPC 2.0 reserved error codes.
const ProtocolVersionHeader = "MCP-Protocol-Version"
ProtocolVersionHeader carries the negotiated version on every post-initialize request in streamable HTTP.
const ServerName = "polaris"
ServerName is the MCP serverInfo.name Polaris advertises.
Variables ¶
var SupportedProtocolVersions = []string{ProtocolVersionLatest, ProtocolVersionLegacy}
SupportedProtocolVersions is the negotiation set, most-preferred first.
Functions ¶
func ProtocolVersionSupported ¶
ProtocolVersionSupported reports whether v is a version Polaris speaks.
Types ¶
type Aggregate ¶
type Aggregate struct {
// contains filtered or unexported fields
}
Aggregate merges several ToolSources into one. Upstream tools are namespaced `{prefix}:{tool}`; the local source (prefix "") stays bare. tools/list results are cached per source with a TTL and refreshed lazily; a failing upstream is skipped, never sinking the whole aggregate.
func NewAggregate ¶
NewAggregate builds an aggregate with a per-source tools/list cache TTL (0 = no caching).
func (*Aggregate) Add ¶
func (a *Aggregate) Add(prefix string, source ToolSource)
Add registers a source under a namespace prefix ("" for the local source).
func (*Aggregate) CallTool ¶
func (a *Aggregate) CallTool(ctx context.Context, name string, arguments json.RawMessage) (ToolResult, error)
CallTool routes by the namespace prefix; a bare name goes to the local source.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an upstream MCP client speaking streamable HTTP. It implements ToolSource by calling a remote server's tools/list and tools/call. On a version-mismatch (4xx) it retries once pinned to the legacy protocol version, so older upstream servers keep working. Bearer tokens from downstream callers are never forwarded here — only the binding's configured headers are sent.
func (*Client) CallTool ¶
func (c *Client) CallTool(ctx context.Context, name string, arguments json.RawMessage) (ToolResult, error)
CallTool invokes an upstream tool.
type ContentBlock ¶
ContentBlock is one element of a tool result's content array.
func TextContent ¶
func TextContent(text string) []ContentBlock
TextContent builds a single text content block.
type Error ¶
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
Error is a JSON-RPC 2.0 error object.
type OAuthConfig ¶
type OAuthConfig struct {
ResourceURI string
AuthorizationServers []string
JWKSCacheTTL time.Duration
}
OAuthConfig configures the MCP OAuth 2.1 resource server (RFC 9728).
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 omits id.
func DecodeRequests ¶
DecodeRequests parses a single request or a batch array. The bool reports whether the payload was a batch (so the response is encoded as an array).
func (Request) IsNotification ¶
IsNotification reports whether the request carries no id (fire-and-forget).
type ResourceServer ¶
type ResourceServer struct {
// contains filtered or unexported fields
}
ResourceServer validates bearer JWTs against the configured authorization servers' JWKS (fetched, cached, and rotated with a stale-grace fallback) and serves RFC 9728 protected-resource metadata. Downstream tokens are never forwarded upstream.
func NewResourceServer ¶
func NewResourceServer(cfg OAuthConfig, httpClient *http.Client) *ResourceServer
NewResourceServer builds a resource server. A nil client uses a 10s default.
func (*ResourceServer) Challenge ¶
func (rs *ResourceServer) Challenge(metadataURL string) string
Challenge is the WWW-Authenticate value for a 401 pointing at the metadata.
func (*ResourceServer) ProtectedResourceMetadata ¶
func (rs *ResourceServer) ProtectedResourceMetadata() map[string]any
ProtectedResourceMetadata is the RFC 9728 document served at /.well-known/oauth-protected-resource.
func (*ResourceServer) ValidateToken ¶
ValidateToken parses and verifies a bearer JWT and returns its claims. It enforces the signing algorithm allow-list, an allowed issuer, aud == resource URI, and a required expiry.
type Response ¶
type Response struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id"`
Result any `json:"result,omitempty"`
Error *Error `json:"error,omitempty"`
}
Response is a JSON-RPC 2.0 response. Exactly one of Result/Error is set.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server dispatches MCP JSON-RPC over streamable HTTP against a ToolSource. It is stateless: no session id, no initialize handshake requirement. A POST is answered as a single JSON body, or — when the client sends `Accept: text/event-stream` — as SSE frames on the POST response.
func (*Server) Handle ¶
func (s *Server) Handle(w http.ResponseWriter, r *http.Request, source ToolSource)
Handle processes a POST JSON-RPC request (single or batch) against source. GET and other verbs return 405 — the gateway handler owns any GET metadata path.
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
InputSchema json.RawMessage `json:"inputSchema,omitempty"`
}
Tool is one callable tool in a tools/list result.
type ToolResult ¶
type ToolResult struct {
Content []ContentBlock `json:"content"`
StructuredContent any `json:"structuredContent,omitempty"`
IsError bool `json:"isError"`
}
ToolResult is the result of a tools/call.
type ToolSource ¶
type ToolSource interface {
ListTools(ctx context.Context, cursor string) (tools []Tool, nextCursor string, err error)
CallTool(ctx context.Context, name string, arguments json.RawMessage) (ToolResult, error)
}
ToolSource is what the Server dispatches against: a set of listable, callable tools. Local toolsets, upstream MCP servers, and aggregates all implement it.