AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP unreviewed Apache-2.0 Self-run

Dokan

mcp-tsukumohq-dokan · by TsukumoHQ

dokan 導管 — agent-operated deterministic script runtime in Docker. MCP control plane + thin operator UI.

No reviews yet
0 installs
19 views
0.0% view→install

Install

$ agentstack add mcp-tsukumohq-dokan

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Pipes remote content directly into a shell (remote code execution).

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Dokan? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

dokan (導管)

Your AI coding agent builds and runs the workflow. You don't click.

Agent-operated automation runtime · deterministic scripts in Docker · zero LLM inside · Apache-2.0


dokan is an automation runtime built for the agent era. Instead of a human clicking through a UI, your coding agent stands up, runs, and schedules workflows itself by talking to dokan over MCP. The platform runs deterministic code in clean containers and burns zero tokens: the expensive intelligence stays in your agent, outside the runtime.

Think Sidekiq/cron for AI agents: the agent scripts the mechanical 80%, dokan executes it cheaply and reliably, you don't touch a dashboard.

Why dokan

  • Agent-operated. your agent uploads, wires, triggers, reads logs over MCP. No UI.
  • Zero LLM inside = zero token burn. deterministic code, not LLM-in-the-loop. The platform never spends tokens to run your workflows.
  • Hermetic by default. one job = one clean container, per-job CPU/mem caps, timeouts, retries. Jobs run with network disabled by default (v0.4.0) — output is a pure function of its inputs, so identical inputs hit a content-addressed cache instead of recomputing, and the run is provable by re-execution. Set network=true for a job that must reach an API (most monitors do). Every run carries a tamper-evident receipt (advisory for networked runs, since their output can depend on the outside world).
  • Real triggers. cron + inbound webhooks (POST /hook/, Stripe/Calendly/GitHub-ready).
  • Token-frugal. every MCP response is shaped for an agent's context budget — IDs over payloads, paginated logs, counts over dumps.

How it works

flowchart LR
  agent["your coding agent"] -- MCP --> dokan["dokan daemon(Rust · axum + rmcp)"]
  dokan -- state --> pg[("Postgres")]
  dokan -- one job, one container --> c1["job container(isolated; hermetic by default, network=true to opt in)"]
  c1 -- "stdout · ::dokan:result::" --> dokan
  dokan -- "result POST" --> relay["your agent / relay"]
  human["operator (optional)"] -. watch .-> cockpit["cockpit /"]
  cockpit --- dokan

A single Rust daemon (axum + an rmcp MCP server, stdio or Streamable HTTP). State lives in Postgres. Execution is one job → one fresh container (python:3.12-slim / node:22-slim / alpine), discarded after the run, with per-job caps and a hard timeout. Logs stream into Postgres, served cursor-paginated. A thin operator cockpit runs at /, Prometheus at /metrics. No LLM runs inside dokan — the agent is the only place tokens are spent.

Quickstart

Prereq: Docker running (Docker Desktop, or colima / podman). The daemon talks to the default Docker socket — set DOCKER_HOST for colima/podman. No Rust toolchain needed.

One command stands up the runtime and installs the Claude Code operator skill:

curl -fsSL https://raw.githubusercontent.com/TsukumoHQ/dokan/main/install.sh | sh

It downloads and SHA-256-verifies the binary into ~/.local/bin, lands the operator skill in ~/.claude/skills/dokan/ (where Claude Code loads it), generates per-install crypto keys (secure-by-default — secrets sealed at rest, receipts signed; saved 0600 in ~/.dokan/dokan.env), starts Postgres on :5499, and brings up the daemon on 127.0.0.1:8088. Re-running is safe (idempotent). Then wire your agent:

claude mcp add --transport http dokan http://127.0.0.1:8088/mcp

Verify it's up: open (the operator cockpit) — once it loads, an agent can wire MCP and run scripts. Schema migrations apply automatically on boot.

Build from source instead (contributors / unsupported platforms)

