AI agents (MCP)
devkit mcp is an MCP server on stdin and stdout. Your agent starts it at the beginning of a session and it exits when the session ends. Every tool calls the same code as the CLI command it mirrors and returns the same JSON as that command with --json, so an agent can start sites, create lanes, run tests and read logs exactly as you would, without guessing ports or paths.
Set up your agent
devkit mcp config <agent> prints the exact command or config entry, with the absolute path of the devkit you ran (apps started from the Dock or a launcher do not get your shell's PATH, so a bare devkit would not be found). Without an agent it prints all of them. In the examples below <devkit> stands for that path, for instance /Applications/devkit.app/Contents/Helpers/devkit or ~/.local/bin/devkit.
--write merges the entry into the agent's config file instead: other servers and keys stay, an existing devkit entry is replaced, the previous file is kept as <file>.devkit-backup-<time>, and a JSON file with comments is refused rather than rewritten. For the agents configured per project, --dir <project> picks the project folder (default: the current one).
Claude Code
claude mcp add --scope project devkit -- <devkit> mcp
or devkit mcp config claude-code --write, which merges this into .mcp.json in the project:
{
"mcpServers": {
"devkit": { "type": "stdio", "command": "<devkit>", "args": ["mcp"] }
}
}
Codex CLI
codex mcp add devkit -- <devkit> mcp
or devkit mcp config codex --write, which merges this into ~/.codex/config.toml ($CODEX_HOME/config.toml when set):
[mcp_servers.devkit]
command = "<devkit>"
args = ["mcp"]
Gemini CLI
gemini mcp add devkit <devkit> mcp
or devkit mcp config gemini --write, into .gemini/settings.json in the project:
{ "mcpServers": { "devkit": { "command": "<devkit>", "args": ["mcp"] } } }
Cursor
devkit mcp config cursor --write, into .cursor/mcp.json in the project:
{ "mcpServers": { "devkit": { "command": "<devkit>", "args": ["mcp"] } } }
VS Code (Copilot)
devkit mcp config vscode --write, into .vscode/mcp.json in the project. Note the key is servers:
{ "servers": { "devkit": { "type": "stdio", "command": "<devkit>", "args": ["mcp"] } } }
Claude Desktop
devkit mcp config claude-desktop --write, into ~/Library/Application Support/Claude/claude_desktop_config.json (Linux: ~/.config/Claude/). Restart Claude Desktop afterwards.
{ "mcpServers": { "devkit": { "command": "<devkit>", "args": ["mcp"] } } }
Any other MCP client
An MCP server on stdio, no environment needed:
{ "command": "<devkit>", "args": ["mcp"], "transport": "stdio" }
In the app
The MCP section has a pill per agent with its command or config and Copy. For Claude Code, Gemini CLI, Cursor and VS Code, Write to project… asks for the project folder and runs devkit mcp config <agent> --write --dir <folder>. When an agent connects, it appears under Connected, in the menu bar and in the status bar.
The tools
devkit mcp tools lists them with their group and description (--json adds the input schemas). Arguments are snake_case; a bad one is an INVALID_ARGUMENT result, not a protocol error.
| Group | Tools |
|---|---|
| status, doctor | status (everything at once, checked live), doctor |
| stacks | stack_list, stack_up, stack_restart, stack_logs, stack_down confirm |
| sites | site_list, site_link, site_park, site_set, site_action, site_clone, site_setup, site_hide, site_unhide, site_delete confirm, site_up, site_down, url |
| templates | template_get, template_set |
| xdebug | xdebug_status, xdebug_set |
| processes | proc_list, proc_start, proc_stop, proc_restart |
| exec, logs | exec, logs |
| lanes | lane_list, lane_new, lane_up, lane_down, lane_rm confirm |
| databases | db_snapshot, db_snapshot_list, db_restore confirm, db_snapshot_rm confirm, db_reset confirm, db_query |
| git | git_status, git_checkout, git_fetch, git_pull, git_push (with_submodules, default true) |
| modules | modules_status, modules_checkout, modules_pull, modules_push, modules_add (group, only) |
A few worth knowing in detail:
exec- Runs a command in a site's or lane's folder with its PHP.
commandis an argv array such as["php","artisan","migrate","--force"];shortcut(artisan,composerorphpunit) putsphp artisan,composerorphp vendor/bin/phpunitin front of it.timeout_secondsdefaults to 600,xdebug: trueruns this one command with Xdebug. The output is the last 64 KiB; a failing command is stillok: true, with itsexitCode. url- Where a site or lane is served, whether it answers (one GET; a status below 500 is healthy), its Vite ports and the mail inbox URL. It works for a stopped site too.
logssourceislaravel(default),engine(the web server),proc:<name>orcontainer:<service>;linesdefaults to 200.db_query- One read-only
SELECT,SHOW,DESCRIBEorEXPLAINin a read-only transaction, at most 500 rows (truncatedsays when there were more). lane_new,site_clone,site_setup- Report each step as a progress notification when the agent asks for progress. Every tool given a progress token also reports "still running" every 10 seconds, and cancelling a call cancels the work (an
execis stopped, in a PHP container too).
Two things are deliberately not tools: devkit trust and devkit hosts sync, because they ask for your password.
Destructive tools and confirm
Six tools can destroy something: stack_down, site_delete, lane_rm, db_reset, db_restore and db_snapshot_rm. Called without "confirm": true they change nothing and return CONFIRM_REQUIRED describing exactly what would happen:
{"ok":false,"error":{"code":"CONFIRM_REQUIRED",
"message":"this would remove lane core-development--crm-fix: stop it, drop its database core_development_l1 and its snapshots, remove its worktree …",
"hint":"show this to the user; call lane_rm again with \"confirm\": true to go ahead"}}
A well-behaved agent shows you that text and asks before calling again with confirm. On top of that, the usual safety checks still apply with confirm: site_delete and lane_rm refuse with DIRTY_WORKTREE while there is uncommitted or unpushed work unless force is also true, and db_restore takes a safety snapshot unless safety is false. These tools are also marked with MCP's destructiveHint, so clients that ask before destructive calls do so.
The audit log
Every tool call is appended to ~/.config/devkit/audit.log as one JSON line: the time, the server's pid, the client (the name the agent reports for itself), the tool, its arguments, whether it only reads, ok or the error code, and how long it took. Secrets are replaced by [redacted] (template contents, password-like names, credentials in URLs). The log is rotated to audit.log.1 at 10 MB.
devkit mcp audit --limit 20
2026-10-26 14:31:07 claude-code exec ok {"command":["php","vendor/bin/phpunit"],"site":"core-development--agent-a"}
2026-10-26 14:29:40 claude-code lane_rm CONFIRM_REQUIRED {"lane":"core-development--old-spike"}
2026-10-26 14:22:13 claude-code lane_new ok {"name":"agent-a","site":"core-development","start":true}
In the app, MCP → Audit log shows the same, reloaded when an agent makes a call. While a server runs, ~/.config/devkit/mcp/<pid>.json records which agent is connected, since when, and its last tool; devkit status lists these sessions and cleans up the files of servers that were killed.
Recommended workflows
One lane per agent
Never let two agents (or an agent and you) work in the same folder. Give each its own lane: a branch, a database and a port of its own.
Create a lane "agent-a" of core-development with lane_new (start: true),
work only in its folder, and run tests with exec on core-development--agent-a.
When the work is pushed, remove the lane with lane_rm; the agent will get CONFIRM_REQUIRED first and should show you what goes.
Tests and commands through exec
- Ask the agent to run tests with
execon its lane (shortcut: "phpunit", or["php","artisan","test"]) rather than its own shell, so the lane's PHP version and.envare used. - For one debug run, use
execwithxdebug: trueinstead of turning Xdebug on for the site: Xdebug slows every request, and under caddy it is shared by every site on the container. - Let it read errors with
logs(laravel, thenproc:queue) and check data withdb_queryinstead of opening a database shell.
Snapshots before risky steps
Before a migration or a data fix, have the agent call db_snapshot with a clear name (before_orders_migration). If things go wrong, db_restore needs your confirmation and keeps a safety snapshot of the broken state too.
Start with status and doctor
A good first instruction: "call status, then doctor for the site, and tell me what is running and what is broken before you change anything". Both read only.
What devkit guarantees
- Nothing destructive without confirm. The six destructive tools only describe what they would do until called with
"confirm": true. - No lost work by default. Deleting a site or removing a lane refuses while there is uncommitted or unpushed work, unless the agent also passes
force. A restore keeps a safety snapshot. - No password prompts. Trusting certificates and editing
/etc/hostsare not tools. Git runs with your existing credentials and never prompts. - Read-only queries are read-only.
db_queryrefuses anything but one read statement and runs it in a read-only transaction. - Everything is recorded in the audit log on your machine, with secrets removed.
- Nothing leaves your machine. devkit has no account and no telemetry; the MCP server talks only to the agent that started it.
rm or git push --force itself; use your agent's own permission settings for that.