MCP
Zilean exposes a Model Context Protocol endpoint so an AI agent can read your job registry, check on activity and metrics, and enable, disable or run a job — without you building a custom integration on top of the admin API.
Quick start
Section titled “Quick start”- Turn the endpoint on: Settings → MCP → Enabled.
- Click Create token, pick the least-privileged role that covers what the agent needs, and copy the token — it is shown only once.
- Paste the snippet for your client from Connecting a client,
replacing
<your-host>and<token>.
Then ask the agent something like “list my Zilean jobs” to confirm it works.
Enabling the endpoint
Section titled “Enabling the endpoint”The endpoint is off by default. Turn it on under Settings → MCP, or with the API:
curl -X PUT https://<your-host>/api/settings/mcp \ -H 'Content-Type: application/json' \ -d '{"enabled": true}'While disabled, every request to the endpoint gets a 503 — a signal that the surface exists but is turned off, rather than a 404 that would send you hunting for a typo.
cmd/mcp — the process that actually serves this endpoint — is deployed separately from
the admin API/UI (see Architecture), so turning the toggle on
doesn’t guarantee it’s running. The Settings page live-probes it (an internal health check
against cmd/mcp, not the metrics dashboard) on every load and warns — without blocking
the toggle or token creation — when it isn’t reachable; if you see that warning, check that
binary is actually up before assuming a client-side problem.
Issuing a token
Section titled “Issuing a token”Tokens are issued and managed under Settings → MCP, alongside the enabled toggle, or:
curl -X POST https://<your-host>/api/mcp-tokens \ -H 'Content-Type: application/json' \ -d '{"name": "claude-desktop", "role_id": "<uuid>", "expires_in": "90d"}'role_id picks the role the token acts as — this is what decides which tools the token
can see, so choose the least-privileged role that covers what the agent needs to do (see
Permissions). expires_in is one of 30d, 90d, 365d, or
never.
The response’s token field is the plaintext bearer credential, returned exactly once.
Copy it before closing the panel — only its hash is stored, and there is no way to recover
it afterward. Losing it means issuing a new token.
Each token is backed by its own hidden service account, so calls made with it are attributable to that exact token in the audit log rather than to a shared identity.
Connecting a client
Section titled “Connecting a client”The endpoint is https://<your-host>/mcp, and it authenticates with a bearer token sent as
Authorization: Bearer <token>. Every client below is configured with those two values.
claude mcp add --transport http zilean https://<your-host>/mcp \ --header "Authorization: Bearer <token>"Add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{ "mcpServers": { "zilean": { "url": "https://<your-host>/mcp", "headers": { "Authorization": "Bearer <token>" } } }}Add to .vscode/mcp.json:
{ "servers": { "zilean": { "type": "http", "url": "https://<your-host>/mcp", "headers": { "Authorization": "Bearer <token>" } } }}Claude Desktop’s config file launches local commands rather than connecting to a URL, so
bridge to the endpoint with mcp-remote (needs
Node.js). Add to claude_desktop_config.json:
{ "mcpServers": { "zilean": { "command": "npx", "args": [ "-y", "mcp-remote", "https://<your-host>/mcp", "--header", "Authorization:${ZILEAN_AUTH}" ], "env": { "ZILEAN_AUTH": "Bearer <token>" } } }}The header value goes through env because some clients mangle spaces inside args.
Any client that supports remote (streamable HTTP) MCP servers works: give it the URL and an
Authorization: Bearer <token> header.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause |
|---|---|
| 503 | The endpoint is disabled — enable it under Settings → MCP. |
| 401 | The token is missing, mistyped, revoked, or expired. There is no session-cookie fallback; issue a new token. |
| Connects, but a tool is missing | The token’s role lacks that tool’s permission. tools/list only shows what the role allows — see Tools. |
| Certificate or connection errors | The client must reach https://<your-host>/mcp directly; check your reverse proxy passes /mcp through. |
A token only ever sees the tools its role’s permissions allow — tools/list reflects
exactly what that token can call, nothing more.
| Tool | Permission | Does |
|---|---|---|
zilean_list_jobs |
jobs:read |
List jobs, with filters. Each entry includes capabilities. |
zilean_get_job |
jobs:read |
Read one job’s full configuration, including its capabilities (declared script volumes) |
zilean_job_activity |
jobs:read |
Windowed call volume, latency, and lifetime invocation counters for one job |
zilean_recent_calls |
jobs:read |
Recent attempts for one job, from River’s own job rows |
zilean_worker_metrics |
metrics:read |
CPU/memory history for a Zilean service |
zilean_audit_log |
audit:read |
Query the audit log |
zilean_enable_job |
jobs:write |
Enable one job |
zilean_disable_job |
jobs:write |
Disable one job |
zilean_run_job |
jobs:write |
Trigger one job to run immediately, bypassing its schedule |
What’s deliberately not here
Section titled “What’s deliberately not here”- No job authoring. There is no create, edit, or delete tool. A token can look at jobs and flip them on or off, but shaping a job’s request, auth, loop, or retry behavior stays an admin-API/UI operation.
- No volume surface. A token can read which volumes a job declares, but nothing here creates a volume or changes a declaration.
- No
jobs:scriptsurface. Nothing here can create or edit a script job, regardless of the token’s role. - No bulk operations. Every write tool acts on exactly one job by id — there’s no enable-all, disable-all, or group enable/disable. One malformed or over-eager agent call should never be able to touch every job at once.
These are intentional boundaries, not gaps waiting to be filled in.