Roadmap
Aegis is small on purpose. Everything below is judged by one question: does it earn its place in a component whose value comes from having very little surface?
v1 — done
Identity
OAuth 2.1 authorization server with discovery, dynamic client registration, PKCE, a login form, and refresh rotation with family invalidation on reuse.
Transport
MCP over Streamable HTTP on port 2019, JSON-RPC with batches, session ids bound to their access token, DNS-rebinding protection on Origin.
Authorisation
Deny-by-default target matching on host, path glob and method, per-user allow_any, per-target rate limits, and a network guard that no user can disable.
Mediation
Declarative injection into headers, query parameters and JSON bodies; response redaction, truncation and cookie stripping; one audit line per request.
Operations
Config hot-reload on file change and SIGHUP that keeps the old config on a bad edit, a validate subcommand, and a distroless image that runs read-only as non-root.
Assurance
Race-enabled tests, a fuzz-style leak harness, govulncheck in CI, and multi-arch images with signed build provenance.
Under consideration
None of these are promised. Each would be added only if it turns out to be needed in practice.
| Idea | Why it might be worth it |
|---|---|
| Trusted proxies for the client IP | Behind Traefik or Cloudflare, per-IP rate limiting collapses into a single bucket. A configured list of proxy addresses whose X-Forwarded-For may be believed would fix it. See the client IP problem. |
| Response filters per target | Allow-listed JSON paths, so only the part of a response the agent needs reaches the context. Shrinks both the token bill and the exfiltration surface — at the cost of maintaining a filter per endpoint. |
| Per-target tool generation | An opt-in that turns a target into its own named tool, improving the model's aim on a busy config. |
| Optional persistence | For deployments that value uptime over amnesia and would rather not have every client re-register after a restart. |
| mTLS or IP allow-listing | A second factor in front of the MCP endpoint, for aegis instances exposed to the open internet. |
| Audit log shipping | Webhook or syslog output, so the record survives the container that produced it. |
| Request approval | Hold a request until a human confirms it — useful for a target with write access that you are not ready to trust unattended. |
| Form-encoded body injection | Today body injection is JSON only. application/x-www-form-urlencoded is common enough that it may deserve support. |
Deliberately rejected
A web admin UI
Every form that edits secrets is a new way to leak them. The config file is the interface.
Request transformation
Aggregation, caching, schema translation. That is an API gateway, and it is a different product.
A plugin system
Arbitrary code in the process that holds the credentials — the opposite of the point.
Model-placed secrets
Letting the model decide where a secret goes hands placement back to the manipulable component.
Being a secret manager
No rotation, no versioning, no checkout. Point env: and file: at Vault or Docker secrets instead.
Multi-tenant SaaS
Aegis is a personal or small-team component. That assumption keeps the code readable.
Open questions
Decisions not yet made. Opinions welcome in an issue.
- Token revocation on password change. Today, changing a password does not invalidate existing tokens — they were issued against a prior successful authentication. Should a per-user
revoke_on_password_changeexist, or should it simply be the default? - Describing
allow_anyto the model. How should an unrestricted user's permission be presented inlist_targetsso the model does not simply start guessing URLs? - Refresh token lifetime. Thirty days is an arbitrary choice. Configurable per user, or a shorter fixed default?
- Streaming responses. v1 buffers a whole response in order to redact it, so downloads are bounded by
max_response_bytes. Is a streaming redactor with a sliding window worth the complexity? - The 8-byte redaction floor. Currently a startup warning. Should a secret too short to redact refuse to load at all?
Contributing
Issues and pull requests are welcome. The bar for new surface is deliberately high — if a change adds a configuration key, a dependency or an endpoint, the pull request should say what it buys and what it costs.
git clone https://github.com/andreaskasper/aegis cd aegis/src go test -race ./... go vet ./... && gofmt -l . go run . validate ../config.example.yaml
CI enforces formatting, vet, a tidy go.mod, race-enabled tests, govulncheck, and that the image builds and answers /healthz while refusing unauthenticated MCP calls.
aegis