MCP / AI integration¶
treeman ships an MCP (Model Context Protocol) server so AI agents — Claude Code, Claude Desktop, Cursor, Continue, anything that speaks MCP — get a structured tool surface onto treeman's state.
treeman mcp # stdio (default): one server per client
treeman mcp --http # shared HTTP daemon on 127.0.0.1:8787
The default stdio transport spawns one server per client, scoped
to that client's working directory — no extra processes, no network
surface. The HTTP transport (--http) runs a single shared server
that every client (e.g. all your Claude Code instances) connects to,
each request scoped to its own worktree via the client's MCP roots or
an X-Repo-Root header. See Shared HTTP server.
What is this actually for¶
Four use cases drive the MCP surface, each backed by tools an agent would otherwise have to drive by reading source + scrolling logs:
-
Configuration assistance. An agent can read the current
.treeman.yaml(config_get), validate edits against the authoritative schema (config_validate,config_schema), patch individual fields by dotted path (config_set), or scaffold a fresh config for a repo it just detected (init_repo,fw_detect,schema_install). This is the biggest win —.treeman.yamlis the surface that decides whether a worktree boots, and editing it without treeman's own validator is where humans burn the most time. -
Diagnosis when prepare fails.
logs_query(event log) +logs_hooks(hook run summaries) +hook_log_read(full per-hook stdout/stderr) give the agent everything the daemon recorded.worktree_showis the per-worktree dossier.doctorruns the health-check matrix.snapshots_inspectresolves a fingerprint to "is this row an orphan or live?" — the canonical answer for "cache hit but prepare still failed". -
Live engine state.
db_queryruns READ-ONLY queries (SELECT/SHOW/EXPLAIN on SQL engines; find-style filters on Mongo;_searchbodies on ES; one of {GET, SCAN, KEYS, INFO, …} on Redis).db_schema_dumpreturns the live CREATE TABLEs.engine_statusprobes every engine declared in.treeman.yaml. Use these to verify a migration's effect or reason about live shape vs. what the config says. -
Snapshot-cache maintenance.
snapshots_listshows what's cached for the current repo;snapshots_dropevicts a single fingerprint when a template went stale;snapshots_purgewipes the whole cache.
Tool discovery (lazy disclosure)¶
To keep the model's context lean, treeman mcp advertises only a
curated core set of six tools up front — doctor,
status_overview, worktree_create, worktree_list, prepare_run,
logs_query — plus one tools gateway. The rest are deferred:
toolswithaction=listreturns every available tool grouped by category with a one-line summary (no schemas).toolswithaction=enable+names=[…](orcategory=…) loads the chosen tools' full schemas so they become callable; the client is notified viatools/list_changed.
Set TREEMAN_MCP_ALL_TOOLS=1 to advertise every tool at startup
instead (the pre-disclosure behavior). The full surface is always
reachable — lazy mode only controls what's loaded into context first.
Permission model¶
treeman mcp takes no permission flags — every tool (read, write,
engine introspection, worktree lifecycle) is reachable (loaded up front
or via the tools gateway above). The MCP surface is designed as the
fully-qualified link to treeman; clients that want a restricted surface
should enforce that at the agent-policy layer (Claude Code's tool
allow-list, Cursor's MCP allow rules, etc.), not here.
Destructive-action confirmation (elicitation)¶
worktree_delete, snapshots_purge, db_reset, repo_remove,
logs_purge, registry_unregister, and the write-mode engine tools
(db_query / es_request with write=true) gate their mutation
behind an MCP notifications/elicitation confirmation when invoked
with dry_run=false. Clients that support
elicitation (Claude Desktop, etc.) get a confirmation pop-up before
the action runs; clients that don't support it (or that error out)
fall through to proceed so non-interactive agents aren't blocked.
Per-call overrides:
dry_run=true— skip elicitation; return the plan instead.ack=true— skip elicitation; proceed (use when the agent has already secured user approval out-of-band).
Refusals (decline/cancel) come back as refused: "<reason>" on the
tool result with no mutation performed.
Tools exposed¶
The complete tool list — grouped by category, flagged core (loaded
up front) vs revealed on demand — is generated from the live registry:
mcp-tools.md. It refreshes via just sync-docs, so it
never drifts from the code (CI fails a PR that forgets to regenerate).
Resources¶
Resources are read-only context attachments — cheaper than re-invoking tools each turn.
| URI | What |
|---|---|
treeman://config/raw |
The repo's .treeman.yaml byte-for-byte. |
treeman://config/resolved |
Post-substitution view (env vars + connection strings rendered, credentials redacted). |
treeman://config/schema |
JSON Schema for .treeman.yaml. |
treeman://logs/recent |
The 200 most recent event-log rows (NDJSON). |
treeman://worktrees/{slug}/events |
Per-worktree event-log slice. |
treeman://worktrees/{slug}/hooks |
Per-worktree hook_run rows. |
treeman://daemon/state |
Mirrors daemon_state — in-flight prepares/teardowns, watcher set, backoff timers. |
treeman://repos/{repo}/snapshots |
Cached snapshots for one repo. Use cwd for the placeholder to mean "the current dir's repo". |
treeman://repos/{repo}/branches |
Branch list with worktree occupancy. Same cwd placeholder. |
Prompts¶
Prompts encode multi-step workflows so an agent doesn't reinvent each flow. Invoke from your MCP client to get a tailored briefing.
| Name | What |
|---|---|
bootstrap-new-repo |
First-time enrollment: detect → probe engines → init → schema_install → daemon ensure → register → first prepare. |
scaffold-from-framework |
Detect → scaffold .treeman.yaml → validate → review. Stops short of running prepare. |
worktree-setup |
Pick branch → daemon ensure → create → wait → verify. |
diagnose-prepare-failure |
Drives logs_query → engine_status → snapshots_inspect → root-cause report. |
cache-cleanup |
Hunt orphan snapshots (template gone, SQLite row remains) and drop only those. |
migration-trial |
Throw-away worktree → run migration → schema diff → tear down. |
edit-config |
Pick the right config file (global vs repo), preview, apply scope-checked, validate. |
Claude Code¶
Claude Code ships a claude mcp add
command:
# User-scoped (available across every project on this machine)
claude mcp add --scope user treeman -- treeman mcp
# Project-scoped (committed to .mcp.json in the repo root)
claude mcp add --scope project treeman -- treeman mcp
# Local-scoped (private to you in this project — `claude mcp add`'s default)
claude mcp add treeman -- treeman mcp
Confirm it registered with claude mcp list. Inside a session,
the tools appear as mcp__treeman__<tool-name> (e.g.
mcp__treeman__worktree_list).
Shared HTTP server¶
Instead of stdio (one treeman mcp process per client), run a single
shared server over HTTP and point every client at it. One daemon backs
all your Claude Code instances; each request is scoped to its own
worktree, so there is no per-process working directory.
treeman mcp --http # 127.0.0.1:8787, path /mcp
treeman mcp --http=127.0.0.1:9000 # custom bind
treeman mcp --http --http-path=/treeman # custom endpoint path
Equivalent env vars (handy for a service unit): TREEMAN_MCP_HTTP_ADDR,
TREEMAN_MCP_HTTP_PATH, or TREEMAN_MCP_HTTP=1 for the loopback default.
A /healthz endpoint returns {"status":"ok"} for liveness probes.
Wire Claude Code to it as an HTTP server — no per-instance config needed, the client's MCP roots scope each request automatically:
How a request is scoped¶
Each request resolves its repo/worktree by precedence (highest first):
- an explicit tool argument (
repo/worktree), - the
X-Repo-Rootrequest header (alsoX-Mcp-Root(s)/Mcp-Root(s);file://URI or absolute path; comma-separated for multiple), - the client's MCP roots (
roots/list) — Claude Code exposes its workspace this way, fetched once per request and only when the client advertised the capability.
Over HTTP there is no working-directory fallback: a request that supplies none of the above gets a clear error rather than resolving against wherever the daemon happens to have been launched. (Over stdio, the process cwd remains the default, as before.)
To pin a client to a fixed worktree regardless of its roots, set a header:
{
"mcpServers": {
"treeman": {
"type": "http",
"url": "http://127.0.0.1:8787/mcp",
"headers": { "X-Repo-Root": "/abs/path/to/worktree" }
}
}
}
Running it as a service (Linux, systemd --user)¶
Run all tools up front (TREEMAN_MCP_ALL_TOOLS=1) so the tools gateway's
enable-state — which is shared across clients on one server — doesn't churn
tools/list_changed for everyone when one client enables a tool.
~/.config/systemd/user/treeman-mcp.service (see also
contrib/treeman-mcp.service):
[Unit]
Description=treeman MCP server (shared HTTP)
After=network.target
[Service]
ExecStart=%h/.local/bin/treeman mcp --http
Environment=TREEMAN_MCP_HTTP_ADDR=127.0.0.1:8787
Environment=TREEMAN_MCP_ALL_TOOLS=1
Restart=on-failure
[Install]
WantedBy=default.target
systemctl --user enable --now treeman-mcp
systemctl --user status treeman-mcp
curl -s http://127.0.0.1:8787/healthz
Security. The endpoint has no authentication, and treeman's tools run shell hooks, prepare scripts and arbitrary DB queries — reaching the port is equivalent to local code execution. Keep the bind on loopback (the default), where DNS-rebinding protection is active. Binding a non-loopback address disables that protection and exposes the surface unauthenticated; only do so behind a reverse proxy that terminates TLS and authenticates, on a trusted network. The server logs a warning when bound non-loopback.
Claude Desktop¶
Edit the desktop config — on macOS:
~/Library/Application Support/Claude/claude_desktop_config.json;
on Linux: ~/.config/Claude/claude_desktop_config.json:
Restart Claude Desktop. The tools surface under the hammer icon.
Cursor¶
Add to ~/.cursor/mcp.json (global) or <repo>/.cursor/mcp.json
(per-project):
Generic MCP client¶
Any client that supports stdio MCP servers takes the same shape:
the command is treeman, the args are ["mcp", ...flags].
Stderr is logging; stdout is the JSON-RPC envelope, so do not
wrap the command in anything that mixes the two.
Security notes¶
- The MCP server runs as the invoking user with full access
to the repo, the daemon socket, and any
.envfiles. Lazy disclosure (see Tool discovery) controls what loads into context first, but every tool stays reachable — it is not a security gate. Restrict the exposed surface at the agent-policy layer (Claude Code's per-tool allow rules, Cursor's MCP allow list, etc.) for any agent you don't fully trust. worktree_deleteand the other destructive tools run their mutation in-process but gate it behind MCP elicitation (see Destructive-action confirmation) — clients without elicitation support fall through to proceed, so enforce policy at the agent layer for untrusted agents.- Hook stdout/stderr and event payloads pass through
redactSecrets(seeinternal/mcp/ops.go) before being returned to the client. False positives just hide a token; false negatives leak it. Project-specific patterns can be added tosecretPatterns.