Skip to main content
An MCP server you connect ships tools that reach out to the network — a fetch, a web_search, a webhook poster. The tool name might be on your allow-list, the arguments might look clean, and the call still ends up posting your data to an attacker-controlled host or pulling credentials off the 169.254.169.254 metadata endpoint. The destination is the part of the call your tool-name rules never see. mcp egress control closes that gap. An egress rule scopes a firewall verdict to where a tool reaches — a host, an IP, or a CIDR range — so the same http_fetch that’s allowed to api.openai.com is denied to everything else. It runs on the firewall’s egress surface, on top of the per-call evaluation every tools/call already goes through.
This is a console task. Firewall rules live on the /api/workspace/firewall/* routes, which authenticate with your session / access token — not a relay sk-orca-… key. Authoring a rule requires the Developer+ role.

1. What an egress rule controls

A normal rule matches on the tool name and its arguments. An egress rule adds a third dimension: the destination the call resolves to. You set the rule’s stage to egress and attach an egress_json list of allow / deny entries. The engine extracts the destination host from the call and only fires the rule when that host is in scope. Entries are matched three ways:

Hostname

Case-insensitive exact match, e.g. api.openai.com. A trailing dot is trimmed on both sides.

IP literal

Exact match against the resolved dial IP, e.g. 169.254.169.254.

CIDR range

The destination IP — literal or DNS-resolved — must fall inside the block, e.g. 10.0.0.0/8.
When a destination is a hostname but your list carries IP/CIDR entries, the name is resolved and its IPs are re-checked — so metadata.internal matches a 169.254.0.0/16 deny even though it isn’t listed by name. This is best-effort defense-in-depth against a name that resolves into a denied range; the authoritative SSRF guard still runs at the gateway’s dial layer.

2. One concrete example

Deny every fetch-shaped tool from reaching the cloud-metadata endpoint and RFC-1918 ranges. This is the canonical SSRF exfil-leg cut: a deny verdict on the egress stage, scoped by an egress_json denylist.
curl https://api.orcarouter.ai/api/workspace/firewall/rules \
  -H "Authorization: Bearer <your-session-or-access-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "policy_id": 12,
    "priority": 10,
    "label": "Deny SSRF / metadata egress",
    "stage": "egress",
    "tool_name_glob": "*",
    "verdict": "deny",
    "egress_json": "{\"deny\":[\"169.254.169.254\",\"10.0.0.0/8\",\"172.16.0.0/12\",\"192.168.0.0/16\"]}"
  }'
A tools/call whose destination resolves into any of those ranges comes back to the model as a tool error; a call to a public host the denylist doesn’t cover passes through.
The allow/deny lists flip meaning with the verdict. On a deny (or other enforcing) rule, the deny list is the in-scope set and allow carves out exemptions — “deny these, except those.” On an allow rule the roles invert: the allow list is the in-scope set and deny carves out exemptions — “allow only these.” A non-empty egress_json must declare at least one allow or deny entry, or the write is rejected.

3. Allow-list only one destination

The inverse of the example above: pin a fetch tool to a single sanctioned host and let the policy’s default_verdict (or a later catch-all) handle the rest. Because this is an allow verdict, the allow list is the in-scope set.
// egress_json on an allow-verdict, stage=egress rule
{ "allow": ["api.openai.com", "api.anthropic.com"] }
The rule now fires (allows) only when the destination is one of those two hosts. Anything else falls through to the next rule — pair this with a default-deny policy so an unlisted destination is refused rather than waved through.
Test it before you trust it. The console’s Test tab and the POST /api/workspace/firewall/test endpoint (Developer+) replay a sample call against your draft policy so you can confirm the verdict on a known destination without sending live traffic.

4. How it composes with the rest of the firewall

An egress rule is one rule among many in a workspace firewall policy. The engine walks rules in priority order (lowest first) and the first match wins, so place a tight egress deny above any broad allow.
Verdict on an egress ruleEffect
denyBlocks the call to in-scope destinations — recorded on the egress surface and returned to the tool as an error.
auditLogs the matched call as a firewall event; still dispatches.
allowPermits in-scope destinations; pairs with a default-deny floor.
pending_approval and cap_cost are not enforced on the egress surface — egress is a destination check, not a hold or a spend cap. Use those verdicts on the mcp or inbound surfaces instead. See the verdict reference.
Two related controls are worth wiring alongside an egress rule:
Independently of any rule you author, the MCP gateway validates every server endpoint and its resolved dial IP against an SSRF policy — intranet ranges and the cloud-metadata address are refused, and the IP is re-checked on every hop to defeat DNS rebinding. Your egress rule layers a workspace-specific destination policy on top of that baseline.
A single egress deny stops a tool reaching a host. A sequence rule stops the chain — e.g. “read a file, then egress within the window” — by flagging the egress leg only when it follows a sensitive read. That’s the lethal-trifecta breaker; egress scoping is the per-call control.

5. Shadow it first, then enforce

Rolling an egress deny straight to enforcement on a busy workspace risks breaking a legitimate integration you forgot about. Two safety nets:
  • Shadow mode. A policy in shadow mode downgrades every enforcing verdict to audit — your egress deny logs [shadow] would deny … instead of blocking, so you see the blast radius before it bites.
  • Observe mode. The workspace firewall_observe_mode setting logs uncovered calls as Discovered Tools, surfacing the real destinations your agents already reach so you can write an accurate allow-list from data instead of guesswork.
Egress destination matching keys on the host the call resolves to at evaluation time. A hostile server can still rebind DNS between the policy check and the actual dial (TOCTOU) — which is exactly why the gateway’s socket-layer IP guard is the authoritative control and this rule is defense-in-depth, not the only line.

6. Roles and routes

All console routes are workspace-scoped and authenticate with your session / access token. Reads are open to any Member; authoring or editing a rule requires Developer+.
Method & pathRolePurpose
GET /api/workspace/firewall/policies/:idMemberRead a policy and its rules.
POST /api/workspace/firewall/rulesDeveloper+Add a rule (set stage: egress).
PUT /api/workspace/firewall/rulesDeveloper+Update a rule (id in body).
DELETE /api/workspace/firewall/rules/:idDeveloper+Remove a rule.
POST /api/workspace/firewall/testDeveloper+Replay a sample call against a draft policy.

Firewall rules reference

The full rule DSL — tool globs, args matching, egress lists, sequences.

Connect an MCP server

Register a server so its tool calls run behind the firewall.

Allow-list MCP tools

Default-deny the tools you didn’t explicitly approve.

Data exfiltration

The threat egress control is built to stop.