All concepts
VisualIntro3 minShipped 1.6.0
foundationsarchitectureenforcementegress-policyproxy

The request path

Updated July 22, 2026

The request path

Hangar is a proxy. A client’s tools/call goes in one side, the upstream MCP server’s result comes back the other, and every control Hangar enforces gets its turn on the same path the call already travels. There is no side channel and no background pass. Governance is whatever fires between the client and the upstream, in order, synchronously, on the way through.

This page is that path, drawn once. Follow the request down the spine, watch each control fire at the seam, and follow the result back up.

The Hangar request pathA client’s tool call travels down through the Hangar enforcement seam — identity, contract, and egress policy — is relayed to the upstream behind an L3/L4 network backstop, and the governed result returns up the right-hand side through redaction and audit.Client / agentsends tools/callEnforcement seam · the Hangar proxy1 · IdentityFront-door auth resolves tenant + principal.Unauthenticated → rejected here.2 · ContractTool-schema digest is pinned and verified.Drift from the pinned contract fails closed.3 · Egress policy (L7)Tool-name globs: deny > requireApproval > allow > default.Argument scan: secret patterns + max payload size.Under mode: Enforce, deny/requireApproval block (fails closed).Every verdict is deterministic — no scores, no heuristics —and written to the append-only provenance chain.Allowed calls are relayed, untouched, to the owner.relayL3/L4 network backstop · NetworkPolicy / Cilium — the seam cannot be bypassedUpstream MCP serverowns and runs the workresult → redact secrets → audit → client
The request travels down the spine; the governed result returns up the right. Every control fires on the same synchronous path.

The stages, one caption each

Client / agent. A tool call enters carrying a token. Nothing about it is trusted yet.

1 · Identity. The front door authenticates the caller and resolves it to a tenant and principal. This binding is what every later control keys off. An unauthenticated caller never reaches stage 2 — it is rejected at the door.

2 · Contract. The call is checked against the tool-schema digest pinned for the exact contract the caller was authorized for — resolved at invoke time from the tool-projection registry. If the upstream tool has drifted from that pinned digest, the path fails closed rather than invoke a contract nobody signed off on.

3 · Egress policy (L7). This is the semantic gate. Tool names are matched by glob in a fixed precedence — deny beats requireApproval beats allow beats the policy’s default action — and arguments are scanned for configured secret patterns and an oversized payload. A secret or an outsized payload denies the call even when the tool name is allowed: deny always wins. requireApproval is a hard gate — the call is blocked pending out-of-band approval. It is enforcement, not an interactive queue; the request stops, it does not hang waiting for a click.

Whether stage 3 blocks at all is opt-in. A policy’s spec.mode defaults to Audit — every verdict above is computed and recorded, but nothing is refused; the seam observes. Only under mode: Enforce do deny and requireApproval actually stop the call. The blocking picture on this page is the Enforce-mode picture; Audit is the adoption path you start on.

L3/L4 network backstop. Underneath the L7 seam, the operator compiles the same policy into a NetworkPolicy (or a CiliumNetworkPolicy for FQDN upstreams) that default-denies the server’s egress to everything but the allow-listed hosts. This is the layer that makes the whole path enforcement rather than a suggestion: a policy without the backstop is bypassable, and Hangar fails it closed rather than open when the backstop can’t be applied.

Upstream MCP server. Only an allowed, in-contract call arrives here, relayed untouched. Hangar does not run the work — it relays and governs. The upstream owns execution.

The return trip. The result comes back up the same seam: output is scanned and secret values are redacted, reusing the redactor’s deterministic value-patterns — the same ones argument scanning refuses on the way in, plus one inbound-only PEM addition the redactor does not carry — and the governed result is written to the append-only provenance chain. So most of what the redactor masks on the way out is what a policy refuses on the way in — largely one set of rules, both directions. (A call the policy denies raises EgressPolicyDeniedError before it reaches the wire, short-circuiting this return trip.)

Why it’s drawn as one line

Every control lives on the call path and nowhere else. There is no anomaly score being computed in the background, no separate policy engine the request detours through, no asynchronous approval the call waits on. The verdicts are deterministic functions of the request, the pinned contract, and the policy — which is what makes the path auditable: the same inputs always produce the same verdict, and every verdict leaves a line in the chain. Governance is credible here precisely because it is thin. It binds where the call already flows, and the call flows through exactly one seam.


Grounded in ADR-013 (the egress enforcement model) and the MCPEgressPolicy guide. Everything is MIT and self-hosted — no SaaS tier.