Zaru MCP Server
An MCP-compliant gateway that proxies tool calls to the AEGIS orchestratorvia SEAL (Signed Envelope Attestation Layer) envelope signing. Also hoststhe canonical Zaru system prompts delivered through the zaru.init andzaru.mode client-side tools.
Written in TypeScript. Runs on Node.js with Express.
How It Works
The server does not implement individual tools. It discovers the toolcatalog from the AEGIS orchestrator and re-exposes it over standard MCPtransports. Every tool invocation is wrapped in a SEAL envelope --cryptographically signed with an Ed25519 session key and authenticatedagainst the orchestrator's attestation endpoint.
Two tools are handled locally (never forwarded to AEGIS):
zaru.init-- Activate the Zaru persona. Returns a system promptand available tool list for a given conversation mode (chat,agentic,workflow,execute,operator). Defaults tochat.zaru.mode-- Switch conversation mode. Returns the updated systemprompt and tool scope for the target mode.
Architecture
MCP Client ──► Zaru MCP Server ──► AEGIS Orchestrator
(this repo) (SEAL attestation + tool registry)
- StreamableHTTP transport (primary) --
POST /mcp/v1,GET /mcp/v1,DELETE /mcp/v1 - SSE transport (legacy) --
GET /mcp/v1/sse,POST /mcp/v1/messages - Execution event proxy --
GET /proxy/v1/executions/:executionId/stream(SSE passthrough for the Zaru Glass Laboratory UI) - Health check --
GET /health
Authentication
Requests must include a token via Authorization: Bearer <token>,x-zaru-user-token header, or token query parameter.
Two authentication methods are supported:
| Method | Token format | Validation |
|---|---|---|
| Keycloak JWT | Standard JWT | Verified against Keycloak JWKS; multi-realm |
| AEGIS API key | aegis_ prefix |
Validated via orchestrator API key EP |
SEAL Protocol Flow
- Attestation -- The server creates an Ed25519 key pair, sends thepublic key to
POST /v1/seal/atteston the orchestrator, and receivesasecurity_token. - Envelope signing -- Each
tools/callrequest is wrapped in a SEALenvelope containing the JSON-RPC payload, security token, timestamp,and Ed25519 signature. - Invocation -- The signed envelope is sent to
POST /v1/seal/invokeon the orchestrator. - Session management -- Sessions are cached per user and automaticallyre-attested on expiry or rejection.
Connecting from External MCP Clients
Claude Code
claude mcp add zaru --transport http https://mcp.myzaru.com/mcp/v1 \
--header "Authorization: Bearer YOUR_API_KEY"
Full setup guide
https://docs.100monkeys.ai/docs/zaru/mcp-client-setup
Development
cd zaru-mcp-server
npm install
npm run build # compile TypeScript
npm test # run test suite
Environment Variables
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Server listen port |
AEGIS_ORCHESTRATOR_URL |
localhost:8088 |
Orchestrator base URL |
JWKS_URI |
(see below) | Keycloak JWKS endpoint |
AEGIS_TOOL_DISCOVERY_URL |
(auto) | Tool discovery override |
AEGIS_TOOL_CACHE_TTL_MS |
5000 |
Tool list cache TTL (ms) |
BYPASS_AUTH |
(unset) | true to skip auth (dev) |
ZARU_CLIENT_URL |
http://zaru-client:3000 |
URL by which zaru-mcp-server reaches zaru-client over the in-pod network for Zaru User Memory read/write |
JWKS_URI defaults tohttp://localhost:8180/realms/zaru-consumer/protocol/openid-connect/certs.AEGIS_TOOL_DISCOVERY_URL defaults to<AEGIS_ORCHESTRATOR_URL>/v1/seal/tools.
Running on Cloudflare Workers
Beside the Express server the container runs (src/index.ts), the server has aCloudflare Workers entrypoint, zaru-mcp-server/src/worker.ts, a fetch handlerbuilt from the same modules: the same authentication(authenticateZaruRequest), the same tool wiring (createMcpServerForUser)and the same route constants (src/http/routes.ts). It serves:
| Route | On the Worker |
|---|---|
GET /health |
{"status":"ok"} |
POST /mcp/v1 |
Streamable HTTP, stateless, through the SDK's Web-standard transport |
GET, DELETE /mcp/v1 |
405 and a no-op, as the container answers |
GET /proxy/v1/executions/:executionId/stream |
The orchestrator's event stream, passed through as the response body |
The legacy SSE transport (/mcp/v1/sse, /mcp/v1/messages) is not served onWorkers: its sessions live in one process's memory, and a Worker's requests canland in different isolates.
The waiting tools (every tool whose name ends in .wait, such asaegis.task.wait and aegis.workflow.wait) wait at most 45 seconds per callon the Worker, whatever timeout_seconds asks, because an MCP client gives upon a tool call after about a minute; a smaller timeout_seconds is honoured.An execution still running at that bound comes back as an ordinary tool resultwith still_running: true, its status, its iteration count or state, theseconds waited, and the sentence that repeating the same call continues thewait. The container's entrypoints keep the orchestrator's own wait.
wrangler.jsonc declares two environments on workers.dev, staging andproduction (Workers zaru-mcp-server-staging andzaru-mcp-server-production), with nodejs_compat (SEAL signs withnode:crypto Ed25519), observability on and placement in gcp:us-central1.There is no route yet. The vars are the container's environment names,unchanged; each pod-local URL is the service's public URL instead, since aWorker cannot resolve pod names:
| Var | Value on Workers |
|---|---|
AEGIS_ORCHESTRATOR_URL |
https://api.myzaru.com |
ZARU_CLIENT_URL |
https://ask.myzaru.com |
JWKS_URI |
https://auth.myzaru.com/realms/zaru-consumer/protocol/openid-connect/certs |
EXPECTED_AUDIENCE |
zaru-client |
LOG_LEVEL |
info |
The server reads no secret. A secret added later is put withnpx wrangler secret put <NAME> --env <environment> and never committed.
cd zaru-mcp-server
npm run worker:typecheck # the runtime types from `wrangler types`, then tsc
npm run worker:test # the Worker in workerd (wrangler's local dev server), upstreams stubbed
npm run worker:dry-run # bundle both environments; needs no Cloudflare token
CI runs all three (.github/workflows/ci.yml, job Worker). After CI passeson a push to main, .github/workflows/deploy.yml deploys staging, checks its/health, then deploys production, with the repository secretCLOUDFLARE_API_TOKEN.
Repository Structure
aegis-mcp-tools/
├── .github/
│ └── workflows/
│ ├── ci.yml
│ ├── docker-publish.yml
│ ├── npm-publish.yml
│ └── security.yml
├── zaru-mcp-server/
│ ├── src/
│ │ ├── index.ts # Express server entry point
│ │ ├── mcp/
│ │ │ ├── index.ts # JSON-RPC request handler
│ │ │ ├── orchestrator-client.ts # SEAL attestation + tool proxy client
│ │ │ ├── seal.ts # Ed25519 key pair and envelope signing
│ │ │ ├── sse.ts # SSE transport (legacy)
│ │ │ ├── streamable-http.ts # StreamableHTTP transport (primary)
│ │ │ └── types.ts # Shared type definitions
│ │ ├── middleware/
│ │ │ └── auth.ts # JWT + API key authentication
│ │ └── prompts/
│ │ └── index.ts # Zaru system prompts
│ ├── test/
│ │ ├── auth.test.ts
│ │ ├── normalize-tool-result.test.ts
│ │ ├── orchestrator-client.test.ts
│ │ ├── proxy-stream.test.ts
│ │ └── seal.test.ts
│ ├── package.json
│ ├── package-lock.json
│ └── tsconfig.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── SECURITY.md
└── README.md
License
AGPL-3.0 -- See LICENSE for details.