pi-delegate-mcp
██████╗ ██╗ ██████╗ ███████╗██╗ ███████╗ ██████╗ █████╗ ████████╗███████╗
██╔══██╗██║ ██╔══██╗██╔════╝██║ ██╔════╝██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝
██████╔╝██║ ██║ ██║█████╗ ██║ █████╗ ██║ ███╗███████║ ██║ █████╗
██╔═══╝ ██║ ██║ ██║██╔══╝ ██║ ██╔══╝ ██║ ██║██╔══██║ ██║ ██╔══╝
██║ ██║ ██████╔╝███████╗███████╗███████╗╚██████╔╝██║ ██║ ██║ ███████╗
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝
███╗ ███╗ ██████╗██████╗
████╗ ████║██╔════╝██╔══██╗
██╔████╔██║██║ ██████╔╝
██║╚██╔╝██║██║ ██╔═══╝
██║ ╚═╝ ██║╚██████╗██║
╚═╝ ╚═╝ ╚═════╝╚═╝
将 pi 编码代理暴露为可委派、可操控工作器的 MCP 服务器。
把它指向 Claude Code(或任何 MCP 主机),即可将工作委派给 pi 的约 38 家提供商中的任意一家 (DeepSeek、Grok、GLM、Kimi、Qwen、Codex、OpenRouter、本地 llama.cpp),子代理的 上下文不会进入你的主对话。
它的用途
你的主框架运行在昂贵的模型上,上下文窗口是你所在意的。它做的很多事情并不需要那个模型, 反而会损害上下文:在仓库中搜索每个调用点、为了回答一个问题而读取 2000 行的文件、 审计重构留下了什么。
把这些工作交给委派代理:
成本。 苦力活跑在 DeepSeek、GLM、Kimi、Qwen 或本地 llama.cpp 上。你只为真正需要前沿模型的推理支付前沿价格。
上下文。 委派代理用自己的预算读取文件并返回结果。它读过的 200 KB 永远不会进入你的对话。
影响范围。 委派代理默认只读(
read, grep, find, ls),在会话构造时强制执行。做探索性工作的廉价模型无法触碰你的代码树,除非你主动允许。
委派代理始终是 pi 代理。Codex、Grok、DeepSeek 等提供其背后的模型;这不是对它们 CLI 的包装。
Related MCP server: handoff-mcp
为什么选 pi,而不是 opencode 或 CLI 包装器?
委派代理只有在两个通道保持畅通时才是可操控的:你必须能在任务中途重定向它,它也必须能向你提问并阻塞直到你回答。大多数从另一个程序驱动编码代理的方式都会关闭这两者。
| opencode SDK | 本服务器 | |
进程内运行 | 否(子进程) | 否(HTTP 客户端连接 | 是( |
重定向正在进行的回合 | 否 | 仅 |
|
代理能向你提问 | 否( | 会话 API 中不支持 |
|
每次调用可选模型 | 否 | 是 |
|
pi -p 和 --mode json 将 ctx.hasUI 设为 false。以这种方式启动的委派代理从构造上就是发后即忘:它无法提出问题,你也无法重定向它。
opencode 的 SDK 是独立服务器进程的类型化客户端:createOpencode() 启动 opencode serve 并通过 HTTP 与之通信。设计干净,但意味着需要监督第二个进程,而且它暴露的会话接口(prompt、abort、revert、messages)没有回合中操控,也没有让代理向调用方提问的途径。
pi 将 createAgentSession 作为可嵌入库提供。本服务器在进程内持有会话对象,因此 session.steer() 可以在当前工具调用之后、下一次模型调用之前投递消息,而合成的 uiContext 会捕获代理的问题并将其暂存以供 answer。无需 shell 调用,也无需监督任何东西。
* 问题来自 pi 扩展,因此该通道仅对以 extensions: true 启动的委派代理开放。参见 Web 搜索及其他扩展工具。
(该表比较的是委派通道,而非沙箱;opencode 有自己的权限配置。参见 默认只读 了解本服务器强制与不强制的内容。)
工具
工具 | 用途 |
| 先调用它。 报告可达模型、允许的工具以及如何驱动委派代理。其他所有工具在它运行过一次之前都会拒绝执行。 |
| 在后台委派。立即返回 |
| 一次调用扇出最多 10 个委派代理。作为批次验证,因此只要有一个任务有问题,就不会启动任何东西。 |
| 委派并阻塞直到完成。仅用于快速提问。 |
| 状态、回合数、使用的工具、最新文本以及待处理的问题。 |
| 重定向正在运行的代理。在其当前工具调用之后生效。 |
| 给已完成的委派代理再一个回合。它会保留读过的所有内容,因此你无需重新解释任务。 |
| 回答 |
| 停止会话;部分输出仍可读取。 |
| 列出此委派代理可用的模型。 |
| 列出会话,包括运行中和已完成的。可按 |
| 从历史中删除已完成的会话,释放其 id。 |
安装
需要 Node.js 22.19+ 以及已登录过一次的可用 pi 安装(pi,然后 /login)。
Claude Code
claude mcp add pi -e PI_DELEGATE_MODEL=openrouter/stealth/ox-alpha -- npx -y pi-delegate-mcp通过 .mcp.json 使用任何 MCP 主机
{
"mcpServers": {
"pi": {
"command": "npx",
"args": ["-y", "pi-delegate-mcp"],
"env": { "PI_DELEGATE_MODEL": "openrouter/stealth/ox-alpha" },
"timeout": 1800000
}
}
}npx 在每次启动时解析包。要固定版本,请全局安装并直接调用二进制文件:
npm install -g pi-delegate-mcp{ "mcpServers": { "pi": { "command": "pi-delegate-mcp", "timeout": 1800000 } } }保持服务器键简短,因为它会作为每个工具名的前缀(mcp__pi__spawn)。
从源码构建
git clone https://github.com/howznguyen/pi-delegate-mcp && cd pi-delegate-mcp
npm install && npm run build && npm link首次运行
让代理委派一些工作。它会调用一次 init 来了解本服务器能访问什么,然后调用 spawn:
{ "id": "audit-01", "label": "who still imports onnxruntime",
"prompt": "Search this repo for anything still importing onnxruntime and list the files.",
"cwd": "/path/to/repo" }{ "sessionId": "audit-01", "state": "running", "model": "opencode-go/deepseek-v4-flash",
"activeTools": ["read", "grep", "find", "ls"] }spawn 立即返回。用 status 轮询以获取有序的工具追踪和答案,或者在有多个进行中时用 sessions。如果 init 失败,它会准确说明缺少什么:pi 未安装、没有提供商登录,或模型范围不匹配任何内容。
下面示例中的模型名称仅作说明。运行 models 查看你自己的 pi 安装实际能访问什么。
可追溯性
spawn 和 run 都接受你自己的 id 和自由文本 label:
{
"id": "search-audit-01",
"label": "what ONNX removal left behind",
"prompt": "...",
"model": "opencode-go/deepseek-v4-flash"
}Id 为 [A-Za-z0-9._:-],1-64 个字符,必须以字母数字开头,并且在活动会话中必须唯一。省略则使用 UUID。
已完成的会话不会消失,而是通过 status 和 sessions 保持可读,因此你可以回头检查委派代理实际做了什么。保留最新的 PI_DELEGATE_HISTORY(默认 50)个;forget 可提前删除一个。
status 返回有序的 toolCalls 追踪:委派代理运行的每个工具,包括参数和计时。添加 verbose: true 可获取调用 id 和结果:
{
"seq": 1,
"id": "call_467b4bb4…",
"name": "bash",
"state": "ok",
"ms": 10,
"args": "{\"command\":\"echo hello-trace\"}",
"result": "hello-trace\n"
}参数和结果会被截断(PI_DELEGATE_TRACE_ARGS、PI_DELEGATE_TRACE_RESULT),并记录丢弃的长度,因此一次对大型文件的 read 不会淹没你的上下文。
给委派代理另一个回合
已完成的委派代理并非用完即弃。pi 会在内存中保留其会话,因此 follow_up 会以已读内容仍在上下文中为前提重新提示同一代理:
{ "sessionId": "search-audit-01", "prompt": "Now check whether the build files reference it too" }{ "sessionId": "search-audit-01", "state": "running", "turnsSoFar": 1 }委派代理会从上次停下的地方继续。它仍然持有第一回合读过的文件,因此第二个问题只需一次模型调用,而不是新会话重新读取仓库。
这是与委派代理对话的廉价方式。启动一个新的意味着重新解释任务并为其重新读取相同文件付费,而且它的答案不会带有得出该答案的推理过程。
follow_up 会拒绝仍在工作的委派代理,因为任务中途重定向正是 steer 的用途。两者不可互换:steer 在运行中代理的工具调用之间生效,follow_up 在已完成的代理上开始新回合。
扇出
spawn_batch 一次调用启动整个批次。任务继承批次级别的 model、cwd、tools 和 extensions,并在需要时单独覆盖:
{
"idPrefix": "audit",
"model": "opencode-go/deepseek-v4-flash",
"cwd": "/repo",
"tools": ["ls"],
"tasks": [
{ "prompt": "What still imports onnxruntime?", "label": "imports" },
{ "prompt": "Which build files still reference ONNX?", "label": "build" },
{
"prompt": "Any ONNX model files left on disk?",
"label": "artifacts",
"model": "opencode-go/ox-alpha-free"
}
]
}这会将它们命名为 audit-01、audit-02、audit-03,并在几毫秒内返回,因为启动委派代理不会等待它思考。
批次在启动任何内容之前进行验证:id 格式、批次内重复的 id、已活动的 id、被阻止的工具以及每个模型名称。一个任务有问题就会使整个调用失败且不启动任何内容。半途而废的扇出是最糟糕的结果,因为你既要为已启动的委派代理付费,还得弄清楚哪些没有启动。
用一次 sessions 调用轮询整个批次,而不是每个委派代理一次 status。只对你真正想读的委派代理使用 status。steer 和 abort 保持按会话操作。
每次调用选择模型
任何调用上的 model 都会覆盖 PI_DELEGATE_MODEL。无法解析的名称是硬错误,绝不会静默回退到默认模型,因为静默回退正是你最终为从未要求的模型付费的方式。
哪些名称可解析由 pi 自己的 enabledModels 范围决定,本服务器强制执行而不仅仅是展示:
opencode-go/deepseek-v4-flash -> ok (listed in enabledModels)
opencode-go/glm-5.3 -> refused (out of scope)
knowns-hub/claude-opus -> ok (custom provider, see below)自定义提供商绕过范围。 由 ~/.pi/agent/models.json 中声明的提供商提供的任何模型,即使 enabledModels 未提及也会被提供,理由是手动声明提供商本身就是使用它的意图。这就是为什么列表可能比 enabledModels 长得多:范围中的三个条目加上两个自定义提供商很容易意味着十五个提供的模型。init 在适用时会在 models.scopeNote 中明确说明这一点。
两个开关可以改变这一点:
效果 | |
| 完全遵守 |
| 完全放弃范围限制。所有已认证的模型都可用。 |
调用 models 查看在当前设置下实际可访问的内容。
状态行
Claude Code 只允许一个 statusLine 命令,因此 pi-delegate-statusline 会包装你已运行的任何命令,并附加一个显示此工作区委派代理的片段:
{
"statusLine": {
"type": "command",
"command": "PI_DELEGATE_STATUSLINE_WRAP=ccstatusline pi-delegate-statusline",
"refreshInterval": 10
}
}设置 PI_DELEGATE_STATUSLINE_WRAP 为假以仅打印 pi 片段。
π ▸ audit engine·t1·12s audit index·t2·8s running, with turn counts and elapsed time
π ▸ migrate·t7·3m04s ?1 waiting one delegate is blocked on a question
π ✓2 finished, nothing running哪些委派代理属于哪个会话
仅按目录过滤是不够的:同一仓库上打开的两个 Claude Code 会话会显示彼此的委派代理。归属改用进程谱系。
MCP 主机为每个会话启动一个服务器,因此服务器记录 process.ppid,即主机的 pid。由同一主机启动的状态行会遍历自己的祖先链,只保留在其中找到 hostPid 的状态文件。同一仓库、两个会话、无串扰。目录过滤器保留作为此功能存在之前写入的状态文件的回退。
State lives in $XDG_STATE_HOME/pi-delegate-mcp/<pid>.json (PI_DELEGATE_STATE_DIR to
relocate). Files are pruned when their process is gone, ESRCH only, since EPERM means the
process is alive under another user. Servers also exit on their own when stdin closes or the
host pid disappears, so a host that dies without closing the transport leaves nothing behind.
Read-only by default
Tools are locked to read, grep, find, ls at session construction. Anything else is refused
before a session is even created.
To widen that, name the extra tools on the server:
"env": { "PI_DELEGATE_ALLOW_TOOLS": "bash" }or PI_DELEGATE_ALLOW_WRITE=1 to permit everything.
bash is not a middle ground. pi ships no permission system, so a delegate holding bash
can write files, delete them, and reach the network regardless of whether write and edit are
on its list. Refusing those two while allowing bash records your intent; it does not enforce
anything. Claude Code's permission prompts and hooks never see what pi does. If you need a real
boundary, run this server inside a container.
Web search and other extension tools
pi's own tools are read, grep, find, ls, bash, powershell, write, edit. There is no
search and no fetch among them. Those come from pi extensions, which register their own tools, and a
delegate can use them.
Set extensions: true on the call and permit the tool names on the server:
"env": { "PI_DELEGATE_ALLOW_TOOLS": "web_search,fetch_content" }{ "prompt": "Find the current Node LTS version and tell me just the number",
"extensions": true, "tools": ["read", "grep", "find", "ls", "web_search"] }{ "seq": 1, "name": "web_search", "state": "ok", "ms": 2568,
"args": "{\"query\":\"latest stable Node.js LTS version\",\"numResults\":5}" }This is how you give a delegate network reach without handing it bash. web_search can search
and nothing else, and it passes through the same allowlist as every other tool, so the read-only
default is unchanged for calls that do not ask for it.
Which tools exist depends on what the user running the server has installed. pi-web-access provides
web_search, fetch_content, source_check and get_search_content. pi-mcp-adapter bridges the
MCP servers in ~/.pi/agent/mcp.json and exposes them as mcp. pi has no MCP client of its own, so
that extension is the only route to one.
extensions: true trusts every installed extension, not just the one you wanted. They load as a
set, they run with the full privileges of this server's process, and some open sockets and timers
that outlive the session. Turn it on per call, for the delegates that need it, rather than leaving it
on by default. It also costs real startup time, which is why it is off unless asked for.
Configuration
Env var | Default | Meaning |
| pi's own default | Model used when a call omits |
| unset | Comma list of extra tools to permit, e.g. |
| unset |
|
|
| Finished sessions kept for review |
|
| Max chars of tool arguments kept in the trace |
|
| Max chars of tool results kept in the trace |
|
| Ceiling on tasks per |
|
| Above this, |
| XDG state dir | Where status-line state is published |
| unset | Status line command to wrap and append to |
| unset | File to append a timestamp to on every status line render, for debugging |
|
| Progress notification interval during |
| unset |
|
| unset |
|
|
| Where pi's |
Long-running work
The MCP TypeScript SDK defaults to a 60 second request timeout, which a real task will blow through. Three defences, in order of preference:
Use
spawn+status. Nothing blocks, so no timeout applies.runemits periodic progress notifications, which reset the host's timeout.Raise the ceiling with
"timeout"in.mcp.jsonorMCP_TOOL_TIMEOUTin the environment.
CLAUDE_AUTO_BACKGROUND_TASKS=1 makes Claude Code background long MCP calls after ~2 minutes.
Note that progress notifications are discarded once a call is backgrounded, so pick (1) or (3),
not both.
Auth
The server does not handle credentials. pi authenticates itself from ~/.pi/agent/auth.json,
then environment variables. MCP hosts often launch servers with a stripped environment, so
prefer auth.json (run pi once and /login) over exporting keys in a shell profile.
Development
npm install
npm run build # tsc, src/*.ts -> dist/
npm run typecheck # tsc --noEmit, strict
npm run test:ci # offline: boots the server over stdio and lists its tools
npm test # full suite: needs a logged-in pi, makes real model callstest:ci is what CI runs and what prepublishOnly gates on, because it needs no credentials and
no network. npm test drives real delegates against real providers, so it costs money and only
works where pi has been logged in.
Path | What lives there |
| Every environment variable, read in one place |
| The tool allowlist and the gate that enforces it |
| Session map, id claiming, history eviction |
| One module per group of MCP tools |
| Everything that touches the pi SDK |
| State file publishing and the status line binary |
Releases are tag-driven. npm version patch && git push --follow-tags runs the build and tests,
then publishes over OIDC trusted publishing, so no npm token is stored anywhere in the repository.
Issues and pull requests are welcome. If you are reporting a delegate that misbehaved, the
toolCalls trace from status with verbose: true is the useful thing to attach.
Prior art
abatilo/pi-mcp-bridge takes the simpler route:
spawn pi --mode json -p --session-id <uuid> and let pi persist sessions on disk, so the bridge
holds no state at all. Elegant, and worth reading. It trades away steering, questions, and tool
control to get there.
License
MIT
Maintenance
Related MCP Servers
- AlicenseCqualityBmaintenanceEnables MCP hosts to delegate coding tasks to Pi CLI as a programmable sub-agent with session tracking and process management.72MIT
- AlicenseAqualityCmaintenanceEnables Claude to delegate tasks to external coding agents (Codex or Antigravity) for independent reviews, separate quota usage, and async processing.6MIT
- AlicenseNot gradedqualityBmaintenanceEnables Hermes agents to delegate bounded coding tasks to persistent oh-my-pi sessions with isolated git worktrees, live steering, and durable follow-ups, requiring explicit user confirmation before each task.AGPL 3.0
- AlicenseAqualityBmaintenanceEnables delegating asynchronous coding tasks and DAG workflows to local Oh My Pi (OMP) CLI sub-agents, with topological orchestration, path isolation, and supervised resumption.91MIT
Related MCP Connectors
Stop re-explaining yourself to Agents. Give it the right context, right when needed.
The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.
Human-as-a-Service for AI agents. Delegate tasks that need a real human, get results via API.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/howznguyen/pi-delegate-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server