15 -- Interceptor Discovery
Prerequisite: 14 -- Upgrade: Digest Pinning You will need: Docker,
curl,jqTime: 10 minutes Adds: SEP-1763 interceptor discovery client checks
The Problem
MCP Hangar exposes its validator and mutator capabilities through
/interceptors/list. Clients can use this endpoint to discover what Hangar can
validate or mutate before sending traffic through it.
The interceptor framework shipped in v1.2.0, and since v1.2.1 the two interceptor
entries have distinct names. Since 2.29.1 they are SEP-2133 identifiers,
{vendor-prefix}/{extension-name}:
io.mcp-hangar/validatorio.mcp-hangar/mutator
From 2.0.0 to 2.29.0 the default listing named them io.mcp-hangar.validator
and io.mcp-hangar.mutator, with a dot, and from v1.2.1 to v1.6.x
mcp-hangar-validator and mcp-hangar-mutator. The listing answers only the
new names; interceptor/invoke still accepts the older ones as aliases.
If your client still assumes one shared mcp-hangar name, it can overwrite one
entry with the other or fail uniqueness validation.
The Config
Create a minimal config for a local Docker smoke test:
mkdir -p /tmp/hangar-interceptors
printf 'mcp_servers: {}\n' > /tmp/hangar-interceptors/config.yaml
No MCP servers are required. /interceptors/list describes Hangar itself.
Try It
-
Start Hangar in HTTP mode
docker run -d --name hangar-interceptors \ -p 127.0.0.1:8000:8000 \ -v /tmp/hangar-interceptors/config.yaml:/config.yaml:ro \ python:3.11-slim sh -lc ' pip install --quiet "mcp-hangar>=1.3.0" && mcp-hangar --config /config.yaml serve \ --http --host 0.0.0.0 --port 8000 --unsafe-no-auth '--unsafe-no-authis only for this local smoke test. Do not use it for a production deployment. -
Wait for readiness
until curl -fsS http://localhost:8000/health/ready 2>/dev/null; do sleep 2; doneExpected output:
{"status":"healthy","ready_mcp_servers":0,"total_mcp_servers":0} -
Fetch interceptor capabilities
curl -s http://localhost:8000/interceptors/list | jqExpected output:
{ "interceptors": [ { "name": "io.mcp-hangar/validator", "version": "2.24.0", "type": "validator", "supportedEvents": ["tools/call", "tools/list"], "modes": ["audit", "enforce"], "trustBoundary": "host" }, { "name": "io.mcp-hangar/mutator", "version": "2.24.0", "type": "mutator", "supportedEvents": ["tools/call"], "modes": ["enforce"], "trustBoundary": "host" } ] } -
Verify names are unique
curl -s http://localhost:8000/interceptors/list | jq -e ' .interceptors as $items | ($items | length) == ($items | map(.name) | unique | length) 'Expected output:
true -
Build a lookup table by interceptor name
curl -s http://localhost:8000/interceptors/list | jq ' .interceptors | map({key: .name, value: .}) | from_entries | keys 'Expected output:
[ "io.mcp-hangar/mutator", "io.mcp-hangar/validator" ] -
Check the capabilities your client needs
curl -s http://localhost:8000/interceptors/list | jq -e ' any(.interceptors[]; .name == "io.mcp-hangar/validator" and .type == "validator" and (.supportedEvents | index("tools/list")) and (.modes | index("audit")) ) 'Expected output:
true -
Stop the smoke-test container
docker rm -f hangar-interceptors
What Just Happened
/interceptors/list returns a list of Hangar interceptor instances. Since v1.2.1
the validator and mutator entries use different names so SEP-1763 clients can
treat them as separate capabilities.
The important client rule is: key interceptors by name, then validate the
fields you care about (type, supportedEvents, and modes). Do not collapse
all Hangar entries into a single hard-coded mcp-hangar record.
The response above is the default shape. A client that negotiates the
interceptor extension -- the header
MCP-Interceptor-Ext: io.modelcontextprotocol/interceptors, or
?ext=io.modelcontextprotocol/interceptors on the GET -- receives the newer
shape instead: type is validation or mutation, events move into a
hooks array with a phase, and modes becomes a single mode. Up to 2.29.0
that shape named the entries mcp-hangar-validator and
mcp-hangar-mutator. Since 2.29.1 both shapes use the same two names, one per
interceptor.
Key Config Reference
No config keys are required for discovery. The endpoint is exposed by the HTTP server when Hangar runs in HTTP mode.
| Field | Meaning |
|---|---|
name | Unique interceptor instance name |
version | MCP Hangar package version |
type | Interceptor role, such as validator or mutator |
supportedEvents | MCP event names the interceptor handles |
modes | Supported operation modes |
trustBoundary | Where the interceptor runs relative to the client |
What's Next
Use this check in integration tests for clients that consume SEP-1763 metadata. For implementation details, see Interceptor Framework.