Agent Teams
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Agent Teamsdispatch a job to the codex worker to fix the failing tests and report progress"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Agent Teams
English | 简体中文
An MCP server that runs work as visible DSH worker sessions instead of hidden subagents.
Each dispatch pins an exact provider, model and reasoning effort, writes a durable job
journal under stateDir, and reports progress back to the chat that started it.
This is an experimental public repository extracted from a private deployment. An
end-to-end install on a clean machine has not been verified: external supervisor identity
records and an authenticated DSH owner remain prerequisites. The
release targets Windows, Node.js 24 LTS, the DSH 0.2.1-rc.2 plugin interface
and the loopback endpoint http://127.0.0.1:3080. Ownership attestation is a Windows
PowerShell script (scripts/verify-owner.ps1). Other platforms, Node lines, DSH plugin
versions and endpoints are outside this release.
Requirements
Windows. Attestation runs
scripts/verify-owner.ps1through Windows PowerShell 5.1.Node.js 24 LTS; tested on 24.14.0. Codex thread state is read through
node:sqlite, imported without a flag.A running DSH owner at
http://127.0.0.1:3080that you can log in to. The server refuses any other URL and the hub plugin answers only that exact host, so the endpoint is part of this release's contract rather than a setting.The DSH worker plugin in
hub/installed into your DSH profile (see below).
Related MCP server: arjun-mcp
Install
git clone https://github.com/Phantomthedog/agent-teams-mcp.git
Set-Location agent-teams-mcp
npm ci
Copy-Item config.example.json config.json
npm testconfig.json is read from the repository root by default; pass a different path as
argv[2] when starting the server. The angle-bracket entries in config.example.json
(<provider>, <model>, <you>) are placeholders that must be replaced. The remaining
values are example defaults: review them and adjust paths and settings for your deployment.
package.json declares os: ["win32"], so npm ci refuses to install on another
platform. Tests use temp fixtures and need no config.json.
1. State and workspace roots
stateDir holds the job journal, the async store and the hub token. allowedRoots
lists the directories a worker's cwd and task files may resolve inside; anything
outside is refused before a worker is created.
2. Hub token
The MCP server asks DSH to create a worker over HTTP, authenticated with a bearer token. Create it once, at the path the plugin reads:
node -e "const fs=require('node:fs'),path=require('node:path'),c=require('node:crypto');const f=process.argv[1];fs.mkdirSync(path.dirname(f),{recursive:true});fs.writeFileSync(f,c.randomBytes(32).toString('hex'),{encoding:'utf8',flag:'wx'})" "C:/agent-teams/state/hub-token"That writes 64 lowercase hex characters as UTF-8 without a BOM, creates the parent
directory, and flag: 'wx' fails instead of overwriting an existing token (you get an
EEXIST error and the file is left as it was). Shell redirection is not used because
Windows PowerShell 5.1 would write UTF-16LE. The plugin
reads <stateDir>/hub-token and requires exactly /^[a-f0-9]{64}$/; a UTF-16LE file,
which is what a PowerShell redirection would produce, is rejected. Set
dsh.hubTokenFile to the same path.
3. Owner login
dsh.authFile points at a JSON file holding the DSH owner's browser session cookie:
{ "cookie": "<session cookie value>" }The server sends that value as a Cookie header to the owner and refuses with
auth-unavailable: DSH owner login is unavailable. when the file is missing or holds
no non-empty cookie string. How you obtain the cookie is your deployment's business;
DSH has no standard file for it.
4. DSH worker plugin
hub/ is a DSH plugin package: it exports one plugin that registers a single
POST /_codex/dispatch/create endpoint on the DSH web server. The DSH plugin manager
installs a local plugin straight from an absolute directory path — it reads
hub/package.json, requires the dsh.bundle field that is already there, and records
the path with pnpm — so no packaging or publishing step is needed:
Edit
hub/cordis.patch.yml:stateDirandallowedRootsmust matchconfig.json.Install that absolute path into the profile named by
dsh.profile, then restart the profile.
A relative path is refused (a local path must be absolute).
5. Owner attestation (required)
Dispatch fails closed until your deployment can prove which process owns DSH. The
server runs scripts/verify-owner.ps1 before it sends any credential or creates any
worker, and refuses with:
owner-unverified: The DSH owner verifier is not configured for restart recovery; no credentials sent.Set these four dsh fields, all published by your DSH supervisor:
Field | What it must point at |
| Lifecycle receipt written when the owner started: |
| Runtime identity of that same process: |
| The DSH home directory the owner must be running from. |
| The script the owner process must be executing, compared against its real command line. |
The verifier requires that exactly one process owns 127.0.0.1:<port> and that it
executes nodeExecutable (or the receipt's executable). The receipt counts as
current only when its pid equals the live process PID and its startedAt is within
two seconds of that process's start time; otherwise the runtime identity must describe
that same pid, port and home, and must have been published between process start and
ten minutes later. The owner's
real command line must name <expectedEntrypoint> as its script argument and must
carry --profile <dsh.profile>; a --host, --port or --home that disagrees with
the configuration is refused. That is the shape a DSH supervisor starts:
node <expectedEntrypoint> ... --profile <dsh.profile> --host 127.0.0.1 --port 3080 --home <expectedHome>If your deployment publishes neither a matching receipt nor a runtime identity, there is no supported way to dispatch.
6. Register with Codex
Add one stanza to ~/.codex/config.toml and leave every other entry as it is:
[mcp_servers.agent-teams]
command = "C:/Program Files/nodejs/node.exe"
args = ["<checkout>/src/server.mjs", "<checkout>/config.json"]
tool_timeout_sec = 3700Command and arguments alone are not a complete registration. Codex applies its own
MCP tool timeout, which is far shorter than dispatch_wait's 600000 ms default budget,
so a long wait would be cut off by the client. tool_timeout_sec = 3700 covers the
3600000 ms maximum wait plus process start-up. Point command at the Node executable
you run the server with and args at this checkout's absolute paths.
Worked example
scripts/call.mjs runs one tool over stdio against config.json. It needs the
prerequisites above: a live owner, the hub plugin, a hub token and owner records.
<your-host> and <parent-thread-uuid> are the calling chat's own values; they are
never inferred from the server environment.
# 1. Dispatch one worker. request_id is yours; reuse it verbatim on a retry.
Set-Content -Path args.json -Encoding utf8 -Value '{"request_id":"demo-0001","cwd":"C:/agent-teams/workspace","task":"List the files in this directory."}'
node scripts/call.mjs dispatch_dsh args.json
# -> {"job_id":"dispatch-<32 hex>","sessionId":"session-...","status":"queued",...}
# 2. Bind the chat that will receive events. Registration also arms session follow.
Set-Content -Path args.json -Encoding utf8 -Value '{"action":"register","job_id":"dispatch-<32 hex>","parent":{"host":"<your-host>","threadUuid":"<parent-thread-uuid>"}}'
node scripts/call.mjs dispatch_watch args.json
# 3. Wait for the first outcome. Pass the same parent so receipts are accounted once.
Set-Content -Path args.json -Encoding utf8 -Value '{"job_id":"dispatch-<32 hex>","parent":{"host":"<your-host>","threadUuid":"<parent-thread-uuid>"},"budget_ms":600000}'
node scripts/call.mjs dispatch_wait args.json
# -> {"job_id":"...","status":"completed","terminal":true,"actionable":true,"delivery":{"event_id":"..."},"wait":{...}}
# 4. Acknowledge receipt before reviewing the work. Receipt is not acceptance.
Set-Content -Path args.json -Encoding utf8 -Value '{"action":"ack","job_id":"dispatch-<32 hex>","parent":{"host":"<your-host>","threadUuid":"<parent-thread-uuid>"},"event_id":"<event_id>"}'
node scripts/call.mjs dispatch_watch args.jsonSet-Content -Encoding utf8 produces a BOM under Windows PowerShell 5.1 and none under
PowerShell 7; both are accepted, because the server and call.mjs strip a leading BOM
before parsing JSON. The hub token is the one file that must stay plain UTF-8.
dispatch_status is the manual check when a watch was never registered or an event
looks stale. It is not the routine progress loop.
Lifecycle limits
One watch binding per job, created by
register;ensurerecovers its observer,detachstops it. A killed watcher helper or a reboot still needsensure.Reports stay in the tool channel. Nothing wakes an idle chat, so a parent turn that has ended will not see a later tool result.
dispatch_waitholds one call open: 600000 ms by default, 3600000 ms at most. The client timeout must exceed the budget, which is why registration sets 3700 s.A turn that ends as
abortedis terminal: the job status becomescancelledanddispatch_waitreturns it like any other end.Uncertain about a turn?
dispatch_statusreports the recorded attempt and whether itsturn/endevidence exists. To keep working, continue the same session withdispatch_followup(defaultqueueadds a next turn;steerworks only while a turn is running) and a newrequest_id. To bind a turn that already exists, usedispatch_adopt_turnwith that turn number and therpcIdof the user message that started it; it refuses running, unknown, earlier or unrelated turns. Do not dispatch a duplicate job to get past an uncertain state.
Legacy queue delivery
The source supports enqueueing reports into a parent chat through the Codex
app-server. That path needs a logged-in Codex CLI and its private thread database,
is unverified in this release, and is off by default
(notifications.queueEnabled: false). Treat it as historical: this candidate
delivers through tool results only.
Tools
Tool | Purpose |
| List live DSH routes and their supported efforts. |
| Create one visible worker with an immutable task and exact route. |
| Recovery check of one job's turn: requires the correlated |
| Request cancellation of a bridge-owned task. |
| Bind an interrupted job to a later turn in its own session. |
| Steer a running turn or queue the next one, with replay-safe IDs. |
| Register the initiating chat, recover the observer, read and ack events. |
| Write an immutable task file without spawning anything. |
| Wait for the first selected job to finish, fail or need input. |
Retry an uncertain dispatch with the same request_id and payload; DSH deduplicates
the replay. Never substitute a different model to get past a failure.
Scripts
scripts/call.mjs— call one tool over stdio without a GUI.scripts/smoke-mcp.mjs— assert the server starts and lists exactly the nine tools.scripts/watch.mjs— the detached watcher helper the server spawns.scripts/watch-activate.mjs— replace a watcher that is running stale code.scripts/worker-report.mjs— a worker's own milestone/blocked report.scripts/recover-writer-lock.mjs— clear a job writer lock left by a killed process.scripts/verify-owner.ps1— the owner attestation script.
Tests
npm test runs the suite with node --test. Tests use temp fixtures and fake
thread IDs, and need no config.json. The owner-attestation tests run the real
verifier against temp receipts and skip the live-owner cases when this host has no
owner records. scripts/smoke-mcp.mjs and scripts/call.mjs do start the server,
so they need config.json to exist.
License
This project's code is released under GPL-3.0-only. The full, authoritative English
license text is LICENSE. Copyright (c) 2026 The Agent Teams contributors.
The npm dependencies keep their own licenses — see
THIRD_PARTY_NOTICES.md.
This server cannot be deployed
Maintenance
Related MCP Connectors
Durable background job execution, async task scheduling, and state persistence for AI agents.
Reliable async execution for agent tool calls: schema gating, retries, idempotency, audit trail.
Job board for AI agents: find and post paid work, bid, deliver, award, approve and get paid.
Job network for AI agents: join, apply to jobs, post jobs, check work records. OAuth for writes.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceLets Claude Code, Codex, or any MCP client drive DeepSeek Harness as a long-lived coding agent: starting and resuming conversations, dispatching tasks in the background, streaming live output and reasoning stats, interjecting or interrupting mid-turn, handling approval prompts, and collecting results later. Sessions persist by ID, so work survives process restarts and can be handed back to a DSH GUI when needed.750 npm15MIT
- AlicenseNot gradedqualityBmaintenanceEnables host agents to launch and supervise durable, long-horizon AI jobs—starting, running, resuming, checking budgets, and inspecting assembled context—so tasks can survive restarts and outlive the conversation with verified completion.MIT
- AlicenseNot gradedqualityBmaintenanceEnables an opt-in manager–worker workflow where a manager agent plans work, dispatches scoped tasks with acceptance criteria to independent worker sessions, tracks progress on a live monitor, audits scope, and verifies artifacts by fingerprint before integrating them. Durable SQLite-backed state, heartbeats, and per-attempt logs support stop/resume, anti-duplicate dispatching, and recovery across closed chats.MIT
- AlicenseNot gradedqualityBmaintenanceEnables Codex/Astra to hand off complete task packets to DSH for real execution in a shared local workspace, with progress, tool calls, questions, and results written back to a shared .astra-dsh task board. Supports blocking waits, queued follow-up instructions, interrupts, cancellation, rework requests, and independent verification or diff review of the resulting changes.1MIT