pronounced "eh-feer"
Cryptographically bounded agent authority with centralized audit.
The first open-source implementation of the Delegation Capability Token (DCT) architecture proposed in Google DeepMind's "Intelligent AI Delegation" framework (February 2026).
MCP gives AI agents access to tools. It does not govern what happens when agents delegate to sub-agents, when permissions need to attenuate across delegation chains, or when every action needs to be correlated back to the task that initiated it. Static credentials -- SSH keys, API tokens, service accounts -- don't expire, can't be scoped per-task, and persist after the agent session ends.
When agent A delegates to agent B, and B delegates to C, the question is: who authorized C to do what, and can you prove the authority only narrowed?
Ephyr is an access broker that sits between AI agents and infrastructure. It replaces scattered credentials with a single MCP endpoint that enforces policy, issues ephemeral certificates, and produces SIEM-ready structured audit logs. Every action is scoped to a task, time-bounded, and cryptographically traceable through the delegation chain.
- HMAC-chained macaroon tokens make restriction removal cryptographically impossible. The broker's effective envelope reducer derives the most-restrictive authority from accumulated caveats using set intersection, minimums, and boolean AND. Capabilities can only narrow across delegation hops.
- Epoch watermark revocation invalidates an entire task tree instantly -- revoking a parent cascades to all descendants with O(depth) validation and no per-token blocklists.
- Centralized audit with ULID correlation ties every SSH command, HTTP proxy request, and MCP federation call back to its originating task tree. "What happened during this deployment?" is a single query.
- Three proxy paths through one endpoint -- SSH certificates, HTTP APIs with credential injection, and federated MCP servers. Agents connect once; the broker handles authentication, authorization, and proxying.
graph LR
Agent(("🤖 Agent")):::agent
Agent -- "Bearer: mac_…" --> Broker
subgraph Broker [" ephyr-broker "]
direction TB
Policy["Policy ∙ RBAC"]:::core
Macaroon["Macaroon verify\n+ HMAC reducer"]:::core
TaskID["Task identity\n+ delegation"]:::core
Audit["Audit logger"]:::core
Proxy["HTTP proxy\n+ MCP federation"]:::core
end
Broker -- "Unix socket IPC" --> Signer
subgraph Signer [" ephyr-signer "]
direction TB
CA["Ed25519 CA key\nNever on network"]:::signer
end
Broker -- "SSH certs" --> T["🖥 Targets"]:::downstream
Broker -- "Credential injection" --> S["🌐 Services"]:::downstream
Broker -- "Proxied tool calls" --> R["🔗 Remote MCP"]:::downstream
classDef agent fill:#7c3aed,stroke:#7c3aed,color:#fff,font-weight:bold
classDef core fill:#1e293b,stroke:#3b82f6,color:#e2e8f0
classDef signer fill:#1e293b,stroke:#22c55e,color:#e2e8f0
classDef downstream fill:#1e293b,stroke:#64748b,color:#94a3b8
ephyr-signer holds the Ed25519 CA private key in a systemd sandbox with ProtectSystem=strict, MemoryDenyWriteExecute, and zero capabilities. Unix socket IPC only. The CA key never leaves this process, never touches the network.
ephyr-broker handles everything else: HMAC chain verification, caveat reduction, policy evaluation, SSH certificate requests via signer IPC, HTTP proxy with credential injection, MCP federation, task tree management, structured audit logging, and the admin dashboard.
Ephyr evolves through three tiers. Each is a strict superset of the previous.
The foundational broker.
- One connection, all access -- SSH, HTTP APIs, and remote MCP servers through a single MCP endpoint
- Ephemeral credentials -- SSH certificates default to 5-minute TTL. Service and MCP grants auto-expire.
- No standing backend credentials -- the broker injects tokens, certificates, and auth headers. Agents never handle long-lived secrets directly.
- Declarative policy -- YAML defines who can access what, with what role, for how long. Hot-reload with SIGHUP.
- Task-scoped identity -- every action correlates to a task run with a ULID. Tiered trust: signer holds root CA, broker operates with short-lived delegated signing authority.
- Epoch watermark revocation -- revoking a task instantly invalidates all descendants without per-token tracking.
- Full audit trail -- every certificate, command, HTTP proxy request, and denied action. Structured JSON, ready for your SIEM.
- Command-level filtering at the broker (the broker issues certificates; command restriction is enforced by target host shell and sudoers)
- Push-revocation of SSH certificates to target hosts (OpenSSH does not support online CRL for user certificates; TTL is the mitigation)
- Multi-tenant isolation (single policy file, single CA; deploy separate instances for tenant boundaries)
Delegated task authority for multi-agent workflows. Implements the Delegation Capability Token architecture from DeepMind's "Intelligent AI Delegation" (arXiv:2602.11865).
- Macaroon-based task tokens -- HMAC-chained caveats make restriction removal cryptographically impossible. The HMAC chain proves caveat accumulation; the reducer derives semantic narrowing.
- Broker-mediated delegation -- parent tasks delegate to children with attenuated scope. The broker mediates every delegation for audit and pre-validation.
- Effective envelope reducer -- set intersection, minimums, and boolean AND derive the most-restrictive authority from accumulated caveats.
- Cross-agent delegation --
claudecan delegate toinvestigator-botwith reduced scope. The child gets the intersection of parent ceiling and child policy. - Lineage-aware audit -- full task trees with ULID correlation. "What happened during this deployment?" is a single query.
- Cryptographic proof of semantic attenuation. The correct claim: cryptographic proof of caveat accumulation (HMAC chain) combined with deterministic semantic narrowing (reducer). Caveats accumulate; the reducer interprets them.
- Holder binding. Task tokens are bearer tokens. A leaked macaroon can be used by anyone until it expires or is revoked. TTL and epoch watermark mitigate this; Ephyr Bind addresses it.
Holder-bound tokens and replay resistance.
- Proof-of-possession -- each request proves the presenter controls a private key bound to the token. Leaked macaroons are useless without the key.
- DPoP-style request signing -- works over existing HTTP/MCP transport, no mTLS infrastructure required.
JSON-RPC 2.0 over Streamable HTTP, implementing MCP 2025-03-26. Fifteen tools (9 core + 5 task identity + 1 delegation) plus federated tools from remote servers.
Core Tools:
| Tool | Description |
|---|---|
list_targets |
Discover available SSH hosts and permitted roles |
exec |
Run a command on a target via ephemeral SSH certificate |
session_create |
Open a persistent SSH session (60x faster for sequential commands) |
session_close |
Close a persistent SSH session |
list_sessions |
List active persistent SSH sessions |
list_certs |
List active certificates for this agent |
http_request |
Make an HTTP request through the credential-injecting proxy |
list_services |
List available HTTP proxy services |
list_remotes |
List federated remote MCP servers and their tools |
Task Identity Tools:
| Tool | Description |
|---|---|
task_create |
Create a task and receive a macaroon-based task token with capability envelope |
task_delegate |
Delegate a child task with attenuated capabilities (macaroon with added caveats) |
task_info |
Get task details, status, and lineage |
task_list |
List active tasks for this agent |
task_revoke |
Revoke a task and all its tokens via epoch watermark (cascading to children) |
Federated Tools:
| Tool | Description |
|---|---|
{server}.{tool} |
Dynamically discovered tools from remote MCP servers (e.g., devtools.list_repos) |
Resources (agent self-discovery):
| URI | Description |
|---|---|
ephyr://overview |
System summary, available targets, services, and agent permissions |
ephyr://targets |
SSH targets with hosts, ports, roles, and auto-approve status |
ephyr://services |
HTTP proxy services with credential injection details |
ephyr://roles |
Role definitions and SSH principal mappings |
ephyr://status |
Agent's active certificates, sessions, and recent activity |
ephyr://tools |
Quick reference for all MCP tools with parameters |
ephyr://remotes |
Federated MCP servers with connection status and available tools |
Ed25519 CA issuing ephemeral, per-request certificates. Default TTL is 5 minutes, configurable up to 30 minutes per-target. Each certificate is scoped to a specific agent, target, and role. Duplicate certificates for the same agent+target+role are automatically revoked when a new one is issued.
Persistent sessions reduce per-command latency from ~850ms to ~14ms for sequential operations.
Agents create tasks via task_create and receive a macaroon-based task token. The token carries:
- Task ID -- ULID (lexicographically sortable, encodes creation time)
- Capability envelope -- Upper-bound permissions (targets, roles, services, remotes, methods) resolved from RBAC policy at creation time
- Lineage -- Parent task reference for sub-task delegation
Delegation with attenuation: Parent tasks created with can_delegate: true can spawn child tasks via task_delegate. Children receive macaroons with additional caveats that further restrict the capability envelope. The HMAC chain guarantees caveats cannot be removed. Maximum chain depth is 5. Child TTL cannot exceed parent's remaining TTL.
Dual-mode authentication: The broker accepts both macaroon tokens (prefixed mac_) and legacy JWT/API key authentication for backward compatibility.
Tiered trust model: The signer issues delegation certificates to the broker. The broker signs task tokens locally using its delegation key -- no IPC round-trip per token. Delegation keys auto-rotate before expiry.
Epoch watermark revocation: task_revoke invalidates all tokens for a task by setting an epoch timestamp. Validation checks the watermark in O(depth) with no per-token blocklists. Cascading revocation propagates to all child tasks in the lineage.
Bearer-token limitation: Task tokens (both JWT and macaroon) are bearer tokens. A leaked token can be used by anyone until TTL expiry or epoch watermark revocation. Ephyr Bind (v0.3) will add holder binding via proof-of-possession.
A generic authenticated proxy for web services. Configure a service once with its URL prefix and credentials, and agents make requests without ever seeing the token. Supports bearer, basic auth, custom header, and query parameter injection. Network policy controls reachable destinations.
Works with internal services (Gitea, Grafana, Portainer) and external APIs (GitHub, cloud providers). Services can be individually enabled/disabled via the dashboard.
Aggregate tools from remote MCP servers through a single unified endpoint. The broker discovers tools automatically via MCP handshake, exposes them namespaced (e.g., devtools.list_repos), and proxies calls transparently with credential injection. Background refresh keeps catalogs current.
Declarative YAML with hot-reload via SIGHUP. Eight-step evaluation pipeline for every certificate request: agent exists, target exists, role allowed, duration clamped, concurrent limits, duplicate handling, global limits, approval mode. Every denial includes a specific reason.
Fine-grained, per-agent access control across all three proxy paths (SSH, HTTP, MCP federation) and the dashboard. Template inheritance, wildcard support, and agent-level overrides. Backwards-compatible legacy mode for agents without RBAC fields.
| Layer | What it checks |
|---|---|
| SSH exec | Agent's roles for the target, intersection with target's allowed_roles |
| HTTP proxy | Agent's allowed services and permitted HTTP methods |
| MCP federation | Agent's allowed remotes and optional tool restrictions |
| Discovery | Filters list_targets, list_services, list_remotes results |
| Dashboard | Agent's dashboard access level (none/viewer/operator/admin) |
GET /v1/metrics endpoint in Prometheus exposition format. Lock-free atomic counters and latency histograms.
Latency histograms (7 buckets: <100us, <500us, <1ms, <5ms, <10ms, <50ms, >50ms):
| Metric | Description |
|---|---|
ephyr_token_sign_seconds |
Token signing latency |
ephyr_token_validate_seconds |
Token validation latency |
ephyr_watermark_check_seconds |
Watermark revocation check latency |
ephyr_envelope_check_seconds |
Capability envelope check latency |
ephyr_policy_eval_seconds |
Policy evaluation latency |
ephyr_ssh_cert_seconds |
SSH certificate signing latency |
ephyr_delegation_ipc_seconds |
Delegation IPC latency |
ephyr_exec_e2e_seconds |
End-to-end exec latency |
Counters and gauges:
| Metric | Type | Description |
|---|---|---|
ephyr_tasks_created_total |
counter | Total tasks created |
ephyr_tasks_active |
gauge | Currently active tasks |
ephyr_tokens_signed_total |
counter | Total tokens signed |
ephyr_tokens_validated_total |
counter | Total tokens validated |
ephyr_tokens_rejected_total |
counter | Total tokens rejected |
ephyr_tokens_delegated_total |
counter | Total delegation tokens issued |
ephyr_watermark_revocations_total |
counter | Total watermark revocations |
ephyr_delegation_rotations_total |
counter | Total delegation cert rotations |
ephyr_legacy_requests_total |
counter | Requests without task token (legacy mode) |
ephyr_auth_cache_hits_total |
counter | Auth cache hits (bcrypt bypassed) |
ephyr_auth_cache_misses_total |
counter | Auth cache misses (bcrypt required) |
ephyr_macaroon_minted_total |
counter | Macaroons minted |
ephyr_macaroon_verified_total |
counter | Macaroons verified |
SHA-256 keyed bcrypt result cache with configurable TTL. Eliminates redundant bcrypt verification on repeated MCP requests from the same agent.
| Metric | Value |
|---|---|
| Cold auth (bcrypt) | ~216ms |
| Warm auth (cache hit) | <1ms |
| Speedup | 187x |
| Default TTL | 60 seconds |
| Configuration | EPHYR_AUTH_CACHE_TTL env var |
| Disable | EPHYR_AUTH_CACHE_TTL=0 or off or false |
Single-page admin UI with eleven views across four groups:
- OVERVIEW: System summary, stat cards, host/service/MCP panels with toggles, active sessions, live event feed
- INFRASTRUCTURE: Hosts, Services, MCP Servers -- enable/disable toggles, configuration panels
- MONITOR: Agents, Activity, Sessions, Audit Log, Tasks (table/tree view, envelope inspector, cascade revocation)
- TOOLS: Terminal (WebSocket SSH proxy), Settings
Key operational controls: policy inspection, emergency certificate revocation, remote enable/disable without restart, audit log search. WebSocket live event streaming.
- Unix socket authentication --
SO_PEERCREDextracts the caller's UID from the kernel - Constant-time token comparison --
crypto/subtleprevents timing attacks - Systemd sandboxing --
ProtectSystem=strict,NoNewPrivileges,MemoryDenyWriteExecute, zero capabilities - CA key isolation -- Private key exists only in the signer process; broker never reads it
- Network isolation -- nftables drops direct agent-to-backend traffic
- Delegation separation -- Broker signs task tokens with a delegated key, not the CA key
- Epoch revocation -- No per-token blocklists; watermark-based invalidation in O(depth)
Benchmarked on a Debian 12 LXC (1 vCPU, 512MB RAM):
| Operation | Latency | Notes |
|---|---|---|
| Auth (cold, bcrypt) | ~216ms | First request per API key |
| Auth (warm, cached) | <1ms | Subsequent requests within TTL (187x speedup) |
| Macaroon mint | ~34us | HMAC-SHA256 chain construction |
| Macaroon verify | ~32us | HMAC chain + reducer evaluation |
| Token signing (JWT) | <1ms | Ed25519 local signing via delegation key |
| Token validation (JWT) | <1ms | Signature + envelope + watermark check |
| SSH exec (new cert) | ~850ms | Full cert issuance + SSH connection |
| SSH exec (session) | ~14ms | Persistent session reuse (60x faster) |
- Access issuance policy -- Which agents can reach which targets, with which roles, for how long
- Task-scoped identity -- Capability envelopes bound what a token can do; watermark revocation invalidates instantly
- Request-level audit -- Every action logged with agent identity, target, timestamp, outcome, and task correlation
- Credential isolation -- Backend credentials live in the broker/signer processes; agents never receive long-lived secrets
- Grant expiry -- All access is time-limited with automatic cleanup
- Command-level permissions -- SSH principals map to Linux users with shell restrictions, sudoers rules, and filesystem permissions. The target host is the final enforcement layer.
- OS-level isolation -- SELinux/AppArmor, filesystem permissions, and host network policy are outside Ephyr's scope
- Holder binding (until Bind ships) -- Task tokens are bearer tokens. TTL and epoch watermark mitigate replay; proof-of-possession is planned for Ephyr Bind.
- Broker compromise does not expose the CA key (signer is a separate process)
- Host compromise can abuse active grants within TTL only (default 5 minutes)
- Network isolation is defense-in-depth, not a substitute for host hardening
- See docs/THREAT_MODEL.md for 14 enumerated threats with mitigations
git clone https://github.com/EphyrAI/Ephyr.git
cd Ephyr
make build
# Output: bin/ephyr-broker bin/ephyr-signer bin/ephyrRequires Go 1.24+.
mkdir -p /etc/ephyr
ssh-keygen -t ed25519 -f /etc/ephyr/ca_key -N ""Create /etc/ephyr/policy.yaml:
global:
max_active_certs: 10
default_ttl: "5m"
max_ttl: "30m"
agents:
claude:
uid: 1000
max_concurrent_certs: 3
can_delegate: true
roles:
read:
principal: "agent-read"
operator:
principal: "agent-op"
targets:
webserver:
host: "10.0.1.10"
port: 22
allowed_roles: [read, operator]
auto_approve: truesudo make install-user
sudo make install-systemd
sudo systemctl enable --now ephyr-signer
sudo systemctl enable --now ephyr-brokerephyr session create
ephyr exec webserver --role read -- systemctl status nginx
ephyr targets
ephyr services
ephyr remotes
ephyr inspect <token> # inspect macaroon caveats{
"mcpServers": {
"ephyr": {
"type": "url",
"url": "http://your-broker:8554/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}Works with Claude Code, Claude Desktop, Cursor, Cline, OpenClaw, and any MCP-compatible client.
| Version | Tier | What ships |
|---|---|---|
| v0.1 | Core | Broker foundation: SSH/HTTP/MCP access, policy, audit |
| v0.2a | Core | Task identity: tiered trust, JWT task tokens, watermarking |
| v0.2b | Delegation | Macaroon engine: reducer, delegation, inspect CLI |
| v0.2c | Delegation | Dashboard: task trees, caveat inspector |
| v0.3 | Bind | Proof-of-possession: holder binding, DPoP-style signing |
Three direct dependencies, all well-established:
| Module | Purpose | Tier |
|---|---|---|
github.com/gorilla/websocket |
WebSocket for dashboard and terminal | Core |
golang.org/x/crypto |
SSH certificates, bcrypt | Core |
gopkg.in/yaml.v3 |
Policy YAML parsing | Core |
The macaroon implementation is pure Go stdlib (HMAC-SHA256 from crypto/hmac). No external macaroon dependency.
No external databases. No message queues. No container runtime.
ephyr/
├── cmd/
│ ├── broker/ # ephyr-broker entry point
│ ├── ephyr/ # CLI tool (includes `inspect` command)
│ └── signer/ # ephyr-signer entry point
├── internal/
│ ├── audit/ # Structured JSON-line audit
│ ├── auth/ # Session manager, SO_PEERCRED
│ ├── broker/ # Core broker: server, handlers, dashboard, MCP,
│ │ # proxy, activity, config, terminal, websocket,
│ │ # rate limiter, federation, grant store
│ ├── macaroon/ # Macaroon minting, verification, reducer (Delegation)
│ ├── policy/ # Policy types, YAML loader, evaluation
│ └── signer/ # Certificate signing, CA key, IPC
├── dashboard/ # React 18 SPA
├── deploy/ # systemd units, provisioning scripts
├── docs/ # Architecture, security, API reference
│ ├── architecture.md
│ ├── security.md
│ ├── THREAT_MODEL.md
│ └── ...
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Makefile
├── go.mod
└── go.sum
253+ tests across 13+ test files:
- Unit tests -- Policy engine, RBAC resolution, delegation, revocation, grants, rate limiting, metrics, token signing/validation, activity store, macaroon minting/verification/reducer
- Integration tests -- 12 end-to-end tests (
test/integration/smoke_test.go) that run against a live Ephyr instance: MCP handshake, tool listing, legacy compatibility, task lifecycle, macaroon delegation, metrics endpoint, and performance benchmarks
make test # Unit tests
make lint # golangci-lint
go test ./test/integration/ # Integration tests (requires running instance)- Go 1.24+ -- uses enhanced routing patterns and recent stdlib features
- Linux --
SO_PEERCREDfor Unix socket peer authentication is Linux-specific - systemd -- optional but recommended for production
- OpenSSH -- target hosts need
TrustedUserCAKeysconfigured - nftables -- recommended for network isolation
| Document | Description |
|---|---|
| Architecture | Trust model, delegation chain, validation flow |
| Security | Security boundaries, hardening guide |
| Configuration | Full policy reference and RBAC setup |
| Deployment | Local, dedicated host, and production scenarios |
| API Reference | Complete REST and MCP API documentation |
| MCP Integration | Client setup for Claude Code, Desktop, Cursor, Cline |
| Threat Model | 14 enumerated threats with mitigations |
Contributions welcome. The codebase is ~24,000 lines of Go across ~64 files with no code generation and no frameworks -- the standard library plus three dependencies.
make test # Run tests
make lint # Run linterPlease open an issue before starting work on large changes.
Apache License 2.0. See LICENSE for details.
~24,000 lines of Go | 64 source files | 253+ tests | 3 dependencies | Zero external databases