Needs a Rust toolchain. The default DATABASE_URL already points at the compose database, so there's nothing to configure.

docker compose up -d            # Postgres state store (pgvector) on :5499
cargo build --release
./target/release/dokan          # HTTP daemon on 127.0.0.1:8088 — UI at /, MCP at /mcp

You'll need crypto keys set (DOKAN_SECRET_KEY, DOKAN_RECEIPT_KEY, DOKAN_RECEIPT_ED25519_SECRET) or DOKAN_DEV_INSECURE=1 for local dev — the daemon fails closed otherwise.

Run your first job

With the daemon up, run the flagship demo — it drives a real DAG over MCP exactly the way an agent does (uploads 4 deterministic steps, wires a flow with map fan-out + a when branch, runs it, prints the result). No secrets, no job network, fully reproducible. Needs curl + jq:

./examples/flagship/run.sh        # override the daemon with DOKAN_ADDR=host:port

That's the whole loop — upload → compose → run → read — in one command. See [examples/flagship/](examples/flagship/) for the steps and the expected output.

Wire into your agent (MCP)

Point your agent's MCP config at the daemon:

"dokan": { "type": "http", "url": "http://127.0.0.1:8088/mcp" }

Your agent now has the full dokan toolset over MCP.

Core concepts

Scripts

A script is code in python | node | bash. It reads its input from the DOKAN_INPUT env var (a JSON string — not stdin, not argv). Secrets arrive as their own env vars. upload_script(..., upsert=true) re-provisions by name idempotently, so a respawning agent never leaves orphan duplicates. A script's nonzero exit is treated as the script's own deterministic verdict (e.g. a monitor finding) and is not retried — only a genuine infra failure (container vanished / timeout) retries.

Flows (DAG)

compose_flow wires scripts into a validated, acyclic graph; run_flow runs it and the engine drives the DAG. Each step is one container run that sees {flow_input, deps, step} as its DOKAN_INPUT.

flowchart LR
  intake["intake"] --> score["score(map: one run per order)"]
  score --> summarize["summarize(structured result + branch token)"]
  summarize -- "when deps.summarize == FLAGGED" --> alert["alert"]
  summarize -- else --> done(["done"])

The engine gives you:

  • map fan-out — one child run per item; the parent collapses the children into a {n, ok, failed} count instead of listing each.
  • when branches — a step runs only if a predicate over an upstream result holds.
  • compensate (saga rollback) — a step can declare a compensating action that runs if a later step fails, so a partially-applied flow unwinds cleanly.
  • retries with backoff on transient failures.
  • step-boundary durability — progress is committed at each step, so a crashed engine resumes; succeeded steps are skipped. Steps must be idempotent (a dying step re-runs).

Schedules & triggers

  • schedule(script_id, cron)6-field cron with leading seconds (0 */5 * * * * = every 5 min). A 5-field expression is rejected loudly rather than silently never firing. Each tick enqueues a run.
  • create_webhook — an external POST /hook/ enqueues a script or flow with the request body as input. The unguessable URL token is the auth (the endpoint sits outside the bearer gate).

Secrets

set_secret(name, value) once → available to a job as a tmpfs file at /run/secrets/ (mode 0400, never persisted) and, for back-compat, as an env var (e.g. $OPENAI_API_KEY). Write-only: values are never returned or logged; list_secrets shows names only. By default a script gets all globals; scope it with a per-script allowlistupload_script(..., secrets=["openai_key"]) injects only those.

Resource limits

Per-job caps default to 1024 MiB / 2.0 CPU, set globally on the daemon. A single heavier script can override them — upload_script(..., mem_limit_mb, cpu_limit) — and only that script runs on a dedicated container with the raised cap; everything else is untouched.

Structured results & stateful monitors

A job prints a line ::dokan:result:: {json} on stdout; dokan captures the last one as the run's structured result. It is returned by wait_for/read_logs and POSTed to the relay on completion — so a monitor emits a finding and the agent reacts event-driven, no polling.

