--- id: mcp-gateways-operations title: MCP Gateways, Registries and Conformance code: GR subtitle: Route through a stateless gateway, admit registry versions, catch drift, test the wire and gate releases. hue: 30 sources: phases/13-tools-and-protocols/17-mcp-gateways-and-registries, phases/13-tools-and-protocols/23-capstone-tool-ecosystem, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift, phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations source_hash: 30a66413dc9dbd36 --- ## Gateway request path type: architecture from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/docs/en.md, phases/13-tools-and-protocols/17-mcp-gateways-and-registries/code/main.py ```arch node | client | 1,1 | Client | bearer and _meta | client node | wire | 2,1 | validate_wire | headers equal body | process node | policy | 3,1 | RBAC and TokenBucket | per principal | process node | pin | 4,1 | Descriptor pin | descriptor_digest | process node | reg | 1,2 | Registry record | publication only | store node | adm | 2,2 | Admission state | verified publisher | store node | notes | 3,2 | notes backend | fresh request id | process node | issues | 4,2 | issues backend | fresh request id | process edge | client | wire | POST edge | wire | policy | -32020 first edge | policy | pin | allow edge | pin | notes | notes.search edge | pin | issues | issues.list edge | reg | adm | join edge | adm | pin | admit ``` ## Run and verify type: command-table from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/docs/en.md, phases/13-tools-and-protocols/23-capstone-tool-ecosystem/docs/en.md, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md, phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/docs/en.md | Command | What it does | |---|---| | `python3 code/main.py` | Runs the demo from the lesson folder | | `python3 -m unittest discover code/tests -v` | Runs the gateway tests (lesson 17) | | `python3 -m unittest discover -s code/tests -v` | Runs the registry and conformance suites | | `python3 -q` | Opens a shell in `code/` for the labs | | `from main import *` | Loads the lab functions in that shell | ## Gateway tasks in code type: task-table from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/code/main.py, phases/13-tools-and-protocols/23-capstone-tool-ecosystem/code/main.py | Task | Code | |---|---| | Build a request and headers | `make_request(method, request_id, params)` | | Send it as a principal | `gateway.handle("bearer-alice", body, headers)` | | Check the wire first | `validate_wire(body, headers)` | | Pin one descriptor | `descriptor_digest(tool)` | | Rate limit a principal | `TokenBucket().consume()` | | Admit a registry record | `registry_record_is_admissible` | | Scope check in the capstone | `gateway_call(token, tool_name, args, ...)` | ## Registry admission, drift, rollback type: annotated-code lang: python from: phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/code/main.py, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md ```python controller = RegistryAdmissionController(clock=lambda: next(ticks)) active_meta = {OFFICIAL_META_KEY: {"status": "active"}} controller.admit(sample_record("1.1.0"), active_meta, namespace_for_domain("example.com"), # gives com.example evidence_for("1.1.0"), sample_live("1.1.0")) # admit 1.0.0 the same way drift = controller.check_live("com.example/inventory", "1.1.0", sample_live("1.1.0", True)) # extra tool: quarantined controller.observe_registry_status("com.example/inventory", "1.1.0", "deprecated") controller.rollback("com.example/inventory", "1.0.0", "unexpected delete tool") controller.ledger.verify() # False after any edit namespace_matches("com.exampleevil/inventory", "com.example") # False ``` ## Conformance harness type: annotated-code lang: python from: phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code/main.py, phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/docs/en.md ```python validate_result({"tools": []}, "legacy") # infers complete validate_result({"tools": []}, "modern") # raises ProtocolViolation select_era({"kind": "timeout"}, "fallback") # fails closed select_era({"kind": "jsonrpc_error", "code": -32021}, "fallback") # modern cases = [run_transcript(case) for case in transcript_suite()] # 15 cases compare_sdk_view(raw_result, {"tools": []}) # droppedFields futureHint inspect_proxy(exchange) # finds a 400 turned into 500 redact(value) # before hashing or upload evaluate_health(healthy_window()) # samples, error rate, p95 ReleaseGate(signers).evaluate(cases, [sdk_report], [proxy_report], healthy_window(), rollback) # promote or rollback ``` ## Seven admission controls type: flow from: phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md 1. **Namespace**: compare the segment before `/` exactly with the verified namespace. 2. **Provenance**: join registry type, identifier, version, ownership and artifact digest. 3. **Pin**: store record, source, toolset and provenance digests. Never `^1.4` or latest. 4. **Live drift**: call `server/discover`. Any descriptor digest change quarantines the pin. 5. **Status**: read the official `_meta` status. Deprecated or deleted quarantines. 6. **Rollback**: route to an admitted pin that is active and not quarantined. 7. **Ledger**: append each decision with the previous hash and its own hash. ## Gateway errors type: troubleshooting from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/code/main.py, phases/13-tools-and-protocols/17-mcp-gateways-and-registries/docs/en.md | Symptom | Cause | Fix | |---|---|---| | 401 `-32001` | Bearer is not known | Authenticate the principal | | 403 `-32003` | Tool is not in `RBAC` for the user | Grant the role or keep the deny | | 429 `-32029` | `TokenBucket` is empty | Wait for refill | | 409 `-32010` | Live descriptor differs from the pin | Review, then re-approve the pin | | 400 `-32020` | Header and body disagree | Match `Mcp-Method` and `Mcp-Name` | | 400 `-32022` | Matched version is not supported | Send a version in `supported` | | 406 on `subscriptions/listen` | Accept has no `text/event-stream` | Accept SSE | | 405 | GET or DELETE on the endpoint | Send each message as POST | ## Defaults and numbers type: defaults from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/code/main.py, phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code/main.py, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md | Setting | Default | Note | |---|---|---| | Gateway discover `ttlMs` | 30_000 | `cacheScope` private | | Gateway tools/list `ttlMs` | 10_000 | Private because RBAC filters it | | `TokenBucket` `capacity` | 5 | `refill_per_second` 1.0 | | `maxErrorRate` | 0.01 | Health gate default | | `maxP95Ms` | 500 | Health gate default | | `MODERN_VERSION` | 2026-07-28 | Needs `resultType` | | `LEGACY_VERSION` | 2025-11-25 | Only by allowlist and valid `initialize` | | Registry schema | 2025-12-11 | Independent of the protocol version | ## Release failures type: troubleshooting from: phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/docs/en.md, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md | Symptom | Cause | Fix | |---|---|---| | Client goes legacy after `-32021` | Recognized modern error read as legacy | Never fall back after a modern error | | SDK shows `resultType` the wire lacked | SDK synthesizes the discriminator | Validate the raw body | | Origin 400 arrives as 500 | Proxy collapses the error | Compare ingress, origin and egress | | Canary has zero errors and no traffic | No minimum sample count | Enforce `sampleCount` above 0 | | New tool appears after approval | Runtime drift | Quarantine the route | | Rollback target was never admitted | Route and approval state disconnected | Refuse, run a new admission | ## Rules type: tips from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/docs/en.md, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md, phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/docs/en.md - Never pass the outer gateway token to a backend. - Do not copy outer client capabilities to a backend. The gateway is its client. - Key rate limits by principal, issuer, resource, tool, cost class and window. - Preserve `requestState` byte for byte. Re-authorize every MRTR retry. - Route `tasks/get`, `tasks/update`, `tasks/cancel` by `params.taskId` in `Mcp-Name`. - Run admission before a server appears in `tools/list`. - Redact before serialization, hashing, logs or upload. ## Questions type: qa from: phases/13-tools-and-protocols/17-mcp-gateways-and-registries/docs/en.md, phases/13-tools-and-protocols/30-mcp-registry-supply-chain-and-drift/docs/en.md, phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/docs/en.md, phases/13-tools-and-protocols/23-capstone-tool-ecosystem/docs/en.md - **Does registry presence approve a server?** No. Admission policy decides. - **Can `serverInfo` prove the publisher?** No. It is diagnostic data only. - **Is an unknown field an unknown result?** No. Keep the field. Reject an unknown `resultType`. - **Does rollback edit the old record?** No. It changes the active route. - **Does a green capstone run prove the wire?** No. It validates the simulation only.