Documentation
¶
Overview ¶
Package interceptors defines the core types for the MCP interceptor framework: interceptor descriptors (Validator, Mutator), wire protocol types (InvokeParams, InvokeResult), result types (ValidationResult, MutationResult), and supporting enums.
This package is transport-agnostic — it has no dependency on the MCP SDK's server or client types. The chain orchestrator lives in the interceptors/chain sub-package, MCP server integration in interceptors/extension, and middleware in interceptors/integrations/gomiddleware.
Usage with MCP ¶
Create an [extension.Extension], register interceptors, install on an mcp.Server, then use [extension.Extension.LocalChain] to get a chain for middleware:
ext := extension.New()
ext.AddInterceptor(myValidator)
ext.AddInterceptor(myMutator)
ext.Install(mcpServer)
chain, err := ext.LocalChain(ctx, mcpServer)
mcpServer.AddReceivingMiddleware(
gomiddleware.Middleware(chain),
)
Validators ¶
A Validator inspects the payload and decides whether the request or response should proceed. All validators for a given event run in parallel. If any validator in enforced mode (ModeEnforce) returns an error-severity message, the chain aborts before any mutators run. Only error-severity messages cause an abort; warn and info findings are recorded in the chain execution result but do not block the chain.
Interceptor handlers receive json.RawMessage payloads when invoked via interceptor/invoke:
v := &interceptors.Validator{
Metadata: interceptors.Metadata{
Name: "block-dangerous-tool",
Hook: interceptors.Hook{
Events: []string{"tools/call"},
Phase: interceptors.PhaseRequest,
},
Mode: interceptors.ModeEnforce,
},
Handler: func(ctx context.Context, inv *interceptors.Invocation) (*interceptors.ValidationResult, error) {
raw := inv.Payload.(json.RawMessage)
var params struct{ Name string `json:"name"` }
json.Unmarshal(raw, ¶ms)
// inspect params ...
return &interceptors.ValidationResult{Valid: true}, nil
},
}
Mutators ¶
A Mutator transforms the payload. Mutators run sequentially in priority order (see Priority). Each mutator receives the payload as json.RawMessage, unmarshals it, modifies it, and sets the updated JSON back on inv.Payload. If any mutator fails (and is not configured with FailOpen), the chain aborts. FailOpen mutators record an InvokeResult (with the error captured) for observability but do not block.
m := &interceptors.Mutator{
Metadata: interceptors.Metadata{
Name: "redact-pii",
Hook: interceptors.Hook{
Events: []string{"tools/call"},
Phase: interceptors.PhaseResponse,
},
Mode: interceptors.ModeEnforce,
},
Handler: func(ctx context.Context, inv *interceptors.Invocation) (*interceptors.MutationResult, error) {
raw := inv.Payload.(json.RawMessage)
var result map[string]any
json.Unmarshal(raw, &result)
// modify result ...
data, _ := json.Marshal(result)
return &interceptors.MutationResult{Modified: true, Payload: data}, nil
},
}
Execution Order ¶
The chain execution order depends on direction:
Request phase (untrusted → trusted):
Validate (parallel) → Mutate (sequential)
Response phase (trusted → untrusted):
Mutate (sequential) → Validate (parallel)
Validators act as a security gate on the trust boundary side, while mutators prepare or sanitize data on the other side.
Modes and FailOpen ¶
Each interceptor has a Mode that controls what happens with successful results, and a FailOpen flag that controls what happens when the handler returns a Go error. These are orthogonal:
- ModeEnforce: fully enforced — validation failures block, mutations are applied.
- ModeAudit: the handler runs and results are recorded, but validation findings do not block and mutated payloads are not propagated to subsequent interceptors.
FailOpen (default false) controls crash resilience:
- FailOpen=false: a handler error aborts the chain. An InvokeResult and a [chain.AbortInfo] are both recorded.
- FailOpen=true: a handler error is logged and an InvokeResult is recorded, but the chain continues.
Note that ModeAudit does NOT imply FailOpen. Audit mode only suppresses enforcement of successful results (validation findings and mutations). If the handler itself returns an error and FailOpen is false, the chain still aborts. For truly safe observation-only interceptors, set both ModeAudit and FailOpen:
Metadata: interceptors.Metadata{
Mode: interceptors.ModeAudit,
FailOpen: true,
}
Behavior matrix for validators:
Mode=Enforce, FailOpen=false → error aborts, Valid=false+SeverityError aborts Mode=Enforce, FailOpen=true → error continues, Valid=false+SeverityError aborts Mode=Audit, FailOpen=false → error aborts, findings recorded only Mode=Audit, FailOpen=true → error continues, findings recorded only
Behavior matrix for mutators:
Mode=Enforce, FailOpen=false → error aborts, mutations applied Mode=Enforce, FailOpen=true → error continues, mutations applied Mode=Audit, FailOpen=false → error aborts, mutations not propagated Mode=Audit, FailOpen=true → error continues, mutations not propagated
Index ¶
- Constants
- type Compat
- type Hook
- type InterceptionEvent
- type InterceptionPhase
- type Interceptor
- type InterceptorInfo
- type InterceptorType
- type Invocation
- type InvocationContext
- type InvokeParams
- type InvokeResult
- type ListParams
- type ListResult
- type Metadata
- type Mode
- type MutationResult
- type Mutator
- type MutatorHandler
- type Principal
- type Priority
- type Severity
- type ValidationMessage
- type ValidationResult
- type ValidationSuggestion
- type Validator
- type ValidatorHandler
Constants ¶
const ( MethodList = "interceptors/list" MethodInvoke = "interceptor/invoke" )
JSON-RPC method names for the interceptor protocol.
const ( // Server Features EventToolsList = "tools/list" EventToolsCall = "tools/call" EventPromptsList = "prompts/list" EventPromptsGet = "prompts/get" EventResourcesList = "resources/list" EventResourcesRead = "resources/read" EventResourcesSubscribe = "resources/subscribe" )
Event name constants for standard MCP methods.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Compat ¶
type Compat struct {
MinProtocol string `json:"minProtocol"`
MaxProtocol string `json:"maxProtocol,omitempty"`
}
Compat represents protocol version compatibility.
type Hook ¶
type Hook struct {
Events []InterceptionEvent `json:"events"`
Phase InterceptionPhase `json:"phase"`
}
Hook defines which lifecycle events and phase trigger an interceptor.
type InterceptionEvent ¶
type InterceptionEvent = string
InterceptionEvent identifies a lifecycle event that can be intercepted.
type InterceptionPhase ¶
type InterceptionPhase string
InterceptionPhase determines when an interceptor runs.
const ( PhaseRequest InterceptionPhase = "request" PhaseResponse InterceptionPhase = "response" PhaseBoth InterceptionPhase = "both" )
type Interceptor ¶
type Interceptor interface {
GetMetadata() *Metadata
GetType() InterceptorType
}
Interceptor is the common interface for all interceptors. It is implemented by both Validator and Mutator.
type InterceptorInfo ¶
type InterceptorInfo struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
Type InterceptorType `json:"type"`
Hook Hook `json:"hook"`
PriorityHint Priority `json:"priorityHint,omitempty"`
Compat *Compat `json:"compat,omitempty"`
ConfigSchema json.RawMessage `json:"configSchema,omitempty"`
Mode Mode `json:"mode"`
FailOpen bool `json:"failOpen,omitempty"`
}
InterceptorInfo describes a registered interceptor in wire format.
func InfoFromInterceptor ¶
func InfoFromInterceptor(i Interceptor) InterceptorInfo
InfoFromInterceptor builds an InterceptorInfo from an Interceptor.
type InterceptorType ¶
type InterceptorType string
InterceptorType identifies the category of an interceptor.
const ( TypeValidation InterceptorType = "validation" TypeMutation InterceptorType = "mutation" )
type Invocation ¶
type Invocation struct {
Event string // e.g. "tools/call"
Phase InterceptionPhase // "request" or "response"
Payload any // The payload (json.RawMessage when invoked via interceptor/invoke)
Config map[string]any // Per-invocation config
Context *InvocationContext // Optional caller context (identity, trace, etc.)
}
Invocation is the context passed to every interceptor handler.
type InvocationContext ¶
type InvocationContext struct {
Principal *Principal `json:"principal,omitempty"`
TraceID string `json:"traceId,omitempty"`
SpanID string `json:"spanId,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
SessionID string `json:"sessionId,omitempty"`
}
InvocationContext holds optional context passed to interceptors.
type InvokeParams ¶
type InvokeParams struct {
mcp.ParamsBase
Name string `json:"name"`
Event string `json:"event"`
Phase InterceptionPhase `json:"phase"`
Payload json.RawMessage `json:"payload"`
TimeoutMs int64 `json:"timeoutMs,omitempty"`
Config map[string]any `json:"config,omitempty"`
Context *InvocationContext `json:"context,omitempty"`
}
InvokeParams are the parameters for the interceptor/invoke method. The caller specifies which interceptor to invoke by name.
type InvokeResult ¶
type InvokeResult struct {
mcp.ResultBase
Interceptor string `json:"interceptor"`
Type InterceptorType `json:"type"`
Phase InterceptionPhase `json:"phase"`
DurationMs int64 `json:"durationMs"`
// Validation result (type == "validation")
Validation *ValidationResult `json:"validation,omitempty"`
// Mutation result (type == "mutation")
Mutation *MutationResult `json:"mutation,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"` // Mutated payload (only for mutators)
}
InvokeResult is the result of the interceptor/invoke method. Fields are type-specific: validators populate Validation, mutators populate Mutation + Payload.
type ListParams ¶
type ListParams struct {
mcp.ParamsBase
Event string `json:"event,omitempty"` // Filter by event name; empty = all
}
ListParams are the optional parameters for the interceptors/list method.
type ListResult ¶
type ListResult struct {
mcp.ResultBase
Interceptors []InterceptorInfo `json:"interceptors"`
}
ListResult is the result of the interceptors/list method.
type Metadata ¶
type Metadata struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
Type InterceptorType `json:"type"`
Hook Hook `json:"hook"`
PriorityHint Priority `json:"priorityHint,omitempty"`
Compat *Compat `json:"compat,omitempty"`
ConfigSchema json.RawMessage `json:"configSchema,omitempty"`
Mode Mode `json:"mode"`
FailOpen bool `json:"failOpen,omitempty"`
}
Metadata holds all common interceptor metadata.
type MutationResult ¶
type MutationResult struct {
Modified bool `json:"modified"`
Info map[string]any `json:"info,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
}
MutationResult is returned by mutation interceptors.
type Mutator ¶
type Mutator struct {
Metadata
Handler MutatorHandler
}
Mutator is a mutation interceptor.
func (*Mutator) GetMetadata ¶
func (*Mutator) GetType ¶
func (m *Mutator) GetType() InterceptorType
type MutatorHandler ¶
type MutatorHandler func(ctx context.Context, inv *Invocation) (*MutationResult, error)
MutatorHandler is the function signature for raw mutation handlers.
type Principal ¶
type Principal struct {
Type string `json:"type"`
ID string `json:"id,omitempty"`
Claims map[string]any `json:"claims,omitempty"`
}
Principal identifies the caller.
type Priority ¶
Priority represents an interceptor's ordering hint. Can be a single value (applies to both phases) or per-phase.
JSON representation is polymorphic: a single number when both phases are equal, or {"request": N, "response": N} when they differ.
func NewPriority ¶
NewPriority creates a Priority with the same value for both phases.
func (Priority) MarshalJSON ¶
MarshalJSON implements polymorphic serialization: emits a single number when both phases are equal, or an object otherwise.
func (Priority) Resolve ¶
func (p Priority) Resolve(phase InterceptionPhase) int
Resolve returns the priority for the given phase.
func (*Priority) UnmarshalJSON ¶
UnmarshalJSON handles both number and {request, response} forms.
type ValidationMessage ¶
type ValidationMessage struct {
Path string `json:"path,omitempty"`
Message string `json:"message"`
Severity Severity `json:"severity"`
}
ValidationMessage is a single validation finding.
type ValidationResult ¶
type ValidationResult struct {
Valid bool `json:"valid"`
Severity Severity `json:"severity,omitempty"`
Messages []ValidationMessage `json:"messages,omitempty"`
Suggestions []ValidationSuggestion `json:"suggestions,omitempty"`
}
ValidationResult is returned by validation interceptors.
type ValidationSuggestion ¶
ValidationSuggestion is an optional suggested correction.
type Validator ¶
type Validator struct {
Metadata
Handler ValidatorHandler
}
Validator is a validation interceptor.
func (*Validator) GetMetadata ¶
func (*Validator) GetType ¶
func (v *Validator) GetType() InterceptorType
type ValidatorHandler ¶
type ValidatorHandler func(ctx context.Context, inv *Invocation) (*ValidationResult, error)
ValidatorHandler is the function signature for validation handlers.
Handlers MUST treat the Invocation and its Payload as read-only. Multiple validators for the same event run concurrently and share the same Invocation pointer, so any mutation of the Payload (or other Invocation fields) is a data race.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package chain provides the SEP-compliant interceptor chain orchestrator.
|
Package chain provides the SEP-compliant interceptor chain orchestrator. |
|
Package extension registers interceptors as first-class MCP primitives.
|
Package extension registers interceptors as first-class MCP primitives. |
|
integrations
|
|
|
gomiddleware
Package gomiddleware provides an optional MCP middleware that automatically executes interceptors for every matching request/response.
|
Package gomiddleware provides an optional MCP middleware that automatically executes interceptors for every matching request/response. |