Documentation
¶
Overview ¶
Package mcp provides runtime MCP transport callers, normalization helpers, and support utilities used by generated MCP adapters.
Package mcp OAuth helpers (oauth.go) provide protected-resource formatting shared by generated MCP servers and hand-written middleware. Pure formatting and URL canonicalization — no token validation happens here.
Index ¶
- Constants
- Variables
- func BuildBearerChallenge(resourceMetadataURL, scope string) string
- func BuildInvalidTokenChallenge(resourceMetadataURL, errorDescription string) string
- func CanonicalizeChallengeOrigin(r *http.Request, trustProxy bool) string
- func CanonicalizeResourceURL(r *http.Request, trustProxy bool) (string, error)
- func CoerceQuery(m map[string][]string) map[string]any
- func EncodeJSONToString(ctx context.Context, ...) (string, error)
- func EnsureSessionID(ctx context.Context) string
- func MarshalCanonicalJSON(v any) ([]byte, error)
- func NewSessionID() string
- func ProtectedResourceMetadataPath(mountPath string) string
- func RequestHeadersFromContext(ctx context.Context) http.Header
- func ResponseWriterFromContext(ctx context.Context) http.ResponseWriter
- func SessionIDFromContext(ctx context.Context) string
- func ToolCallErrorFromResponse(textParts []string, fallbackResult any) error
- func UnmarshalCanonicalJSON(data []byte, dst any) error
- func WithOAuthChallenge(handler http.Handler, mountPath string, challenge ChallengeBuilder) http.Handler
- func WithRequestHeaders(ctx context.Context, headers http.Header) context.Context
- func WithResponseWriter(ctx context.Context, w http.ResponseWriter) context.Context
- func WithSessionID(ctx context.Context, sessionID string) context.Context
- func WriteInvalidToken(w http.ResponseWriter, resourceMetadataURL, errorDescription string)
- func WriteUnauthorized(w http.ResponseWriter, resourceMetadataURL, scope string)
- type Broadcaster
- type CallRequest
- type CallResponse
- type Caller
- type CallerFunc
- type ChallengeBuilder
- type HTTPOptions
- type Notification
- type SessionCaller
- func NewHTTPCaller(ctx context.Context, opts HTTPOptions) (*SessionCaller, error)
- func NewSSECaller(ctx context.Context, opts HTTPOptions) (*SessionCaller, error)
- func NewSessionCaller(session *mcp.ClientSession, cancel context.CancelFunc) *SessionCaller
- func NewStdioCaller(ctx context.Context, opts StdioOptions) (*SessionCaller, error)
- type StdioOptions
- type StreamableHTTPSessions
- func (s *StreamableHTTPSessions) HasIssued() bool
- func (s *StreamableHTTPSessions) Issue(sessionID string)
- func (s *StreamableHTTPSessions) RegisterListener(sessionID string, cancel context.CancelFunc) (func(), error)
- func (s *StreamableHTTPSessions) Terminate(sessionID string) error
- func (s *StreamableHTTPSessions) Validate(sessionID string) error
- type Subscription
- type ToolCallError
Constants ¶
const HeaderKeySessionID = "Mcp-Session-Id"
HeaderKeySessionID is the MCP streamable HTTP session header.
const ProtectedResourceMetadataPrefix = "/.well-known/oauth-protected-resource"
ProtectedResourceMetadataPrefix is the RFC 9728 well-known prefix for OAuth 2.0 protected-resource metadata.
Variables ¶
var ( ErrInvalidSessionID = errors.New("invalid session ID") ErrSessionTerminated = errors.New("session terminated") )
var ErrEmptyResourceURL = errors.New("mcp/oauth: cannot derive canonical resource URL")
ErrEmptyResourceURL signals that CanonicalizeResourceURL could not derive a non-empty scheme+host for the request. Callers should treat this as a 400 Bad Request because RFC 9728 requires `resource` to be a fully-qualified URI.
var ErrInvalidForwardedHeaders = errors.New("mcp/oauth: invalid forwarded identity header")
ErrInvalidForwardedHeaders signals that a forwarded-identity header was present on the request but failed validation (contained control or delimiter characters, or was otherwise unsafe to embed in a URL). Callers that derive the RFC 8707 canonical resource URI from request context should treat this as a 400 Bad Request rather than silently falling back to `r.Host`: a malformed forwarded header signals either a misconfigured proxy or a client probing for injection vectors, and either way the safe response is to reject the request.
Functions ¶
func BuildBearerChallenge ¶ added in v1.1.0
BuildBearerChallenge formats the WWW-Authenticate header value for an OAuth 2.0 Bearer challenge per RFC 6750 §3. resourceMetadataURL is required; scope is appended only when non-empty.
func BuildInvalidTokenChallenge ¶ added in v1.1.0
BuildInvalidTokenChallenge formats the WWW-Authenticate header for an RFC 6750 §3 invalid_token response (used for audience mismatches, expired tokens, and revoked tokens). errorDescription is optional and should be a short human-readable string safe to surface to clients.
func CanonicalizeChallengeOrigin ¶ added in v1.1.1
CanonicalizeChallengeOrigin derives an origin URL suitable for embedding in a WWW-Authenticate `resource_metadata` parameter. Unlike the strict CanonicalizeResourceURL, this function never returns an error: if forwarded headers are malformed (or the caller did not opt into trusting them), it falls back to the request scheme and Host header so the challenge still points at some reachable origin.
This fallback is deliberate and narrow: a challenge is a formatting artifact inside a 401 response, not an identity claim. Emitting a slightly-wrong URL back to a client whose request carried malformed proxy headers is better than emitting nothing. Do not use this function to populate the PRM `resource` field — use CanonicalizeResourceURL there so the request fails loudly on malformed input.
func CanonicalizeResourceURL ¶ added in v1.1.0
CanonicalizeResourceURL derives the RFC 8707 canonical resource URI from an incoming request.
When trustProxy is true, the function honors X-Forwarded-Proto and X-Forwarded-Host (and RFC 7239 Forwarded) so the value reflects the client-visible URL behind a trusted reverse proxy; a forwarded header present but malformed is rejected with ErrInvalidForwardedHeaders.
When trustProxy is false (the default for a generated server without TrustProxyHeaders() in the DSL), forwarded headers are ignored entirely and the origin is derived from r.Host + r.TLS only. This is the safe default for any server reachable directly by clients: without it, an attacker with direct access controls the PRM `resource` field advertised to clients.
Returns ErrEmptyResourceURL when no scheme+host can be derived. Callers should surface errors as 400 Bad Request rather than emitting a PRM document or challenge URL built from attacker-influenced or unusable inputs.
Operators who cannot vouch for forwarded headers should either leave trustProxy at its default or declare the resource identifier explicitly in the MCP DSL; generated code uses the declared value and does not call this function in the pinned case.
func CoerceQuery ¶
CoerceQuery converts a URL query map into a JSON-friendly object: - Repeated parameters become arrays preserving input order - "true"/"false" (case-insensitive) become booleans - RFC3339/RFC3339Nano values become time.Time - Numeric strings become int64 or float64 when obvious It does not coerce "0"/"1" to booleans.
func EncodeJSONToString ¶
func EncodeJSONToString( ctx context.Context, newEncoder func(context.Context, http.ResponseWriter) goahttp.Encoder, v any, ) (string, error)
EncodeJSONToString encodes v into JSON using the provided encoder factory. The factory should produce an Encoder bound to the given ResponseWriter.
func EnsureSessionID ¶
EnsureSessionID returns the existing session ID from ctx or creates a new one. When a response writer is present in ctx, the created session ID is emitted on the MCP session header.
func MarshalCanonicalJSON ¶
MarshalCanonicalJSON encodes v into JSON using explicit JSON tags when present and otherwise falling back to snake_case field names for exported struct fields.
Contract: - Map keys must be strings (including named string aliases). - Unsupported map key kinds fail fast instead of being silently dropped.
func NewSessionID ¶
func NewSessionID() string
NewSessionID generates a transport-agnostic MCP session identifier.
func ProtectedResourceMetadataPath ¶ added in v1.1.0
ProtectedResourceMetadataPath returns the RFC 9728 §3.1 path-suffixed metadata path for a server mounted at mountPath. The root alias "/.well-known/oauth-protected-resource" is produced when mountPath is empty or "/".
func RequestHeadersFromContext ¶ added in v1.0.7
RequestHeadersFromContext returns request-scoped MCP headers from ctx.
func ResponseWriterFromContext ¶
func ResponseWriterFromContext(ctx context.Context) http.ResponseWriter
ResponseWriterFromContext returns the active HTTP response writer from ctx.
func SessionIDFromContext ¶
SessionIDFromContext returns the MCP session ID stored in ctx.
func ToolCallErrorFromResponse ¶ added in v1.1.0
ToolCallErrorFromResponse converts an MCP isError content payload into a Go error while preserving the compact text message when present.
func UnmarshalCanonicalJSON ¶
UnmarshalCanonicalJSON decodes JSON into dst using explicit JSON tags when present and otherwise matching snake_case keys to exported struct fields.
func WithOAuthChallenge ¶ added in v1.1.0
func WithOAuthChallenge(handler http.Handler, mountPath string, challenge ChallengeBuilder) http.Handler
WithOAuthChallenge wraps a handler so that 401 responses missing a resource_metadata-carrying WWW-Authenticate header are augmented with the spec-compliant challenge built by challenge. Responses that already include resource_metadata are left untouched so consumer middleware can still override the default.
func WithRequestHeaders ¶ added in v1.0.7
WithRequestHeaders stores request-scoped MCP headers in ctx.
func WithResponseWriter ¶
WithResponseWriter stores the active HTTP response writer in ctx.
func WithSessionID ¶
WithSessionID stores the MCP session ID in ctx.
func WriteInvalidToken ¶ added in v1.1.0
func WriteInvalidToken(w http.ResponseWriter, resourceMetadataURL, errorDescription string)
WriteInvalidToken writes a 401 response with the invalid_token Bearer challenge. Consumers call this from a verifier wrapper when a decoded token carries the wrong audience, is expired, or is revoked.
func WriteUnauthorized ¶ added in v1.1.0
func WriteUnauthorized(w http.ResponseWriter, resourceMetadataURL, scope string)
WriteUnauthorized writes a spec-compliant 401 response with a Bearer challenge. The resource_metadata parameter points the client at the Protected Resource Metadata document; scope is the space-delimited list of scopes the server advertises. When scope is empty the scope parameter is omitted entirely (RFC 6750 does not require it).
Types ¶
type Broadcaster ¶
type Broadcaster interface {
// Subscribe registers a new subscriber and returns a Subscription. The caller
// must Close the subscription when done.
Subscribe(ctx context.Context) (Subscription, error)
// Publish delivers an event to all current subscribers.
Publish(ev any)
// Close closes the broadcaster and all current subscriptions.
Close() error
}
Broadcaster provides a minimal, concurrency-safe publish/subscribe abstraction used by generated MCP adapters to stream server-initiated events (for example status notifications and resource updates). Implementations must allow Subscribe, Publish and Close to be called from multiple goroutines.
The event payload type is intentionally untyped (any) so generated packages can publish values of their locally-generated result types without creating cyclic dependencies across packages.
Close terminates the broadcaster and all active subscriptions. After Close, future Subscribe calls succeed with a closed Subscription and Publish becomes a no-op.
func NewChannelBroadcaster ¶
func NewChannelBroadcaster(buf int, drop bool) Broadcaster
NewChannelBroadcaster constructs an in-memory Broadcaster backed by buffered channels. The returned implementation is safe for concurrent use.
Buffering and back-pressure:
- buf controls the size of each subscriber channel buffer.
- When drop is true, Publish does not block; if a subscriber channel is full the event is dropped for that subscriber.
- When drop is false, Publish blocks until each subscriber has available buffer space, applying back-pressure to publishers.
type CallRequest ¶
type CallRequest struct {
// Suite identifies the MCP toolset (server name) associated with the tool.
Suite string
// Tool is the MCP-local tool identifier (without the suite prefix).
Tool string
// Payload is the JSON-encoded tool arguments produced by the runtime.
Payload json.RawMessage
}
CallRequest describes the toolset/tool invocation issued by the runtime.
type CallResponse ¶
type CallResponse struct {
// Result is the JSON payload returned by the MCP server.
Result json.RawMessage
// Structured carries the full structured MCP content payload, including text
// items that may also contribute to Result.
Structured json.RawMessage
}
CallResponse captures the MCP tool result returned by the caller.
func NormalizeToolCallResponse ¶
func NormalizeToolCallResponse(textParts []string, structured any, fallbackResult any) (CallResponse, error)
NormalizeToolCallResponse converts raw text parts and structured content into the canonical CallResponse representation used by MCP callers.
Text parts are concatenated in order. If the combined text is valid JSON, it becomes Result directly; otherwise it is marshaled as a JSON string. If no text is present, fallbackResult is marshaled into Result. Structured is marshaled into Structured when non-nil.
type Caller ¶
type Caller interface {
CallTool(ctx context.Context, req CallRequest) (CallResponse, error)
}
Caller invokes MCP tools on behalf of the runtime-generated adapters. It is implemented by transport-specific clients (stdio, HTTP streaming, etc.).
type CallerFunc ¶
type CallerFunc func(ctx context.Context, req CallRequest) (CallResponse, error)
CallerFunc adapts a function to implement Caller.
func (CallerFunc) CallTool ¶
func (f CallerFunc) CallTool(ctx context.Context, req CallRequest) (CallResponse, error)
CallTool implements Caller.
type ChallengeBuilder ¶ added in v1.1.0
ChallengeBuilder formats a WWW-Authenticate header value for a request against the server mounted at mountPath. Generated packages export OAuthChallengeHeader matching this signature.
type HTTPOptions ¶
type HTTPOptions struct {
Endpoint string
Client *http.Client
ClientName string
ClientVersion string
InitTimeout time.Duration
}
HTTPOptions configures the HTTP Caller.
type Notification ¶
type Notification struct {
Type string `json:"type"`
Message *string `json:"message,omitempty"`
Data any `json:"data,omitempty"`
}
Notification describes a server-initiated status update that can be broadcast to connected MCP clients via the Events stream. It carries a machine-usable type, an optional human-readable message, and optional structured data.
type SessionCaller ¶
type SessionCaller struct {
// contains filtered or unexported fields
}
SessionCaller implements Caller by wrapping an MCP SDK ClientSession. It is used by transport-specific callers (stdio, HTTP, SSE) to unify tool invocation.
func NewHTTPCaller ¶
func NewHTTPCaller(ctx context.Context, opts HTTPOptions) (*SessionCaller, error)
NewHTTPCaller creates an HTTP-based Caller and performs MCP initialize handshake.
func NewSSECaller ¶
func NewSSECaller(ctx context.Context, opts HTTPOptions) (*SessionCaller, error)
NewSSECaller creates an SSE-based Caller and performs the MCP initialize handshake.
func NewSessionCaller ¶
func NewSessionCaller(session *mcp.ClientSession, cancel context.CancelFunc) *SessionCaller
NewSessionCaller returns a new SessionCaller wrapping the provided SDK session.
func NewStdioCaller ¶
func NewStdioCaller(ctx context.Context, opts StdioOptions) (*SessionCaller, error)
NewStdioCaller launches the target command using CommandTransport, performs the MCP initialize handshake via Client.Connect, and returns a Caller that wraps the resulting ClientSession.
func (*SessionCaller) CallTool ¶
func (c *SessionCaller) CallTool(ctx context.Context, req CallRequest) (CallResponse, error)
CallTool invokes tools/call over the transport using the SDK session.
func (*SessionCaller) Close ¶
func (c *SessionCaller) Close() error
Close terminates the session and releases resources.
type StdioOptions ¶
type StdioOptions struct {
Command string
Args []string
Env []string
Dir string
ClientName string
ClientVersion string
InitTimeout time.Duration
}
StdioOptions configures the stdio-based MCP caller.
type StreamableHTTPSessions ¶
type StreamableHTTPSessions struct {
// contains filtered or unexported fields
}
StreamableHTTPSessions tracks issued MCP session IDs and active long-lived listeners for generated streamable HTTP transports.
func NewStreamableHTTPSessions ¶
func NewStreamableHTTPSessions() *StreamableHTTPSessions
NewStreamableHTTPSessions creates a store for issued sessions and active stream listeners.
func (*StreamableHTTPSessions) HasIssued ¶
func (s *StreamableHTTPSessions) HasIssued() bool
HasIssued reports whether the store has any active issued sessions.
func (*StreamableHTTPSessions) Issue ¶
func (s *StreamableHTTPSessions) Issue(sessionID string)
Issue records a session ID as valid for future requests.
func (*StreamableHTTPSessions) RegisterListener ¶
func (s *StreamableHTTPSessions) RegisterListener(sessionID string, cancel context.CancelFunc) (func(), error)
RegisterListener atomically validates a session and associates a cancelable stream with it.
func (*StreamableHTTPSessions) Terminate ¶
func (s *StreamableHTTPSessions) Terminate(sessionID string) error
Terminate marks a session as terminated and cancels any active listeners.
func (*StreamableHTTPSessions) Validate ¶
func (s *StreamableHTTPSessions) Validate(sessionID string) error
Validate reports whether a session is currently valid.
type Subscription ¶
type Subscription interface {
// C returns a receive-only channel for events.
C() <-chan any
// Close unregisters the subscription.
Close() error
}
Subscription represents a live registration with a Broadcaster.
The channel returned by C delivers events in publish order. The channel is closed when either Close is called on the subscription or the owning Broadcaster is closed. Close is idempotent and safe to call multiple times.
type ToolCallError ¶ added in v1.1.0
type ToolCallError struct {
Message string
}
ToolCallError reports a remote MCP tool failure that was returned as an isError tool result rather than a transport/protocol error.
func (*ToolCallError) Error ¶ added in v1.1.0
func (e *ToolCallError) Error() string
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package retry defines shared types and helpers for producing standardized retryable errors and compact repair prompts used across generated clients.
|
Package retry defines shared types and helpers for producing standardized retryable errors and compact repair prompts used across generated clients. |