Least privilege for AI agents. A zero-trust security gateway for the Model Context Protocol, in a single Go binary.
Your MCP setup today is a blanket grant: every connected server exposes every tool to the agent, all the time. Aegis-MCP ends that. It sits as the one MCP server your AI host talks to, fronts all your real servers, and enforces capability-level scopes on every single transaction — the agent sees only what the active security profile permits, escalations need a human, and every decision lands in an audit log.
flowchart LR
Host["AI Host<br>Claude Desktop, Cursor, ..."]
Aegis["Aegis-MCP gateway<br>policy - audit - HITL"]
FS["filesystem MCP"]
GH["github MCP"]
SQ["sonarqube MCP"]
Host -->|"stdio (MCP)"| Aegis
Aegis -->|"filtered + namespaced"| Host
Aegis --> FS
Aegis --> GH
Aegis --> SQ
More diagrams — use cases, enforcement and approval flows, the approval lifecycle — in docs/diagrams.md.
- Default-deny capability profiles — tools and resources outside the active profile
are invisible in
tools/listand blocked if called anyway. - No agent self-elevation — profile switches follow a pre-declared transition graph;
everything else requires a human decision (
aegis approve <id>), delivered without blocking the agent or deadlocking the host. - Anti-spoofing tool names — every tool is namespaced by its origin server
(
filesystem__read_file), with startup collision detection against shadowing. - Traversal-safe resource scoping — URI patterns are matched host-aware after
canonicalization;
../and encoded traversal are rejected. - Audit everything — one structured JSON record per security decision, including human approvals. Denials are never silent.
- Fail-closed by construction — invalid policy, an unopenable audit log, or an unbindable approval socket refuse to start.
- Small, auditable footprint — one static binary, two runtime dependencies (the official MCP Go SDK and yaml.v3), a network-free pure core at 82–100% test coverage, race-clean.
This repository contains Cycle 1: the open-source local sidecar. See Roadmap for what's next.
MCP inherits structural gaps from JSON-RPC 2.0: unregulated tool connections enable prompt injection, tool poisoning, broad token passthrough, and command execution. Aegis is a protocol-specific firewall for MCP traffic, built on the zero-trust principles in Anthropic's Zero Trust for AI Agents: assume breach, verify every interaction, least privilege, agent identity, continuous monitoring.
Download a prebuilt binary for Linux, macOS, or Windows (amd64/arm64) from the
latest release, verify it
against checksums.txt, and drop it on your PATH — or build from source:
git clone https://github.com/osick/aegis-mcp
cd aegis-mcp && make build # requires Go 1.26+Or with the Go toolchain directly (releases v0.1.1 and later):
go install github.com/osick/aegis-mcp/cmd/aegis@latestAegis is a single Go binary that speaks MCP over stdio. Point your host at it and let it dial the downstream servers declared in the config.
make build
AEGIS_CONFIG=testdata/aegis.yaml ./aegis # run the gateway (stdio MCP server)
./aegis approve apr_1 # approve a pending profile switch
./aegis deny apr_1 # deny it insteadAEGIS_CONFIGselects the policy file (defaults toaegis.yaml). If it cannot be loaded or validated, Aegis refuses to start (fail-closed, exit 1).- Each configured downstream server is dialed as a stdio subprocess. If a server fails to start it is skipped (per-server fail-closed) and the rest continue.
- Audit records are JSON lines on stderr by default, or an append-only file if
AEGIS_AUDIT_LOG=<path>is set — never stdout, which is reserved for the MCP protocol (ADR 007). Approval prompts also go to stderr.
A profile is a named set of capabilities, declared in aegis.yaml:
allow— tool capabilities (server.tool, orserver.*glob) the profile may call.resources— resource URI patterns (file:///repo/**) the profile may list/read, matched host-aware and traversal-safe.extends— inherit another profile'sallow/resources.allowed_transitions— which profiles this profile may switch to without human approval (the switch-authorization graph).activation.default_profile— the profile Aegis starts in.error_disclosure—verbose(tell the agent which profile would grant a denied capability) orminimal(don't, for hardened deployments).
The host (agent) requests a switch via the aegis.set_profile meta-tool:
- If the target is in the active profile's
allowed_transitions, the switch happens immediately. - Otherwise Aegis returns
AEGIS_PENDING_APPROVALwith an approval id, prints a prompt to stderr, and keeps the old profile active. A human decides out-of-band by runningaegis approve <id>(oraegis deny <id>) — delivered to the running gateway over a per-user unix socket (ADR 008); the agent then callsaegis.approval_statusto apply it, and the applied switch is audited as a human decision. Approvals are single-use and bound to the profile they were granted from.
Tools and resources outside the active profile are invisible in tools/list /
resources/list and blocked (with a structured AEGIS_CAP_DENIED /
AEGIS_RESOURCE_DENIED error) if called directly.
cmd/aegis/ Entrypoint: load config, dial downstreams, serve over stdio (fail-closed)
internal/ All logic. Split into a network-free "pure core" and an "I/O shell".
config/ aegis.yaml schema, loading, and fail-closed validation
policy/ PURE CORE — compiled policy: tool-glob matching, host-aware
traversal-safe resource URI matching, the transition graph
enforcer/ PURE CORE — the chokepoint: filter *_list, authorize *_call
profilestate/ PURE CORE — active profile + switch authorization (graph + HITL routing)
approval/ PURE CORE — non-blocking pending-approval store + terminal channel
naming/ PURE CORE — server__tool wire names, collision detection, anti-shadowing
aegiserr/ PURE CORE — stable structured errors with configurable disclosure
audit/ PURE CORE — structured JSON decision log (one record per decision)
approvalipc/ `aegis approve/deny <id>` → running gateway, over a per-user unix socket
gateway/ I/O SHELL — adapts the official MCP Go SDK to the pure core:
DownstreamClient seam, registry, router, Core, the enforcing
middleware (server.go), and the real-SDK end-to-end tests
testdata/aegis.yaml Sample policy (filesystem / github / sonarqube; default/code-review/deploy)
docs/architecture/ ADR_001–009: the key design decisions and their rationale
docs/diagrams.md Use-case, flow, sequence, and state diagrams (Mermaid)
docs/superpowers/specs/ Full design spec (Cycle 1)
docs/superpowers/plans/ The task-by-task implementation plan
Architecture in one sentence: a security-critical pure core with no network or SDK dependency (so it can be reasoned about and unit-tested exhaustively), wrapped by a thin gateway shell that installs a single receiving middleware as the protocol-boundary chokepoint — nothing reaches a downstream server without passing core authorization. See ADR 006.
Enforced and regression-tested (verified by two adversarial review rounds):
- Default-deny everywhere — unknown profiles and unlisted capabilities/resources are denied.
- No agent self-elevation — an agent can only switch along a pre-declared edge; anything else requires a human. Defeats both vertical escalation and lateral spread between disjoint same-level profiles. (ADR 002)
- Traversal-safe, host-aware resource scoping —
..//encoded traversal is rejected, and patterns scoped to one repo/host can't be bypassed by another. (ADR 004) - Anti-shadowing — origin-namespaced tool names + startup collision detection. (ADR 005)
- Non-blocking HITL — escalations never hold the JSON-RPC call open (no host deadlock); approvals are single-use and context-bound. (ADR 003)
- Fail-closed — bad config, an unopenable audit log, or an unbindable approval socket refuses to start; an unreachable downstream drops out rather than opening access; every denial — and every applied human approval — is audited, never silent.
Requires Go 1.26+ (the version go.mod targets). The only external dependency is the
official github.com/modelcontextprotocol/go-sdk v1.7.0 (plus gopkg.in/yaml.v3).
The SDK negotiates the protocol version per connection, so both classic
(2025-06-18/2025-11-25) hosts and downstream servers on either side of the
2026-07-28 spec work; see
ADR 009.
make build # build ./aegis
make test # go test ./...
make cover # go test -cover ./...
go test -race ./... # race detector (gateway maps are mutex-guarded)The pure-core packages sit at 82–100% coverage; the SDK-facing gateway at ~88%. The
end-to-end tests in internal/gateway/ exercise a real MCP SDK server over an
in-memory transport, and a real stdio subprocess — not mocks. CI runs build, vet, and
the race-enabled suite on every push and pull request.
make build.- Configure your host (Claude Desktop / Cursor) to launch Aegis as an MCP server:
- command: the built
./aegisbinary - env:
AEGIS_CONFIG=/abs/path/to/testdata/aegis.yaml
- command: the built
- In the host, list available tools. Confirm:
- Only
default-profile capabilities appear, namespaced by origin (filesystem__read_file). - The meta-tools
aegis.set_profileandaegis.approval_statusare present. - High-privilege tools such as
github__deployare not listed.
- Only
- Ask the agent to call a non-listed tool (e.g.
github__deploy): expect anAEGIS_CAP_DENIEDerror, with the denial in the audit log on stdout. - Ask the agent to
set_profiletocode-review(a declared transition): it succeeds (code=OK active=code-review) and the additional tools become visible. - Ask the agent to
set_profiletodeployfromdefault(not a direct edge): expectAEGIS_PENDING_APPROVALand a prompt on stderr; the profile stays unchanged until a human approves. - In another terminal, run
aegis approve <id>with the id from the prompt (expectok), then have the agent callaegis.approval_statuswith that id: the switch applies, thedeploytools become visible, and the audit log records the switch with"source":"human".
Aegis is open-core: the local sidecar is OSS; a central control plane is the commercial layer.
- Cycle 1 — this repo (done): aggregating proxy, default-deny policy, context profiles, traversal-safe resource matching, tool namespacing, non-blocking HITL, audit log.
- Cycle 2: kernel sandboxing (seccomp/Seatbelt) + egress/DNS control for downstream servers.
- Cycle 3: OAuth 2.1/PKCE token broker (Client ID Metadata Documents; DCR is deprecated as of MCP 2026-07-28) + central control plane (fleet policy, audit aggregation, dashboards).
Deferred within Cycle 1 (tracked in the spec §10): argument-level constraints, resource content-injection inspection, and timed approval expiry.
- Design spec —
docs/superpowers/specs/2026-06-15-aegis-mcp-gateway-design.md - Implementation plan —
docs/superpowers/plans/2026-06-15-aegis-mcp-gateway-cycle1.md - Architecture decisions —
docs/architecture/ADR_001…ADR_009 - Diagrams — docs/diagrams.md
- Reporting vulnerabilities — docs/SECURITY.md
- Contributing — docs/CONTRIBUTING.md
Apache License 2.0 — see LICENSE.