On this page
Architecture
The proxy sits between any MCP host (Claude Desktop, Cursor, Windsurf, LangChain.js, …) and any upstream MCP server. It is transparent on the protocol — the host sees an MCP server, the upstream sees an MCP client.
(Claude / Cursor / Windsurf / agent)") Upstream_Server("Upstream MCP server
(filesystem, postgres, github, slack, fetch, your own…)") subgraph Euno_MCP["@euno/mcp"] direction TB PolicyEngine("Policy engine
evaluate
conditions") AuditSink("Audit sink
(OCSF + HMAC)
~/.euno/audit.jsonl") Proxy("StdioProxy / HTTP transport") PolicyEngine -- "allow" --> Proxy end MCP_Host -- "tools/call" --> PolicyEngine PolicyEngine -- "deny" --> MCP_Host PolicyEngine --> AuditSink Proxy -- "forward call" --> Upstream_Server Upstream_Server -. "response" .-> Proxy Proxy -. "response" .-> PolicyEngine PolicyEngine -. "post-process" .-> MCP_Host
Two transports are supported: stdio (Claude / Cursor / Windsurf) and HTTP (LangChain.js and other in-process clients). The same policy file works for both. ipRange is enforceable only on HTTP — stdio sessions have no source IP.
Request flow
- The host issues a
tools/callover MCP. - The proxy parses the call, looks up the matching capability in the policy, and evaluates each condition in order. The first deny wins.
- If allowed, the call is forwarded to the upstream over the same MCP transport. The upstream's response is post-processed (e.g.
redactFields) and returned to the host. - If denied, the upstream is never contacted. The host receives a structured
CapabilityDeniedwith theerrorCode,conditionType, andstatusCode. - Every decision — allow or deny — is written to the OCSF audit log, signed with HMAC-SHA256.
~/.euno/audit.jsonl")] %% Allow Path Eval -->|allow| Upstream Upstream -.->|response| Post %% Return Paths back to Host Post -.->|result| Host Eval -->|deny| Host %% Audit Log Paths Post --> Audit Eval -->|deny| Audit
Schema parity — one shape, zero drift
The policy file is a literal subset of AgentCapabilityManifest from @euno/common-core (Apache-2.0). @euno/mcp imports condition types directly from @euno/common-core and never defines its own. This means:
- Policies written for
@euno/mcpuse the same schema as the production capability manifest — no drift between local enforcement and the broader system. - Unknown condition types are denied at two points:
euno-mcp validaterejects the policy, and the runtime engine refuses to evaluate it. - The same enforcement engine is reused by
@euno/langchainfor in-process LangChain.js tools.
Audit log internals
Each event conforms to the OCSF API Activity class (class_uid: 6003). The signer:
- generates a 32-byte random key on first run and stores it at
~/.euno/keywith mode0600; - computes
HMAC-SHA256(key, SHA-256(canonical-json(event))); - writes the event with its signature as a single JSON line to
~/.euno/audit.jsonl.
The log rotates at 100 MiB. Rotated files are named audit.jsonl.<ISO-timestamp>. verifyAuditEvent() recomputes the HMAC for round-trip integrity checks, and euno-mcp stats aggregates denials across active and rotated logs into an ASCII histogram grouped by conditionType and denialCode.
Enforcement guarantees
Enforcement runs on the arguments the agent actually sent — before the upstream is called. The guarantee is: "the agent sent this tool call with these arguments, and it was allowed/denied by this policy." It is not a guarantee about what the upstream server does internally — for that, instrument the upstream as well.
Two practical caveats:
- Tools not listed in the policy are allowed. Policies restrict only the tools they list. To make denial the default, list every tool the upstream exposes; for tools you don't want to enumerate, rely on additional network-level controls.
allowedOperationsis a first-word check — it splits on whitespace and matches the first token against the allowlist. It is not a SQL parser. Pair withargumentSchemaif you need stricter parsing.
Current scope
euno is a local-first policy layer for MCP and LangChain.js integrations. The current release ships the MCP proxy, the in-process LangChain.js runtime, signed OCSF audit logging, and reference policies for common agent backends.
For operational details, see the deployment guide, the repository guide, and the package READMEs.