core

package
v0.3.1 Latest Latest
Warning

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

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

README

core

MCP protocol types and tool-handler APIs.

This package defines the shared types used by both server/ and client/. It has no dependencies on either — only stdlib and encoding/json.

What belongs here

  • JSON-RPC types: Request, Response, Error
  • MCP domain types: ToolDef, ResourceDef, PromptDef, Content, Claims
  • Tool-handler APIs: Sample(), Elicit(), EmitLog(), EmitProgress(), NotifyResourcesChanged()
  • UI metadata types: UIMetadata, UICSPConfig, UIVisibility, AppMIMEType, ToolMeta, ResourceContentMeta
  • Extension types: Extension, ExtensionProvider, RefValidator, ClientExtensionCap, UIExtensionID
  • Context helpers: ClientSupportsExtension(), ClientSupportsUI()
  • Interfaces: Transport, TokenSource, AuthValidator
  • Protocol constants: ServerInfo, ClientInfo, ClientCapabilities

What does NOT belong here

  • Server implementation (Dispatcher, transports, middleware) → server/
  • Client implementation (HTTP transports, reconnection) → client/
  • Auth implementation (JWT, PRM, OAuth) → ext/auth/
  • Anything that imports server/ or client/

Documentation

Index

Constants

View Source
const (
	// RemediationTypeURL indicates remediation via URL-mode elicitation.
	// Composes with the existing URLElicitationRequiredError (-32042).
	RemediationTypeURL = "url"

	// RemediationTypeOAuthRAR indicates the client should re-authorize with
	// RFC 9396 Rich Authorization Request authorization_details. The hint
	// carries an "authorization_details" field at the top level.
	RemediationTypeOAuthRAR = "oauth_authorization_details"
)

SEP-defined remediation hint type values.

View Source
const (
	CacheScopePublic  = "public"
	CacheScopePrivate = "private"
)

SEP-2549 cache-scope values for the cacheScope field carried on the cacheable result types: ToolsListResult, PromptsListResult, ResourcesListResult, ResourceTemplatesListResult, and ResourceResult (resources/read). cacheScope mirrors HTTP Cache-Control: public vs private and controls who may serve a cached copy of a response.

  • CacheScopePublic — the response holds no caller-specific data. Any client, shared gateway, or caching proxy MAY store the response and serve it to any user. Appropriate for tool, prompt, and resource template lists that are identical for every caller.
  • CacheScopePrivate — the response holds caller-specific data. A cache MAY be reused only within the same authorization context and MUST NOT be shared across access tokens. Appropriate for resources/read results that depend on the authenticated user, or for per-user filtered lists.

When cacheScope is absent clients default to "public", so a server whose response varies per caller MUST set CacheScopePrivate explicitly. See docs/LIST_TTL_MIGRATION.md for the security rationale.

View Source
const (
	// ElicitModeForm is the default form-based elicitation mode.
	// The server sends a JSON schema and the client renders a form.
	ElicitModeForm = "form"

	// ElicitModeURL is the URL-based elicitation mode (SEP-1036).
	// The server directs the user to a URL for out-of-band interaction.
	// The MCP client's bearer token remains unchanged.
	ElicitModeURL = "url"
)

Elicitation mode constants (SEP-1036).

View Source
const (
	FileInputReasonTooLarge        = "file_too_large"
	FileInputReasonTypeNotAccepted = "file_type_not_accepted"
)

File-input error reason strings. Pinned by the conformance suite as stable machine-readable identifiers — clients can branch on these without parsing the human-readable message. JS-side bridge errors (ext/ui/assets/file-picker.ts) use the same constants.

View Source
const (
	HTTPHeaderTraceparent = "Traceparent"
	HTTPHeaderTracestate  = "Tracestate"
	HTTPHeaderBaggage     = "Baggage"
)

HTTP header names per W3C — Go's net/http canonicalizes header keys to title-case on Set; both the canonical and the W3C-spec lowercase forms read identically via http.Header.Get (case-insensitive). These constants document the spec name and give a single edit point if a future version renames them.

View Source
const (
	// Standard JSON-RPC 2.0 error codes — use only for JSON-RPC protocol errors.
	ErrCodeParse          = -32700 // Invalid JSON
	ErrCodeInvalidRequest = -32600 // Not a valid JSON-RPC request
	ErrCodeMethodNotFound = -32601 // Method not found
	ErrCodeInvalidParams  = -32602 // Invalid params
	ErrCodeInternal       = -32603 // Internal JSON-RPC error (marshaling, framework bugs)

	// ErrCodeServerError is the base of the implementation-defined range (-32000 to -32099).
	// Avoid using this directly — prefer the MCP-specific codes below.
	ErrCodeServerError = -32000

	// ErrCodeSubscriptionLimitExceeded is returned by resources/subscribe
	// when the requesting session has hit a server-configured cap on
	// concurrent subscriptions or on subscribe/unsubscribe churn rate.
	// The error data SHOULD carry a `reason` string ("cap_exceeded" or
	// "rate_limited") and MAY carry the configured limit for client-side
	// adaptive backoff. Mcpkit servers ship the cap off by default; it
	// is opt-in via server.WithSubscriptionCap and
	// server.WithSubscriptionRateLimit. The wire shape is a standard
	// JSON-RPC error response so spec-conformant clients handle it
	// generically.
	ErrCodeSubscriptionLimitExceeded = -32010

	// MCP application error codes — outside the JSON-RPC reserved range.
	// These indicate application-level failures in tool, resource, or prompt handlers.
	ErrCodeToolExecutionError = -31000 // Tool handler returned an error
	ErrCodeResourceError      = -31001 // Resource handler returned an error
	ErrCodePromptError        = -31002 // Prompt handler returned an error
	ErrCodeCompletionError    = -31003 // Completion handler returned an error

	// ErrCodeURLElicitationRequired indicates that the request cannot proceed
	// until the user completes one or more URL-based elicitation flows (SEP-1036).
	// The error data contains an elicitations array with URL-mode elicitation
	// requests. Clients should present the URLs to the user and retry after
	// receiving notifications/elicitation/complete.
	//
	// This error code is also the composition point for FineGrainedAuth (UC1):
	// the authorization denial envelope is additive metadata in the same data
	// object, alongside the elicitations array.
	ErrCodeURLElicitationRequired = -32042

	// ErrCodeMissingRequiredClientCapability is returned when the server
	// cannot service a request because the client did not declare a
	// capability the server requires for that request. The error data SHOULD
	// carry a `requiredCapabilities` object mirroring the InitializeRequest
	// capabilities shape so the client can self-describe what to add.
	//
	// Defined by SEP-2575 §"Missing Required Capabilities". SEP-2663
	// applies the rule to the tasks extension (TaskSupport=required tools
	// reject with this code when the client did not declare
	// io.modelcontextprotocol/tasks). Reusable for any future extension
	// whose required-mode path needs the same affordance.
	//
	// Renumbered from -32003 per modelcontextprotocol/modelcontextprotocol#2907.
	ErrCodeMissingRequiredClientCapability = -32021

	// ErrCodeHeaderMismatch indicates an HTTP-header / body cross-check
	// failure. Two surfaces use the same code:
	//
	//   - SEP-2243 §Server Validation: the request's Mcp-Method /
	//     Mcp-Name routing headers disagree with the JSON-RPC body, or
	//     a required routing header is missing.
	//   - SEP-2575 stateless wire: the MCP-Protocol-Version HTTP header
	//     and the _meta protocolVersion field do not agree.
	//
	// Both surfaces pair the code with HTTP 400 Bad Request.
	//
	// Renumbered from -32001 per modelcontextprotocol/modelcontextprotocol#2907.
	ErrCodeHeaderMismatch = -32020

	// ErrCodeUnsupportedProtocolVersion is returned by the SEP-2575
	// stateless wire when the request's protocol version is unknown or
	// has been declined by this server. The error data carries
	// {supported: [...], requested: "..."} (see UnsupportedProtocolVersionData)
	// so the client can pick a mutually supported version and retry.
	// HTTP status: 400.
	//
	// Value is -32022 per the SEP-2575 draft JSON schema. mcpkit emitted
	// -32004 through v0.3.0 — the upstream conformance server scenario only
	// asserts HTTP 400 + the data members, not the numeric code, so the
	// off-schema value slipped through. Aligned to -32022 afterward.
	ErrCodeUnsupportedProtocolVersion = -32022
)

