All concepts
VisualIntro3 minSince 1.6.0
foundationsarchitectureenforcementegress-policyproxy

The request path

Updated July 22, 2026

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. Open a stage to read what fires there — the explanations live inside the diagram, in the order the call meets them.

  1. ClientClient / agentA tools/call arrives, carrying a token.

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

  2. Enforcement seam · the Hangar proxy

    IdentityThe front door resolves the caller to a tenant and a principal.unauthenticated: rejected here

    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.

  3. ContractThe tool-schema digest pinned for this caller is verified.drift fails closed

    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.

  4. Egress policy (L7)Tool-name globs and an argument scan produce the verdict.deny always winsaudit is the default

    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 this stage 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.

  5. Network · L3/L4The network backstopNetworkPolicy or Cilium — the seam cannot be bypassed.no backstop: fails closed

    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.

  6. UpstreamUpstream MCP serverAllowed calls are relayed untouched. The upstream owns the work.

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

  7. ResponseThe return tripResult → redact secrets → audit → client.

    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 recorded as a governance event. 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.)

Every verdict is deterministic — no scores, no heuristics — and recorded as an attributed governance event.

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.