For a monitor that should fire only when something changes, set upload_script(..., feed_prev_result=true): dokan feeds the previous run's structured result into the next run as DOKAN_INPUT.prev_result. The monitor reads prev_result.state, diffs against the current state, emits the new state, and exits nonzero on a change — a cross-run diff with no host files and no external store, on a stateless runtime.

Run artifacts (input files)

To hand a job a real document — a PDF, a dataset, a big .md — without stuffing it into DOKAN_INPUT (an env var, ~100 KB): upload_blob(bytes) stores it in a content-addressed blob store (re-uploading identical bytes deduplicates) and returns a handle; run_script(..., files={"doc.md": ""}) materializes each file read-only at /input/ in the container. The blob hashes fold into the run's cache key and receipt, so a job that reads /input stays a pure function of its declared inputs.

Determinism & receipts

A network=false job is a pure function of its inputs — source + DOKAN_INPUT + input-file blobs + the pinned image digest. Two consequences:

  • Content-addressed cache. run_script(..., cache=true) recalls a prior identical success instead of recomputing — no container spawned.
  • Tamper-evident, publicly-verifiable receipt. every run carries a receipt binding (image digest, source hash, input hash, output hash, input-blob hashes). It's HMAC-keyed for holders of DOKAN_RECEIPT_KEY and Ed25519-signed inside an in-toto / DSSE envelope — so a third party can verify it offline with only the public key (no shared secret), and reproduce re-executes the run and byte-compares the output against the receipt (REPRODUCED / DIVERGED / TAMPERED). A networked job's receipt is advisory, since its output can depend on the outside world.
  • Honesty note: the structured ::dokan:result:: output is compared by JSON value (object key order doesn't matter). Output FILES are compared by raw bytes — dokan does not yet canonicalize file-packaging metadata, so an artifact that differs only in non-content metadata (gzip mtime, tar entry order, embedded build timestamps) will DIVERGE. Emit reproducible archives (e.g. gzip -n, sorted tar, SOURCE_DATE_EPOCH) for a clean REPRODUCED. (Canonicalizing this safely is a tracked follow-up.)

MCP surface (token-frugal)

| Tool | Returns | |---|---| | searchscript · listscripts · getscript | ranked / listed IDs + 1-line desc; bodies only on request | | uploadscript | scriptid + version (flags: network, mem/cpu limit, feedprevresult) | | runscript | runid immediately, never blocks (input + files for /input artifacts) | | readlogs · waitfor | cursor logs / long-poll to terminal + tail + structured result | | schedule · listschedules · unschedule | cron a script (6-field) | | composeflow · runflow · getflowrun | declarative DAG; per-step status (map children collapsed to a count) | | createwebhook · listwebhooks · deletewebhook | inbound HTTP trigger to a script/flow | | uploadblob · downloadblob · listblobs | content-addressed input/output files | | getreceipt · verify · reproduce | fetch / offline-Ed25519-verify / re-execute + byte-compare a run's receipt | | setsecret · listsecrets | write-only secrets → /run/secrets tmpfs (+ env); per-script allowlist | | onresult · listtriggers · deletetrigger | reactive triggers: enqueue a script when a result matches | | cancel · listruns · listexecutors | … |

Server instructions ship in-band so the agent self-limits.

Status

v0.4.x — beta / preview. Active development, built and run in production by the team that makes it (we run our own agent fleet's automation on dokan). Ready for: demos, design partners, technical early adopters. Not yet turnkey multi-tenant enterprise (no SSO/RBAC/HA; the MCP control plane is unauthenticated + single-tenant — see [SECURITY.md](SECURITY.md)). Honest about where it is.

License

Apache-2.0. Use it, embed it, build on it.


dokan is one of four open tools from the Tsukumo studio for running AI agents well at scale: trovex (canonical context) · yoru (session record + replay) · dokan (job runtime) · wrai.th (agent relay).

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.