Standard JSON-RPC 2.0 error codes (https://www.jsonrpc.org/specification#error_object).

Reserved ranges:

-32700           Parse error (invalid JSON)
-32600           Invalid Request (not a valid JSON-RPC request)
-32601           Method not found
-32602           Invalid params
-32603           Internal error
-32000 to -32099 Server error (implementation-defined)
View Source
const (
	MetaKeyProtocolVersion    = "io.modelcontextprotocol/protocolVersion"
	MetaKeyClientInfo         = "io.modelcontextprotocol/clientInfo"
	MetaKeyClientCapabilities = "io.modelcontextprotocol/clientCapabilities"

	// MetaKeyLogLevel is the per-request log-level opt-in. Absent ⇒ no
	// notifications/message frames may be emitted for this request.
	MetaKeyLogLevel = "io.modelcontextprotocol/logLevel"

	// MetaKeySubscriptionID is set by the server on every notification
	// frame dispatched over an open subscriptions/listen stream so the
	// client can route frames to the correct subscription.
	MetaKeySubscriptionID = "io.modelcontextprotocol/subscriptionId"
)

SEP-2575 _meta envelope keys. Carried inside the params._meta object on every stateless request; missing any of the three triggers -32602.

View Source
const (
	MetaKeyTraceparent = "traceparent"
	MetaKeyTracestate  = "tracestate"

	// MetaKeyTraceLink carries the W3C `traceparent` of a logically-related
	// upstream span that should be attached as an OTel Link to the
	// receiving dispatch span. Used by SEP-2322 MRTR multi-round-trip
	// requests (issue 682) so round-2's server dispatch span links back
	// to round-1's, stitching the logical operation across separate
	// W3C traces.
	//
	// Vendor-namespaced because W3C doesn't define a `tracelink` field;
	// bare names are reserved for W3C-defined keys (see MetaKeyTraceparent).
	// The mcpkit-side convention is fixed; upstream MCP WG standardization
	// of a bare cross-SDK name is a future-discussion item — when (if)
	// that lands, this constant gets a sibling under the new name, with
	// adapters reading both during the transition window.
	MetaKeyTraceLink = "io.modelcontextprotocol/tracelink"
)

MetaKeyTraceparent and MetaKeyTracestate are the keys under which W3C Trace Context fields are carried inside an MCP request's `_meta` envelope. Their values mirror the W3C HTTP header names exactly, without the `io.modelcontextprotocol/` namespace prefix — that prefix is reserved for MCP-defined fields (see core/stateless.go), and `traceparent` / `tracestate` are W3C-defined.

View Source
const AppMIMEType = "text/html;profile=mcp-app"

AppMIMEType is the MIME type for MCP App HTML resources. This profile parameter distinguishes MCP App HTML from regular HTML — hosts use it to decide whether to render in a sandboxed iframe.

View Source
const DataURIDefaultMediaType = "text/plain;charset=US-ASCII"

DataURIDefaultMediaType is the media type assumed when a data URI omits the mediatype component (per RFC 2397 §3).

View Source
const DataURIPrefix = "data:"

DataURIPrefix is the literal prefix that all data URIs share.

View Source
const DefaultContentChunkMethod = "notifications/tools/content_chunk"

DefaultContentChunkMethod is the default notification method for streaming tool content. This is an mcpkit extension — not yet standardized in MCP spec. Override per-server via server.WithContentChunkMethod(method).

View Source
const DraftProtocolVersion2026V1 = "2026-07-28"

DraftProtocolVersion2026V1 names the in-flight draft series that carries the next round of MCP SEPs (2243, 2549, 2356, 2567, 2575, 2663, ...) ahead of their inclusion in a dated stable. Shared by every draft-targeted SEP, not specific to any one of them — see core/stateless.go for the SEP-2575 stateless-wire surfaces that key off this version string.

The CONSTANT NAME labels the draft window. The VALUE is the dated wire string the spec adopted in modelcontextprotocol/spec PR 331 (merged 2026-06-08): the prior DRAFT placeholder was replaced with the dated "2026-07-28" form, which is the literal that now appears on the wire in `MCP-Protocol-Version` headers and `_meta.io.modelcontextprotocol/protocolVersion`. Treat this constant as the source of truth — never hardcode either form.

View Source
const FileInputSchemaKey = "x-mcp-file"

FileInputSchemaKey is the JSON Schema extension keyword used to mark a string property as a file input (SEP-2356). Servers attach a FileInputDescriptor under this key on schema properties of {"type": "string", "format": "uri"} to signal "render a file picker here."

Clients that declare the fileInputs capability encode selected files as RFC 2397 data URIs and pass them as the property's string value.

View Source
const HTTPProtocolVersionHeader = "MCP-Protocol-Version"

HTTPProtocolVersionHeader is the HTTP header carrying the protocol version on every stateless request. Its value MUST equal _meta[MetaKeyProtocolVersion].

View Source
const MaxCompletionValues = 100

MaxCompletionValues is the MCP spec limit on the number of values in a completion response (schema maxItems: 100).

View Source
const McpMethodHeader = "Mcp-Method"

McpMethodHeader is the SEP-2243 standard routing header name carrying the JSON-RPC method. Streamable HTTP transports set it on every outbound request; servers MAY use it to route without parsing the body.

View Source
const McpNameHeader = "Mcp-Name"

McpNameHeader is the SEP-2243 standard routing header name carrying the per-method routable identifier — `params.name` for tools/call and prompts/get, `params.uri` for resources/read. Absent for methods whose params have no such field.

View Source
const MetaKeyAuthorizationContextID = "io.modelcontextprotocol/authorization-context-id"

Retry meta key per SEP-2643. The client MUST echo the server-issued authorizationContextId verbatim under this key on retry.

View Source
const MetaKeyBaggage = "baggage"

MetaKeyBaggage is the key under which the W3C Baggage list is carried inside an MCP request's `_meta` envelope. Bare W3C name, not under the `io.modelcontextprotocol/` namespace — same rule MetaKeyTraceparent / MetaKeyTracestate follow, because the W3C spec defines the field, not MCP.

View Source
const PerRequestClientCapsKey = "io.modelcontextprotocol/clientCapabilities"

PerRequestClientCapsKey is the SEP-2575 _meta key under which a client may declare a per-request capability override. The value is shaped like ClientCapabilities and is merged additively on top of the session-level capabilities for the duration of one request.

View Source
const PrincipalTenantSeparator = "/"

PrincipalTenantSeparator is the single character that separates the tenant prefix from the subject inside an encoded principal string. Validators in ext/auth populate Claims.Subject and Claims.Tenant as separate typed fields; consumers that need a string-form identity (session binding, webhook canonical-key, audit logs) call PrincipalFor to get the encoded form. The encoding is the canonical contract.

Pinned to "/" because it is unambiguous in OAuth subject identifiers (subjects are opaque strings; an embedded "/" would already break any tenancy-naive equality check upstream) and matches the natural Keycloak realm-URL slash layout. Changing the separator is a wire- shape change — bump a major version, do not flip it in a patch.

View Source
const StreamableHTTPAccept = "application/json, text/event-stream"

StreamableHTTPAccept is the Accept header value for Streamable HTTP requests. Per MCP spec: clients MUST include both application/json and text/event-stream.

View Source
const TasksExtensionID = "io.modelcontextprotocol/tasks"

TasksExtensionID is the protocol extension identifier for SEP-2663 Tasks. Servers advertise it under capabilities.extensions in the initialize response; clients declare support under capabilities.extensions in the initialize request (or per-request via SEP-2575 _meta).

View Source
const UIExtensionID = "io.modelcontextprotocol/ui"

UIExtensionID is the extension identifier for MCP Apps. Used in initialize handshake for both server advertisement and client capability declaration.

Variables

View Source
var (
	ErrNotDataURI         = errors.New("not a data URI")
	ErrMalformedDataURI   = errors.New("malformed data URI")
	ErrNonBase64DataURI   = errors.New("data URI is not base64-encoded")
	ErrInvalidDataURIName = errors.New("data URI name parameter is malformed")
)

Sentinel errors returned by DecodeDataURI.

View Source
var (
	ErrElicitationNotSupported    = errors.New("client does not support elicitation")
	ErrElicitationURLNotSupported = errors.New("client does not support URL-mode elicitation")
)

Sentinel errors for elicitation.

View Source
var (
	ErrFileTooLarge        = errors.New("file too large")
	ErrFileTypeNotAccepted = errors.New("file type not accepted")
)

Sentinel errors for callers that just want to test category. The typed errors below carry structured fields; these constants are useful for `errors.Is` checks.

View Source
var ErrNoRequestFunc = errors.New("server-to-client requests not available in this context")

ErrNoRequestFunc is returned when Sample() or Elicit() is called outside a session context where server-to-client requests are not available (e.g., no transport wired, or stateless mode).

View Source
var ErrNoTokenYet = errors.New("no token yet: deferring acquisition until a server challenge selects the scope")

ErrNoTokenYet is returned by a TokenSource.Token call when the source has no token to hand out yet and is deliberately deferring acquisition until the server tells it what scope to request.

Lazy OAuth sources (e.g. auth.OAuthTokenSource) return this before any operation has triggered a 401: per RFC 6750 §3.1 a least-privilege client SHOULD acquire its token using the scope= from the most recent WWW-Authenticate challenge rather than a broader catalog (PRM scopes_supported), so the source waits for that challenge instead of pre-acquiring.

The client transport treats ErrNoTokenYet specially: it sends the next request WITHOUT an Authorization header (rather than failing the request), lets the server respond with a 401 carrying the per-operation scope, and then drives acquisition through the auth-retry path. Any other error from Token is fatal to the request.

View Source
var ErrRequestStateExpired = errors.New("requestState expired")

ErrRequestStateExpired indicates the payload's expiry is in the past.

View Source
var ErrRequestStateInvalidSignature = errors.New("requestState signature invalid")

ErrRequestStateInvalidSignature indicates the HMAC signature did not match — either tampered payload or wrong key.

View Source
var ErrRequestStateMalformed = errors.New("requestState malformed")

ErrRequestStateMalformed indicates the encoded requestState couldn't be parsed (missing separator, bad base64, bad JSON inside the payload).

View Source
var ErrSamplingNotSupported = errors.New("client does not support sampling")

Sentinel errors for sampling.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

View Source
var SupportedStatelessVersions = []string{DraftProtocolVersion2026V1}

SupportedStatelessVersions enumerates the protocol versions this build speaks on the stateless wire. Returned from server/discover.

Distinct from the legacy supportedProtocolVersions list (which the initialize handshake negotiates) — the two are advertised independently. The version string itself, DraftProtocolVersion2026V1, lives in core/protocol.go since it's the draft series identifier shared across every draft-targeted SEP (2243, 2549, 2356, 2567, 2575, 2663, ...).

Functions

func AllowedRoots deprecated added in v0.1.26

func AllowedRoots(ctx context.Context) []string

AllowedRoots returns the current enforced roots for the session, or nil if no roots enforcement is configured. The returned slice is the snapshot from the allowed-roots function — it may change on the next call if client roots update.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func ApplySessionNotifyFilter added in v0.2.47

func ApplySessionNotifyFilter(ctx context.Context, dropMethods ...string) context.Context

ApplySessionNotifyFilter wraps the session's current notifyFunc with a filter that silently drops notifications whose method matches any entry in dropMethods, forwarding everything else to the inner notifyFunc. Used by execution surfaces that need to suppress notification kinds disallowed by their spec — for example, SEP-2663 forbids notifications/progress and notifications/message on tasks, so the v2 task goroutine applies this filter before invoking the inner tool handler.

No-op if the context has no session, has no notifyFunc, or dropMethods is empty.

func ClientSupportsExtension

func ClientSupportsExtension(ctx context.Context, extensionID string) bool

ClientSupportsExtension checks whether the connected client declared support for the given extension ID during the initialize handshake. Returns false if no session context is present or the client did not advertise the extension.

Usage in a tool handler:

if core.ClientSupportsExtension(ctx, "io.modelcontextprotocol/ui") {
    // client can render MCP Apps
}

func ClientSupportsExtensionForRequest added in v0.2.41

func ClientSupportsExtensionForRequest(ctx context.Context, extensionID string, requestCapsRaw json.RawMessage) bool

ClientSupportsExtensionForRequest reports whether the client supports the given extension at session level (initialize handshake) OR per-request level (SEP-2575 _meta override). Per-request opt-in is additive — it cannot revoke a session-level declaration.

requestCapsRaw is the raw JSON bytes from the SEP-2575 _meta override; the caller extracts it from a typed envelope (e.g., a json.RawMessage field tagged "io.modelcontextprotocol/clientCapabilities" inside _meta). Pass an empty slice if the request had no override.

func ClientSupportsTasks added in v0.2.41

func ClientSupportsTasks(ctx context.Context) bool

ClientSupportsTasks checks whether the connected client declared support for the SEP-2663 Tasks extension during the initialize handshake. Equivalent to ClientSupportsExtension(ctx, TasksExtensionID).

func ClientSupportsTasksV1 added in v0.2.41

func ClientSupportsTasksV1(ctx context.Context) bool

ClientSupportsTasksV1 reports whether the connected client declared the v1 ServerCapabilities.Tasks slot during the initialize handshake. Used by hybrid v1+v2 servers to dispatch tasks/* methods to the v1 path when the client opted into v1 (and not the io.modelcontextprotocol/tasks extension).

V2-only servers and clients can ignore this — see ClientSupportsTasks / ClientSupportsExtension(TasksExtensionID) instead.

func ClientSupportsUI

func ClientSupportsUI(ctx context.Context) bool

ClientSupportsUI checks whether the connected client declared support for the MCP Apps extension during the initialize handshake. Tool handlers can use this to decide whether to include UI-specific content or fall back to text-only.

func CollectResponseHeaders added in v0.2.41

func CollectResponseHeaders(ctx context.Context) map[string]string

CollectResponseHeaders returns a snapshot of the response headers staged on the current request via SetResponseHeader. HTTP transports call this after dispatch returns, before writing response headers. Returns nil when no collector was attached or no headers were staged.

func ContentChunkMethodFromContext added in v0.1.17

func ContentChunkMethodFromContext(ctx context.Context) string

ContentChunkMethodFromContext returns the configured content chunk method, or DefaultContentChunkMethod if not set.

func ContextWithSession

func ContextWithSession(ctx context.Context, notify NotifyFunc, request RequestFunc, logLevel *atomic.Pointer[LogLevel], clientCaps *ClientCapabilities, claims *Claims) context.Context

ContextWithSession returns a context carrying the session's notification state, request sender, client capabilities, and authenticated claims. Exported for use by the server sub-package; tool handlers should use EmitLog, Sample, Elicit, AuthClaims instead.

func DecodeDataURI added in v0.2.43

func DecodeDataURI(uri string) (data []byte, mediaType, filename string, err error)

DecodeDataURI parses an RFC 2397 base64 data URI as produced by EncodeDataURI. Returns the decoded payload, the media type (with the default substituted when omitted), and the decoded filename from any `name=` parameter (empty when absent).

Non-base64 data URIs are rejected with ErrNonBase64DataURI; SEP-2356 requires the base64 form because payloads are binary.

func DeriveMcpName added in v0.2.47

func DeriveMcpName(method string, params any) string

DeriveMcpName extracts the McpNameHeader value from a JSON-RPC params payload for the methods that carry a routable identifier: tools/call and prompts/get (params.name), resources/read (params.uri), and the SEP-2663 task methods tasks/get, tasks/update, tasks/cancel (params.taskId). Returns "" for any other method or when the field is missing / non-string — callers should skip emitting Mcp-Name in that case (server-side fail-closed will reject mismatches).

This MUST mirror the server's body-side derivation (the producer and the validator have to agree on which field names the routable value): see server header validation's per-method name extraction. The task cases matter on the SEP-2575 stateless wire — there is no session to route task operations by, so the server requires Mcp-Name: <taskId> and the client must supply it.

params is the Go value the producer holds — typically `map[string]any` or `map[string]string`. Other shapes (structs, json.RawMessage) return "" — callers that need struct-typed support should marshal/unmarshal to a map first.

func DetachForBackground added in v0.2.41

func DetachForBackground(ctx context.Context) context.Context

DetachForBackground returns a context suitable for background goroutines. It preserves session state (notifications, claims, capabilities) but replaces transport-scoped functions with session-level equivalents.

If the server registered a detach strategy (via SetDetachStrategy), it is used. Otherwise, falls back to context.WithoutCancel (preserves values, detaches cancellation).

Use this instead of context.WithoutCancel when spawning goroutines that need to send server-to-client requests (elicitation, sampling) after the original HTTP request has returned.

func DetachFromClient added in v0.1.25

func DetachFromClient(ctx context.Context) context.Context

DetachFromClient returns a context that preserves all session state (EmitLog, EmitSSERetry, Sample, Elicit, AuthClaims, etc.) but is NOT cancelled when the client's HTTP request context is cancelled. Use this in a tool handler that needs to continue processing after the client disconnects — e.g., long-running computations where the result is delivered via EventStore replay on reconnection.

Under the hood, this calls context.WithoutCancel (Go 1.21+), which copies all context Values but strips the parent's Done channel and any inherited deadlines/timeouts.

Important caveats:

  • Any per-tool timeout (ToolDef.Timeout, WithToolTimeout) set by the server is inherited BEFORE the handler runs. DetachFromClient strips it. If the handler needs a deadline, add one explicitly: ctx = core.DetachFromClient(ctx) ctx, cancel := context.WithTimeout(ctx, 1*time.Hour) defer cancel()

  • Session idle timeouts (WithSessionTimeout) may reap the session while the detached tool is still running if the client doesn't reconnect within the idle window. Combine with a generous WithSSEGracePeriod to keep the session alive long enough.

  • Notifications (EmitLog, EmitSSERetry) emitted after the client disconnects are buffered in the EventStore (if configured) and replayed on reconnection. Without an EventStore, they are dropped.

  • The tool's final ToolResult is still serialized as an SSE event via emitSSEEvent — if the client has disconnected but the session is alive (grace period), the event lands in the store and is replayed.

Example:

func longRunningTool(ctx context.Context, req core.ToolRequest) (core.ToolResponse, error) {
    // Hint the client to reconnect in 5 minutes
    core.EmitSSERetry(ctx, 5*time.Minute)

    // Detach: tool keeps running even if the client drops the connection
    ctx = core.DetachFromClient(ctx)

    // Long computation — ctx.Done() no longer fires on client disconnect
    result := doExpensiveWork(ctx)

    return core.TextResult(result), nil
}

func EmitContent added in v0.1.17

func EmitContent(ctx context.Context, requestID json.RawMessage, content Content)

EmitContent sends a partial content block to the client during tool execution. Each call emits a notification via the session's notify function, delivered as an SSE event on streaming transports.

On non-streaming transports (JSON response path), the notification is silently dropped — the final ToolResult is the only response.

The tool's final ToolResult should contain the complete aggregated content. Streaming chunks are a preview for responsive UX; the final result is authoritative.

Example:

func myTool(ctx context.Context, req core.ToolRequest) (core.ToolResponse, error) {
    core.EmitContent(ctx, req.RequestID, core.Content{Type: "text", Text: "Step 1..."})
    // ... work ...
    core.EmitContent(ctx, req.RequestID, core.Content{Type: "text", Text: "Step 2..."})
    return core.TextResult("Complete"), nil
}

func EmitLog deprecated

func EmitLog(ctx context.Context, level LogLevel, logger string, data any)

EmitLog sends a notifications/message to the connected client if the session's log level allows it. Safe to call even if no session context is present (no-op).

level is the severity of the message. logger is an optional logger name (typically the tool or subsystem name). data is the log payload (string, map, etc.).

Usage in a tool handler:

func myHandler(ctx context.Context, req mcpkit.ToolRequest) (mcpkit.ToolResult, error) {
    mcpkit.EmitLog(ctx, mcpkit.LogInfo, "my-tool", "processing started")
    // ... do work ...
    return mcpkit.TextResult("done"), nil
}

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func EmitProgress

func EmitProgress(ctx context.Context, token any, progress, total float64, message string)

EmitProgress sends a notifications/progress to the connected client. Safe to call even if no session context is present or if token is nil (both are no-ops).

token is the ProgressToken from the ToolRequest — pass req.ProgressToken directly. progress is the current progress value, total is the expected total (0 for indeterminate). message is an optional human-readable status string.

Usage in a tool handler:

func myHandler(ctx context.Context, req mcpkit.ToolRequest) (mcpkit.ToolResult, error) {
    mcpkit.EmitProgress(ctx, req.ProgressToken, 0, 100, "starting")
    // ... do work ...
    mcpkit.EmitProgress(ctx, req.ProgressToken, 50, 100, "halfway")
    // ... more work ...
    mcpkit.EmitProgress(ctx, req.ProgressToken, 100, 100, "done")
    return mcpkit.TextResult("complete"), nil
}

func EmitSSERetry added in v0.1.23

func EmitSSERetry(ctx context.Context, retryAfter time.Duration) error

EmitSSERetry emits an SSE "retry:" hint to the connected client on the current session's SSE stream. The retryAfter duration is rounded down to whole milliseconds and sent to the client as the next reconnection delay.

No-op on non-SSE transports (stdio, in-process, Streamable HTTP responses that chose the JSON path over SSE). Returns nil in all cases — callers don't need to branch on transport type.

Non-positive durations are dropped (no hint emitted). The servicekit writer additionally drops zero/negative retry values to prevent "reconnect immediately" thundering herds.

Thread safety: safe to call from any goroutine spawned by the handler. Delivery is asynchronous — the function returns as soon as the message is enqueued on the SSE hub writer.

Usage in a tool handler:

func longRunningTool(ctx context.Context, req mcpkit.ToolRequest) (mcpkit.ToolResult, error) {
    // Tell the client to back off for 30s before reconnecting if the
    // connection drops. The tool continues running regardless.
    mcpkit.EmitSSERetry(ctx, 30*time.Second)

    // ...do long work...

    return mcpkit.TextResult("done"), nil
}

func EncodeDataURI added in v0.2.43

func EncodeDataURI(data []byte, mediaType, filename string) string

EncodeDataURI builds an RFC 2397 base64 data URI suitable for SEP-2356 file inputs. mediaType is embedded verbatim (e.g. "image/png"); pass an empty string to omit it (the consumer will assume text/plain;charset=US-ASCII per RFC 2397). filename is optional; if non-empty it is percent-encoded and emitted as a `name=` parameter.

func EncodeMRTRStatePlaintext added in v0.2.41

func EncodeMRTRStatePlaintext(state MRTRRoundState) (string, error)

EncodeMRTRStatePlaintext returns a base64url-encoded JSON of state with no integrity guarantee — used by the dispatcher in plaintext mode when no signing key is configured. The encoded form is parseable but trivially forgeable; SEP-2322 servers without a signing key must treat it as untrusted regardless.

func EncodeMcpHeaderValue added in v0.2.47

func EncodeMcpHeaderValue(v any) (string, bool)

EncodeMcpHeaderValue produces the wire form of an SEP-2243 header value per §value-encoding. Returns the encoded string and ok=true if a header should be sent for this value, or ok=false if the header should be omitted entirely (nil arguments).

String values are emitted verbatim when they're plain ASCII without edge-whitespace or control chars; otherwise wrapped as `=?base64?{base64-utf8}?=`. Numbers use the shortest round-trip representation. Booleans use "true"/"false". Nil omits the header. Other types fall through to `fmt.Sprintf("%v", v)`; the conformance suite catches unsafe results.

func ExtractMcpHeaderParams added in v0.2.47

func ExtractMcpHeaderParams(inputSchema any) map[string]string

ExtractMcpHeaderParams walks a tool's inputSchema and returns a map from property name to header-name fragment. The HTTP header on the wire is `Mcp-Param-{fragment}` (see McpParamHeaderName).

Only primitive-typed properties (string/number/integer/boolean) participate per the SEP-2243 spec; properties with `x-mcp-header` on object/array/null types are ignored here. Tool-registration validation (see ValidateMcpHeaderSchema) catches misannotations at registration time; this extractor is producer-side and stays tolerant so a misannotated tool yields no headers rather than panicking.

Returns an empty (non-nil) map for nil schemas or schemas without any `x-mcp-header` annotations. Never returns an error.

func FileInputArrayProperty added in v0.2.43

func FileInputArrayProperty(desc FileInputDescriptor) map[string]any

FileInputArrayProperty builds a JSON Schema property for an array of file inputs. The returned map is shaped as `{"type": "array", "items": {"type": "string", "format": "uri", "x-mcp-file": desc}}`.

func FileInputProperty added in v0.2.43

func FileInputProperty(desc FileInputDescriptor) map[string]any

FileInputProperty builds a JSON Schema property for a single file input. The returned map is shaped as `{"type": "string", "format": "uri", "x-mcp-file": desc}` and is suitable for embedding in a tool's inputSchema properties.

func FileMatchesAccept added in v0.2.44

func FileMatchesAccept(mediaType, filename string, accept []string) bool

FileMatchesAccept implements the SEP-2356 accept-pattern matcher. Pattern rules — same set as the JS-side bridge matcher in ext/ui/assets/file-picker.ts so both sides agree on what passes:

  • "image/png" — exact MIME match (case-sensitive on type, as RFC 6838)
  • "image/*" — wildcard subtype match (prefix on `type/`)
  • ".pdf" — extension match against filename suffix (case-insensitive)

Empty / nil accept means anything matches.

func FileURIToPath added in v0.1.26

func FileURIToPath(uri string) string

FileURIToPath converts a file:// URI to a local filesystem path. Returns the path portion with the "file://" prefix stripped. Returns the input unchanged if it doesn't have a file:// prefix. Used by the server dispatch layer to convert client-provided root URIs to paths for IsPathAllowed.

func GenerateSchema added in v0.2.26

func GenerateSchema[T any]() json.RawMessage

GenerateSchema derives a JSON Schema from a Go type using the current schema generator. Panics if no generator is set.

func GetScopes added in v0.2.47

func GetScopes(ctx context.Context) []string

GetScopes returns the scope set granted to the authenticated caller, or nil when no claims are attached to ctx. Consistent with HasScope, absent claims and present-but-empty scopes both yield nil — callers that need to distinguish "unauthenticated" from "authenticated but no scopes" must reach for AuthClaims directly.

func GetSessionID added in v0.2.41

func GetSessionID(ctx context.Context) string

GetSessionID returns the session ID from a raw context.Context. For use in middleware that doesn't have a typed BaseContext. Returns empty string if no session context is present.

func HTTPForwardTransport added in v0.2.47

func HTTPForwardTransport(base http.RoundTripper) http.RoundTripper

HTTPForwardTransport wraps base so every outgoing request automatically carries the W3C Trace Context (`Traceparent` / `Tracestate`) and W3C Baggage (`Baggage`) headers derived from the request's Context. Tool handlers compose this into an http.Client they use for downstream API calls:

client := &http.Client{
    Transport: core.HTTPForwardTransport(http.DefaultTransport),
}
// inside a tool handler:
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com", nil)
resp, err := client.Do(req)

Behavior:

  • Reads core.TraceContextFromContext(req.Context()) and core.BaggageFromContext(req.Context()); when both are zero, the request is forwarded to base untouched (zero allocation, no header mutation).
  • When at least one is non-zero, the request is cloned (per the http.RoundTripper contract: implementations MUST NOT modify the request) and the corresponding headers are stamped on the clone.
  • Caller-set headers WIN. If the request already carries a `Traceparent` / `Tracestate` / `Baggage` header set by user code, the existing value is preserved — the wrap never clobbers explicit intent.
  • A nil base is replaced with http.DefaultTransport so callers can construct ad-hoc transports without checking. Matches the net/http stdlib defaulting convention.

Why a free function returning http.RoundTripper instead of a public struct: callers compose this into an http.Client's Transport field, and the contract surface is just RoundTrip — hiding the concrete type prevents implementation drift from becoming a breaking change. Mirrors the servicekit / oneauth / OTel-Go convention for transport wrappers.

This helper is one of the actionable pieces from SEP-2028 (mcpkit issue 739). It ships independently of the upstream spec advancing because the W3C standards it propagates are stable and the user value is concrete today.

func HasFileInputs added in v0.2.43

func HasFileInputs(ctx context.Context) bool

HasFileInputs reports whether the connected client declared the SEP-2356 fileInputs capability during the initialize handshake. Servers consult this before advertising x-mcp-file in tool inputSchemas — per spec, the keyword MUST NOT appear if the client cannot handle it.

func HasScope

func HasScope(ctx context.Context, scope string) bool

HasScope checks if the context's authenticated claims include the given scope. Returns false if no claims are present.

func InjectBaggage added in v0.2.47

func InjectBaggage(meta map[string]any, b Baggage)

InjectBaggage writes the W3C `baggage` field into an MCP `_meta` map. Empty Baggage is NOT written — `_meta` stays clean. A nil meta panics; callers MUST provide a non-nil map (mirrors InjectTraceContext).

Idempotent: calling InjectBaggage twice with the same b leaves meta in the same end state.

func InjectBaggageIntoParams added in v0.2.47

func InjectBaggageIntoParams(params any, b Baggage) any

InjectBaggageIntoParams returns a params value with `_meta.baggage` populated from b. Contract mirrors InjectTraceContextIntoParams:

  • If b is zero, params is returned unchanged.
  • If params is nil, a fresh map with just `_meta` is returned.
  • If params marshals to a JSON object, `_meta` is read/created and the baggage key is set. Existing entries are preserved (the injection never clobbers — explicit caller-set values win).
  • If params marshals but is not a JSON object (positional array, scalar, etc.), the value is returned unchanged.
  • If params fails to marshal, it is returned unchanged so the downstream encoder can surface the original error.

Used by SEP-414 P2 / P3 trace middleware extensions to relay baggage alongside `traceparent` / `tracestate` on every outbound MCP message. Caller-set values win on both wires.

func InjectTraceContext added in v0.2.47

func InjectTraceContext(meta map[string]any, tc TraceContext)

InjectTraceContext writes the W3C `traceparent` and `tracestate` fields into an MCP `_meta` map. Empty fields on tc are NOT written — `_meta` stays clean. A nil meta panics; callers MUST provide a non-nil map (mirrors the standard library's `http.Header.Set` expectations).

Idempotent: calling InjectTraceContext twice with the same tc leaves meta in the same end state.

func InjectTraceContextIntoParams added in v0.2.47

func InjectTraceContextIntoParams(params any, tc TraceContext) any

InjectTraceContextIntoParams returns a params value with `_meta.traceparent` and (if non-empty) `_meta.tracestate` populated from tc. The contract:

  • If tc is zero, params is returned unchanged.
  • If params is nil, a fresh map with just `_meta` is returned.
  • If params marshals to a JSON object, the object's `_meta` is read/created and the trace keys are added. Existing entries are preserved — explicit caller-set values win, the injection never clobbers.
  • If params marshals but is not a JSON object (positional array, scalar, etc.), the value is returned unchanged. The JSON-RPC spec permits non-object params; `_meta` is only defined inside objects.
  • If params fails to marshal, it is returned unchanged so the downstream encoder can surface the original error.

The function decodes via json.Unmarshal into a fresh map and re-encodes implicitly when the params are subsequently marshaled — it never mutates a struct or map the caller may still reference.

Used by both the SEP-414 P2 server-side outbound wraps (notifications, server-to-client requests) and the P3 client-side outbound wraps (Client.Call), so both wires apply the same precedence rule when the caller has already set `_meta.traceparent` explicitly.

func InjectTraceLinkIntoParams added in v0.2.47

func InjectTraceLinkIntoParams(params any, tc TraceContext) any

InjectTraceLinkIntoParams returns a params value with `_meta.io.modelcontextprotocol/tracelink` populated from tc. Contract mirrors InjectTraceContextIntoParams:

  • If tc is zero, params is returned unchanged.
  • If params is nil, a fresh map with just `_meta` is returned.
  • If params marshals to a JSON object, `_meta` is read/created and the tracelink key is set. Existing entries are preserved (the injection never clobbers — explicit caller-set values win).
  • If params marshals but is not a JSON object (positional array, scalar, etc.), the value is returned unchanged.

Tracestate is intentionally NOT injected — the tracelink field carries link IDENTITY only, not a full propagation context. Backends use the link's traceparent to navigate; tracestate vendor data isn't relevant to the link relationship.

Used by the SEP-2322 MRTR client loop (CallToolWithInputs) on rounds 2+ to stamp the round-1 traceparent so the server dispatch span can AddLink back to it. SEP-414 P6 / issue 682.

func IntPtr added in v0.2.41

func IntPtr(v int) *int

IntPtr returns a pointer to the given int. Convenience for setting TaskInfo.TTL.

func IsDataURI added in v0.2.43

func IsDataURI(s string) bool

IsDataURI reports whether s starts with the "data:" scheme prefix. Cheap prefix check; use DecodeDataURI to actually parse.

func IsJSONRPCResponse

func IsJSONRPCResponse(data []byte) bool

isJSONRPCResponse detects whether raw JSON is a JSON-RPC response (not a request). A response has an "id" field and either "result" or "error", but no "method" field. Used by transports to route incoming client messages that are responses to server-to-client requests (sampling/createMessage, elicitation/create).

func IsNewRootSpanRequested added in v0.2.47

func IsNewRootSpanRequested(ctx context.Context) bool

IsNewRootSpanRequested reports whether ctx was marked by WithNewRootSpan. TracerProvider adapter implementations read this to decide whether to strip any inherited parent before starting the new span. End-user code should not need to call this — use WithNewRootSpan at the call site and let the adapter do the rest.

func IsPathAllowed deprecated added in v0.1.26

func IsPathAllowed(ctx context.Context, path string) bool

IsPathAllowed reports whether the given file path falls within at least one of the session's enforced roots. Returns true if:

  • No session context is present (bare context, no sandbox)
  • No allowed-roots function is installed (no WithAllowedRoots, no client roots)
  • The allowed-roots function returns nil (no restriction)

Returns false if the allowed-roots function returns a non-nil empty slice (explicit "nothing allowed") or the path doesn't match any root.

Path matching uses cleaned, directory-prefix semantics: "/workspace" allows "/workspace/src/main.go" but NOT "/workspace-other/y". Both the root and the path are cleaned via filepath.Clean before comparison.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func IsStatelessWire added in v0.2.47

func IsStatelessWire(ctx context.Context) bool

IsStatelessWire reports whether the current request arrived over the SEP-2575 stateless wire. Returns true exactly when the stateless dispatcher attached a per-request _meta envelope to ctx via WithRequestMeta.

Push-shaped handlers (events/stream, future server-initiated streams) use this to fail fast with the spec-shape -32014 Unsupported when push is structurally impossible on the wire — the stateless dispatch path has no session and no GET SSE channel to deliver notifications onto. Non-stateless paths whose notify channel is merely temporarily absent (legacy session before a GET SSE is opened, test fixtures) keep the historical silent-drop behavior so callers can attach a channel later or assert on non-push side effects.

func IsTemplateURI added in v0.2.4

func IsTemplateURI(uri string) bool

IsTemplateURI reports whether uri is a valid RFC 6570 URI template with at least one variable expression.

func MCPToSlogLevel deprecated added in v0.2.28

func MCPToSlogLevel(level LogLevel) slog.Level

MCPToSlogLevel maps an MCP LogLevel to the nearest slog.Level.

LogDebug, LogNotice → slog.LevelDebug / slog.LevelInfo
LogInfo             → slog.LevelInfo
LogWarning          → slog.LevelWarn
LogError            → slog.LevelError
LogCritical+        → slog.LevelError + 4

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func MarshalJSON added in v0.2.19

func MarshalJSON(v any) ([]byte, error)

MarshalJSON encodes v as JSON without HTML-escaping <, >, &. Go's json.Marshal escapes these to \u003c/\u003e/\u0026 for HTML safety, but JSON-RPC payloads are not HTML contexts. This matches how Node.js and Python serialize JSON.

func MarshalNotification

func MarshalNotification(method string, params any) (json.RawMessage, error)

MarshalNotification builds a JSON-RPC notification (no id field). Exported for use by the server transport sub-package.

func McpParamHeaderName added in v0.2.47

func McpParamHeaderName(fragment string) string

McpParamHeaderName returns the wire HTTP header name for an `x-mcp-header` fragment. The HTTP header is case-insensitive but the spec-canonical spelling is `Mcp-Param-{fragment}`.

func NeedsBase64Encoding added in v0.2.47

func NeedsBase64Encoding(s string) bool

NeedsBase64Encoding reports whether a string value must be base64-wrapped for SEP-2243 header transport. Triggers:

  • any byte outside printable ASCII range (0x20-0x7E)
  • any tab character (0x09)
  • leading or trailing whitespace (including spaces)

Internal whitespace within the visible-ASCII range is fine (plain ASCII). Exported so server-side decoders and external producers can apply the same predicate without duplicating it.

func Notify

func Notify(ctx context.Context, method string, params any) bool

Notify sends an arbitrary server-to-client JSON-RPC notification. Returns false if no notification sender is available in the context. This is the low-level API; prefer EmitLog for logging notifications.

func NotifyElicitationComplete added in v0.2.41

func NotifyElicitationComplete(ctx context.Context, elicitationID string) bool

NotifyElicitationComplete sends a notifications/elicitation/complete notification to the client (SEP-1036). Call this after the user completes the out-of-band URL-mode elicitation flow so the client knows it can retry the original request.

func NotifyResourceUpdated added in v0.1.28

func NotifyResourceUpdated(ctx context.Context, uri string)

NotifyResourceUpdated sends a notifications/resources/updated to all sessions subscribed to the given resource URI. This is the handler-facing wrapper around Server.NotifyResourceUpdated — it routes through the subscription registry to fan out across sessions, not just the caller's session.

No-op if subscriptions are not enabled or no session context is present. Uses the existing MCP spec subscription mechanism (exact URI match); no wildcard or pattern extensions.

Usage in a tool handler:

func updateWidget(ctx context.Context, req core.ToolRequest) (core.ToolResponse, error) {
    db.UpdateWidget(args.ID, args.Name)
    core.NotifyResourceUpdated(ctx, "widgets/" + args.ID)
    return core.TextResult("updated"), nil
}

func NotifyResourcesChanged

func NotifyResourcesChanged(ctx context.Context)

NotifyResourcesChanged sends a notifications/resources/list_changed notification to the connected client, signaling that the set of available resources has changed. MCP App tool handlers should call this after mutating state that affects the UI resource, so clients know to re-fetch resources/list.

Note: this notifies the CURRENT session only (via sc.notify). For targeted fan-out to all sessions subscribed to a specific resource URI, use NotifyResourceUpdated(ctx, uri) instead.

Safe to call even if no session context is present (no-op).

func ParseWWWAuthenticate

func ParseWWWAuthenticate(header string) (resourceMetadata string, scopes []string, err error)

ParseWWWAuthenticate extracts the resource_metadata URL and scopes from a WWW-Authenticate: Bearer header value. Used by MCP clients to discover the PRM endpoint after receiving a 401, and to parse required scopes from a 403 insufficient_scope response.

Per MCP spec (2025-11-25): clients MUST use resource_metadata from WWW-Authenticate when present.

func PrincipalFor added in v0.2.47

func PrincipalFor(claims *Claims) string

PrincipalFor returns the string-form principal for an authenticated Claims value — Tenant + PrincipalTenantSeparator + Subject when Tenant is non-empty, otherwise Subject verbatim. This is the canonical encoder; every consumer that needs string-form identity (session binding, webhook canonical-key, audit logs) should call PrincipalFor rather than concatenate Tenant and Subject by hand. Returns "" for a nil Claims, matching ClaimsProvider's "no claims" convention.

Lives in core/ (not ext/auth) because the encoding is a property of Claims itself — consumers like experimental/ext/events and server's session-binding need it without taking an auth-extension dependency.

func ReplaceSessionNotifyFunc added in v0.2.41

func ReplaceSessionNotifyFunc(ctx context.Context, fn NotifyFunc) context.Context

ReplaceSessionNotifyFunc returns a new context with the session's notifyFunc replaced. Used by detach strategies to swap the dead POST-scoped notifyFunc with a live session-level one.

No-op if the context has no session.

func ReplaceSessionRequestFunc added in v0.2.41

func ReplaceSessionRequestFunc(ctx context.Context, fn RequestFunc) context.Context

ReplaceSessionRequestFunc returns a new context with the session's requestFunc replaced. Used by detach strategies to swap the dead POST-scoped requestFunc with a live session-level one.

No-op if the context has no session.

func SetAllowedRoots deprecated added in v0.1.26

func SetAllowedRoots(ctx context.Context, fn func() []string) context.Context

SetAllowedRoots installs an allowed-roots supplier on the session stored in ctx. Exported for the server dispatch layer to wire in the computed root set during session setup. Must be called AFTER ContextWithSession.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func SetDetachStrategy added in v0.2.41

func SetDetachStrategy(ctx context.Context, strategy DetachStrategy) context.Context

SetDetachStrategy registers a background detach strategy on the context. Called by the server's dispatch layer to provide transport-aware detachment.

func SetNotifyResourceUpdated added in v0.1.28

func SetNotifyResourceUpdated(ctx context.Context, fn func(uri string)) context.Context

SetNotifyResourceUpdated installs the resource-updated fan-out function on the session context. Exported for the server dispatch layer to wire the subscription registry's notify method. Must be called AFTER ContextWithSession.

func SetResponseHeader added in v0.2.41

func SetResponseHeader(ctx context.Context, key, value string)

SetResponseHeader stages an HTTP response header that the transport applies before writing the response body. Used by middleware and handlers that need to surface protocol metadata at the HTTP layer (e.g., the v2 task middleware emits Mcp-Name: <taskId> per SEP-2243). Silent no-op when the request was not wrapped with WithResponseHeaderCollector (e.g., non-HTTP transports).

func SetSSERetryHint added in v0.1.23

func SetSSERetryHint(ctx context.Context, fn func(ms int)) context.Context

SetSSERetryHint installs a retry-hint emitter on the session stored in ctx. Exported for the server transport layer to wire in an SSE-capable emitter during session setup. Non-SSE transports omit this call and EmitSSERetry becomes a silent no-op for handlers running under that transport.

Must be called AFTER ContextWithSession has populated the session context. Returns ctx unchanged if no session context is present (in which case the setter has nothing to attach to).

Idempotent: calling twice overwrites the previous emitter. Intended to be called exactly once per session during transport setup.

func SetSchemaGenerator added in v0.2.26

func SetSchemaGenerator(sg SchemaGenerator)

SetSchemaGenerator replaces the default schema generator used by TypedTool and TextTool. Call this once at program startup before registering tools.

core.SetSchemaGenerator(myCustomGen)

func SetSessionID added in v0.2.41

func SetSessionID(ctx context.Context, id string)

SetSessionID sets the transport-assigned session ID on the session context. Called by the server dispatch layer after session creation. No-op if no session context is present.

func SignMRTRState added in v0.2.41

func SignMRTRState(key []byte, state MRTRRoundState, ttl time.Duration) (string, error)

SignMRTRState produces an HMAC-SHA256-signed requestState token wrapping state. ttl bounds the token's validity. Same wire format as SignRequestState ("<base64url-sig>.<base64url-payload>") so the same helpers in transports/middleware that already strip / re-add the prefix work uniformly. Panics if key is empty — callers should fall back to the plaintext encoder when no signing key is configured.

func SignRequestState added in v0.2.41

func SignRequestState(key []byte, taskID string, ttl time.Duration) string

SignRequestState produces an HMAC-SHA256-signed requestState token for the given taskID, valid for ttl. The encoded form is opaque to clients and round-trippable via VerifyRequestState. Panics if key is empty.

Retained for backward-compat with legacy MRTR tokens; see the section banner above.

func StripFileInputKeywords added in v0.2.44

func StripFileInputKeywords(schema any) any

StripFileInputKeywords returns a deep-copy of the given JSON Schema (typed as `any` because ToolDef.InputSchema and ElicitationRequest's requestedSchema both accept arbitrary shapes) with every occurrence of the `x-mcp-file` keyword removed. Properties remain — only the keyword is stripped, so a tool advertising `{type: "string", format: "uri", x-mcp-file: ...}` becomes `{type: "string", format: "uri"}` for clients that did not declare the SEP-2356 fileInputs capability.

Per spec interpretation locked by panyam/mcpconformance `pending` (`src/scenarios/server/file-inputs/`): keep the property visible (so legacy clients can still call the tool with a text-input fallback) instead of hiding the whole tool. The strip walks recursively into `properties` and array `items` so both single and array-of-files shapes are handled.

The input is not mutated. Schemas in shapes other than `map[string]any` (typed structs, json.RawMessage) pass through unchanged — they wouldn't have an `x-mcp-file` keyword at the expected path anyway.

func SubjectOf added in v0.2.47

func SubjectOf(principal string) string

SubjectOf returns the subject portion of a previously-encoded principal string — everything after the first PrincipalTenantSeparator. When the string has no separator (single-tenant deployment), SubjectOf returns the input verbatim. Pair with TenantOf when a caller needs both halves from a stored principal; live requests should read Claims.Subject directly.

Examples:

SubjectOf("tenant-a/alice")   == "alice"
SubjectOf("alice")            == "alice"   // no separator → no tenant
SubjectOf("")                 == ""
SubjectOf("/alice")           == "alice"   // leading separator → empty tenant
SubjectOf("a/b/c")            == "b/c"     // splits on first separator only

func TaskBucketKey added in v0.3.1

func TaskBucketKey(ctx context.Context) string

TaskBucketKey resolves the task-store isolation bucket for this request. If a TaskBucketKeyer was installed (via WithTaskBucketKeyer / the server.WithTaskBucketKeyer option) it is used; otherwise it falls back to the session ID. This is the single accessor both the v1 and v2 task surfaces call instead of reading the session ID directly.

func TenantOf added in v0.2.47

func TenantOf(principal string) string

TenantOf returns the tenant prefix of a previously-encoded principal string, or "" when the string carries no tenant prefix. Useful when a consumer holds a principal string (e.g., the principal stored on a webhook target) rather than a live Claims value — within a request path, prefer reading Claims.Tenant directly.

Examples:

TenantOf("tenant-a/alice")    == "tenant-a"
TenantOf("alice")             == ""        // single-tenant deployment
TenantOf("")                  == ""
TenantOf("/alice")            == ""        // leading separator → empty tenant
TenantOf("a/b/c")             == "a"       // splits on first separator only

func URITemplateVars added in v0.2.4

func URITemplateVars(uri string) []string

URITemplateVars parses uri as an RFC 6570 URI template and returns the variable names it contains. Returns nil when uri is not a valid template or contains no variables (i.e. is a concrete URI).

func ValidateFileInput added in v0.2.44

func ValidateFileInput(uri string, desc *FileInputDescriptor) error

ValidateFileInput decodes a data URI argument and verifies it against a server-declared FileInputDescriptor.

  • Returns nil on success, or when desc is nil (no constraint).
  • Returns *FileTooLargeError when MaxSize is set and exceeded.
  • Returns *FileTypeNotAcceptedError when Accept is set and unmet.
  • Returns the underlying decoder error when uri is malformed.

The returned typed errors carry structured fields that the dispatcher packs into the JSON-RPC `data` object — see the conformance suite for the frozen wire shape.

func ValidateMcpHeaderSchema added in v0.2.47

func ValidateMcpHeaderSchema(inputSchema any) error

ValidateMcpHeaderSchema verifies a tool's inputSchema against SEP-2243's rules for `x-mcp-header` annotations. Returns nil if every annotation is spec-compliant (or the schema has no annotations at all), or an error describing the first violation if any property breaks the rules.

Rules per SEP-2243 §custom-headers-from-tool-parameters:

  • The keyword value MUST be a non-empty string.
  • The keyword MUST only appear on primitive-typed properties (string / number / integer / boolean).
  • The keyword value MUST contain only printable-ASCII chars excluding space, colon, tab, control chars, and non-ASCII.
  • The keyword values within a single tool MUST be unique case-insensitively (e.g. "MyField" and "myfield" collide and the tool is invalid).

Schemas not shaped as `{properties: {name: {...}}}` (or nil inputSchema) return nil — there's nothing to validate.

func VerifyRequestState added in v0.2.41

func VerifyRequestState(key []byte, state string) (taskID string, err error)

VerifyRequestState checks an incoming requestState token against the signing key and current time. Returns the embedded taskID on success. Errors:

  • ErrRequestStateMalformed: structural parse failures (split, base64, JSON)
  • ErrRequestStateInvalidSignature: signature mismatch (tampered or wrong key)
  • ErrRequestStateExpired: payload exp is in the past

Uses hmac.Equal for constant-time signature comparison. Retained for backward-compat with legacy MRTR tokens; see the section banner above.

func WithActiveSpan added in v0.2.47

func WithActiveSpan(ctx context.Context, span Span) context.Context

WithActiveSpan returns a derived context carrying span as the "currently active" mcpkit Span. SpanFromContext reads it back. The primary caller is a TracerProvider implementation: after StartSpan creates a new Span, it publishes that Span via WithActiveSpan so inner middleware and handler code can later read the same Span without re-importing the adapter. The in-tree NoopTracerProvider and the ext/otel adapter both follow this pattern.

Nil span is a no-op (ctx returned unchanged) so defensive call sites can pass through without branching. Storing a non-nil span shadows any previously-attached span on this ctx — nested StartSpan calls naturally produce a stack via context.Context derivation.

Why expose this as a public API rather than fold it into StartSpan: the adapter sub-modules (ext/otel today, third-party adapters tomorrow) live in different Go modules and can't reach an internal helper. The contract is "after StartSpan, SpanFromContext returns the same span" — each adapter enforces it by calling WithActiveSpan itself.

func WithBaggage added in v0.2.47

func WithBaggage(ctx context.Context, b Baggage) context.Context

WithBaggage returns a derived context carrying b. The dispatch layer (server trace middleware) calls this after extracting the inbound `_meta.baggage` field (or the SEP-2028 HTTP `Baggage` header bridge) so handlers can read the active baggage via BaseContext.Baggage() or BaggageFromContext.

A zero b is stored as-is so downstream calls observe an explicit "no baggage on this request" signal rather than falling through to whatever ctx may have carried before. Use this to scrub an inherited baggage value at a boundary.

func WithContentChunkMethod added in v0.1.17

func WithContentChunkMethod(ctx context.Context, method string) context.Context

WithContentChunkMethod returns a context with a custom notification method for streaming content chunks. Used by the server to plumb the configured method name through to EmitContent calls in tool handlers.

func WithNewRootSpan added in v0.2.47

func WithNewRootSpan(ctx context.Context) context.Context

WithNewRootSpan marks ctx so that the next TracerProvider.StartSpan / StartSpanLinked call produces a span with no parent — even when ctx carries an inherited parent (a core.TraceContext attached upstream, or the adapter's own internal span context, e.g. the OTel trace.SpanContext installed by a previous StartSpan).

Use this when spawning work that conceptually outlives the originating request — async tasks, events-bus producers — so the new span shows up as a root trace rather than as a long-running child nested under a short request span. Pair with StartSpanLinked plus a Link back to the originating span so the lifecycle stays navigable across the boundary.

The marker is read by the TracerProvider adapter via IsNewRootSpanRequested. Adapters that don't honor the marker (or the NoopTracerProvider) silently ignore it — the spawned span starts under whatever parent ctx happened to carry, which degrades to the same trace tree the unmarked path would produce. Best-effort by design: callers don't have to branch on adapter capability.

The marker is one-shot in spirit (it signals the upcoming StartSpan) but is NOT auto-consumed — any nested StartSpan call on the returned ctx would also see the marker. In practice this doesn't matter because the adapter's StartSpan publishes a fresh span context (and a fresh core.TraceContext) on the returned ctx, so nested calls naturally derive from the new root. Callers that want to defensively gate further reads can branch on IsNewRootSpanRequested themselves.

func WithRequestMeta added in v0.2.47

func WithRequestMeta(ctx context.Context, meta *RequestMeta) context.Context

WithRequestMeta returns a derived context carrying the validated SEP-2575 per-request _meta envelope. The stateless dispatcher calls this after validating the envelope so handlers can read the per- request capabilities via ctx.ClientCaps(). Returns ctx unchanged when meta is nil so callers can drop the nil-check at the call site.

func WithResponseHeaderCollector added in v0.2.41

func WithResponseHeaderCollector(ctx context.Context) context.Context

WithResponseHeaderCollector attaches a fresh per-request HTTP response header collector to ctx. Transports call this on the inbound request context BEFORE dispatching so middleware/handlers can stage headers via SetResponseHeader, and the transport reads them via CollectResponseHeaders before writing the response. Non-HTTP transports skip this and the staging functions become silent no-ops.

func WithStatelessClaims added in v0.2.47

func WithStatelessClaims(ctx context.Context, claims *Claims) context.Context

WithStatelessClaims threads the authenticated claims into ctx for the SEP-2575 stateless dispatch path. Symmetric to WithRequestMeta — the stateless transport calls this after CheckAuth produces the claims so handlers can read them via ctx.AuthClaims().

On the legacy wire claims live on the session (see ContextWithSession); BaseContext.AuthClaims coalesces the two sources so handlers do not special-case the wire. Returns ctx unchanged when claims is nil so callers can drop the nil-check at the call site.

func WithStatelessNotifyFunc added in v0.2.47

func WithStatelessNotifyFunc(ctx context.Context, fn NotifyFunc) context.Context

WithStatelessNotifyFunc threads a NotifyFunc onto ctx for the SEP-2575 stateless dispatch path. The stateless transport calls this when a POST request carries Accept: text/event-stream — the handler's ctx.Notify(...) writes notification frames down the open POST response stream (response-as-SSE).

On the legacy wire the notify channel lives on the sessionCtx (set when a GET SSE stream attaches, or when handlePostSSE wraps the dispatch). BaseContext.Notify coalesces the two sources so the events/stream handler (and any other streaming endpoint) does not special-case the wire.

Returns ctx unchanged when fn is nil so callers can drop the nil-check at the call site.

func WithTaskBucketKeyer added in v0.3.1

func WithTaskBucketKeyer(ctx context.Context, keyer TaskBucketKeyer) context.Context

WithTaskBucketKeyer installs a TaskBucketKeyer on the context so downstream task create/get/update/cancel sites resolve the bucket through it. A nil keyer is a no-op (the context is returned unchanged), so callers can inject unconditionally.

func WithTraceContext added in v0.2.47

func WithTraceContext(ctx context.Context, tc TraceContext) context.Context

WithTraceContext returns a derived context carrying tc. The dispatch layer (P2) calls this after extracting the inbound `_meta.traceparent` / `_meta.tracestate` fields so handlers can read the active trace context via BaseContext.TraceContext() or TraceContextFromContext.

A zero tc is stored as-is so that downstream calls observe an explicit "tracing disabled for this request" signal rather than falling through to whatever ctx may have carried before. Use this to scrub an inherited trace context at a boundary.

func WrapSessionNotifyFunc added in v0.2.47

func WrapSessionNotifyFunc(ctx context.Context, wrap func(NotifyFunc) NotifyFunc) context.Context

WrapSessionNotifyFunc replaces the session's notifyFunc with the result of applying wrap to the current one. Returns ctx unchanged when no session is attached or wrap is nil. Provided so cross-cutting concerns (trace context injection, audit logging) can wrap notify without re-implementing the sessionCtx clone dance — symmetric with WrapSessionRequestFunc.

Common usage from middleware that has the request ctx:

ctx = core.WrapSessionNotifyFunc(ctx, func(orig core.NotifyFunc) core.NotifyFunc {
    return func(method string, params any) {
        // mutate params or method, then forward
        orig(method, params)
    }
})

func WrapSessionRequestFunc added in v0.2.47

func WrapSessionRequestFunc(ctx context.Context, wrap func(RequestFunc) RequestFunc) context.Context

WrapSessionRequestFunc replaces the session's requestFunc with the result of applying wrap to the current one. Returns ctx unchanged when no session is attached, the session has no requestFunc (e.g., transports that do not support server-to-client requests), or wrap is nil. Symmetric with WrapSessionNotifyFunc.

Types

type Attribute added in v0.2.47

type Attribute struct {
	Key   string
	Value string
}

Attribute is a single key/value pair attached to a span. Both fields are strings to keep the contract surface dep-free; see Span.SetAttribute for the rationale.

type AuthError

type AuthError struct {
	Code            int
	Message         string
	WWWAuthenticate string // optional WWW-Authenticate header value
}

AuthError is returned when authentication fails.

func (*AuthError) Error

func (e *AuthError) Error() string

type AuthValidator

type AuthValidator interface {
	Validate(r *http.Request) error
}

AuthValidator validates an HTTP request and returns claims on success.

type AuthorizationDenial added in v0.2.41

type AuthorizationDenial struct {
	// Reason classifies the denial. The SEP currently defines a single value:
	// "insufficient_authorization". Additional values may be defined in future SEPs.
	Reason string `json:"reason"`

	// AuthorizationContextID is an optional correlation handle. When provided,
	// the client MUST echo it on retry in _meta under MetaKeyAuthorizationContextID.
	// Per spec, servers MUST NOT reject a retry solely because the handle is
	// absent or cannot be resolved.
	AuthorizationContextID string `json:"authorizationContextId,omitempty"`

	// CredentialDisposition signals the lifecycle relationship between a
	// newly-issued credential and existing credentials.
	//   - "replacement" (default): new credential supersedes existing
	//   - "additional": new credential coexists with existing (UC3)
	CredentialDisposition string `json:"credentialDisposition,omitempty"`

	// RemediationHints are optional MCP-level hints that complement the
	// transport's authorization challenge. Each hint has a type that
	// determines its additional members (which appear at the top level of
	// the hint object, NOT nested under a `data` field).
	RemediationHints []RemediationHint `json:"remediationHints,omitempty"`
}

AuthorizationDenial is the structured authorization denial envelope returned in JSON-RPC error data. It classifies the failure and optionally carries remediation hints.

EXPERIMENTAL: subject to rename/removal as SEP-2643 evolves.

type Baggage added in v0.2.47

type Baggage string

Baggage is the propagated W3C Baggage list for a single MCP request. The value is opaque to mcpkit core — it carries the same shape that lands on the HTTP `Baggage` header and the same shape the OTel SDK's propagator consumes. mcpkit-side validation is structural only (see isValidBaggage); semantic parsing happens in adapters.

A zero Baggage ("") means "no baggage active." Callers must treat it as a valid absence, not an error. Sibling to TraceContext but kept as a distinct type so signatures stay precise about which W3C standard they propagate.

func BaggageFromContext added in v0.2.47

func BaggageFromContext(ctx context.Context) Baggage

BaggageFromContext returns the Baggage carried by ctx, or a zero Baggage when none has been attached. Always safe to call; never panics. Use Baggage.IsZero to test for absence.

The HTTPForwardTransport reads this to decide whether to stamp the `Baggage` HTTP header on outbound tool-handler HTTP calls; the server / client trace middleware reads it to relay baggage onto outbound MCP messages.

func ExtractBaggage added in v0.2.47

func ExtractBaggage(meta map[string]any) Baggage

ExtractBaggage reads the W3C `baggage` field from an MCP `_meta` map. Returns a zero Baggage when the key is absent, when the value is not a string, when the value fails structural validation, or when the value exceeds maxBaggageLength. Mirror of ExtractTraceContext — same defensive contract: malformed input never panics, never propagates.

func ExtractBaggageFromParams added in v0.2.47

func ExtractBaggageFromParams(params json.RawMessage) Baggage

ExtractBaggageFromParams reads the W3C `baggage` field out of a JSON-RPC request's raw `params` envelope by parsing the `_meta` object inside. Returns a zero Baggage when params is nil / not a JSON object / `_meta` is absent or non-object, or when the value fails the same structural validation as ExtractBaggage. Mirror of ExtractTraceContextFromParams.

func (Baggage) IsZero added in v0.2.47

func (b Baggage) IsZero() bool

IsZero reports whether b carries no baggage at all. Provided so call sites read as a single branch ("if b.IsZero() { ... }").

type BaseContext added in v0.2.0

type BaseContext struct {
	context.Context
	// contains filtered or unexported fields
}

BaseContext provides typed access to session capabilities shared by all MCP handler types (tools, resources, prompts, completions). It embeds context.Context so stdlib functions (Done(), Deadline(), WithTimeout) work transparently.

All methods are safe to call even when the underlying capability is unavailable (e.g., EmitLog on a transport without logging is a no-op).

func FromContext added in v0.2.0

func FromContext(ctx context.Context) BaseContext

FromContext returns a BaseContext for the given context.Context. This is the bridge for code using the free-function API — existing free functions like EmitLog(ctx, ...) delegate to FromContext(ctx).EmitLog(...).

Always returns a usable BaseContext (never nil). Methods become no-ops when no session state is present.

func (BaseContext) AllowedRoots deprecated added in v0.2.0

func (bc BaseContext) AllowedRoots() []string

AllowedRoots returns the current enforced roots for the session.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (BaseContext) AuthClaims added in v0.2.0

func (bc BaseContext) AuthClaims() *Claims

AuthClaims returns the authenticated identity, or nil if unavailable.

Coalesces the two wire sources:

  • Legacy wire: claims stashed on the sessionCtx during initialize and threaded via ContextWithSession.
  • Stateless wire (SEP-2575): no session — claims threaded by the stateless transport via WithStatelessClaims after CheckAuth.

Handlers do not special-case the wire; the accessor returns the authenticated principal from whichever source populated it.

func (BaseContext) Baggage added in v0.2.47

func (bc BaseContext) Baggage() Baggage

Baggage returns the active W3C Baggage list for this request, or a zero Baggage when none has been attached. Symmetric to TraceContext() — same dispatch-layer plumbing extracts `_meta.baggage` from the inbound request and attaches it via core.WithBaggage before the handler runs.

W3C Baggage is a separate W3C standard from W3C Trace Context (they can version independently — see SEP-2028 § Predefined Groups), but they're commonly propagated together. Use this accessor to read arbitrary key=value pairs the upstream caller chose to propagate (e.g. tenant_id, user_id, feature flags).

The value is opaque to mcpkit core — the comma-separated W3C list format is parsed by adapters (the OTel propagator already implements the W3C parsing rules). Use Baggage.IsZero to detect absence.

Stamped onto outbound MCP messages alongside the trace context by the server's trace middleware, and onto outbound HTTP calls via core.HTTPForwardTransport when handlers compose it into their http.Client.

func (BaseContext) CanNotify added in v0.2.47

func (bc BaseContext) CanNotify() bool

CanNotify reports whether a notify channel is currently attached. Same resolution order as Notify — true means a subsequent Notify call will deliver, false means it will silently drop.

Use this in long-lived push-shaped handlers (events/stream, future server-initiated streams) to fail fast at admission rather than running a heartbeat loop whose ctx.Notify calls no-op. On the legacy wire CanNotify==true once a session-bound notify is attached (GET SSE open, or POST-SSE wrapping the dispatch). On the stateless wire CanNotify==true exactly when the POST request carried Accept: text/event-stream and the transport opened the response-as-SSE path.

func (BaseContext) ClientCaps added in v0.2.47

func (bc BaseContext) ClientCaps() *ClientCapabilities

ClientCaps returns the client capabilities the handler should gate against for THIS request. SEP-2322 says servers MUST only emit inputRequests for methods the client declared support for; the rule is the same on both wires, but the source of truth differs:

  • Legacy wire: capabilities are negotiated once during `initialize` and cached on the session.
  • Stateless wire (SEP-2575): no session — capabilities are declared per-request inside the _meta envelope, fresh on every call.

This accessor coalesces the two into a single typed view so handlers don't have to special-case the wire. On the legacy wire it returns the session-cached caps; on the stateless wire it returns the per- request envelope's caps (which is the only source there). Either pointer may be nil — handlers MUST nil-check before reading sub- capabilities.

Usage in a tool handler that wants to skip elicitation inputRequests when the client did not declare elicitation:

caps := ctx.ClientCaps()
if caps != nil && caps.Elicitation != nil {
    reqs["user_name"] = core.InputRequest{Method: "elicitation/create", ...}
}

func (BaseContext) ClientSupportsExtension added in v0.2.0

func (bc BaseContext) ClientSupportsExtension(extensionID string) bool

ClientSupportsExtension checks whether the client declared support for the given extension ID during initialize.

func (BaseContext) ClientSupportsUI added in v0.2.0

func (bc BaseContext) ClientSupportsUI() bool

ClientSupportsUI checks whether the client declared MCP Apps support.

func (BaseContext) DetachFromClient added in v0.2.0

func (bc BaseContext) DetachFromClient() BaseContext

DetachFromClient returns a BaseContext that preserves session state but is NOT cancelled when the client disconnects. See core.DetachFromClient.

func (BaseContext) Elicit added in v0.2.0

Elicit sends an elicitation/create request to the connected client via the legacy server-initiated push path.

SEP-2356: if the client did not declare the `fileInputs` capability, the `x-mcp-file` keyword is stripped from `req.RequestedSchema` before the request goes on the wire (spec mandate for cap-less clients — matches the `tools/list` strip on the server-side dispatch path).

Returns ErrNoRequestFunc on the SEP-2575 stateless wire (server-initiated push is forbidden on tools/call streams). Stateless handlers route elicitation through MRTR:

return ctx.RequestInput(core.InputRequests{
    "user-name": core.NewElicitationInputRequest(req),
})

Caller is responsible for any SEP-2356 strip in that path — the MRTR helpers do not introspect ctx for the cap declaration.

func (BaseContext) EmitLog deprecated added in v0.2.0

func (bc BaseContext) EmitLog(level LogLevel, logger string, data any)

EmitLog sends a log notification at the given severity level.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (BaseContext) EmitSSERetry added in v0.2.0

func (bc BaseContext) EmitSSERetry(retryAfter time.Duration) error

EmitSSERetry emits an SSE "retry:" hint to the connected client.

func (BaseContext) HasScope added in v0.2.0

func (bc BaseContext) HasScope(scope string) bool

HasScope checks if the authenticated claims include the given scope.

func (BaseContext) IsPathAllowed deprecated added in v0.2.0

func (bc BaseContext) IsPathAllowed(path string) bool

IsPathAllowed reports whether the given file path falls within the session's enforced roots.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (BaseContext) Notify added in v0.2.0

func (bc BaseContext) Notify(method string, params any) bool

Notify sends an arbitrary server-to-client JSON-RPC notification. Returns false if no notification sender is available.

Resolution order:

  1. Legacy wire: sessionCtx-attached notify func (set by the GET SSE stream or by handlePostSSE for a POST that opted into SSE streaming).
  2. Stateless wire: ctx-attached NotifyFunc threaded by WithStatelessNotifyFunc when the stateless transport handles a POST with Accept: text/event-stream (response-as-SSE).

Returns false when neither source is present — for example, a stateless POST that did NOT request SSE has no channel to push to.

func (BaseContext) NotifyResourceUpdated added in v0.2.0

func (bc BaseContext) NotifyResourceUpdated(uri string)

NotifyResourceUpdated sends a notifications/resources/updated to all sessions subscribed to the given URI.

func (BaseContext) NotifyResourcesChanged added in v0.2.0

func (bc BaseContext) NotifyResourcesChanged()

NotifyResourcesChanged sends a notifications/resources/list_changed to the current session.

func (BaseContext) Sample deprecated added in v0.2.0

Sample sends a sampling/createMessage request to the connected client via the legacy server-initiated push path.

Returns ErrNoRequestFunc on the SEP-2575 stateless wire (no per-request push channel exists — the spec forbids independent JSON-RPC requests on a tools/call response stream). Stateless handlers must enqueue a sampling request via MRTR instead:

return ctx.RequestInput(core.InputRequests{
    "draft-summary": core.NewSamplingInputRequest(req),
})

The client retries the same tools/call; the handler reads the answer via ctx.InputResponse("draft-summary") + core.DecodeSamplingInputResponse.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (BaseContext) SessionID added in v0.2.41

func (bc BaseContext) SessionID() string

SessionID returns the transport-assigned session ID for this request. Empty for stateless or stdio transports.

func (BaseContext) Span added in v0.2.47

func (bc BaseContext) Span() Span

Span returns the currently active mcpkit Span for this request, or a no-op Span when no TracerProvider has been wired. The returned Span is NEVER nil — handlers can unconditionally call SetAttribute / RecordError without nil-checking.

This is the symmetric sibling of TraceContext() above: TraceContext() surfaces the W3C trace identity propagated over the wire; Span() surfaces the local in-process span the trace middleware started around this dispatch.

The enrichment pattern:

ctx.Span().SetAttribute("mcp.auth.principal", ctx.AuthClaims().Subject)

Prefer this when you want to decorate the existing dispatch span with extra attributes — e.g., an auth middleware adding principal info, a tool handler adding result-shape hints. Use a TracerProvider directly (StartSpan + child span) when you want a separate finer-grained span instead.

Always cheap — a single ctx.Value lookup. Safe for concurrent use.

func (BaseContext) TraceContext added in v0.2.47

func (bc BaseContext) TraceContext() TraceContext

TraceContext returns the active W3C Trace Context for this request, or a zero TraceContext when none has been attached.

The dispatch layer is responsible for extracting `_meta.traceparent` / `_meta.tracestate` from inbound requests and attaching the result via core.WithTraceContext before invoking the handler — the same plumbing pattern as ProgressToken on ToolContext. Per SEP-414, both the legacy wire and the stateless wire SEP-2575 use the same `_meta` carrier shape, so this accessor returns the same value regardless of the wire the request arrived on. Handlers SHOULD NOT branch on the wire.

Callers consume the returned TraceContext as the parent of any spans the handler starts (typically by passing ctx — which carries the same value — to TracerProvider.StartSpan). Use TraceContext.IsZero to detect absence.

Until SEP-414 P2 lands (server middleware that actually extracts `_meta.traceparent` on the dispatch path), this accessor returns the zero value on every request — the contract is in place so downstream code (events EventBus, middleware) can be written and reviewed against the eventual wire.

type CancelTaskResult added in v0.2.41

type CancelTaskResult struct {
	// ResultType is the SEP-2322 polymorphic-dispatch discriminator. Always
	// "complete" for the tasks/cancel ack (defaulted by MarshalJSON when empty).
	ResultType ResultType `json:"resultType"`
}

CancelTaskResult is the (essentially empty) ack returned by tasks/cancel. Per SEP-2663, cancellation does not return task state — the client should issue tasks/get if it wants to observe the resulting "cancelled" status. Like UpdateTaskResult, the wire payload carries only the SEP-2322 resultType discriminator.

func (CancelTaskResult) MarshalJSON added in v0.2.41

func (c CancelTaskResult) MarshalJSON() ([]byte, error)

MarshalJSON defaults ResultType to ResultTypeComplete so the zero value (CancelTaskResult{}) emits the spec-compliant wire shape automatically.

type CancelTaskResultV1 added in v0.2.41

type CancelTaskResultV1 struct {
	TaskInfo
}

CancelTaskResultV1 is the v1 response to tasks/cancel. Per spec 2025-11-25: flat Result & Task intersection — same shape as GetTaskResultV1. (V2 returns an empty ack per SEP-2663.)

type CancelledTask added in v0.2.41

type CancelledTask = DetailedTask

SEP-2663 narrowed aliases — convenient names for callers that have already branched on status. The wire shape is identical to DetailedTask; the alias just communicates which fields the caller expects to be populated.

type Claims

type Claims struct {
	// Subject is the authenticated principal's raw OAuth subject — the
	// token's `sub` claim, unmodified. Use auth.PrincipalFor(claims) for
	// a tenant-aware string identity.
	Subject string `json:"sub"`

	// SessionID is the OIDC `sid` claim (RFC 8417 / OIDC core § 2),
	// when present. Populated by validators that can extract it from
	// the token — JWTValidator reads `sid` directly from MapClaims;
	// IntrospectionValidator pulls it from the bearer JWT payload
	// without re-verifying (introspection already vouched). Empty
	// when the token carries no sid (legacy issuers, opaque tokens,
	// non-OIDC ASes).
	//
	// Consumed by Back-Channel Logout fan-out (panyam/mcpkit issue
	// 709) so a single AS-revoked session can be matched against
	// any application-level state keyed on it (webhook subscriptions,
	// long-running streams, cached lookups).
	SessionID string `json:"sid,omitempty"`

	// Tenant is the multi-tenancy partition the subject belongs to.
	// Empty for single-tenant deployments or validators that don't
	// expose a tenant concept. Populated by the IntrospectionValidator
	// from the introspection response's iss claim (Keycloak realm) and
	// by future tenant-aware validators.
	Tenant string `json:"tenant,omitempty"`

	// Issuer identifies the authorization server that issued the token.
	Issuer string `json:"iss"`

	// Audience lists the intended recipients of the token (RFC 8707).
	Audience []string `json:"aud"`

	// Scopes lists the granted scopes.
	Scopes []string `json:"scope"`

	// Extra holds additional claims not covered by the standard fields.
	Extra map[string]any `json:"extra,omitempty"`
}

Claims holds the authenticated identity extracted from a validated request. Populated by AuthValidators that also implement ClaimsProvider.

Subject vs Tenant: Subject is the raw OAuth subject (the token's `sub` claim). Tenant is the multi-tenancy partition the subject belongs to, when the validator can derive one — for Keycloak, the realm name from the issuer URL. Single-tenant deployments leave Tenant empty.

Consumers that need a string-form identity (session-binding, webhook canonical-key construction, audit logs that mention "who") should call the ext/auth helper auth.PrincipalFor(claims) rather than concatenating Tenant + Subject themselves — the encoding rule (separator character, empty-tenant fallback) lives in one place.

func AuthClaims

func AuthClaims(ctx context.Context) *Claims

AuthClaims returns the authenticated identity from the context, or nil if no auth was configured or the validator does not provide claims.

Usage in a tool handler:

func myHandler(ctx context.Context, req mcpkit.ToolRequest) (mcpkit.ToolResult, error) {
    claims := mcpkit.AuthClaims(ctx)
    if claims != nil {
        log.Printf("called by %s", claims.Subject)
    }
    // ...
}

type ClaimsProvider

type ClaimsProvider interface {
	Claims(r *http.Request) *Claims
}

ClaimsProvider is an optional interface for AuthValidators that can extract identity claims from a validated request. Called only after Validate succeeds.

Validators that only perform pass/fail checks (like bearerTokenValidator) do not need to implement this interface.

type ClientCapabilities

type ClientCapabilities struct {
	Sampling    *struct{}       `json:"sampling,omitempty"`
	Roots       *RootsCap       `json:"roots,omitempty"`
	Elicitation *ElicitationCap `json:"elicitation,omitempty"`
	Tasks       *ClientTasksCap `json:"tasks,omitempty"`
	// FileInputs advertises SEP-2356 support: the client can render
	// x-mcp-file schema properties as file pickers and encode the
	// chosen files as RFC 2397 data URIs. Currently a marker — the
	// SEP does not define sub-fields yet.
	FileInputs *struct{} `json:"fileInputs,omitempty"`

	// Extensions maps extension IDs to the client's capability declaration
	// for that extension. Sent during initialize to advertise extension support.
	Extensions map[string]ClientExtensionCap `json:"extensions,omitempty"`
}

ClientCapabilities describes features the client supports.

func PerRequestClientCaps added in v0.2.41

func PerRequestClientCaps(raw json.RawMessage) *ClientCapabilities

PerRequestClientCaps decodes the SEP-2575 per-request client-capabilities override from raw JSON bytes (typically the value of _meta[PerRequestClientCapsKey] in the calling middleware's typed envelope). Returns nil if the bytes are empty or malformed — the caller falls back to session-level caps.

type ClientExtensionCap

type ClientExtensionCap struct {
	// MIMETypes lists content types the client supports for this extension.
	MIMETypes []string `json:"mimeTypes,omitempty"`
}

ClientExtensionCap describes a client's support for a specific extension. The contents are extension-specific; MCP Apps uses MIMETypes to declare which app content types the client can render.

type ClientInfo

type ClientInfo struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

ClientInfo identifies an MCP client from the initialize request.

type ClientTasksCap added in v0.2.41

type ClientTasksCap struct {
	List     *TasksCapMethod   `json:"list,omitempty"`
	Cancel   *TasksCapMethod   `json:"cancel,omitempty"`
	Requests *TasksCapRequests `json:"requests,omitempty"`
}

ClientTasksCap declares client support for tasks in ClientCapabilities. Mirrors TasksCap structure.

type CompletedTask added in v0.2.41

type CompletedTask = DetailedTask

SEP-2663 narrowed aliases — convenient names for callers that have already branched on status. The wire shape is identical to DetailedTask; the alias just communicates which fields the caller expects to be populated.

type CompletionArgument

type CompletionArgument struct {
	// Name is the argument name being completed.
	Name string `json:"name"`

	// Value is the partial input the user has typed so far.
	Value string `json:"value"`
}

CompletionArgument describes the argument being completed and the partial input so far.

type CompletionCompleteResult

type CompletionCompleteResult struct {
	Completion CompletionResult `json:"completion"`
}

CompletionCompleteResult is the typed result for completion/complete responses.

type CompletionHandler

type CompletionHandler func(ctx PromptContext, ref CompletionRef, arg CompletionArgument) (CompletionResult, error)

CompletionHandler provides autocompletion suggestions for a specific reference. ref identifies the prompt or resource being completed, arg contains the argument name and partial value. Return matching suggestions.

type CompletionRef

type CompletionRef struct {
	// Type is "ref/prompt" for prompt argument completion or "ref/resource" for resource URI completion.
	Type string `json:"type"`

	// Name is the prompt name (when Type is "ref/prompt").
	Name string `json:"name,omitempty"`

	// URI is the resource URI template (when Type is "ref/resource").
	URI string `json:"uri,omitempty"`
}

CompletionRef identifies what is being completed — a prompt argument or resource URI.

type CompletionResult

type CompletionResult struct {
	// Values is the list of completion suggestions.
	Values []string `json:"values"`

	// Total is the total number of available completions (may be larger than len(Values)).
	Total int `json:"total,omitempty"`

	// HasMore indicates there are additional completions beyond what was returned.
	HasMore bool `json:"hasMore"`
}

CompletionResult is the server's response with completion suggestions.

type Content

type Content struct {
	Type     string           `json:"type"`
	Text     string           `json:"text,omitempty"`
	MimeType string           `json:"mimeType,omitempty"`
	Data     string           `json:"data,omitempty"`
	Resource *ResourceContent `json:"resource,omitempty"`
}

Content is a single content item in a tool result. Supports text, image, audio, and embedded resource types per MCP spec.

func (*Content) UnmarshalJSON added in v0.1.21

func (c *Content) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a Content, tolerating an array-form `resource` field from peers that confuse EmbeddedResource (single) with ReadResourceResult (array). The first array element wins. See #81 for cardinality rationale.

type ContentChunk added in v0.1.17

type ContentChunk struct {
	// RequestID links the chunk to the original tools/call request.
	RequestID json.RawMessage `json:"requestId"`

	// Content is the partial content block.
	Content Content `json:"content"`
}

ContentChunk is the notification payload for a streaming content block. Sent during tool execution to deliver partial results incrementally.

type CreateMessageRequest deprecated

type CreateMessageRequest struct {
	Messages         []SamplingMessage `json:"messages"`
	SystemPrompt     string            `json:"systemPrompt,omitempty"`
	IncludeContext   string            `json:"includeContext,omitempty"` // "none", "thisServer", "allServers"
	Temperature      *float64          `json:"temperature,omitempty"`
	MaxTokens        int               `json:"maxTokens"`
	ModelPreferences *ModelPreferences `json:"modelPreferences,omitempty"`
	StopSequences    []string          `json:"stopSequences,omitempty"`
	Metadata         map[string]any    `json:"metadata,omitempty"`
	Meta             *SamplingMeta     `json:"_meta,omitempty"`
}

CreateMessageRequest is the params for a sampling/createMessage server-to-client request. The server sends this to ask the client to perform LLM inference.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type CreateMessageResult deprecated

type CreateMessageResult struct {
	Model      string  `json:"model"`
	StopReason string  `json:"stopReason,omitempty"`
	Role       string  `json:"role"`
	Content    Content `json:"content"`
}

CreateMessageResult is the client's response to a sampling/createMessage request.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func DecodeSamplingInputResponse deprecated added in v0.2.47

func DecodeSamplingInputResponse(raw json.RawMessage) (CreateMessageResult, error)

DecodeSamplingInputResponse decodes a single inputResponses entry as a CreateMessageResult — symmetric with NewSamplingInputRequest above. Used on the second tools/call round after the client has answered the sampling request.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func Sample deprecated

Sample sends a sampling/createMessage request to the connected client and blocks until the client responds with an LLM inference result.

Returns ErrNoRequestFunc if called outside a session context (e.g., no transport). Returns ErrSamplingNotSupported if the client did not declare sampling capability. Returns context.DeadlineExceeded if the context expires before the client responds.

Usage in a tool handler:

func myHandler(ctx context.Context, req mcpkit.ToolRequest) (mcpkit.ToolResult, error) {
    result, err := mcpkit.Sample(ctx, mcpkit.CreateMessageRequest{
        Messages:  []mcpkit.SamplingMessage{{Role: "user", Content: mcpkit.Content{Type: "text", Text: "summarize this"}}},
        MaxTokens: 1000,
    })
    if err != nil {
        return mcpkit.ErrorResult(err.Error()), nil
    }
    return mcpkit.TextResult(result.Content.Text), nil
}

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (*CreateMessageResult) UnmarshalJSON added in v0.1.21

func (r *CreateMessageResult) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a CreateMessageResult, tolerating an array-form `content` field (first element wins) from peers that emit the array shape. See #81.

type CreateTaskResult added in v0.2.41

type CreateTaskResult struct {
	ResultType ResultType `json:"resultType"`
	TaskInfoV2
}

CreateTaskResult is returned by tools/call when the server elects to handle the call as an async task. Per SEP-2663 it is `Result & Task` — a flat intersection where the discriminator and the task fields share one object (taskId / status / ttlMs / ... at the top level alongside resultType).

Per SEP-2663, this envelope MUST NOT carry result, error, inputRequests, or requestState — those belong on tasks/get's DetailedTask response.

Wire shape (flat — no `task` wrapper):

{"resultType": "task", "taskId": "...", "status": "working",
 "createdAt": "...", "lastUpdatedAt": "...", "ttlMs": 60000,
 "pollIntervalMs": 1000}

TaskInfoV2 is embedded so encoding/json promotes its fields to the parent (same trick DetailedTask uses); no custom MarshalJSON is needed.

type CreateTaskResultV1 added in v0.2.41

type CreateTaskResultV1 struct {
	Task TaskInfo `json:"task"`
}

CreateTaskResultV1 is returned by tools/call when a v1 task is created instead of the immediate tool result. Per spec 2025-11-25: nested under "task" key. (V1 wire format; v2 uses CreateTaskResult with resultType.)

type DetachStrategy added in v0.2.41

type DetachStrategy func(ctx context.Context) context.Context

DetachStrategy is a function that creates a background-safe context from a request-scoped context. The server registers a strategy that replaces transport-scoped functions (like requestFunc) with session-level equivalents that remain valid after the original HTTP request completes.

type DetailedTask added in v0.2.41

type DetailedTask struct {
	// ResultType is the SEP-2322 polymorphic-dispatch discriminator. For
	// tasks/get responses it is always "complete" — the JSON-RPC request
	// itself completes with this response, even when the underlying task
	// is still running. (The task lifecycle is on the Status field.)
	// MarshalJSON defaults this to ResultTypeComplete when empty so
	// existing struct literals don't have to set it.
	ResultType ResultType `json:"resultType"`

	TaskInfoV2

	// Result is inlined when Status == TaskCompleted. Includes the original
	// ToolResult (with isError flag for tool-side errors).
	Result *ToolResult `json:"result,omitempty"`

	// Error is inlined when Status == TaskFailed. Mirrors the JSON-RPC error
	// shape and represents protocol-level failures only.
	Error *TaskError `json:"error,omitempty"`

	// InputRequests is populated when Status == TaskInputRequired and lists
	// the MRTR input requests the client must satisfy via tasks/update. // SEP-2322
	InputRequests InputRequests `json:"inputRequests,omitempty"`
}

DetailedTask is the SEP-2663 discriminated union returned by tasks/get. The Status field discriminates which optional fields are populated:

  • working → no inlined payload
  • input_required → InputRequests populated
  • completed → Result populated
  • failed → Error populated
  • cancelled → no inlined payload

func (DetailedTask) MarshalJSON added in v0.2.41

func (d DetailedTask) MarshalJSON() ([]byte, error)

MarshalJSON defaults ResultType to ResultTypeComplete when empty so every tasks/get response carries the SEP-2322 polymorphic discriminator without every call site having to set it. The task lifecycle stays on Status.

type DisplayMode added in v0.1.29

type DisplayMode string

DisplayMode represents an iframe display mode for MCP Apps.

const (
	// DisplayModeInline renders the app inline within the host UI.
	DisplayModeInline DisplayMode = "inline"

	// DisplayModeFullscreen renders the app in a fullscreen overlay.
	DisplayModeFullscreen DisplayMode = "fullscreen"

	// DisplayModePIP renders the app in a picture-in-picture window.
	DisplayModePIP DisplayMode = "pip"
)

type ElicitationCap added in v0.2.41

type ElicitationCap struct {
	Form *ElicitationFormCap `json:"form,omitempty"`
	URL  *ElicitationURLCap  `json:"url,omitempty"`
}

ElicitationCap describes client support for elicitation modes. Per SEP-1036: Form is the default mode (JSON schema → form). URL mode enables out-of-band interactions where the user visits a URL.

type ElicitationCompleteParams added in v0.2.41

type ElicitationCompleteParams struct {
	ElicitationID string `json:"elicitationId"`
}

ElicitationCompleteParams is the params for the notifications/elicitation/complete notification (SEP-1036). The server sends this after the user completes an out-of-band URL-mode elicitation flow. The client uses elicitationId to correlate with the original elicitation request and may retry the denied operation.

type ElicitationFormCap added in v0.2.41

type ElicitationFormCap struct{}

ElicitationFormCap is a marker for form-mode elicitation support. Currently empty; future specs may add fields (e.g., schema constraints).

type ElicitationMeta added in v0.1.29

type ElicitationMeta struct {
	// UI contains MCP Apps presentation metadata.
	// When set, the host can render a UI resource during input collection
	// instead of falling back to the default schema-driven form.
	UI *UIMetadata `json:"ui,omitempty"`

	// RelatedTask identifies the task this request is associated with.
	// Set automatically by TaskContext.TaskElicit() so the client can
	// correlate side-channel requests with the originating task.
	RelatedTask *RelatedTaskMeta `json:"io.modelcontextprotocol/related-task,omitempty"`
}

ElicitationMeta holds protocol-level metadata for an elicitation request. Serialized as "_meta" in the elicitation/create params.

type ElicitationRequest

type ElicitationRequest struct {
	Message         string           `json:"message"`
	RequestedSchema json.RawMessage  `json:"requestedSchema,omitempty"`
	Mode            string           `json:"mode,omitempty"`          // "form" (default) or "url"
	URL             string           `json:"url,omitempty"`           // Required for url mode
	ElicitationID   string           `json:"elicitationId,omitempty"` // Required for url mode; correlates with completion notification
	Meta            *ElicitationMeta `json:"_meta,omitempty"`
}

ElicitationRequest is the params for an elicitation/create server-to-client request. The server sends this to ask the client to collect structured user input.

For form mode (default): Message + RequestedSchema are used. For URL mode (SEP-1036): Message + URL + ElicitationID are used; RequestedSchema must NOT be set.

type ElicitationResult

type ElicitationResult struct {
	Action  string         `json:"action"` // "accept", "decline", or "cancel"
	Content map[string]any `json:"content,omitempty"`
}

ElicitationResult is the client's response to an elicitation/create request.

func DecodeElicitationInputResponse added in v0.2.47

func DecodeElicitationInputResponse(raw json.RawMessage) (ElicitationResult, error)

DecodeElicitationInputResponse decodes a single inputResponses entry as an ElicitationResult.

func Elicit

Elicit sends a form-mode elicitation/create request to the connected client and blocks until the client responds with user input.

Returns ErrNoRequestFunc if called outside a session context (e.g., no transport). Returns ErrElicitationNotSupported if the client did not declare elicitation capability. Returns context.DeadlineExceeded if the context expires before the client responds.

Usage in a tool handler:

func myHandler(ctx context.Context, req mcpkit.ToolRequest) (mcpkit.ToolResult, error) {
    result, err := mcpkit.Elicit(ctx, mcpkit.ElicitationRequest{
        Message: "Which database should I connect to?",
        RequestedSchema: json.RawMessage(`{
            "type": "object",
            "properties": {"database": {"type": "string", "enum": ["prod", "staging", "dev"]}}
        }`),
    })
    if err != nil {
        return mcpkit.ErrorResult(err.Error()), nil
    }
    if result.Action != "accept" {
        return mcpkit.TextResult("User declined"), nil
    }
    return mcpkit.TextResult(fmt.Sprintf("Selected: %v", result.Content["database"])), nil
}

func ElicitURL added in v0.2.41

ElicitURL sends a URL-mode elicitation/create request to the connected client (SEP-1036). The client presents the URL to the user for out-of-band interaction. The client's bearer token remains unchanged.

Returns ErrElicitationURLNotSupported if the client did not declare URL-mode elicitation capability.

After calling this, the server should send notifications/elicitation/complete (via NotifyElicitationComplete) when the out-of-band flow is done.

type ElicitationURLCap added in v0.2.41

type ElicitationURLCap struct{}

ElicitationURLCap is a marker for URL-mode elicitation support (SEP-1036). Currently empty; future specs may add fields (e.g., allowed domains).

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 Extension

type Extension struct {
	// ID is the extension identifier (e.g., "io.mcpkit/auth").
	ID string `json:"id"`

	// SpecVersion is the version of the spec this extension implements.
	SpecVersion string `json:"specVersion"`

	// Stability indicates the maturity of this extension.
	Stability Stability `json:"stability"`

	// Config holds extension-specific configuration, if any.
	Config map[string]any `json:"config,omitempty"`
}

Extension describes a protocol extension with maturity metadata. Extensions are advertised in the initialize response under capabilities.extensions.

type ExtensionCapability

type ExtensionCapability struct {
	SpecVersion string         `json:"specVersion"`
	Stability   string         `json:"stability"`
	Config      map[string]any `json:"config,omitempty"`
}

ExtensionCapability describes a server extension's metadata in the initialize response capabilities.

Config carries extension-specific settings. SEP-2640 (Skills) uses it for the directoryRead flag added in commit 2e04c48d on 2026-06-09; other extensions define their own shape under their own reverse-domain ID. Absent or empty when the extension declares no settings (the wire-level value is then the bare empty object {}).

type ExtensionProvider

type ExtensionProvider interface {
	Extension() Extension
}

ExtensionProvider is implemented by sub-modules to declare their extension. This is how mcpkit/auth registers itself without the core module knowing about auth.

type FailedTask added in v0.2.41

type FailedTask = DetailedTask

SEP-2663 narrowed aliases — convenient names for callers that have already branched on status. The wire shape is identical to DetailedTask; the alias just communicates which fields the caller expects to be populated.

type FileInputDescriptor added in v0.2.43

type FileInputDescriptor struct {
	// Accept is the list of accepted MIME patterns or file extensions.
	// Each entry is one of:
	//   - exact MIME type:    "image/png"
	//   - wildcard subtype:   "image/*"
	//   - file extension:     ".pdf"  (matched against known MIME types)
	//
	// Empty Accept means any type is allowed.
	Accept []string `json:"accept,omitempty"`

	// MaxSize is the maximum size in bytes of the decoded file payload.
	// nil means no server-declared limit (the client may still impose its own).
	MaxSize *int `json:"maxSize,omitempty"`
}

FileInputDescriptor is the value of the x-mcp-file schema extension keyword (SEP-2356). It tells the client which file types the server will accept and the maximum decoded size in bytes.

Both fields are optional. An empty descriptor (`{}`) means "any file, any size" — the server still has to validate the payload at the transport boundary.

func ExtractFileInputDescriptor added in v0.2.43

func ExtractFileInputDescriptor(schemaProp map[string]any) *FileInputDescriptor

ExtractFileInputDescriptor pulls the x-mcp-file descriptor from a JSON Schema property, or nil if the keyword is absent.

The descriptor may have been built by FileInputProperty (Go map of FileInputDescriptor) or unmarshalled from JSON (map[string]any with "accept" / "maxSize" fields) — both shapes are handled.

type FileTooLargeData added in v0.2.44

type FileTooLargeData struct {
	Reason     string `json:"reason"` // always "file_too_large"
	Field      string `json:"field,omitempty"`
	ActualSize int    `json:"actualSize"`
	MaxSize    int    `json:"maxSize"`
}

FileTooLargeData is the wire-shape of FileTooLargeError. Frozen by the conformance suite: `{reason, actualSize, maxSize}`.

type FileTooLargeError added in v0.2.44

type FileTooLargeError struct {
	// Field is the JSON-Schema property path of the offending arg (e.g.
	// "image" or "documents[0]"). Optional — empty when the validator
	// doesn't have path context.
	Field      string
	ActualSize int
	MaxSize    int
}

FileTooLargeError reports that a decoded payload exceeds the descriptor's MaxSize. The dispatcher serializes Data() as the JSON-RPC `error.data` object on the wire.

func (*FileTooLargeError) Data added in v0.2.44

Data returns the structured wire payload for this error.

func (*FileTooLargeError) Error added in v0.2.44

func (e *FileTooLargeError) Error() string

func (*FileTooLargeError) Unwrap added in v0.2.44

func (e *FileTooLargeError) Unwrap() error

Unwrap lets errors.Is(err, ErrFileTooLarge) succeed.

type FileTypeNotAcceptedData added in v0.2.44

type FileTypeNotAcceptedData struct {
	Reason    string   `json:"reason"` // always "file_type_not_accepted"
	Field     string   `json:"field,omitempty"`
	MediaType string   `json:"mediaType"`
	Filename  string   `json:"filename,omitempty"`
	Accept    []string `json:"accept"`
}

FileTypeNotAcceptedData is the wire-shape of FileTypeNotAcceptedError. Frozen by the conformance suite: `{reason, mediaType, accept}`.

type FileTypeNotAcceptedError added in v0.2.44

type FileTypeNotAcceptedError struct {
	Field     string
	MediaType string
	Filename  string
	Accept    []string
}

FileTypeNotAcceptedError reports that a decoded payload's media type or filename does not match any pattern in the descriptor's Accept list.

func (*FileTypeNotAcceptedError) Data added in v0.2.44

Data returns the structured wire payload for this error.

func (*FileTypeNotAcceptedError) Error added in v0.2.44

func (e *FileTypeNotAcceptedError) Error() string

func (*FileTypeNotAcceptedError) Unwrap added in v0.2.44

func (e *FileTypeNotAcceptedError) Unwrap() error

Unwrap lets errors.Is(err, ErrFileTypeNotAccepted) succeed.

type Float64Histogram added in v0.2.47

type Float64Histogram interface {
	// Record records a single observation. Negative values are
	// permitted by the OTel histogram contract (e.g. time-deltas
	// expressed as negative seconds) — adapters that disallow them
	// surface the rejection via their own contract.
	Record(ctx context.Context, value float64, attrs ...Attribute)
}

Float64Histogram is a distribution-recording instrument measured in float64 units. Record receives the active context so adapters can extract exemplars from the surrounding span.

type GetTaskResult added in v0.2.41

type GetTaskResult = DetailedTask

GetTaskResult is the response shape for tasks/get. Identical to DetailedTask.

type GetTaskResultV1 added in v0.2.41

type GetTaskResultV1 struct {
	TaskInfo
}

GetTaskResultV1 is the v1 response to tasks/get. Per spec 2025-11-25: flat Result & Task intersection — task fields at the root level, no "task" wrapper. (V2 returns DetailedTask with inlined result/error/inputRequests.)

type GoAsyncResult added in v0.2.47

type GoAsyncResult struct{}

GoAsyncResult is an in-process signal returned by a tool handler when it has finished its synchronous work (e.g. gathering input via MRTR) and wants the remainder of its execution to run as a background task.

The ext/tasks middleware observes a GoAsyncResult on a tool whose Execution.TaskSupport is optional/required when the client has negotiated the io.modelcontextprotocol/tasks extension. On observation it:

  1. mints a fresh task,
  2. spawns a goroutine that re-invokes the handler with a [tasks.TaskContext] attached (the handler discovers it via [tasks.GetTaskContext] and switches to the async branch), and
  3. returns CreateTaskResult to the original caller.

The continuation goroutine is what runs the "real" work, so a handler that emits notifications/progress or notifications/message from the async branch gets the SEP-2663 G6 session-notify filter applied. A handler that returns ToolResult sync (no GoAsyncResult) does NOT get that filter, because no goroutine ever runs.

Ignored when:

  • the tool's Execution.TaskSupport is forbidden or absent
  • the client has not negotiated the tasks extension

GoAsyncResult has no wire envelope of its own — it never escapes the in-process boundary.

type HeaderMismatchData added in v0.2.47

type HeaderMismatchData struct {
	// Reason is a human-readable description, e.g.
	// "Mcp-Method header value does not match request body" or
	// "MCP-Protocol-Version header value does not match request body".
	Reason string `json:"reason"`

	// Header is the HTTP header name that triggered the mismatch.
	Header string `json:"header"`

	// Expected is what the server computed from the JSON-RPC body —
	// the value the header SHOULD have carried.
	Expected string `json:"expected"`

	// Received is what the header actually carried (empty when the
	// header was required-but-absent rather than mismatched).
	Received string `json:"received"`

	// Extra holds extension-specific context (e.g., "tool" = "create_cart"
	// for Mcp-Name failures). Decoded into the same JSON object as the
	// fixed fields above; MarshalJSON flattens on the way out.
	Extra map[string]any `json:"-"`
}

HeaderMismatchData is the typed shape of the structured `data` payload carried on every -32020 ErrCodeHeaderMismatch response. Clients decode resp.Error.Data into this to inspect which header disagreed with what value. Matches the wire shape emitted by both surfaces that use the code (SEP-2243 routing-header validation and SEP-2575 protocol-version cross-check) — see server/header_validation.go for the producer.

Extra carries any additional surface-specific key/value pairs the server tacked on (for instance, the tool name on Mcp-Name mismatch). MarshalJSON flattens Extra into the top-level object alongside the fixed fields, matching how the server emits it.

func (HeaderMismatchData) MarshalJSON added in v0.2.47

func (d HeaderMismatchData) MarshalJSON() ([]byte, error)

MarshalJSON flattens Extra keys into the top-level alongside the four fixed fields, matching server/header_validation.go's emit shape.

func (*HeaderMismatchData) UnmarshalJSON added in v0.2.47

func (d *HeaderMismatchData) UnmarshalJSON(data []byte) error

UnmarshalJSON populates the fixed fields and collects everything else into Extra so callers see the same structure regardless of which producer (SEP-2243, SEP-2575, future) emitted the response.

type InitializeResult

type InitializeResult struct {
	ProtocolVersion string             `json:"protocolVersion"`
	Capabilities    ServerCapabilities `json:"capabilities"`
	ServerInfo      ServerInfo         `json:"serverInfo"`
}

InitializeResult is the typed result for the initialize response.

type InputRequest added in v0.2.41

type InputRequest struct {
	Method string          `json:"method"`
	Params json.RawMessage `json:"params,omitempty"`
}

InputRequest is a single MRTR input request enqueued by a server during tool execution: a method (e.g., "elicitation/create", "sampling/createMessage") plus opaque params encoded per that method's request schema. // SEP-2322

func NewElicitationInputRequest added in v0.2.47

func NewElicitationInputRequest(req ElicitationRequest) InputRequest

NewElicitationInputRequest wraps an ElicitationRequest as a MRTR InputRequest. The wire method is elicitation/create. Symmetric with NewSamplingInputRequest above.

Caller is responsible for any SEP-2356 fileInputs schema stripping if the calling client may not declare the capability — the legacy ctx.Elicit does this transparently; the MRTR path is opt-in so the caller stays in control.

func NewListRootsInputRequest deprecated added in v0.2.47

func NewListRootsInputRequest() InputRequest

NewListRootsInputRequest builds the MRTR InputRequest the server sends when it needs the client's current set of workspace roots. Symmetric with NewSamplingInputRequest / NewElicitationInputRequest. The wire method is roots/list and the spec defines no params — the value carries an empty `{}` so wire decoders that branch on params shape stay on the common path. Used by the SEP-2322 `input-required-result-basic-list-roots` conformance scenario.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func NewSamplingInputRequest deprecated added in v0.2.47

func NewSamplingInputRequest(req CreateMessageRequest) InputRequest

NewSamplingInputRequest wraps a CreateMessageRequest as a MRTR InputRequest the handler can enqueue under any key in InputRequests. The wire method is sampling/createMessage, identical to the legacy server-initiated path — client-side dispatch routes either form into the same SamplingHandler.

On a marshal failure the returned InputRequest has empty Params; the dispatch path will surface that as a client-side validation error so the round trip still terminates rather than hanging.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type InputRequests added in v0.2.41

type InputRequests = map[string]InputRequest

InputRequests is the wire-format map from request key to InputRequest. Keys are server-chosen identifiers (e.g., "elicit-1") that the client echoes verbatim in the matching InputResponses entry. // SEP-2322

type InputRequiredResult added in v0.2.46

type InputRequiredResult struct {
	// ResultType is always "input_required". Defaulted by MarshalJSON when
	// empty so server handlers can build the struct without thinking about
	// it.
	ResultType ResultType `json:"resultType"`

	// InputRequests is the map of server-chosen request keys → InputRequest
	// describing what the server needs from the client. Keys are echoed back
	// verbatim by the client in the matching InputResponses entry.
	InputRequests InputRequests `json:"inputRequests,omitempty"`

	// RequestState is the opaque session-continuation token. SEP-2322 says
	// servers MUST treat any echoed value as attacker-controlled; the helper
	// API in dispatch HMAC-signs it when a key is configured.
	RequestState string `json:"requestState,omitempty"`
}

InputRequiredResult is the SEP-2322 wire envelope returned by tools/call (and other request methods, in principle) when the server needs additional input from the client before it can produce a final result. Clients retry the same request with `inputResponses` (and the echoed `requestState`) until the server returns a complete result, a CreateTaskResult, or an error.

Renamed from IncompleteResult in SEP-2322 commit de6d76fb (merged 2026-05-06) per dsp-ant request. The wire `resultType` value flipped from "incomplete" to "input_required" at the same time. SEP-2663 had not yet adopted the rename as of 2026-05-07 PM, but Caitie committed to a coherent Draft Spec + Schema at the 5/15 RC (issue comment 4384052694), so the alignment direction is "input_required" both places.

Wire-format note: the `resultType` discriminator is camelCase like every other MCP wire field — Luca confirmed camelCase is the SEP-2322 spec standard. (The upstream conformance suite briefly used snake_case but that's being corrected on their side.)

func (InputRequiredResult) MarshalJSON added in v0.2.46

func (r InputRequiredResult) MarshalJSON() ([]byte, error)

MarshalJSON defaults ResultType to ResultTypeInputRequired so handlers that build an InputRequiredResult{} literal don't have to set the discriminator.

type InputRequiredTask added in v0.2.41

type InputRequiredTask = DetailedTask

SEP-2663 narrowed aliases — convenient names for callers that have already branched on status. The wire shape is identical to DetailedTask; the alias just communicates which fields the caller expects to be populated.

type InputResponses added in v0.2.41

type InputResponses = map[string]json.RawMessage

InputResponses is the wire-format map from request key to opaque response payload. Keys MUST match those previously returned in InputRequests. The payload shape is defined by the original request method. // SEP-2322

type InstrumentConfig added in v0.2.47

type InstrumentConfig struct {
	// Description is free-form documentation surfaced by the backend.
	// May include semantic-conventions language (e.g. "Number of
	// tools/call requests dispatched."). Empty string is treated as
	// "no description" by every adapter.
	Description string

	// Unit follows the UCUM convention (https://ucum.org/) — e.g.
	// `"ms"` for milliseconds, `"By"` for bytes, `"1"` for
	// dimensionless. Empty string is treated as "no unit". Adapters
	// pass this through verbatim; backends that need a different
	// dialect (Prometheus' suffix style) translate internally.
	Unit string
}

InstrumentConfig is the resolved configuration for a single instrument: description (free-form text for observability backends to render in tooltips / docs) and unit (UCUM-style string like `"ms"`, `"By"`, `"1"`). Adapters convert these to their backend's native concept (OTel uses identical fields; Prometheus encodes unit into the metric name suffix).

Fields are exported so adapters in different go.mod can read them without a getter dance. Both fields are optional — a zero InstrumentConfig is a valid instrument with no description and no unit.

func ApplyInstrumentOptions added in v0.2.47

func ApplyInstrumentOptions(opts ...InstrumentOption) InstrumentConfig

ApplyInstrumentOptions runs opts against a fresh InstrumentConfig and returns the resolved value. Adapters call this once at the top of each factory method to translate the variadic option list into the backend's instrument construction arguments.

Provided as a helper so adapters do not duplicate the "var cfg; for _, o := range opts { o(&cfg) }; return cfg" boilerplate in three factory methods.

type InstrumentOption added in v0.2.47

type InstrumentOption func(*InstrumentConfig)

InstrumentOption mutates an InstrumentConfig during instrument construction. The Option type is exported so adapters and instrument call sites can layer their own helpers without depending on the unexported config shape — matches the ext/otel.Option pattern.

func WithDescription added in v0.2.47

func WithDescription(d string) InstrumentOption

WithDescription sets the instrument description. Last call wins on duplicate; empty string is a no-op (preserves any earlier setting).

func WithUnit added in v0.2.47

func WithUnit(u string) InstrumentOption

WithUnit sets the instrument unit. Last call wins on duplicate; empty string is a no-op.

type Int64Counter added in v0.2.47

type Int64Counter interface {
	// Add records a non-negative delta against the counter. Attributes
	// scope the measurement along the named dimensions (e.g.
	// `tool=fetch`, `code=-32601`).
	Add(ctx context.Context, value int64, attrs ...Attribute)
}

Int64Counter is a monotonic counter measured in int64 units. Add receives the active context so adapters that support exemplars (OTel SDK) can read the active span via SpanFromContext and attach it to the measurement. Adapters without exemplar support ignore ctx.

Negative values are forbidden by OTel spec; mcpkit-side instrumentation should never pass a negative value. Adapters MAY clamp or panic per their underlying SDK's contract — the seam does not enforce.

type Int64UpDownCounter added in v0.2.47

type Int64UpDownCounter interface {
	// Add records a signed delta. Negative values are permitted and
	// expected — that's the up-down contract.
	Add(ctx context.Context, value int64, attrs ...Attribute)
}

Int64UpDownCounter is a bidirectional counter measured in int64 units. Use for "currently N" gauges where the caller knows the delta (e.g. session create → +1, session expire → -1). Combine with attributes if the gauge spans dimensions (e.g. `state=initializing`).

type InvalidatingTokenSource added in v0.2.47

type InvalidatingTokenSource interface {
	TokenSource
	// Invalidate drops cached discovery, client credentials, and any
	// cached access token. The next Token call MUST re-run the full
	// flow. Safe to call multiple times — implementations clear what
	// they have and otherwise no-op.
	Invalidate()
}

InvalidatingTokenSource extends TokenSource with an explicit cache-invalidation hook. Retry layers call Invalidate before re-calling Token to force the source to re-run discovery and any client-credential resolution — necessary when the upstream authorization server has changed (SEP-2352) or when a previously cached token has been rejected with 401.

Without this hook, a TokenSource that caches an authInfo / DCR credentials pair will keep handing back the same stale token on every retry, defeating the retry. With it, the source has a defined moment to drop cached state.

Optional — implementations that have no internal cache (static tokens, the simple Bearer wrapper) need not implement it. DoWithAuthRetry checks for the interface via type assertion.

type Link struct {
	// TraceContext identifies the upstream span this link points at.
	// A zero TraceContext indicates "no link" — adapters drop such
	// entries silently rather than emit invalid OTel links.
	TraceContext TraceContext

	// Attributes are optional per-link metadata. Common keys:
	//   - "link.kind" — semantic role (`originated-from`,
	//     `sibling-task`, `spawned-by`, ...)
	//   - "mcp.method" — the originating MCP method name when the link
	//     points at a request-shaped span
	//
	// Attribute keys follow the same OTel semantic-conventions
	// guidance as Span attributes. Empty slice / nil is valid and
	// produces a link with no per-link attributes.
	Attributes []Attribute
}

Link is a causal pointer from one span to another span's identity. Use it when the spanned work has a "related-to" relationship with an upstream span that doesn't fit a parent-child lifecycle — async task execution that outlives the request that spawned it; a server reverse-call (sampling/elicitation) modelled as a detached CLIENT-kind span rather than a child of the inbound handler; an events-bus consumer processing batched messages each linked to its emitter.

The shape mirrors the OpenTelemetry spec's Link definition: a trace identity plus optional per-link attributes that observability backends use to label the link in their UI (Jaeger / Tempo / Honeycomb all render `link.kind=...` semantically rather than as generic span attributes). Per-link attributes are NOT span attributes — they describe the *relationship*, not the span itself.

TraceContext is the upstream identity (the same W3C traceparent / tracestate pair propagated on the MCP wire via _meta). Adapters silently drop links whose TraceContext is zero or fails W3C validation, so call sites can build links from `core.ExtractTraceContext` outputs without pre-filtering.

func LinkFromTraceContext added in v0.2.47

func LinkFromTraceContext(tc TraceContext) Link

LinkFromTraceContext returns a Link with only the TraceContext field set (no per-link attributes). Convenience for the common case where the link's role is obvious from context — e.g., `tasks/poll` spans pointing at the task they surveil. When you want to disambiguate multiple links on the same span (originating request vs. sibling task vs. spawned child), construct the Link literal directly with the Attributes field populated.

type LinkedTracerProvider added in v0.2.47

type LinkedTracerProvider interface {
	TracerProvider

	// StartSpanLinked is the option-at-start variant of StartSpan that
	// attaches one or more causal Links to the new span (in addition
	// to any parent extracted from ctx). Use this when the call site
	// knows all links upfront; use TracerProvider.StartSpan + Span.AddLink
	// when links are discovered mid-span.
	//
	// Implementations MUST behave identically to StartSpan for the
	// no-links case (nil or empty links slice). Each Link entry whose
	// TraceContext is zero or fails W3C validation is silently dropped
	// — defensive call sites do not have to filter.
	StartSpanLinked(ctx context.Context, name string, links []Link, attrs ...Attribute) (context.Context, Span)
}

LinkedTracerProvider extends TracerProvider with explicit support for causal links at span creation. Adapters opt in by implementing this interface alongside TracerProvider — callers reach it via the package-level core.StartSpanLinked helper, which falls back to TracerProvider.StartSpan when the configured provider does not implement LinkedTracerProvider (links silently dropped).

The capability-widening pattern (sibling interface + helper) was chosen over widening the base TracerProvider interface so that non-tracing-aware test fakes and the default NoopTracerProvider stay unchanged. The in-tree ext/otel adapter implements both interfaces; future adapters that consume an SDK with link support do the same.

type ListTasksResultV1 added in v0.2.41

type ListTasksResultV1 struct {
	Tasks      []TaskInfo `json:"tasks"`
	NextCursor string     `json:"nextCursor,omitempty"`
}

ListTasksResultV1 is the v1 response to tasks/list with cursor pagination. (Removed in v2 — tasks/list is no longer part of the protocol.)

type LogLevel deprecated

type LogLevel int

LogLevel represents MCP log severity levels (syslog-based, ascending severity). Used with logging/setLevel to control the minimum level of log notifications sent to the client, and with EmitLog to specify the severity of a message.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

const (
	LogDebug     LogLevel = iota // debug: detailed debugging information
	LogInfo                      // info: general informational messages
	LogNotice                    // notice: normal but significant events
	LogWarning                   // warning: warning conditions
	LogError                     // error: error conditions
	LogCritical                  // critical: critical conditions
	LogAlert                     // alert: action must be taken immediately
	LogEmergency                 // emergency: system is unusable
)

MCP log severity levels.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func ParseLogLevel deprecated

func ParseLogLevel(s string) (LogLevel, bool)

ParseLogLevel converts a string to a LogLevel. Returns the level and true on success, or (LogDebug, false) for unknown strings.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func SlogToMCPLevel deprecated added in v0.2.28

func SlogToMCPLevel(level slog.Level) LogLevel

SlogToMCPLevel maps a slog.Level to an MCP LogLevel.

slog.LevelDebug  (-4) → LogDebug
slog.LevelInfo   (0)  → LogInfo
slog.LevelWarn   (4)  → LogWarning
slog.LevelError  (8)  → LogError
> slog.LevelError      → LogCritical

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (LogLevel) String

func (l LogLevel) String() string

String returns the MCP wire name for the log level.

type LogMessage deprecated

type LogMessage struct {
	Level  string `json:"level"`
	Logger string `json:"logger,omitempty"`
	Data   any    `json:"data"`
}

LogMessage is the params payload for a notifications/message notification.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type LoggingTransport added in v0.2.27

type LoggingTransport struct {
	// Inner is the wrapped transport.
	Inner Transport

	// Logger receives log output. If nil, log.Default() is used.
	Logger *log.Logger

	// LogBodies controls whether full JSON-RPC message bodies are included
	// in log output. When false (default), only method names and direction
	// are logged — suitable for production. When true, full request/response
	// JSON is logged — useful for debugging but verbose.
	LogBodies bool
}

LoggingTransport is a Transport decorator that logs every JSON-RPC message flowing through the transport. Use it for wire-level debugging, conformance testing, and audit logging.

Wraps any Transport — zero cost when not used. Complements server middleware (which operates at the method level, post-deserialization) by providing raw message visibility before parsing.

Example:

inner := server.NewInProcessTransport(srv)
logged := &core.LoggingTransport{Inner: inner, Logger: log.Default()}
c := client.NewClient("", info, client.WithTransport(logged))

func (*LoggingTransport) Call added in v0.2.27

func (t *LoggingTransport) Call(ctx context.Context, req *Request) (*Response, error)

Call delegates to the inner transport and logs the request, response, and latency.

func (*LoggingTransport) Close added in v0.2.27

func (t *LoggingTransport) Close() error

Close delegates to the inner transport and logs the close.

func (*LoggingTransport) Connect added in v0.2.27

func (t *LoggingTransport) Connect(ctx context.Context) error

Connect delegates to the inner transport and logs the result.

func (*LoggingTransport) Notify added in v0.2.27

func (t *LoggingTransport) Notify(ctx context.Context, req *Request) error

Notify delegates to the inner transport and logs the notification.

func (*LoggingTransport) SessionID added in v0.2.27

func (t *LoggingTransport) SessionID() string

SessionID delegates to the inner transport.

type MCPLogHandler deprecated added in v0.2.28

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

MCPLogHandler implements slog.Handler, routing structured log records through MCP's notifications/message protocol to the connected client.

The handler respects the per-session logging/setLevel — records below the client's requested level are dropped silently. slog levels are mapped to MCP LogLevel: Debug→debug, Info→info, Warn→warning, Error→error, >Error→critical.

Create via NewMCPLogHandler inside a tool/resource/prompt handler:

func myTool(ctx core.ToolContext, req core.ToolRequest) (core.ToolResponse, error) {
    logger := slog.New(core.NewMCPLogHandler(ctx, nil))
    logger.Info("processing", "key", "value")  // → notifications/message
    ...
}

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func NewMCPLogHandler deprecated added in v0.2.28

func NewMCPLogHandler(ctx context.Context, opts *MCPLogHandlerOptions) *MCPLogHandler

NewMCPLogHandler creates an slog.Handler that sends log records as MCP notifications/message to the connected client. The ctx must carry an MCP session (as set by the dispatch layer in tool/resource/prompt handlers).

If ctx has no session (e.g., called outside a handler), the handler is a safe no-op — Enabled() returns false for all levels.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (*MCPLogHandler) Enabled added in v0.2.28

func (h *MCPLogHandler) Enabled(_ context.Context, level slog.Level) bool

Enabled reports whether the handler handles records at the given level. Returns false when: the slog level filter rejects it, the session has no logging enabled (client never called logging/setLevel), or the MCP session level threshold is above the mapped MCP level.

func (*MCPLogHandler) Handle added in v0.2.28

func (h *MCPLogHandler) Handle(_ context.Context, record slog.Record) error

Handle sends the slog record as an MCP notifications/message.

func (*MCPLogHandler) WithAttrs added in v0.2.28

func (h *MCPLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new handler with the given attributes pre-set.

func (*MCPLogHandler) WithGroup added in v0.2.28

func (h *MCPLogHandler) WithGroup(name string) slog.Handler

WithGroup returns a new handler that nests subsequent attributes under the given group name.

type MCPLogHandlerOptions deprecated added in v0.2.28

type MCPLogHandlerOptions struct {
	// Logger is the MCP logger name sent in the "logger" field of
	// notifications/message. Defaults to "" (empty).
	Logger string

	// Level sets the minimum slog level. Records below this are dropped
	// before the MCP session level check. If nil, only the session's
	// logging/setLevel threshold applies.
	Level slog.Leveler
}

MCPLogHandlerOptions configures NewMCPLogHandler.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type MRTRRoundState added in v0.2.41

type MRTRRoundState struct {
	Tool     string                     `json:"tool"`
	Answered map[string]json.RawMessage `json:"answered,omitempty"`
	Exp      int64                      `json:"exp"`
}

MRTRRoundState is the payload encoded inside an SEP-2322 ephemeral requestState token across multi-round flows. The dispatcher uses it to carry accumulated InputResponses from previous rounds back to the handler — the wire protocol only ships the current round's responses, so without this carry-over a stateless handler couldn't see history.

Tool is the tool name the token was issued for; replays against a different tool fail with ErrRequestStateInvalidSignature. Answered is the merged inputResponses map (raw, opaque per-key payloads). Exp is the unix-seconds expiry, mirroring the requestStatePayload semantics.

func DecodeMRTRStatePlaintext added in v0.2.41

func DecodeMRTRStatePlaintext(token string) (MRTRRoundState, error)

DecodeMRTRStatePlaintext parses a token produced by EncodeMRTRStatePlaintext. Returns ErrRequestStateMalformed for unparseable tokens and ErrRequestStateExpired when the embedded exp is in the past. No signature check (plaintext mode has none).

func VerifyMRTRState added in v0.2.41

func VerifyMRTRState(key []byte, token string) (MRTRRoundState, error)

VerifyMRTRState validates an incoming MRTR requestState token against the signing key + current time and returns the embedded round state. Errors:

  • ErrRequestStateMalformed: structural parse failures (split, base64, JSON)
  • ErrRequestStateInvalidSignature: signature mismatch (tampered or wrong key)
  • ErrRequestStateExpired: payload exp is in the past

Uses hmac.Equal for constant-time signature comparison.

type MetaValidationError added in v0.2.47

type MetaValidationError struct {
	// Field names the missing/invalid envelope component for diagnostics:
	// "_meta", "protocolVersion", "clientInfo", or "clientCapabilities".
	Field string
}

MetaValidationError is returned by DecodeRequestMeta when the envelope is missing or its required sub-fields are absent. Translates to JSON-RPC -32602 + HTTP 400 at the transport boundary.

func (*MetaValidationError) Error added in v0.2.47

func (e *MetaValidationError) Error() string

type MeterProvider added in v0.2.47

type MeterProvider interface {
	// Int64Counter returns a monotonic Int64Counter instrument named
	// `name`. Call sites typically use this for "events seen" style
	// counts (tools/call dispatches, JSON-RPC errors). Re-calling
	// with the same name MAY return the same underlying instrument
	// (adapter-dependent) — call sites store the returned instrument
	// once at install time and reuse it.
	Int64Counter(name string, opts ...InstrumentOption) Int64Counter

	// Float64Histogram returns a Float64Histogram instrument named
	// `name`. Use for latency / duration / size distributions where
	// percentiles matter. Adapters choose bucket boundaries — the
	// seam does not surface them so swappable backends (OTel's
	// exponential default, Prometheus' fixed-bucket variant) are
	// drop-in compatible.
	Float64Histogram(name string, opts ...InstrumentOption) Float64Histogram

	// Int64UpDownCounter returns an Int64UpDownCounter instrument
	// named `name`. Use for "currently active" gauges where the
	// caller knows the deltas (active sessions, queued requests).
	// Distinct from OTel's "observable gauge" — the seam keeps the
	// synchronous-only flavor because mcpkit's dispatch path always
	// knows the delta at the call site.
	Int64UpDownCounter(name string, opts ...InstrumentOption) Int64UpDownCounter
}

MeterProvider is the minimal metrics seam mcpkit components consume. Implementations construct instruments (counters, histograms, up-down counters) at install time and hand them to the dispatch middleware that records measurements per request.

Implementations MUST:

  • Be safe for concurrent use by multiple goroutines.
  • Return a non-nil instrument from every factory method even when the provider is a no-op — call sites do not nil-check returned instruments.
  • Treat instrument construction as the only allocation-heavy step; subsequent measurements (Add / Record) should be hot path.

The default implementation, NoopMeterProvider, returns shared no-op instrument singletons and performs no allocation on measurement.

type MethodContext added in v0.2.34

type MethodContext struct {
	BaseContext
}

MethodContext is the context passed to custom JSON-RPC method handlers registered via server.HandleMethod or server.WithMethodHandler. It embeds BaseContext with no additional methods — custom methods get the same session capabilities as other handlers (EmitLog, Sample, Elicit, etc.).

func NewMethodContext added in v0.2.34

func NewMethodContext(ctx context.Context) MethodContext

NewMethodContext constructs a MethodContext from a standard context.Context.

func (MethodContext) DetachFromClient added in v0.2.34

func (mc MethodContext) DetachFromClient() MethodContext

DetachFromClient returns a MethodContext that preserves session state but is NOT cancelled when the client disconnects.

type MissingCapabilityError added in v0.2.47

type MissingCapabilityError struct {
	Required ClientCapabilities
	Message  string
}

MissingCapabilityError is a typed error tool/resource/prompt handlers return when the per-request _meta.clientCapabilities does not declare a capability the handler needs. The stateless dispatcher detects the type via errors.As at the tools/call boundary and translates it into a JSON-RPC -32021 response carrying MissingRequiredClientCapabilityData.

Usage from inside a tool handler under the SEP-2575 wire:

if meta.ClientCapabilities.Sampling == nil {
    return core.ToolResult{}, &core.MissingCapabilityError{
        Required: core.ClientCapabilities{Sampling: &struct{}{}},
        Message:  "this tool requires the sampling capability",
    }
}

Required mirrors the shape of ClientCapabilities so the client can merge it into the next request's _meta envelope and retry without guessing.

func (*MissingCapabilityError) Error added in v0.2.47

func (e *MissingCapabilityError) Error() string

type MissingRequiredClientCapabilityData added in v0.2.47

type MissingRequiredClientCapabilityData struct {
	RequiredCapabilities ClientCapabilities `json:"requiredCapabilities"`
}

MissingRequiredClientCapabilityData is the structured error payload for ErrCodeMissingRequiredClientCapability (-32021). RequiredCapabilities mirrors the ClientCapabilities shape — the server returns the same capability object it expects the client to declare, so the client can merge it into its next request's _meta[MetaKeyClientCapabilities] and retry. Example: {"elicitation": {}} for a tool that requires elicitation.

HTTP status: 400. JSON-RPC code: -32021.

Wire-shape note: the SEP-2575 conformance scenario as of this writing checks for a string-array shape (Array.isArray + .includes("sampling")), which contradicts the schema's object shape exemplified at schema/draft/examples/MissingRequiredClientCapabilityError/. We emit the schema-correct object shape; an upstream conformance follow-up is tracked to align the test.

type ModelHint deprecated

type ModelHint struct {
	Name string `json:"name,omitempty"`
}

ModelHint provides hints about which model the server prefers for sampling.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type ModelPreferences deprecated

type ModelPreferences struct {
	Hints                []ModelHint `json:"hints,omitempty"`
	CostPriority         *float64    `json:"costPriority,omitempty"`
	SpeedPriority        *float64    `json:"speedPriority,omitempty"`
	IntelligencePriority *float64    `json:"intelligencePriority,omitempty"`
}

ModelPreferences describes the server's preferences for model selection when the client performs LLM sampling.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type NoopMeterProvider added in v0.2.47

type NoopMeterProvider struct{}

NoopMeterProvider is the default MeterProvider used when no metrics are configured. Every factory method returns a shared no-op singleton; every measurement call returns immediately without allocating. Safe to embed in tests, production wiring where metrics are disabled, and zero-overhead serve loops.

func (NoopMeterProvider) Float64Histogram added in v0.2.47

Float64Histogram returns the shared no-op histogram singleton.

func (NoopMeterProvider) Int64Counter added in v0.2.47

Int64Counter returns the shared no-op counter singleton.

func (NoopMeterProvider) Int64UpDownCounter added in v0.2.47

Int64UpDownCounter returns the shared no-op up-down counter singleton.

type NoopTracerProvider added in v0.2.47

type NoopTracerProvider struct{}

NoopTracerProvider is the default TracerProvider used when no tracing is configured. StartSpan returns the input context unchanged plus a noopSpan whose methods do nothing. Zero allocations on the hot path.

func (NoopTracerProvider) StartSpan added in v0.2.47

StartSpan returns ctx (with the no-op span published via WithActiveSpan so SpanFromContext returns the same span the caller just got back) and a no-op Span. The WithValue overhead is one pointer write per call; the noopSpan it stores is the zero-size noopSpan{} singleton, so the Noop path stays allocation-equivalent to the previous behavior while gaining contract symmetry with non-Noop providers — callers who use SpanFromContext to enrich the active span never need to branch on which provider is configured.

type NotificationHandler

type NotificationHandler func(method string, params []byte)

NotificationHandler receives server-to-client notifications (logging, progress, resource updates). Used by tests to verify notification delivery.

type NotifyFunc

type NotifyFunc func(method string, params any)

NotifyFunc sends a server-to-client JSON-RPC notification. method is the notification method (e.g., "notifications/message"). params will be JSON-marshaled as the notification's params field. This type is reusable for all server→client notifications (logging, progress, etc.).

type PingResult

type PingResult struct{}

PingResult is the typed result for ping responses. Currently empty per spec, but typed to allow future extension.

type ProgressNotification

type ProgressNotification struct {
	// ProgressToken is the token from the request's _meta.progressToken field.
	// It links this notification to the original request.
	ProgressToken any `json:"progressToken"`

	// Progress is the current progress value (e.g., bytes processed, items completed).
	Progress float64 `json:"progress"`

	// Total is the expected total value. Zero means indeterminate progress.
	Total float64 `json:"total,omitempty"`

	// Message is an optional human-readable status message.
	Message string `json:"message,omitempty"`
}

ProgressNotification is the params payload for a notifications/progress notification. Servers send this during long-running operations to report progress to the client. The ProgressToken must match the token from the client's original request _meta.

type PromptArgument

type PromptArgument struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Required    bool   `json:"required,omitempty"`

	// Schema is an optional JSON Schema describing the expected value shape
	// for this argument. Mirrors ToolDef.InputSchema: typically a
	// map[string]any with "type", "enum", "minimum", etc. Arbitrary JSON
	// Schema keywords ($ref, $defs, additionalProperties, ...) are preserved
	// as-is through registration, serialization, and client deserialization.
	//
	// Enforced server-side: when set, the dispatcher validates incoming
	// argument values against the schema before invoking the handler and
	// returns -32602 Invalid Params with a structured errors list on
	// failure (#184). Arguments without a Schema bypass validation.
	// Use server.WithSchemaValidation(false) to opt out of call-time
	// validation if you prefer to validate in the handler.
	Schema any `json:"schema,omitempty"`
}

PromptArgument describes a single argument to a prompt.

type PromptContext added in v0.2.0

type PromptContext struct {
	BaseContext
	// contains filtered or unexported fields
}

PromptContext is the context passed to PromptHandler and CompletionHandler functions. It embeds BaseContext and adds SEP-2322 MRTR accessors symmetric with ToolContext — a prompts/get handler can branch on `ctx.HasInputResponses()`, return `ctx.RequestInput(...)` on the first call, and decode `ctx.InputResponse("key")` on the second.

func NewPromptContext added in v0.2.0

func NewPromptContext(ctx context.Context) PromptContext

NewPromptContext constructs a PromptContext from a standard context.Context.

func NewPromptContextWithMRTR added in v0.2.47

func NewPromptContextWithMRTR(ctx context.Context, inputResponses InputResponses, requestState string) PromptContext

NewPromptContextWithMRTR constructs a PromptContext for an SEP-2322 MRTR retry: the inputResponses/requestState the client echoed back into the prompts/get request. Called by the dispatch layer after parsing the envelope; handlers read the values via ctx.InputResponse / ctx.InputResponses / ctx.RequestState.

func (PromptContext) DetachFromClient added in v0.2.0

func (pc PromptContext) DetachFromClient() PromptContext

DetachFromClient returns a PromptContext that preserves session state but is NOT cancelled when the client disconnects.

func (PromptContext) HasInputResponses added in v0.2.47

func (pc PromptContext) HasInputResponses() bool

HasInputResponses reports whether the client echoed any inputResponses back.

func (PromptContext) InputResponse added in v0.2.47

func (pc PromptContext) InputResponse(key string) json.RawMessage

InputResponse returns the raw response payload for a specific request key from the inputResponses map, or nil if the key is missing.

func (PromptContext) InputResponses added in v0.2.47

func (pc PromptContext) InputResponses() InputResponses

InputResponses returns the SEP-2322 inputResponses map the client echoed back into this prompts/get. Nil on the first call.

func (PromptContext) RequestInput added in v0.2.47

func (pc PromptContext) RequestInput(reqs InputRequests) (InputRequiredResult, error)

RequestInput is the SEP-2322 ephemeral retry primitive for prompts/get. Symmetric with ToolContext.RequestInput; the dispatch layer reshapes the InputRequiredResult onto the wire with a freshly-minted requestState.

func (PromptContext) RequestState added in v0.2.47

func (pc PromptContext) RequestState() string

RequestState returns the SEP-2322 requestState token the client echoed back. Empty on the first call. Already verified by dispatch when a signing key is configured.

type PromptDef

type PromptDef struct {
	// Name is the prompt identifier used in prompts/get.
	Name string `json:"name"`

	// Title is an optional display title.
	Title string `json:"title,omitempty"`

	// Description explains what this prompt does.
	Description string `json:"description,omitempty"`

	// Arguments defines the parameters this prompt accepts.
	Arguments []PromptArgument `json:"arguments,omitempty"`

	// Annotations holds optional metadata for this prompt.
	Annotations map[string]any `json:"annotations,omitempty"`

	// Timeout is a per-prompt execution timeout. Not serialized to clients.
	Timeout time.Duration `json:"-"`
}

PromptDef describes a prompt exposed via MCP.

type PromptHandler

type PromptHandler func(ctx PromptContext, req PromptRequest) (PromptResponse, error)

PromptHandler generates prompt messages, optionally using arguments.

Returns the sealed PromptResponse interface — handlers typically return a PromptResult literal which satisfies the interface.

type PromptMessage

type PromptMessage struct {
	Role    string  `json:"role"`
	Content Content `json:"content"` // reuses Content from tool.go
}

PromptMessage is a single message in a prompt result.

func (*PromptMessage) UnmarshalJSON added in v0.1.21

func (m *PromptMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a PromptMessage, tolerating an array-form `content` field from peers that emit the array shape by mistake. First element wins. See #81.

type PromptRequest

type PromptRequest struct {
	Name      string
	Arguments map[string]any

	// InputResponses is the SEP-2322 ephemeral MRTR retry payload — the
	// client echoes the inputResponses map back into the SAME prompts/get
	// request that previously returned an InputRequiredResult. Symmetric
	// with ToolRequest.InputResponses. Nil on the first call.
	InputResponses InputResponses

	// RequestState is the opaque session-continuation token the client
	// echoed back from a previous InputRequiredResult. The dispatch layer
	// verifies it (HMAC when a key is configured) before invoking the
	// handler. Empty on the first call.
	RequestState string
}

PromptRequest is the validated input passed to a PromptHandler.

Arguments holds the decoded JSON values from the prompts/get request, keyed by argument name. Values retain their JSON types after decode: strings stay as string, numbers become float64, booleans stay bool, objects become map[string]any, arrays become []any. Handlers type-assert as needed. This shape mirrors how tool handlers receive ToolRequest.Arguments (raw JSON), but pre-decoded for ergonomic access — a prompt argument count is tiny, so eager decode is fine. See #87.

type PromptResponse added in v0.2.47

type PromptResponse interface {
	// contains filtered or unexported methods
}

PromptResponse is the sealed interface returned by PromptHandler implementations. Today only PromptResult (the sync wire envelope) implements it; a future InputRequiredResult PromptResponse impl plugs in by adding a one-line promptResponse() method (see issue #452 / SEP-2322 prompt scenarios).

The interface is sealed via the unexported promptResponse() marker so external types cannot impersonate a core response variant.

type PromptResult

type PromptResult struct {
	Description string          `json:"description,omitempty"`
	Messages    []PromptMessage `json:"messages"`
}

PromptResult is the response from a prompt handler.

type PromptsCap

type PromptsCap struct {
	ListChanged bool `json:"listChanged,omitempty"`
}

PromptsCap describes the server's prompts capability.

type PromptsListResult

type PromptsListResult struct {
	Prompts    []PromptDef `json:"prompts"`
	NextCursor string      `json:"nextCursor,omitempty"`

	// TTLMs is the SEP-2549 cache-freshness hint in integer milliseconds.
	// See ToolsListResult.TTLMs for full semantics — nil/absent and &0 are
	// both "immediately stale", &N>0 is "fresh for N milliseconds".
	TTLMs *int `json:"ttlMs,omitempty"`

	// CacheScope is the SEP-2549 cache-scope hint. See ToolsListResult.CacheScope.
	CacheScope string `json:"cacheScope,omitempty"`
}

PromptsListResult is the typed result for prompts/list responses.

type PropertyBuilder added in v0.2.47

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

PropertyBuilder is a fluent editor over one property's schema. All setter methods chain.

func (*PropertyBuilder) Default added in v0.2.47

func (p *PropertyBuilder) Default(v any) *PropertyBuilder

Default sets the `default` field. The value should match the property's JSON type.

func (*PropertyBuilder) Desc added in v0.2.47

Desc sets the `description` field on the property.

func (*PropertyBuilder) End added in v0.2.47

func (p *PropertyBuilder) End() *SchemaBuilder

End returns the parent SchemaBuilder. Use when a chain wants to step back up to add more properties or call Require with multiple names — purely a style choice; sequential `s.Prop(...)` calls work without it.

func (*PropertyBuilder) Enum added in v0.2.47

func (p *PropertyBuilder) Enum(values ...any) *PropertyBuilder

Enum sets the `enum` field. Values are stored verbatim as a JSON array; the property's `type` should be set separately when needed.

func (*PropertyBuilder) Max added in v0.2.47

Max sets `maximum` (number-typed properties).

func (*PropertyBuilder) MaxLength added in v0.2.47

func (p *PropertyBuilder) MaxLength(n int) *PropertyBuilder

MaxLength sets `maxLength` (string-typed properties).

func (*PropertyBuilder) Min added in v0.2.47

Min sets `minimum` (number-typed properties).

func (*PropertyBuilder) MinLength added in v0.2.47

func (p *PropertyBuilder) MinLength(n int) *PropertyBuilder

MinLength sets `minLength` (string-typed properties).

func (*PropertyBuilder) Pattern added in v0.2.47

func (p *PropertyBuilder) Pattern(re string) *PropertyBuilder

Pattern sets the `pattern` field (string-typed properties), a regex constraint per JSON Schema spec.

func (*PropertyBuilder) Replace added in v0.2.47

func (p *PropertyBuilder) Replace(schema map[string]any) *PropertyBuilder

Replace swaps the property's entire schema with the supplied map. Use for nullable (anyOf with null), record-of-union, and any JSON Schema 2020-12 feature the typed setters don't express. The map's keys land at the property's top level — caller is responsible for the wire shape.

func (*PropertyBuilder) Required added in v0.2.47

func (p *PropertyBuilder) Required() *PropertyBuilder

Required adds this property's name to the parent schema's `required` array. Idempotent. Equivalent to `builder.Require(p.name)`.

func (*PropertyBuilder) Type added in v0.2.47

Type sets the JSON Schema `type` field ("string", "number", "integer", "boolean", "object", "array", "null"). Replaces any previous type value.

type RefValidator

type RefValidator interface {
	ValidateRefs(tools []ToolDef, resourceURIs []string, templateURIs []string) []string
}

RefValidator is an optional interface that ExtensionProviders can implement to validate tool-to-resource references at server startup. The server calls ValidateRefs for each extension that implements this interface, passing all registered tools and the URIs of registered resources and templates. Returns a list of human-readable warning messages (empty if all refs resolve).

type RelatedTaskMeta added in v0.2.41

type RelatedTaskMeta struct {
	TaskID string `json:"taskId"`
}

RelatedTaskMeta identifies a task associated with a result. Per MCP spec, tasks/result responses MUST include this in _meta["io.modelcontextprotocol/related-task"].

type RemediationHint added in v0.2.41

type RemediationHint struct {
	// Type identifies the remediation mechanism. SEP-defined values:
	// "url", "oauth_authorization_details".
	Type string

	// Extra carries type-specific members. These are flattened to the
	// top level of the hint object on marshal (per SEP wire format).
	Extra map[string]any
}

RemediationHint is a single remediation suggestion within an authorization denial. Per SEP-2643, each hint has a `type` field plus zero or more type-specific members at the **top level** of the object (not nested).

To match the SEP wire format, this type uses custom JSON marshaling that flattens Extra fields onto the top level alongside `type`.

Example wire format for the oauth_authorization_details hint:

{
  "type": "oauth_authorization_details",
  "authorization_details": [ ... ]
}

EXPERIMENTAL: subject to rename/removal as SEP-2643 evolves.

func OAuthAuthorizationDetailsHint added in v0.2.41

func OAuthAuthorizationDetailsHint(authorizationDetails any) RemediationHint

OAuthAuthorizationDetailsHint creates a SEP-2643 remediation hint of type "oauth_authorization_details" carrying an RFC 9396 authorization_details array. Used for UC2 example 2 (RAR) and UC3 (additional credential).

func URLHint added in v0.2.41

func URLHint() RemediationHint

URLHint creates a SEP-2643 remediation hint of type "url". Used for UC1 (URL-based approval composed with URLElicitationRequiredError).

func (RemediationHint) MarshalJSON added in v0.2.41

func (h RemediationHint) MarshalJSON() ([]byte, error)

MarshalJSON flattens Extra at the top level of the JSON object, alongside the "type" field, per SEP-2643.

func (*RemediationHint) UnmarshalJSON added in v0.2.41

func (h *RemediationHint) UnmarshalJSON(b []byte) error

UnmarshalJSON splits the "type" field from the other top-level members, reversing the flattening done by MarshalJSON.

type Request

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

Request is a JSON-RPC 2.0 request envelope.

func (*Request) IsNotification

func (r *Request) IsNotification() bool

IsNotification returns true if this request has no ID (JSON-RPC notification).

type RequestFunc

type RequestFunc func(ctx context.Context, method string, params any) (json.RawMessage, error)

RequestFunc sends a server-to-client JSON-RPC request and blocks until the client sends a response. method is the JSON-RPC method (e.g., "sampling/createMessage"). params will be JSON-marshaled as the request's params field. Returns the raw JSON result on success, or an error on timeout, transport failure, or JSON-RPC error from the client.

type RequestMeta added in v0.2.47

type RequestMeta struct {
	ProtocolVersion    string              `json:"io.modelcontextprotocol/protocolVersion"`
	ClientInfo         *ClientInfo         `json:"io.modelcontextprotocol/clientInfo"`
	ClientCapabilities *ClientCapabilities `json:"io.modelcontextprotocol/clientCapabilities"`

	// LogLevel is set when the client opts in to log frames for this
	// request via _meta[MetaKeyLogLevel]. Empty means no logging.
	LogLevel string `json:"io.modelcontextprotocol/logLevel,omitempty"`
}

RequestMeta is the SEP-2575 per-request envelope. Every stateless request MUST carry one in params._meta.

Decoded via DecodeRequestMeta from a raw params blob; a missing or malformed envelope produces a typed *MetaValidationError that the dispatcher translates into a -32602 / HTTP 400 response.

func DecodeRequestMeta added in v0.2.47

func DecodeRequestMeta(rawParams json.RawMessage) (*RequestMeta, error)

DecodeRequestMeta extracts the SEP-2575 _meta envelope from raw params. Returns a typed *MetaValidationError when the envelope is absent or any required sub-field (protocolVersion, clientInfo, clientCapabilities) is missing; the dispatcher maps these to -32602 / HTTP 400.

An absent params (empty raw) is treated as "missing _meta" — the wire requires _meta on every stateless request.

func RequestMetaFromContext added in v0.2.47

func RequestMetaFromContext(ctx context.Context) *RequestMeta

RequestMetaFromContext returns the validated SEP-2575 per-request _meta envelope attached by the stateless dispatcher, or nil if the call did not arrive over the stateless wire. Handlers that just want to check whether a capability is declared should prefer the typed ctx.ClientCaps() accessor; this raw view is for the rare path that needs the full envelope.

type ResourceContent

type ResourceContent struct {
	URI      string `json:"uri"`
	MimeType string `json:"mimeType,omitempty"`
	Text     string `json:"text,omitempty"`
	Blob     string `json:"blob,omitempty"`
}

ResourceContent is an embedded resource reference in a tool result.

type ResourceContentMeta

type ResourceContentMeta struct {
	// UI contains MCP Apps presentation metadata.
	UI *UIMetadata `json:"ui,omitempty"`
}

ResourceContentMeta holds per-content metadata in resources/read responses. Takes precedence over the resource-level metadata from resources/list.

type ResourceContext added in v0.2.0

type ResourceContext struct {
	BaseContext
}

ResourceContext is the context passed to ResourceHandler and TemplateHandler functions. It embeds BaseContext with no additional methods — resources don't support progress or content streaming.

func NewResourceContext added in v0.2.0

func NewResourceContext(ctx context.Context) ResourceContext

NewResourceContext constructs a ResourceContext from a standard context.Context.

func (ResourceContext) DetachFromClient added in v0.2.0

func (rc ResourceContext) DetachFromClient() ResourceContext

DetachFromClient returns a ResourceContext that preserves session state but is NOT cancelled when the client disconnects.

type ResourceDef

type ResourceDef struct {
	// URI uniquely identifies this resource.
	URI string `json:"uri"`

	// Name is a human-readable short name.
	Name string `json:"name"`

	// Title is an optional display title.
	Title string `json:"title,omitempty"`

	// Description explains what this resource provides.
	Description string `json:"description,omitempty"`

	// MimeType is the MIME type of the resource content.
	MimeType string `json:"mimeType,omitempty"`

	// Annotations holds optional metadata for this resource.
	Annotations map[string]any `json:"annotations,omitempty"`

	// Timeout is a per-resource execution timeout. Not serialized to clients.
	Timeout time.Duration `json:"-"`
}

ResourceDef describes a resource exposed via MCP.

type ResourceHandler

type ResourceHandler func(ctx ResourceContext, req ResourceRequest) (ResourceResult, error)

ResourceHandler reads a resource by URI.

type ResourceReadContent

type ResourceReadContent struct {
	URI      string `json:"uri"`
	MimeType string `json:"mimeType,omitempty"`
	Text     string `json:"text,omitempty"`
	Blob     string `json:"blob,omitempty"`

	// Meta holds per-content metadata (e.g., UI overrides).
	// Takes precedence over the resource-level _meta from resources/list.
	Meta *ResourceContentMeta `json:"_meta,omitempty"`
}

ResourceReadContent is a single content item returned by resources/read. Either Text or Blob is set, not both.

type ResourceRequest

type ResourceRequest struct {
	URI string
}

ResourceRequest is the validated input passed to a ResourceHandler.

type ResourceResult

type ResourceResult struct {
	Contents []ResourceReadContent `json:"contents"`

	// TTLMs is the SEP-2549 cache-freshness hint in integer milliseconds
	// for this resources/read response. See ToolsListResult.TTLMs for
	// semantics. A resource handler MAY set this per-read on its return
	// value; if it leaves the field nil the server applies the
	// WithReadResourceCacheControl default.
	TTLMs *int `json:"ttlMs,omitempty"`

	// CacheScope is the SEP-2549 cache-scope hint. resources/read responses
	// frequently depend on the authenticated user — set CacheScopePrivate
	// when the content varies per caller. See ToolsListResult.CacheScope.
	// A handler MAY set this per-read; otherwise the server applies the
	// WithReadResourceCacheControl default.
	CacheScope string `json:"cacheScope,omitempty"`
}

ResourceResult is the response from a resource handler — the typed result for resources/read responses (the spec calls it ReadResourceResult).

func (*ResourceResult) UnmarshalJSON added in v0.1.21

func (r *ResourceResult) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a ResourceResult, tolerating a single-object `contents` form from peers that emit a bare object instead of the spec-canonical array. Single objects are wrapped into a 1-element slice. See #81. The SEP-2549 ttlMs / cacheScope hints are decoded alongside.

type ResourceTemplate

type ResourceTemplate struct {
	// URITemplate is an RFC 6570 URI template (e.g., "file:///{path}").
	// This serves as the unique identifier for the template in the registry —
	// registering a template with the same URI template string overwrites the
	// previous registration.
	URITemplate string `json:"uriTemplate"`

	// Name is a human-readable short name.
	Name string `json:"name"`

	// Title is an optional display title.
	Title string `json:"title,omitempty"`

	// Description explains what this template provides.
	Description string `json:"description,omitempty"`

	// MimeType is the default MIME type for resources matching this template.
	MimeType string `json:"mimeType,omitempty"`

	// Annotations holds optional metadata for this template.
	Annotations map[string]any `json:"annotations,omitempty"`

	// Timeout is a per-template execution timeout. Not serialized to clients.
	Timeout time.Duration `json:"-"`
}

ResourceTemplate describes a parameterized resource URI template.

type ResourceTemplatesListResult

type ResourceTemplatesListResult struct {
	ResourceTemplates []ResourceTemplate `json:"resourceTemplates"`
	NextCursor        string             `json:"nextCursor,omitempty"`

	// TTLMs is the SEP-2549 cache-freshness hint in integer milliseconds.
	// See ToolsListResult.TTLMs for full semantics — nil/absent and &0 are
	// both "immediately stale", &N>0 is "fresh for N milliseconds".
	TTLMs *int `json:"ttlMs,omitempty"`

	// CacheScope is the SEP-2549 cache-scope hint. See ToolsListResult.CacheScope.
	CacheScope string `json:"cacheScope,omitempty"`
}

ResourceTemplatesListResult is the typed result for resources/templates/list responses.

type ResourceUpdatedNotification

type ResourceUpdatedNotification struct {
	URI string `json:"uri"`
}

ResourceUpdatedNotification is the params payload for notifications/resources/updated. Sent by the server to subscribed clients when a resource's content has changed.

type ResourcesCap

type ResourcesCap struct {
	Subscribe   bool `json:"subscribe,omitempty"`
	ListChanged bool `json:"listChanged,omitempty"`
}

ResourcesCap describes the server's resources capability.

type ResourcesListResult

type ResourcesListResult struct {
	Resources  []ResourceDef `json:"resources"`
	NextCursor string        `json:"nextCursor,omitempty"`

	// TTLMs is the SEP-2549 cache-freshness hint in integer milliseconds.
	// See ToolsListResult.TTLMs for full semantics — nil/absent and &0 are
	// both "immediately stale", &N>0 is "fresh for N milliseconds".
	TTLMs *int `json:"ttlMs,omitempty"`

	// CacheScope is the SEP-2549 cache-scope hint. See ToolsListResult.CacheScope.
	CacheScope string `json:"cacheScope,omitempty"`
}

ResourcesListResult is the typed result for resources/list responses.

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.

func NewAuthorizationDenialError added in v0.2.41

func NewAuthorizationDenialError(id []byte, code int, message string, denial AuthorizationDenial) *Response

NewAuthorizationDenialError creates a JSON-RPC error response with an authorization denial envelope in the error data. The error code should be chosen based on the use case:

  • UC1 (URL approval): use ErrCodeURLElicitationRequired (-32042)
  • UC2/UC3 (credential change): use the tool execution error code

The denial is composed into the error data alongside any other fields (e.g., elicitations for UC1).

EXPERIMENTAL: subject to change as the FineGrainedAuth SEP evolves.

func NewErrorResponse

func NewErrorResponse(id json.RawMessage, code int, message string) *Response

NewErrorResponse creates an error response for the given request ID.

func NewErrorResponseWithData

func NewErrorResponseWithData(id json.RawMessage, code int, message string, data any) *Response

NewErrorResponseWithData creates an error response with additional structured data. Used for protocol errors that carry machine-readable context (e.g., supported versions).

func NewResponse

func NewResponse(id json.RawMessage, result any) *Response

NewResponse creates a success response for the given request ID. Result is stored as-is and serialized once when the transport sends it.

func NewURLElicitationRequiredError added in v0.2.41

func NewURLElicitationRequiredError(id json.RawMessage, message string, data URLElicitationRequiredErrorData) *Response

NewURLElicitationRequiredError creates a -32042 error response indicating that URL-based elicitation flows must be completed before retrying.

func (*Response) ResultAs added in v0.2.20

func (r *Response) ResultAs(v any) error

ResultAs unmarshals the response result into v. Use this when you need to inspect the result after it has been through JSON round-trip (e.g., in tests or client code). Handles both typed results (any) and pre-serialized json.RawMessage.

type ResultType added in v0.2.41

type ResultType string

ResultType is the discriminator on a tools/call response.

"task" indicates a task-based response (CreateTaskResult). The "complete" and "input_required" values come from MRTR (Multi-Round Tool Result, SEP-2322) and signal whether a tool result is final or expects further input rounds. The "input_required" variant was renamed from "incomplete" in SEP-2322 commit de6d76fb, merged 2026-05-06.

const (
	ResultTypeTask          ResultType = "task"
	ResultTypeComplete      ResultType = "complete"       // SEP-2322
	ResultTypeInputRequired ResultType = "input_required" // SEP-2322
)

type Root added in v0.1.18

type Root struct {
	// URI is the root's location (e.g., "file:///home/user/project").
	URI string `json:"uri"`

	// Name is an optional human-readable label for this root.
	Name string `json:"name,omitempty"`
}

Root represents a filesystem root provided by the client. Roots inform the server about available directories for tool execution.

type RootsCap

type RootsCap struct {
	ListChanged bool `json:"listChanged,omitempty"`
}

RootsCap describes the client's roots capability.

type RootsListResult deprecated added in v0.1.18

type RootsListResult struct {
	Roots []Root `json:"roots"`
}

RootsListResult is the response to a roots/list server-to-client request.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func DecodeListRootsInputResponse deprecated added in v0.2.47

func DecodeListRootsInputResponse(raw json.RawMessage) (RootsListResult, error)

DecodeListRootsInputResponse decodes a single inputResponses entry as a RootsListResult — symmetric with NewListRootsInputRequest. Used on the second tools/call round after the client has reported its current roots.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type SamplingMessage deprecated

type SamplingMessage struct {
	Role    string  `json:"role"`
	Content Content `json:"content"`
}

SamplingMessage is a single message in a sampling/createMessage request.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

func (*SamplingMessage) UnmarshalJSON added in v0.1.21

func (m *SamplingMessage) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a SamplingMessage, tolerating an array-form `content` field (first element wins). The spec currently specifies single-content for SamplingMessage; widening to multi-part is tracked by #141 and will reuse this hook by switching to decodeContentSlice. See #81.

type SamplingMeta deprecated added in v0.1.29

type SamplingMeta struct {
	// UI contains MCP Apps presentation metadata.
	// When set, the host can associate the sampling request with a UI resource.
	UI *UIMetadata `json:"ui,omitempty"`

	// RelatedTask identifies the task this request is associated with.
	// Set automatically by TaskContext.TaskSample() so the client can
	// correlate side-channel requests with the originating task.
	RelatedTask *RelatedTaskMeta `json:"io.modelcontextprotocol/related-task,omitempty"`
}

SamplingMeta holds protocol-level metadata for a sampling request. Serialized as "_meta" in the sampling/createMessage params.

Deprecated: per SEP-2577, scheduled for removal in v0.4. See docs/SEP_2577_DEPRECATIONS.md.

type SchemaBuilder added in v0.2.47

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

SchemaBuilder is a fluent editor over a JSON Schema object. Created internally during TypedTool registration when a Patch option is set; the user-supplied patch function receives a builder backed by the reflected schema, edits it, and returns. The builder writes through to the underlying map; there's no commit / apply step.

func (*SchemaBuilder) Prop added in v0.2.47

func (s *SchemaBuilder) Prop(name string) *PropertyBuilder

Prop returns a PropertyBuilder for the named property. If the property doesn't exist in the reflected schema yet, an empty object schema is inserted and returned for editing — patches are additive, not strict.

func (*SchemaBuilder) Raw added in v0.2.47

func (s *SchemaBuilder) Raw() map[string]any

Raw returns the underlying schema map. Mutations land on the original — use sparingly for surgical edits the builder doesn't express directly.

func (*SchemaBuilder) Require added in v0.2.47

func (s *SchemaBuilder) Require(names ...string) *SchemaBuilder

Require adds names to the `required` array idempotently. Duplicate adds are silently dropped; entries not in `properties` are still added — the JSON Schema spec accepts it.

type SchemaGenerator added in v0.2.26

type SchemaGenerator func(v any) json.RawMessage

SchemaGenerator converts a Go value (typically a pointer to a struct) into a JSON Schema representation. The value is used only for type reflection — its fields are not read.

Implementations should return a JSON-encoded schema suitable for ToolDef.InputSchema / OutputSchema (type: "object" with properties, required, etc.).

Example usage:

schema := sg(new(MyInput))  // reflects on MyInput struct tags

type ScopeAwareTokenSource

type ScopeAwareTokenSource interface {
	TokenSource
	// TokenForScopes invalidates the cached token and triggers a new
	// authorization flow with the given scopes merged into the existing set.
	TokenForScopes(scopes []string) (string, error)
}

ScopeAwareTokenSource extends TokenSource with scope step-up capability. When the server returns 403 with required scopes in the WWW-Authenticate header, the client transport calls TokenForScopes to re-authenticate with broader permissions.

Implementations that support interactive re-auth (like OAuthTokenSource) should implement this interface. Static tokens and implementations that cannot acquire new scopes need not implement it — the transport will return a ClientAuthError instead of retrying.

type ServerCapabilities

type ServerCapabilities struct {
	Tools       *ToolsCap                      `json:"tools,omitempty"`
	Resources   *ResourcesCap                  `json:"resources,omitempty"`
	Prompts     *PromptsCap                    `json:"prompts,omitempty"`
	Tasks       *TasksCap                      `json:"tasks,omitempty"`
	Logging     *struct{}                      `json:"logging,omitempty"`
	Completions *struct{}                      `json:"completions,omitempty"`
	Extensions  map[string]ExtensionCapability `json:"extensions,omitempty"`
}

ServerCapabilities describes the features the server supports, returned in the initialize response.

type ServerInfo

type ServerInfo struct {
	Name         string `json:"name"`
	Version      string `json:"version"`
	Title        string `json:"title,omitempty"`
	Description  string `json:"description,omitempty"`
	Instructions string `json:"instructions,omitempty"`
	WebsiteURL   string `json:"websiteUrl,omitempty"`
}

ServerInfo identifies an MCP server in the initialize response.

type ServerRequestHandler

type ServerRequestHandler func(ctx context.Context, req *Request) *Response

ServerRequestHandler handles server-to-client JSON-RPC requests (sampling, elicitation). The client registers this on the transport so the server can send requests during tool execution and receive responses.

type Span added in v0.2.47

type Span interface {
	// End closes the span and emits it to the configured exporter.
	// Subsequent calls are no-ops.
	End()

	// SetAttribute records a string-valued attribute on the span. Keys
	// follow OpenTelemetry semantic conventions where applicable
	// (e.g. `mcp.method`, `mcp.session.id`). Numeric or bool attributes
	// are out of scope for the P1 interface — callers stringify if
	// needed; a richer typed attribute interface may land in a future
	// version once a real adapter requires it.
	SetAttribute(k, v string)

	// RecordError attaches an error to the span. The adapter decides
	// the exact mapping (e.g. OTel records an event with name
	// `exception` and the error message as the `exception.message`
	// attribute). Passing nil is a no-op.
	RecordError(err error)

	// AddLink attaches a causal Link to the span. Mid-flight links are
	// the right model when the work being spanned references upstream
	// trace identities that don't fit a parent-of relationship — e.g. a
	// poll handler discovering new upstream events while it executes, or
	// an async task spawning a side-effect that should reference the
	// original request but doesn't nest under it.
	//
	// Implementations MUST:
	//   - Silently drop links whose TraceContext is zero or fails W3C
	//     structural validation. Defensive call sites do not have to
	//     filter.
	//   - Be safe to call concurrently with SetAttribute / RecordError.
	//   - Treat calls after End as no-ops (the underlying OTel SDK
	//     contract is "before the span is read"; the adapter enforces
	//     this via its post-End guard).
	//
	// The OTel-aligned Link type carries per-link attributes so
	// observability backends can render the link UI semantically
	// (`link.kind=originated-from`, `link.kind=sibling-task`, etc.) — see
	// the Link doc comment for the shape.
	AddLink(link Link)
}

Span is a single in-flight tracing span. Implementations MUST be safe for concurrent SetAttribute / RecordError calls; End MUST be called exactly once. After End returns, subsequent SetAttribute / RecordError calls are no-ops (implementations may log a warning but MUST NOT panic).

func SpanFromContext added in v0.2.47

func SpanFromContext(ctx context.Context) Span

SpanFromContext returns the currently active Span carried by ctx, or a no-op Span when none has been attached. The returned Span is NEVER nil — callers can unconditionally call SetAttribute / RecordError / End without nil-checking. The no-op Span's methods do nothing and never panic, so call sites that always-decorate (e.g. an auth middleware adding `mcp.auth.*` attributes) work correctly regardless of whether a TracerProvider is configured.

The enrichment pattern that this accessor unlocks:

span := core.SpanFromContext(ctx)
span.SetAttribute("mcp.auth.principal", claims.Subject)
span.SetAttribute("mcp.auth.method", "jwt")

Use this when you want to decorate the existing dispatch span (one span per request, attribute-rich) rather than nest a child span (more spans, finer-grained timing). Both patterns are supported; pick whichever matches the observability story you're after.

Safe for concurrent use. Always cheap — a single ctx.Value lookup.

func StartSpanLinked added in v0.2.47

func StartSpanLinked(tp TracerProvider, ctx context.Context, name string, links []Link, attrs ...Attribute) (context.Context, Span)

StartSpanLinked routes through a TracerProvider's link-aware path when available, falling back to plain StartSpan otherwise. Callers reach the link surface through this helper rather than type-asserting the provider themselves.

Behavior:

  • If tp implements LinkedTracerProvider, links are passed through verbatim (the adapter is responsible for the silent-drop rule on invalid Link entries).
  • Otherwise, links are silently dropped and the call degrades to tp.StartSpan(ctx, name, attrs...). Consumers that depend on link emission for *correctness* (rather than observability) should branch on tp.(LinkedTracerProvider) explicitly; the observability use case the surface targets treats links as best-effort enrichment.
  • nil tp panics — same contract as calling any TracerProvider method on nil.

Why a free function instead of a method on TracerProvider: keeping the base interface minimal lets test fakes and the default NoopTracerProvider satisfy it without each gaining a link-aware method that would always degrade to a no-op.

type Stability

type Stability string

Stability represents the maturity level of an extension.

const (
	// Experimental indicates the extension is in development and may change.
	Experimental Stability = "experimental"
	// Stable indicates the extension is production-ready.
	Stable Stability = "stable"
	// Deprecated indicates the extension will be removed in a future version.
	Deprecated Stability = "deprecated"
)

type TaskBucketKeyer added in v0.3.1

type TaskBucketKeyer func(ctx context.Context) string

TaskBucketKeyer derives the per-request bucket key that the task store isolates against — the value passed as the store's sessionID argument for Create / Get / Update / Cancel / List.

The default (no keyer installed) is the transport session ID: on the legacy wire that is the per-connection session; on the SEP-2575 stateless wire it is "" (no session), which is why, by default, all stateless tasks share one bucket per process. Multi-tenant stateless deployments install a keyer that derives the bucket from an authenticated subject (JWT `sub`), a request header, or any other per-tenant signal, so tenants cannot read / cancel / update each other's tasks.

The keyer takes a raw context.Context so it stays decoupled from ext/auth: an auth-based keyer reads the subject from the auth claims already on the context, but the core/server/ext-tasks packages never import ext/auth. Wire it with server.WithTaskBucketKeyer.

type TaskError added in v0.2.41

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

TaskError is the error shape for protocol-level failures (status: failed). Mirrors the JSON-RPC error object shape.

type TaskInfo added in v0.2.41

type TaskInfo struct {
	TaskID        string     `json:"taskId"`
	ParentTaskID  string     `json:"parentTaskId,omitempty"` // set for sub-tasks spawned by TaskContext.SpawnTool
	Status        TaskStatus `json:"status"`
	StatusMessage string     `json:"statusMessage,omitempty"`
	CreatedAt     string     `json:"createdAt"`
	LastUpdatedAt string     `json:"lastUpdatedAt"`
	TTL           *int       `json:"ttl"`                    // milliseconds; null = unlimited
	PollInterval  int        `json:"pollInterval,omitempty"` // milliseconds
}

TaskInfo is the wire-format task object returned by tasks/* methods. TTL is required but nullable per spec: *int with null = unlimited.

type TaskInfoV2 added in v0.2.41

type TaskInfoV2 struct {
	TaskID         string     `json:"taskId"`
	Status         TaskStatus `json:"status"`
	StatusMessage  string     `json:"statusMessage,omitempty"`
	CreatedAt      string     `json:"createdAt"`
	LastUpdatedAt  string     `json:"lastUpdatedAt"`
	TTLMs          *int       `json:"ttlMs"`                    // required+nullable, null = unlimited
	PollIntervalMs *int       `json:"pollIntervalMs,omitempty"` // optional
}

TaskInfoV2 is the v2 wire shape for task metadata. Differences from (v1) TaskInfo:

  • ttl renamed to ttlMs. Units in the field name. Integer milliseconds.
  • pollInterval renamed to pollIntervalMs. Integer milliseconds.
  • parentTaskId removed. SEP-2663 does not expose task parentage.

The TaskStore already uses milliseconds internally, so the v2 wire surface is a pass-through (no unit conversion at the boundary). Per SEP-2663 the server MAY change ttlMs over the lifetime of a task (e.g. reset on each tasks/get to extend liveness while a client is observing it).

type TaskStatus added in v0.2.41

type TaskStatus string

TaskStatus is the lifecycle state of an MCP task.

const (
	// TaskWorking means the task is actively executing.
	TaskWorking TaskStatus = "working"

	// TaskInputRequired means the task is paused, awaiting client input
	// (e.g., via elicitation or sampling).
	TaskInputRequired TaskStatus = "input_required"

	// TaskCompleted means the task succeeded (terminal).
	TaskCompleted TaskStatus = "completed"

	// TaskFailed means the task errored (terminal).
	TaskFailed TaskStatus = "failed"

	// TaskCancelled means the task was cancelled by the client (terminal).
	TaskCancelled TaskStatus = "cancelled"
)

func (TaskStatus) IsTerminal added in v0.2.41

func (s TaskStatus) IsTerminal() bool

IsTerminal reports whether the status is a terminal state.

type TaskSupport added in v0.2.41

type TaskSupport string

TaskSupport declares how a tool interacts with the tasks capability. Set on ToolDef.Execution.TaskSupport.

const (
	// TaskSupportRequired means clients SHOULD invoke as a task; servers
	// MUST return an error if clients ignore the requirement.
	TaskSupportRequired TaskSupport = "required"

	// TaskSupportOptional means clients may choose either synchronous
	// or task-based invocation.
	TaskSupportOptional TaskSupport = "optional"

	// TaskSupportForbidden means clients must NOT invoke as a task.
	TaskSupportForbidden TaskSupport = "forbidden"
)

type TasksCap added in v0.2.41

type TasksCap struct {
	List     *TasksCapMethod   `json:"list,omitempty"`
	Cancel   *TasksCapMethod   `json:"cancel,omitempty"`
	Requests *TasksCapRequests `json:"requests,omitempty"`
}

TasksCap declares server support for the tasks capability in ServerCapabilities. Per spec: nested structure with list, cancel, requests.

type TasksCapElicitationMethods added in v0.2.41

type TasksCapElicitationMethods struct {
	Create *TasksCapMethod `json:"create,omitempty"`
}

TasksCapElicitationMethods declares which elicitation methods support task augmentation.

type TasksCapMethod added in v0.2.41

type TasksCapMethod struct{}

TasksCapMethod is an empty struct used as a marker in capability negotiation.

type TasksCapRequests added in v0.2.41

type TasksCapRequests struct {
	Tools       *TasksCapToolsMethods       `json:"tools,omitempty"`
	Sampling    *TasksCapSamplingMethods    `json:"sampling,omitempty"`
	Elicitation *TasksCapElicitationMethods `json:"elicitation,omitempty"`
}

TasksCapRequests declares which request types support task-augmented responses.

type TasksCapSamplingMethods added in v0.2.41

type TasksCapSamplingMethods struct {
	CreateMessage *TasksCapMethod `json:"createMessage,omitempty"`
}

TasksCapSamplingMethods declares which sampling methods support task augmentation.

type TasksCapToolsMethods added in v0.2.41

type TasksCapToolsMethods struct {
	Call *TasksCapMethod `json:"call,omitempty"`
}

TasksCapToolsMethods declares which tool methods support task augmentation.

type TemplateHandler

type TemplateHandler func(ctx ResourceContext, uri string, params map[string]string) (ResourceResult, error)

TemplateHandler reads a resource matched by a URI template. The uri parameter is the full resolved URI, params contains the extracted template variables.

type TokenSource

type TokenSource interface {
	// Token returns a valid access token, refreshing if necessary.
	Token() (string, error)
}

TokenSource provides access tokens for the MCP client. Simple implementations return a static token; OAuth implementations handle the full flow including discovery, browser auth, and refresh.

type ToolContext added in v0.2.0

type ToolContext struct {
	BaseContext
	// contains filtered or unexported fields
}

ToolContext is the context passed to ToolHandler functions. It embeds BaseContext and adds tool-specific methods (EmitProgress, EmitContent).

func NewToolContext added in v0.2.0

func NewToolContext(ctx context.Context) ToolContext

NewToolContext constructs a ToolContext from a standard context.Context. Called by the dispatch layer before invoking tool handlers.

func NewToolContextWithMRTR added in v0.2.41

func NewToolContextWithMRTR(ctx context.Context, progressToken any, inputResponses InputResponses, requestState string) ToolContext

NewToolContextWithMRTR constructs a ToolContext for an SEP-2322 MRTR retry: progress token plus the inputResponses/requestState the client echoed back. Called by the tools/call dispatch layer after parsing the request envelope; handlers read the values via ctx.InputResponse / ctx.InputResponses / ctx.RequestState.

func NewToolContextWithProgress added in v0.2.26

func NewToolContextWithProgress(ctx context.Context, progressToken any) ToolContext

NewToolContextWithProgress constructs a ToolContext with a stored progress token. The dispatch layer passes the token from _meta.progressToken so that handlers can call ctx.Progress() without threading the token manually.

func (ToolContext) DetachFromClient added in v0.2.0

func (tc ToolContext) DetachFromClient() ToolContext

DetachFromClient returns a ToolContext that preserves session state but is NOT cancelled when the client disconnects.

func (ToolContext) EmitContent added in v0.2.0

func (tc ToolContext) EmitContent(requestID json.RawMessage, content Content)

EmitContent sends a partial content block to the client during tool execution. On non-streaming transports, the notification is silently dropped.

func (ToolContext) EmitProgress added in v0.2.0

func (tc ToolContext) EmitProgress(token any, progress, total float64, message string)

EmitProgress sends a notifications/progress to the connected client. No-op if token is nil. Prefer ctx.Progress() when the token is stored in the context (TypedTool handlers, or dispatch with NewToolContextWithProgress).

func (ToolContext) HasInputResponses added in v0.2.41

func (tc ToolContext) HasInputResponses() bool

HasInputResponses reports whether the client echoed any inputResponses back. Equivalent to len(ctx.InputResponses()) > 0; provided for readable branching in handlers ("if ctx.HasInputResponses() { ... }").

func (ToolContext) InputResponse added in v0.2.41

func (tc ToolContext) InputResponse(key string) json.RawMessage

InputResponse returns the raw response payload for a specific request key from the inputResponses map, or nil if the key is missing. The payload shape matches the method declared in the original InputRequest (ElicitResult, CreateMessageResult, ListRootsResult, ...) — callers json.Unmarshal it into the matching typed struct.

func (ToolContext) InputResponses added in v0.2.41

func (tc ToolContext) InputResponses() InputResponses

InputResponses returns the SEP-2322 inputResponses map the client echoed back into this tools/call. Nil on the first call (no prior InputRequiredResult) or when the client did not include the field.

Handlers branch on this to detect retries: nil = first call, ask for input; non-nil = client has answered, build the final result.

func (ToolContext) Progress added in v0.2.26

func (tc ToolContext) Progress(progress, total float64, message string)

Progress sends a notifications/progress using the stored progress token from _meta.progressToken. No-op if the client didn't request progress. This is the preferred method in TypedTool handlers where the token is automatically captured from the request.

func (ToolContext) ProgressToken added in v0.2.26

func (tc ToolContext) ProgressToken() any

ProgressToken returns the stored progress token, or nil if not set.

func (ToolContext) RequestInput added in v0.2.41

func (tc ToolContext) RequestInput(reqs InputRequests) (InputRequiredResult, error)

RequestInput is the SEP-2322 ephemeral retry primitive. Handlers return the value as their ToolResponse to signal "I need more input from the client before I can produce a final result"; the dispatch layer mints a fresh requestState onto the returned InputRequiredResult before emitting it on the wire.

Usage in a tool handler:

func myTool(ctx core.ToolContext, req core.ToolRequest) (core.ToolResponse, error) {
    if !ctx.HasInputResponses() {
        return ctx.RequestInput(core.InputRequests{
            "user_name": {
                Method: "elicitation/create",
                Params: rawElicitationParams,
            },
        })
    }
    // Decode ctx.InputResponse("user_name") and build the final result.
}

The error return is always nil — the helper exists so the call site reads as a single return statement matching the ToolHandler signature. The concrete return type is InputRequiredResult (not ToolResponse) so callers can use the typed value directly when they need to.

func (ToolContext) RequestState added in v0.2.41

func (tc ToolContext) RequestState() string

RequestState returns the SEP-2322 requestState token the client echoed back. Empty on the first call. The token has already been verified by the dispatch layer (HMAC-checked when a signing key is configured), so handlers can trust its presence as proof the round-trip is intact — the embedded payload itself is opaque to handlers.

type ToolDef

type ToolDef struct {
	// Name is the tool identifier used in tools/call.
	Name string `json:"name"`

	// Title is an optional human-readable display name distinct from Name.
	// Per MCP spec: hosts SHOULD prefer Title for user-facing surfaces
	// (dropdowns, button labels) and use Name only as the machine identifier
	// passed to tools/call. Omitted when empty so existing tools without a
	// Title don't drift on the wire.
	Title string `json:"title,omitempty"`

	// Description is a human-readable summary of what the tool does.
	Description string `json:"description"`

	// InputSchema is the JSON Schema for the tool's arguments.
	// Typically a map[string]any with "type": "object", "properties": {...}, "required": [...].
	// Arbitrary JSON Schema fields (e.g. "$schema", "$defs", "$ref",
	// "additionalProperties") are preserved as-is through registration,
	// serialization, and client-side deserialization.
	InputSchema any `json:"inputSchema"`

	// OutputSchema is an optional JSON Schema for the tool's structuredContent output.
	// When present, the tool SHOULD return StructuredContent matching this schema.
	// Per MCP spec: enables clients to validate and process tool output programmatically.
	OutputSchema any `json:"outputSchema,omitempty"`

	// Execution holds task-related execution metadata.
	// Per MCP spec: declares whether this tool supports async task execution.
	Execution *ToolExecution `json:"execution,omitempty"`

	// Annotations holds optional metadata for this tool.
	// Convention: {"experimental": true} marks experimental tools.
	Annotations map[string]any `json:"annotations,omitempty"`

	// Meta holds protocol-level metadata (e.g., UI presentation hints).
	// Serialized as "_meta" in the tools/list response.
	Meta *ToolMeta `json:"_meta,omitempty"`

	// Timeout is a per-tool execution timeout. If set, overrides the
	// server-wide WithToolTimeout for this tool. Not serialized to clients.
	Timeout time.Duration `json:"-"`

	// RequiredScopes are OAuth scopes the caller's access token must include
	// to invoke this tool. Enforced by ext/auth's scope middleware
	// (auth.NewToolScopeMiddleware), which returns HTTP 403 + WWW-Authenticate
	// when scopes are missing — per SEP-2643 (FineGrainedAuth UC2).
	//
	// Not serialized to clients (it's enforcement metadata, not API contract).
	// Empty/nil means no per-tool scope check; the tool is callable by any
	// authenticated client (subject to global server.WithRequiredScopes).
	RequiredScopes []string `json:"-"`

	// AcceptedScopes is an opt-in OR escape hatch on top of RequiredScopes'
	// AND semantics. When non-empty, the scope middleware passes the gate if
	// the caller's token includes ANY scope in AcceptedScopes — supporting
	// hierarchies where a parent scope like `repo` satisfies a tool nominally
	// requiring `repo:read`. Nil or an explicitly empty slice falls back to
	// the AND-on-RequiredScopes default (the two-state is deliberate so
	// allocating `[]string{}` cannot silently disable enforcement).
	//
	// Gate-only contract: AcceptedScopes participates in the satisfaction
	// check but NEVER appears in the 403 WWW-Authenticate challenge. Re-auth
	// guidance stays least-privilege — the challenge advertises RequiredScopes
	// alone so clients don't escalate by requesting tolerated alternatives.
	// Aligns with the upstream TypeScript SDK PR modelcontextprotocol/typescript-sdk#1624.
	//
	// Not serialized to clients.
	AcceptedScopes []string `json:"-"`
}

ToolDef describes a tool exposed via MCP.

type ToolExecution added in v0.2.41

type ToolExecution struct {
	TaskSupport TaskSupport `json:"taskSupport"`
}

ToolExecution describes task-related execution metadata on a tool definition. Per MCP spec: declared at the tool level, not in annotations (because it implies binding guarantees about behavior, not hints).

type ToolHandler

type ToolHandler func(ctx ToolContext, req ToolRequest) (ToolResponse, error)

ToolHandler is the function signature for tool implementations. The ToolContext provides typed access to session capabilities (EmitLog, EmitProgress, EmitContent, Sample, Elicit, etc.) with IDE discoverability.

The return type is the sealed ToolResponse interface — handlers may return any of ToolResult, InputRequiredResult, CreateTaskResult, or GoAsyncResult. The most common form is a ToolResult literal:

return core.ToolResult{Content: []core.Content{{Type: "text", Text: "ok"}}}, nil

Or the convenience helpers — TextResult, ErrorResult, StructuredResult — which return concrete ToolResult values that satisfy ToolResponse.

type ToolMeta

type ToolMeta struct {
	// UI contains MCP Apps presentation metadata.
	UI *UIMetadata `json:"ui,omitempty"`
}

ToolMeta holds protocol-level metadata for a tool definition. Serialized as "_meta" in the tools/list response.

Custom MarshalJSON/UnmarshalJSON mirror upstream `ext-apps`'s `registerAppTool` (`RESOURCE_URI_META_KEY` constant): when UI.ResourceUri is set, BOTH `ui.resourceUri` (nested) and `ui/resourceUri` (flat) keys are emitted on the wire. Unmarshaling accepts either form; if both are present they must agree (or the nested form wins). This keeps mcpkit tools interoperable with hosts that read either the older flat key convention or the newer nested form.

func (ToolMeta) MarshalJSON added in v0.2.47

func (m ToolMeta) MarshalJSON() ([]byte, error)

MarshalJSON serializes ToolMeta so that UI.ResourceUri appears under BOTH the nested ui.resourceUri key and the flat ui/resourceUri key, matching upstream ext-apps's emit. Other UI fields stay under the nested form only.

func (*ToolMeta) UnmarshalJSON added in v0.2.47

func (m *ToolMeta) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts either the nested ui.resourceUri form, the flat ui/resourceUri form, or both. If both are present and disagree, the nested form wins (callers reading the flat-form-only branch would have missed any other UI fields anyway, so the nested form is the more complete one).

type ToolRequest

type ToolRequest struct {
	// Name of the tool being called.
	Name string

	// Arguments is the raw JSON arguments from the tools/call params.
	Arguments json.RawMessage

	// RequestID is the JSON-RPC request ID.
	RequestID json.RawMessage

	// ProgressToken is the token from the request's _meta.progressToken field.
	// Nil if the client did not request progress reporting. Pass this to
	// EmitProgress to send notifications/progress notifications.
	ProgressToken any

	// InputResponses is the SEP-2322 ephemeral MRTR retry payload — the
	// client echoes the inputResponses map back into the SAME tools/call
	// request that previously returned an InputRequiredResult. Keys MUST match
	// those the server returned in the matching InputRequests; values are
	// opaque per-method response payloads (ElicitResult, CreateMessageResult,
	// ListRootsResult, ...). Nil on the first call.
	//
	// Handlers usually access this through ToolContext.InputResponses() /
	// ToolContext.InputResponse(key); the raw field is here so middleware
	// and conformance tests can inspect the wire payload directly.
	InputResponses InputResponses

	// RequestState is the opaque session-continuation token the client
	// echoed back from a previous InputRequiredResult. The dispatch layer
	// verifies it (HMAC when a key is configured) before invoking the
	// handler. Empty on the first call.
	RequestState string
}

ToolRequest is the validated input passed to a ToolHandler.

func (*ToolRequest) Bind

func (r *ToolRequest) Bind(v any) error

Bind unmarshals the tool arguments into the provided struct.

type ToolResponse added in v0.2.47

type ToolResponse interface {
	// contains filtered or unexported methods
}

ToolResponse is the sealed interface returned by ToolHandler implementations.

Four core variants implement it:

  • ToolResult — the sync "complete" wire envelope.
  • InputRequiredResult — the SEP-2322 multi-round "input_required" envelope.
  • CreateTaskResult — the SEP-2663 "task" envelope (handler-emitted; rare).
  • GoAsyncResult — in-process signal that the ext/tasks middleware should mint a task and run the handler again on a background goroutine. Never serialized.

The interface is sealed via the unexported toolResponse() marker so external types cannot impersonate a core response variant. Dispatch type-switches on the concrete value; the previous IsInputRequired/InputRequests/GoAsync sentinel fields on ToolResult are gone.

type ToolResult

type ToolResult struct {
	// ResultType is the SEP-2322 polymorphic-dispatch discriminator. For
	// sync tools/call responses the wire value is "complete" (defaulted by
	// MarshalJSON when this field is empty). Task-creating responses use
	// ResultTypeTask on CreateTaskResult; multi-round results use
	// ResultTypeInputRequired on InputRequiredResult instead.
	ResultType ResultType `json:"resultType"`

	// Content is the list of content items to return.
	Content []Content `json:"content"`

	// IsError indicates the tool execution failed (but the JSON-RPC call itself succeeded).
	IsError bool `json:"isError,omitempty"`

	// StructuredContent holds optional structured data for the tool result.
	// When the tool has an OutputSchema, this field carries typed data matching
	// that schema. On error (IsError=true), it can carry structured error details.
	// Per MCP spec: "If outputSchema is present, structuredContent SHOULD be included."
	StructuredContent any `json:"structuredContent,omitempty"`

	// Meta holds optional result metadata (e.g., pagination cursor).
	Meta *ToolResultMeta `json:"_meta,omitempty"`
}

ToolResult is the sync "complete" response from a tool handler.

func ErrorResult

func ErrorResult(text string) ToolResult

ErrorResult creates a ToolResult marked as an error with the given message.

func StructuredError

func StructuredError(text string, data any) ToolResult

StructuredError creates a ToolResult marked as an error with both text and structured error data. Use this to return machine-readable error details alongside a human-readable error message.

func StructuredResult

func StructuredResult(text string, data any) ToolResult

StructuredResult creates a ToolResult with both text content and structured data. Use this when the tool has an OutputSchema — structuredContent carries typed data matching the schema, while content provides a human-readable summary.

func TextResult

func TextResult(text string) ToolResult

TextResult creates a ToolResult with a single text content item.

func (ToolResult) MarshalJSON added in v0.2.41

func (r ToolResult) MarshalJSON() ([]byte, error)

MarshalJSON ensures every ToolResult on the wire carries a ResultType. Empty defaults to ResultTypeComplete so existing callers and struct literals don't have to set the field explicitly. SEP-2322 requires this discriminator on every non-task tools/call response so clients can dispatch sync vs task vs multi-round without inspecting payload shape.

func (*ToolResult) UnmarshalJSON added in v0.1.21

func (r *ToolResult) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a ToolResult, tolerating a single-object `content` form from peers that haven't caught up to the array-form spec. Single objects are wrapped into a 1-element slice. See #81.

type ToolResultMeta added in v0.1.18

type ToolResultMeta struct {
	// NextCursor is a pagination cursor for fetching the next page.
	// Empty when there are no more pages.
	NextCursor string `json:"nextCursor,omitempty"`

	// RelatedTask identifies a task associated with this result.
	// Per MCP spec: set by tasks/result responses.
	RelatedTask *RelatedTaskMeta `json:"io.modelcontextprotocol/related-task,omitempty"`

	// Extras carries extension- or feature-namespaced metadata that
	// doesn't fit the typed fields above. Keys serialize at the top
	// level of the `_meta` object alongside the typed fields. Use
	// namespaced keys ("vendor.com/feature") to avoid collisions with
	// future spec fields. Typed fields take precedence on collision.
	Extras map[string]any `json:"-"`
}

ToolResultMeta carries optional metadata on a tool result.

On the wire `_meta` is an open object — extensions can carry vendor- or feature-namespaced keys alongside the typed fields. The `Extras` field is the seam for that: typed fields take precedence when their keys collide, otherwise extras spread at the top level. Same pattern used by ErrorData.Extra in core/jsonrpc.go.

func (ToolResultMeta) MarshalJSON added in v0.2.47

func (m ToolResultMeta) MarshalJSON() ([]byte, error)

MarshalJSON spreads Extras at the top level alongside the typed fields. Typed fields take precedence if a key collides.

func (*ToolResultMeta) UnmarshalJSON added in v0.2.47

func (m *ToolResultMeta) UnmarshalJSON(data []byte) error

UnmarshalJSON absorbs unknown keys into Extras so round-tripping peer-emitted _meta doesn't drop extension data.

type ToolsCap

type ToolsCap struct {
	ListChanged bool `json:"listChanged,omitempty"`
}

ToolsCap describes the server's tools capability.

type ToolsListResult

type ToolsListResult struct {
	Tools      []ToolDef `json:"tools"`
	NextCursor string    `json:"nextCursor,omitempty"`

	// TTLMs is the SEP-2549 cache-freshness hint, in integer milliseconds,
	// that the client MAY use to cache the tools list before re-fetching.
	// Semantics mirror HTTP Cache-Control: max-age:
	//
	//   - nil (field omitted) — no server guidance. Per the merged spec
	//     clients treat an absent ttlMs the same as 0: the response is
	//     immediately stale. This is the "older server / not configured"
	//     case; clients fall back to notifications/list_changed or their
	//     own heuristics.
	//   - &0 ("ttlMs": 0 on the wire) — the response SHOULD be considered
	//     immediately stale; the client MAY re-fetch every time the list is
	//     needed. Wire-distinct from nil but client-equivalent — the pointer
	//     just lets a server state the 0 deliberately.
	//   - &N>0 — the list is fresh for N milliseconds from receipt; the
	//     client SHOULD NOT re-fetch before it expires unless it receives a
	//     list_changed notification.
	//
	// SEP-2549 renamed this field from `ttl` (integer seconds) to `ttlMs`
	// (integer milliseconds) during its final review. See
	// docs/LIST_TTL_MIGRATION.md.
	TTLMs *int `json:"ttlMs,omitempty"`

	// CacheScope is the SEP-2549 hint controlling who may serve a cached
	// copy of this response — core.CacheScopePublic or CacheScopePrivate.
	// Empty (field omitted) defaults to "public" client-side, so a server
	// whose tool list varies per caller MUST set CacheScopePrivate. See
	// docs/LIST_TTL_MIGRATION.md for the security rationale.
	CacheScope string `json:"cacheScope,omitempty"`
}

ToolsListResult is the typed result for tools/list responses.

type TraceContext added in v0.2.47

type TraceContext struct {
	// Traceparent is the W3C `traceparent` value as it appears on the
	// wire: e.g. `00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01`.
	// Empty when no trace context is propagated.
	Traceparent string

	// Tracestate is the W3C `tracestate` value (vendor-specific list).
	// May be empty even when Traceparent is set. Opaque to mcpkit core.
	Tracestate string
}

TraceContext is the propagated W3C Trace Context for a single MCP request. Both fields are opaque strings — this package validates the `traceparent` field's structural form (W3C version-00) but does not parse the trace-id or span-id; an adapter (e.g., ext/otel) consumes the raw strings and feeds them to the OTel propagator.

A zero TraceContext (both fields empty) means "no trace context is active." Callers must treat it as a valid absence, not an error.

func CapturedTraceContextHolder added in v0.2.47

func CapturedTraceContextHolder(ctx context.Context) *TraceContext

CapturedTraceContextHolder returns the holder a previous WithCapturedTraceContext placed on ctx, or nil if none. TracerProvider adapters and trace middleware call this immediately after StartSpan resolves the outbound TraceContext and (if non-nil holder) write the new identity into *holder.

Defensive: nil-holder is silently the no-op path — callers writing into the holder check non-nil first. Reading by the requester after the call completes always returns the holder they constructed via WithCapturedTraceContext — no nil-check needed on that side.

func ExtractTraceContext added in v0.2.47

func ExtractTraceContext(meta map[string]any) TraceContext

ExtractTraceContext reads the W3C `traceparent` and `tracestate` fields from an MCP `_meta` map. It returns a zero TraceContext when the keys are absent, when the values are not strings, or when the traceparent value fails W3C structural validation (wrong length, non-hex characters, all-zero trace-id or parent-id, or an unknown version byte).

Lenient values are not retained: a malformed traceparent yields an empty Traceparent AND an empty Tracestate, because per W3C recommendation a vendor MUST NOT forward a tracestate it cannot associate with a valid traceparent.

func ExtractTraceContextFromParams added in v0.2.47

func ExtractTraceContextFromParams(params json.RawMessage) TraceContext

ExtractTraceContextFromParams reads the W3C `traceparent` / `tracestate` fields out of a JSON-RPC request's raw `params` envelope by parsing the `_meta` object inside. Returns a zero TraceContext when params is nil, when params is not a JSON object, when `_meta` is absent or non-object, or when the traceparent value fails the same W3C validation as ExtractTraceContext. Provided so server middleware can read the inbound trace context without coupling to method-specific envelope structs (tools/call's `name`/`arguments`, prompts/get's `name`, ...) — all of them carry the same `_meta` shape per the MCP spec.

func ExtractTraceLinkFromParams added in v0.2.47

func ExtractTraceLinkFromParams(params json.RawMessage) TraceContext

ExtractTraceLinkFromParams reads `_meta.io.modelcontextprotocol/tracelink` from a JSON-RPC request's raw `params` envelope, returning the carried W3C traceparent as a TraceContext (Tracestate is intentionally NOT part of the link payload — a link is identity-only, not a full propagation context). Returns a zero TraceContext when params is nil / non-object / missing the key, or when the value fails W3C structural validation (same rules ExtractTraceContext applies).

Used by the server's SEP-414 P2 trace middleware to detect MRTR round-2+ requests and Add an OTel Link from the new dispatch span back to the originating round-1 span — see SEP-414 P6 / issue 682.

Defensive: never panics on malformed input.

func TraceContextFromContext added in v0.2.47

func TraceContextFromContext(ctx context.Context) TraceContext

TraceContextFromContext returns the TraceContext carried by ctx, or a zero TraceContext when none has been attached. Always safe to call; never panics. Use TraceContext.IsZero to test for absence.

func WithCapturedTraceContext added in v0.2.47

func WithCapturedTraceContext(ctx context.Context) (context.Context, *TraceContext)

WithCapturedTraceContext returns a derived context carrying a holder the TracerProvider adapter (or trace middleware) writes the call's outbound TraceContext into. Used by callers that need to learn what identity their outbound call ended up emitting under, without changing the Call / Notify return shape.

Primary consumer: SEP-2322 MRTR's CallToolWithInputs (issue 682). Round 1's tools/call goes through the client trace middleware, which writes the round-1 span's identity into the holder. CallToolWithInputs reads the holder, captures round-1's traceparent, and on subsequent rounds stamps it as `_meta.io.modelcontextprotocol/tracelink` so the server dispatch span can AddLink back to it. Star-link semantic — every round 2+ links to round 1, not the previous round.

The holder is goroutine-private (each WithCapturedTraceContext call allocates a fresh holder). The middleware writes to the holder at most once per call (after StartSpan resolves the outbound identity). Reading the holder after the call completes is safe — no concurrent writes once the call has returned.

Zero overhead unconfigured: when neither the middleware nor the caller reads the holder, this is a single ctx.WithValue allocation per call site that opts in. Holder pointers are NOT propagated by context.WithoutCancel / detach — the holder is scoped to the active request's ctx tree.

func (TraceContext) IsZero added in v0.2.47

func (tc TraceContext) IsZero() bool

IsZero reports whether tc carries no trace context at all. Equivalent to `tc == TraceContext{}`; provided so call sites read as a single branch ("if tc.IsZero() { ... }").

type TracerProvider added in v0.2.47

type TracerProvider interface {
	// StartSpan begins a new span named `name` and returns a derived
	// context that carries the span as the parent for any nested
	// StartSpan calls. The returned Span MUST have its End method called
	// exactly once when the span's work is done.
	StartSpan(ctx context.Context, name string, attrs ...Attribute) (context.Context, Span)
}

TracerProvider is the minimal tracing seam mcpkit components consume. It is intentionally smaller than the full go.opentelemetry.io/otel `trace.TracerProvider` so the base module can stay dep-free; the experimental/ext/otel adapter (P4) implements this interface on top of the real OTel SDK.

Implementations MUST:

  • Be safe for concurrent use by multiple goroutines.
  • Return a non-nil Span even when the provider is a no-op — callers do not nil-check the returned Span.
  • Honor the parent trace context carried in ctx (extracted via TraceContextFromContext or by an adapter-specific propagator).

The default implementation, NoopTracerProvider, performs no allocation and is safe to embed in tests and in production wiring where tracing is disabled.

type Transport

type Transport interface {
	// Connect establishes the transport (e.g., SSE handshake, session creation).
	Connect(ctx context.Context) error

	// Call sends a JSON-RPC request and returns the response.
	Call(ctx context.Context, req *Request) (*Response, error)

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

	// Close shuts down the transport.
	Close() error

	// SessionID returns the transport's session identifier (empty if none).
	SessionID() string
}

Transport is the minimal interface for client-server communication. Both HTTP transports and the in-process transport satisfy this interface. The client package consumes it; the server package provides implementations.

type TypedToolOption added in v0.2.26

type TypedToolOption func(*typedToolConfig)

TypedToolOption configures optional fields on a TypedTool.

func WithInputSchemaOverride added in v0.2.47

func WithInputSchemaOverride(schema any) TypedToolOption

WithInputSchemaOverride replaces the reflection-derived input schema with a caller-supplied schema. Use this when the tool's input shape needs JSON Schema 2020-12 features that struct tags cannot express — for example conditional validation (if/then/else), composition (allOf/anyOf), shared definitions with $anchor / $ref, or a custom $schema dialect declaration.

The override is preserved as-is through tools/list (per ToolDef.InputSchema docs). The handler still unmarshals request arguments into In, so callers are responsible for keeping the override compatible with In's wire shape.

Example:

type DeployInput struct {
    Env      string `json:"env"`
    Approver string `json:"approver,omitempty"`
}
schema := map[string]any{
    "type":     "object",
    "properties": map[string]any{ /* ... */ },
    "if":   map[string]any{"properties": map[string]any{"env": map[string]any{"const": "prod"}}},
    "then": map[string]any{"required": []string{"approver"}},
}
r := core.TypedTool[DeployInput, string]("deploy", "Deploy to env", handler,
    core.WithInputSchemaOverride(schema),
)

