Connect an agent
How to connect Claude Code, Codex or any MCP client to a site running Darwin AI, with the Darwin client or directly.
Written for Darwin AI 2.87.3
This page is for whoever runs the AI agent. You will need a handoff from the site's administrator (see Passes and access levels). The easiest route is the small Darwin client. It keeps tokens out of command lines and refreshes them for you. You can also talk to the endpoints directly.
The connection block
When a handoff is created, or Copy is clicked on its card, the administrator gets a block of JSON (structured text) like this:
{
"site": "https://example.com/",
"protocol": "1",
"handoff_token": "dai_h_h_…",
"endpoints": { "mcp": "…", "fast": "…", "lease": "…", "refresh": "…", "revoke": "…", "client": "…", "call": "…" },
"fallbacks": { "mcp": "…", "lease": "…" },
"how": [ "1. …", "2. …", "3. …" ]
}
| Field | Meaning |
|---|---|
site | The site's address. |
protocol | The Darwin protocol version. This release uses 1. |
handoff_token | The secret that opens leases. It cannot call tools itself. |
endpoints | The addresses to use (see Endpoints). fast is only listed when the site's own check found it answering. |
fallbacks | Plainer addresses to switch to if a main address returns something that is not JSON, such as a host's error page. |
how | Three written steps for the agent: get the client, mint a lease, then make one start call. |
The block tells the agent to ask you, in plain words, before it runs the downloaded client in a new folder for the first time, and to run nothing until you agree.
Setting up the Darwin client
The client is two small scripts with no secrets in them. darwin.sh is for macOS, Linux and Git Bash, and needs curl or GNU wget. darwin.ps1 with darwin.cmd is for Windows PowerShell 5.1 and PowerShell 7. Everything the client keeps, including the lease file, lives in its own folder.
- Make an empty folder and save the connection block in it as
connection.json. - Download the client next to it, from the address in
endpoints.client. - Run
updateto fetch Darwin AI's extra modules (darwin harnessanddarwin mockup). - Mint a lease with a label that describes the job.
- Make the start call once.
On macOS, Linux or Git Bash:
curl -fsSL <endpoints.client>/darwin.sh -o darwin.sh
sh darwin.sh update
sh darwin.sh lease "contact-page" --level editor
sh darwin.sh start
On Windows (PowerShell):
Invoke-WebRequest <endpoints.client>/darwin.ps1 -OutFile darwin.ps1
Invoke-WebRequest <endpoints.client>/darwin.cmd -OutFile darwin.cmd
.\darwin.cmd update
.\darwin.cmd lease "contact-page" --level editor
.\darwin.cmd start
start answers once with what the agent needs: the core knowledge, the tool index, the skills and plugin-specific knowledge. To name the job up front, pass JSON, for example start '{"scope":"elementor","skill_id":"core.page-build-flow"}'.
Client commands
| Command | What it does |
|---|---|
lease <label> | Mints a lease from connection.json and saves it in the folder. Options: --level, --ttl (seconds), --calls, --tools a,b (only show these tools), --file (lease file name). |
refresh | Rotates the lease's tokens now. Other commands refresh automatically when needed. |
start [json] | The one-off start call. |
call <tool> [mode] [json or @file] | Runs one tool. Add --format json or --format toon to choose the answer format. Answers over 12,000 characters are saved under answers/. |
batch <json or @file> | Up to 10 calls in one request. |
op <op_id> [--wait] | Checks on a long operation, or waits for it to finish. |
apply | Re-sends the last successful dry run for real. |
mcp [--lease F] | Runs a local MCP server (see below). |
gc | Tidies up: removes dead lease files, old answers and modules the site no longer offers. |
kit <id> | Fetches a kit when the server offers kits. Darwin AI 2.87.3 advertises none, so this reports that. |
update | Fetches the latest client files and modules from the site. |
version | Shows the client and server versions. |
help | Lists the commands. |
To give a sub-agent its own session, mint a separate lease with --file. Then run the sub-agent's commands with the environment variable DARWIN_LEASE set to that file. The sub-agent never needs to see the connection block.
sh darwin.sh lease "seo-audit" --level inspector --file seo.lease
DARWIN_LEASE=seo.lease sh darwin.sh call rankmath_seo_read audit
Using Darwin AI from an MCP client
MCP (Model Context Protocol) is the standard way AI tools like Claude Code and Codex connect to outside services. darwin mcp runs a local MCP server over stdio, meaning the MCP client starts the command and talks to it directly. It forwards each request to the site and keeps the lease fresh. It retries when the site is briefly busy, and switches to the fallback address if the main one returns something that is not JSON.
- Set up the client folder and mint a lease, as above.
- Register
darwin mcpin your MCP client as a stdio server. Use full paths, because the client may start it from another folder.
A typical entry looks like this. Check your MCP client's documentation for exactly where it goes.
{
"mcpServers": {
"darwin": {
"command": "sh",
"args": ["/full/path/to/folder/darwin.sh", "mcp"]
}
}
}
On Windows, use C:\full\path\to\folder\darwin.cmd as the command, with mcp as its argument. To use a lease file other than the default, add --lease <file>.
Endpoints
When the site's rewrite rules allow it, addresses sit under /dai/. Otherwise they sit under /wp-json/dai/v2/. Always use the addresses in the connection block rather than building your own.
| Endpoint | Request | Token |
|---|---|---|
lease | POST JSON { label, level?, ttl?, calls?, tools? } | Handoff token |
refresh | POST; both tokens rotate, so replace both | Refresh token |
revoke | DELETE …/lease/{id} when a sub-agent is done | Handoff token |
mcp | MCP over JSON-RPC: initialize, ping, tools/list, tools/call, resources/list, resources/templates/list, resources/read | Access token |
fast | The same MCP server. It answers discovery calls (initialize, ping, tools/list, get_info) without loading the site's other plugins, which is much quicker. | Access token |
call | Plain HTTP POST { tool, arguments }; key facts come back in X-Darwin-* headers | Access token |
client | GET the client manifest and scripts | None |
Every request sends its token as Authorization: Bearer <token>. On the MCP endpoints, a refusal arrives as JSON-RPC error -32001, or -32029 when throttled, with the cause in error.data.reason. On the other endpoints it is HTTP 401, 429 or 503. If the cause is access_expired or usage_limit, refresh and retry. For anything about the handoff or lease ending, stop and ask the administrator for a new handoff.
A tool call over MCP looks like this:
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": { "name": "content_read",
"arguments": { "mode": "info", "args": { "id": 6620 }, "_note": "Checking the page before editing it." } } }
By default, reads answer in TOON, a compact text format, and writes answer in JSON. Add "format": "json" next to mode to choose.
Dry runs, then apply
Write modes accept "dry_run": true in their arguments. Darwin AI then answers with the exact plan and changes nothing. Read the plan, then run it for real. With the client, apply repeats your last successful dry run with the dry run switched off:
sh darwin.sh call content_manage status '{"status":"publish","ids":[12,15],"dry_run":true,"_note":"Publishing the two reviewed drafts."}'
sh darwin.sh apply
Add a _note to every call
_note is one sentence saying why you are making the call. Site owners read it in History next to each call, so it is how they follow your work. Darwin AI accepts calls without it, but write one on every call, and always on retries and corrections. It can sit next to mode, inside args, or on each entry of a batch.
Batches and long operations
batch runs up to 10 calls in one request, in order. Each call is checked, recorded and counted against the lease exactly as if it had been sent alone. It is not all-or-nothing: calls before a failure have already happened. Set "continue_on_error": false to stop at the first failure. With the client, a bare list is accepted:
sh darwin.sh batch '[{"tool":"content_read","mode":"info","args":{"id":12},"_note":"Check draft 12"},{"tool":"content_read","mode":"info","args":{"id":15},"_note":"Check draft 15"}]'
Never put the dry run and the real run of the same change in one batch. A failed dry run does not stop the real run queued after it. Rehearse in one batch, read the plans, then write in the next.
Some tools, such as the in-browser page checks, start a long operation and answer straight away with an op_id. Wait for the result with op. Checking an operation never uses up lease calls.
sh darwin.sh op op_0123456789abcdef --wait
Windows notes
- Run
darwin.cmd. It startsdarwin.ps1without your PowerShell profile, and lets it run for that one call without changing your execution policy (the Windows setting that controls which scripts may run). - From PowerShell, pass JSON as a file: write it to a file and pass
@file. PowerShell strips the quotes inside JSON handed to a.cmd, so inline JSON arrives broken. - Inside the JSON, a top-level value of
"@page.html"is replaced by that file's contents. Write"@@text"when you mean a literal value starting with@.
.\darwin.cmd call content_read info '@args.json'
On any system, tokens stay in the lease file and are never put on a command line or in a log. To learn what each tool does, see Tools.