func WithInputSchemaPatch added in v0.2.47

func WithInputSchemaPatch(fn func(*SchemaBuilder)) TypedToolOption

WithInputSchemaPatch returns a TypedToolOption that runs fn against the reflected input schema after generation. The patch sees a SchemaBuilder backed by the live schema map and edits in place.

Use the patch path when the diff between reflection and the desired schema is "tweak a few fields" (descriptions, defaults, min/max, enum, required). Use WithInputSchemaOverride when you genuinely want to start from a blank schema and stuff the entire shape in.

Precedence: WithInputSchemaOverride wins over WithInputSchemaPatch when both are set on the same registration — Override is the stronger "replace entirely" intent and we don't want silent merging. Calling both on the same option set is almost certainly a bug; the godoc note here is the only signpost.

func WithOutputSchemaOverride added in v0.2.47

func WithOutputSchemaOverride(schema any) TypedToolOption

WithOutputSchemaOverride replaces the reflection-derived output schema with a caller-supplied schema. Symmetric mirror of WithInputSchemaOverride for the OutputSchema field. Use when struct-tag reflection can't express the exact output shape — common cases include nullable types (upstream's `z.string().nullable()` wants `{"type": ["string", "null"]}` which Go reflection won't produce), `interface{}` / `any` fields that invopop reflects to schemas strict MCP-SDK clients reject, or matching an external reference schema byte-for-byte.

The override is preserved as-is on the wire. The handler still returns Out, so callers must keep the override compatible with Out's wire shape.

func WithOutputSchemaPatch added in v0.2.47

func WithOutputSchemaPatch(fn func(*SchemaBuilder)) TypedToolOption

WithOutputSchemaPatch is the symmetric mirror for the output schema. Behaves identically to WithInputSchemaPatch except it edits the schema generated for Out (or skipped when Out is string / ToolResult / ToolResponse — in those cases there's no output schema to patch and the function is silently skipped).

func WithToolAcceptedScopes added in v0.3.0

func WithToolAcceptedScopes(scopes ...string) TypedToolOption

WithToolAcceptedScopes sets the AcceptedScopes OR-hierarchy escape hatch on the generated ToolDef. When non-empty, the scope-check gate satisfaction flips from "every RequiredScopes scope must be present" (AND) to "any AcceptedScopes scope must be present" (OR). Supports declarative scope hierarchies — a tool that nominally requires "repo:read" can additionally accept "repo" without the caller needing to spell out the AND/OR logic. Empty (default) preserves the AND-only behavior set by RequiredScopes.

AcceptedScopes is gate-only: it never appears in the 403 WWW-Authenticate challenge advertisement (which carries only RequiredScopes), keeping the re-auth guidance least-privilege per SEP-2350.

func WithToolAnnotations added in v0.2.26

func WithToolAnnotations(a map[string]any) TypedToolOption

WithToolAnnotations sets the Annotations field on the generated ToolDef.

func WithToolExecution added in v0.2.47

func WithToolExecution(execution *ToolExecution) TypedToolOption

WithToolExecution sets the Execution field on the generated ToolDef. Use this for tools that participate in the v2 tasks protocol (SEP-2557) and need to declare task-support semantics (TaskSupportRequired, TaskSupportOptional, or the default TaskSupportForbidden). Without this option the generated ToolDef has no Execution field, which is equivalent to TaskSupportForbidden per the spec (sync-only tool).

Example:

type SlowComputeInput struct {
    Seconds int `json:"seconds"`
}
r := core.TypedTool[SlowComputeInput, core.ToolResponse]("slow_compute", "...",
    func(ctx core.ToolContext, in SlowComputeInput) (core.ToolResponse, error) { ... },
    core.WithToolExecution(&core.ToolExecution{TaskSupport: core.TaskSupportOptional}),
)

For tools that also need server-side per-tool task callbacks (TaskCallbacks for GetTask/GetResult overrides), use the lower-level server.Tool{ToolDef, Handler, TaskCallbacks} struct path instead — TaskCallbacks is a server-level concept that cannot be exposed via this core-only helper without crossing module boundaries.

func WithToolMeta added in v0.2.26

func WithToolMeta(m *ToolMeta) TypedToolOption

WithToolMeta sets the Meta field on the generated ToolDef.

func WithToolRequiredScopes added in v0.2.41

func WithToolRequiredScopes(scopes ...string) TypedToolOption

WithToolRequiredScopes sets the RequiredScopes field on the generated ToolDef. When auth.NewToolScopeMiddleware is registered on the server, calls to this tool from clients without all of the named scopes are rejected at the transport layer with HTTP 403 + WWW-Authenticate per RFC 6750.

func WithTypedToolTimeout added in v0.2.26

func WithTypedToolTimeout(d time.Duration) TypedToolOption

WithTypedToolTimeout sets a per-tool execution timeout on the generated ToolDef.

type TypedToolResult added in v0.2.26

type TypedToolResult struct {
	ToolDef
	Handler ToolHandler
}

TypedToolResult holds the generated ToolDef and wrapped ToolHandler produced by TypedTool or TextTool. Use this to pass typed tool registrations to any registration API (server.Register, ext/ui.RegisterAppTool, etc.).

func TextTool added in v0.2.26

func TextTool[In any](name, desc string,
	handler func(ctx ToolContext, input In) (string, error),
	opts ...TypedToolOption,
) TypedToolResult

TextTool creates a ToolDef and ToolHandler with auto-derived InputSchema where the handler returns a string. This is sugar for TypedTool[In, string].

Example:

r := core.TextTool[GreetInput]("greet", "Say hello",
    func(ctx core.ToolContext, input GreetInput) (string, error) {
        return "Hello, " + input.Name, nil
    },
)

func TypedTool added in v0.2.26

func TypedTool[In, Out any](name, desc string,
	handler func(ctx ToolContext, input In) (Out, error),
	opts ...TypedToolOption,
) TypedToolResult

TypedTool creates a ToolDef and ToolHandler with InputSchema (and optionally OutputSchema) auto-derived from Go struct types via the current SchemaGenerator. The handler receives typed input — no manual Bind() needed.

The Out type parameter controls output behavior:

  • string: handler returns text, wrapped via TextResult. No OutputSchema.
  • ToolResult: handler returns a ToolResult directly. No OutputSchema.
  • ToolResponse: handler returns any ToolResponse variant (ToolResult, InputRequiredResult, CreateTaskResult, GoAsyncResult). No OutputSchema. Use this for MRTR / SEP-2663 tools.
  • any struct: handler returns typed data. OutputSchema auto-derived from Out. Result uses StructuredResult with JSON text fallback.

Example (text output — use TextTool for convenience):

r := core.TypedTool[SearchInput, string]("search", "Search books",
    func(ctx core.ToolContext, input SearchInput) (string, error) {
        return fmt.Sprintf("found %d books", len(results)), nil
    },
)

Example (structured output):

r := core.TypedTool[SearchInput, SearchOutput]("search", "Search books",
    func(ctx core.ToolContext, input SearchInput) (SearchOutput, error) {
        return SearchOutput{Results: results, Total: len(results)}, nil
    },
)

type UICSPConfig

type UICSPConfig struct {
	// ConnectDomains → CSP connect-src (fetch, XHR, WebSocket targets).
	ConnectDomains []string `json:"connectDomains,omitempty"`

	// ResourceDomains → CSP script-src, style-src, img-src, font-src, media-src.
	ResourceDomains []string `json:"resourceDomains,omitempty"`

	// FrameDomains → CSP frame-src (nested iframes).
	FrameDomains []string `json:"frameDomains,omitempty"`

	// BaseUriDomains → CSP base-uri.
	BaseUriDomains []string `json:"baseUriDomains,omitempty"`
}

UICSPConfig declares external domains for Content-Security-Policy construction. Hosts use these declarations when sandboxing MCP App iframes.

type UIMetadata

type UIMetadata struct {
	// ResourceUri points to a ui:// resource containing the HTML to render.
	// Required for tools that want inline UI rendering.
	ResourceUri string `json:"resourceUri,omitempty"`

	// Visibility controls who can see/call this tool.
	// Default (nil): host applies its own default (typically ["model", "app"]).
	Visibility []UIVisibility `json:"visibility,omitempty"`

	// CSP declares external domains the app needs to load resources from.
	// Hosts construct Content-Security-Policy from these declarations.
	CSP *UICSPConfig `json:"csp,omitempty"`

	// Permissions declares browser Permission-Policy capabilities the App
	// requests (camera, microphone, geolocation, clipboardWrite).
	//
	// Per the MCP Apps spec (McpUiResourcePermissions), permissions belong
	// on the UI **resource** _meta.ui — NOT on tool _meta. mcpkit emits
	// permissions only via ResourceContentMeta.UI; setting Permissions on
	// a tool's UIMetadata has no wire effect.
	//
	// Wire shape is an object with optional keys per the spec, each value
	// an empty object `{}` (placeholder for future per-permission options):
	//   "permissions": { "microphone": {}, "clipboardWrite": {} }
	Permissions *UIPermissions `json:"permissions,omitempty"`

	// PrefersBorder hints whether the host should draw a visible border.
	// nil = host decides, true = border, false = no border.
	PrefersBorder *bool `json:"prefersBorder,omitempty"`

	// Domain requests a dedicated sandbox origin for the app.
	// Format is host-dependent (e.g., "myapp" → myapp.claudemcpcontent.com).
	Domain string `json:"domain,omitempty"`

	// SupportedDisplayModes declares which display modes this app can render in.
	// Nil means the host decides. Hosts use this to offer mode switching UI.
	SupportedDisplayModes []DisplayMode `json:"supportedDisplayModes,omitempty"`
}

UIMetadata describes UI presentation metadata for tools and resources. Serialized as the "_meta.ui" object in tools/list and resources/read responses. Part of the MCP Apps extension (io.modelcontextprotocol/ui).

type UIPermissions added in v0.2.47

type UIPermissions struct {
	// Camera maps to Permission Policy `camera`.
	Camera *struct{} `json:"camera,omitempty"`

	// Microphone maps to Permission Policy `microphone`.
	Microphone *struct{} `json:"microphone,omitempty"`

	// Geolocation maps to Permission Policy `geolocation`.
	Geolocation *struct{} `json:"geolocation,omitempty"`

	// ClipboardWrite maps to Permission Policy `clipboard-write`.
	ClipboardWrite *struct{} `json:"clipboardWrite,omitempty"`
}

UIPermissions declares browser Permission-Policy capabilities the App requests. Mirrors the upstream MCP Apps spec's McpUiResourcePermissions shape: a named struct with optional pointer-to-struct{} fields.

The pointer-to-empty-struct pattern matches the spec's wire shape — each permission field marshals to `{}` when set (placeholder for future per-permission options) and is omitted entirely when nil.

Wire example:

"permissions": { "microphone": {}, "clipboardWrite": {} }

Hosts MAY honor these by setting iframe `allow=` attributes. Apps SHOULD NOT assume permissions are granted — use JS feature detection as fallback.

type UIVisibility

type UIVisibility string

UIVisibility controls tool access scope in the MCP Apps extension.

const (
	// UIVisibilityModel means the tool appears in tools/list for the LLM.
	UIVisibilityModel UIVisibility = "model"

	// UIVisibilityApp means the tool is callable by apps from the same server.
	UIVisibilityApp UIVisibility = "app"
)

type URLElicitationRequiredErrorData added in v0.2.41

type URLElicitationRequiredErrorData struct {
	Elicitations []ElicitationRequest `json:"elicitations"`
	Extra        map[string]any       `json:"-"`
}

URLElicitationRequiredErrorData is the structured data for a -32042 error. The Elicitations field carries URL-mode elicitation requests. Extra holds additional metadata (e.g., authorization denial context from FineGrainedAuth UC1). Extra keys are flattened into the top-level JSON object.

func (URLElicitationRequiredErrorData) MarshalJSON added in v0.2.41

func (d URLElicitationRequiredErrorData) MarshalJSON() ([]byte, error)

MarshalJSON flattens Extra keys into the top-level alongside elicitations.

type UnsupportedProtocolVersionData added in v0.2.47

type UnsupportedProtocolVersionData struct {
	Supported []string `json:"supported"`
	Requested string   `json:"requested"`
}

UnsupportedProtocolVersionData is the structured error payload returned when a stateless request advertises a protocol version this server does not implement. Supported lists the server's full SupportedStatelessVersions so the client can pick a fallback; Requested echoes the version string the client sent for diagnostics.

HTTP status: 400. JSON-RPC code: ErrCodeUnsupportedProtocolVersion (-32022).

type UpdateTaskRequest added in v0.2.41

type UpdateTaskRequest struct {
	TaskID         string         `json:"taskId"`
	InputResponses InputResponses `json:"inputResponses,omitempty"`
}

UpdateTaskRequest is the params payload for tasks/update — the MRTR-driven resume path. The client supplies InputResponses keyed by the same ids returned in DetailedTask.InputRequests. // SEP-2663

type UpdateTaskResult added in v0.2.41

type UpdateTaskResult struct {
	// ResultType is the SEP-2322 polymorphic-dispatch discriminator. Always
	// "complete" for the tasks/update ack (defaulted by MarshalJSON when empty).
	ResultType ResultType `json:"resultType"`
}

UpdateTaskResult is the (essentially empty) ack returned by tasks/update. Servers resume task execution asynchronously; clients learn the outcome via the next tasks/get. The wire payload carries only the SEP-2322 resultType discriminator so polymorphic dispatch on tools/call vs tasks/update vs tasks/get is uniform across the protocol. // SEP-2663

func (UpdateTaskResult) MarshalJSON added in v0.2.41

func (u UpdateTaskResult) MarshalJSON() ([]byte, error)

MarshalJSON defaults ResultType to ResultTypeComplete so callers using the zero value (UpdateTaskResult{}) emit the spec-compliant wire shape without thinking about it.

type WorkingTask added in v0.2.41

type WorkingTask = DetailedTask

SEP-2663 narrowed aliases — convenient names for callers that have already branched on status. The wire shape is identical to DetailedTask; the alias just communicates which fields the caller expects to be populated.

Jump to

Keyboard shortcuts

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