pi-exec-mcp
README.md
# pi-exec-mcp
An MCP server that runs [pi](https://github.com/badlogic/pi-mono) coding-agent tasks in the
background. An assistant dispatches a task, polls its status, reads the result, and cancels
it if it is no longer needed — without pulling the delegate's context into its own.
This is a small, self-contained server. It contains **no network code of its own**: the
delegate's model calls happen inside pi, using the provider, model, and key you have already
configured in pi. There is no relay, no bundled endpoint, and no telemetry.
- [English](#english)
- [中文](#中文)
---
## English
### Tools
| Tool | Purpose |
|------|---------|
| `dispatch_task` | Start a task in the background. Returns a `taskId` immediately. |
| `get_status` | Poll `state`, `turns`, the tool trace, and the latest text. |
| `get_result` | Read the final answer once the state is terminal. |
| `cancel_task` | Stop a running task. Partial output stays readable. |
A task moves through `starting → running → done | aborted | error`. Judge liveness by
`state` and `turns`, never by how much text has arrived: a reasoning model can be silent for
a long time while it is still working.
### Requirements
- Node.js `>= 22.19.0`.
- `pi` installed and authenticated by **you**, so it has a provider, a model, and a key in
its own configuration. This server reads that configuration; it never supplies credentials.
- A working directory for each task that is an absolute path and is neither `/` nor your
home directory.
### Install
**Cursor plugin.** Clone or install this repository as a plugin and the bundled
[`mcp.json`](./mcp.json) runs the server out of the plugin folder itself:
```json
{
"mcpServers": {
"pi-exec": {
"type": "stdio",
"command": "node",
"args": ["${CURSOR_PLUGIN_ROOT}/dist/index.js"]
}
}
}
```
`${CURSOR_PLUGIN_ROOT}` is the folder the plugin was installed into. No `npm install` and no
`npx` are involved: `dist/` is committed with every dependency bundled into it, so the only
thing the plugin needs is the Node.js from the requirements above (`>= 22.19.0`).
`dist/` is generated by `npm run build` — `tsc` for the type declarations, esbuild for the
self-contained server — so rebuild it after touching `src/`.
**npm.** Not published yet, so there is nothing to install today. Once it is, the same server
is available as:
```sh
npm install -g pi-exec-mcp
```
### Configure your MCP client
Any stdio client works: point it at the `dist/index.js` in the plugin folder as above, or at
the published package once there is one. Set any environment variables below in the server's
`env` block, not in a shell profile: MCP hosts often launch servers with a stripped
environment.
### Environment variables
| Variable | Default | Purpose |
|----------|---------|---------|
| `PI_EXEC_ALLOWED_MODELS` | *(empty)* | Comma-separated allowlist of `provider/modelId` refs. A trailing `/*` allows every model of a provider, e.g. `provider/*`. Empty means no extra restriction. |
| `PI_EXEC_MIN_FREE_MB` | `0` (off) | Refuse to start a task when `/proc/meminfo` reports less than this much `MemAvailable`. Platforms without `/proc/meminfo` are never blocked. |
| `PI_EXEC_MAX_CONCURRENCY` | `2` | Maximum number of tasks running at once. Further dispatches are refused until one finishes or is cancelled. |
| `PI_EXEC_MODEL` | pi's own default | Model used when a task omits `model`. |
| `PI_EXEC_ALLOW_TOOLS` | *(empty)* | Extra tools this server may grant, comma-separated. |
| `PI_EXEC_ALLOW_WRITE` | `0` | `1` permits **any** tool, including shell and writes. Dangerous; see safety notes. |
| `PI_EXEC_IGNORE_SCOPE` | `0` | `1` ignores pi's `enabledModels` scope. |
| `PI_EXEC_STRICT_SCOPE` | `0` | `1` honours `enabledModels` exactly, without the custom-provider exception. |
| `PI_EXEC_HISTORY` | `50` | Finished tasks kept for review; oldest are evicted first. |
| `PI_EXEC_TRACE_ARGS` | `400` | Tool arguments are clipped to this many characters in the trace. |
| `PI_EXEC_TRACE_RESULT` | `600` | Tool results are clipped to this many characters in the trace. |
| `PI_EXEC_STATE_DIR` | `~/.local/state/pi-exec-mcp` | Where the optional status line reads live state. |
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | Where pi keeps its own configuration. Read, never written by this server. |
### Safety notes
- **This is not a sandbox.** pi has no permission system. A delegate granted `bash` can do
anything the user running this server can do. The default tool set is read-only
(`read`, `grep`, `find`, `ls`), and anything wider is opt-in per task or via
`PI_EXEC_ALLOW_TOOLS` / `PI_EXEC_ALLOW_WRITE`.
- **The working directory is enforced.** Each task must name an absolute, existing directory
that is not `/` and not the home directory. Relative paths are refused rather than resolved
against the server's own working directory.
- **Credential paths are blocked.** A guard installed on every session refuses tool calls that
target `.env*` files, `.ssh`, `.aws`, `.gnupg`, `.docker`, `.kube`, `auth.json`, and similar
locations, including through symlinks.
- **No secrets are stored or relayed.** The provider, model, and key come from your pi
configuration. This server adds no endpoints, no proxy, and no telemetry.
- **Resource limits are advisory guards, not guarantees.** The memory floor and concurrency
ceiling prevent obvious overcommitment; they do not make a task safe to run.
### Attribution
This project is based on and derived from two MIT-licensed works:
- [`howznguyen/pi-delegate-mcp`](https://github.com/howznguyen/pi-delegate-mcp) — the base
server, worker, and tool architecture.
- [`Nyarlathoteppppp/pi-durabletask-mcp`](https://github.com/Nyarlathoteppppp/pi-durabletask-mcp) —
the working-directory and credential-path guards (`src/workspace.ts`, `src/secrets.ts`).
Both are used and redistributed under the MIT License. See [`LICENSE`](./LICENSE) for the
original copyright notices.
### License
MIT. See [`LICENSE`](./LICENSE).
---
## 中文
一个 MCP 服务器,把 [pi](https://github.com/badlogic/pi-mono) 编码智能体的任务放到后台运行。
助手可以派发任务、轮询状态、读取结果,并在不再需要时取消它,而不会把被委派者的上下文
带进自己的对话。
这是一个小巧、自包含的服务器。它**自身没有任何网络代码**:被委派者的模型调用发生在 pi
内部,使用你已经在 pi 里配置好的服务商、模型和密钥。没有中转,没有内置端点,也没有遥测。
### 工具
| 工具 | 用途 |
|------|------|
| `dispatch_task` | 在后台启动任务,立即返回 `taskId`。 |
| `get_status` | 轮询 `state`、`turns`、工具调用轨迹和最新文本。 |
| `get_result` | 状态终止后读取最终答案。 |
| `cancel_task` | 停止正在运行的任务,部分输出仍可读取。 |
任务的状态流转为 `starting → running → done | aborted | error`。判断存活要看 `state` 和
`turns`,**不要**看已经产出多少文本:推理模型可能长时间没有输出,但它仍在工作。
### 环境要求
- Node.js `>= 22.19.0`。
- **你**已经安装并登录 `pi`,它自己的配置里已有服务商、模型和密钥。本服务器只读取该
配置,绝不提供凭据。
- 每个任务的工作目录必须是绝对路径,且不能是 `/`,也不能是主目录。
### 安装
**Cursor 插件。** 把本仓库作为插件克隆或安装后,仓库自带的 [`mcp.json`](./mcp.json) 会直接
在插件目录里启动本服务器:
```json
{
"mcpServers": {
"pi-exec": {
"type": "stdio",
"command": "node",
"args": ["${CURSOR_PLUGIN_ROOT}/dist/index.js"]
}
}
}
```
`${CURSOR_PLUGIN_ROOT}` 是插件被安装到的目录。全程不需要 `npm install`,也不需要 `npx`:
`dist/` 已随仓库提交,并且把全部依赖都打包了进去,插件唯一需要的就是上面「环境要求」中的
Node.js(`>= 22.19.0`)。
`dist/` 由 `npm run build` 生成 —— `tsc` 产出类型声明,esbuild 产出自包含的服务器 —— 修改
`src/` 后请重新构建。
**npm。** 目前尚未发布到 npm,因此暂时无可安装的内容。发布之后,同一个服务器也可以这样运行:
```sh
npm install -g pi-exec-mcp
```
### 配置 MCP 客户端
任何 stdio 客户端都可以:像上面那样指向插件目录里的 `dist/index.js`;等 npm 发布后也可以
指向 npm 包。下面这些环境变量请写在服务器的 `env` 块里,而不是 shell 配置里:MCP 宿主启动
服务器时常常会清空环境变量。
### 环境变量
| 变量 | 默认值 | 作用 |
|------|--------|------|
| `PI_EXEC_ALLOWED_MODELS` | *(空)* | 逗号分隔的 `provider/modelId` 白名单。以 `/*` 结尾表示允许该服务商的全部模型,例如 `provider/*`。为空表示不做额外限制。 |
| `PI_EXEC_MIN_FREE_MB` | `0`(关闭) | 当 `/proc/meminfo` 的 `MemAvailable` 低于该值时拒绝启动任务。没有 `/proc/meminfo` 的平台不会被拦截。 |
| `PI_EXEC_MAX_CONCURRENCY` | `2` | 同时运行的最大任务数。达到上限后新的派发会被拒绝,直到有任务结束或被取消。 |
| `PI_EXEC_MODEL` | pi 自身默认值 | 任务未指定 `model` 时使用的模型。 |
| `PI_EXEC_ALLOW_TOOLS` | *(空)* | 允许本服务器授予的额外工具,逗号分隔。 |
| `PI_EXEC_ALLOW_WRITE` | `0` | 设为 `1` 允许**任意**工具,包括 shell 和写操作。危险,见安全说明。 |
| `PI_EXEC_IGNORE_SCOPE` | `0` | 设为 `1` 忽略 pi 的 `enabledModels` 范围限制。 |
| `PI_EXEC_STRICT_SCOPE` | `0` | 设为 `1` 严格遵循 `enabledModels`,不再对自定义服务商例外。 |
| `PI_EXEC_HISTORY` | `50` | 保留以供查看的已完成任务数;超出时先淘汰最旧的。 |
| `PI_EXEC_TRACE_ARGS` | `400` | 轨迹中工具参数截断的字符数。 |
| `PI_EXEC_TRACE_RESULT` | `600` | 轨迹中工具结果截断的字符数。 |
| `PI_EXEC_STATE_DIR` | `~/.local/state/pi-exec-mcp` | 可选状态栏读取实时状态的目录。 |
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | pi 自身配置所在目录。本服务器只读,不写。 |
### 安全说明
- **这不是沙箱。** pi 没有权限系统。被授予 `bash` 的任务能做运行本服务器的用户能做的
任何事。默认工具集是只读的(`read`、`grep`、`find`、`ls`),更宽的权限需要按任务显式
开启,或通过 `PI_EXEC_ALLOW_TOOLS` / `PI_EXEC_ALLOW_WRITE` 打开。
- **强制校验工作目录。** 每个任务必须指定一个绝对且存在的目录,且不能是 `/`,也不能是
主目录。相对路径会被直接拒绝,而不会回退到服务器自身的工作目录。
- **凭据路径被拦截。** 每个会话都会安装一个守卫,拒绝访问 `.env*` 文件、`.ssh`、`.aws`、
`.gnupg`、`.docker`、`.kube`、`auth.json` 等位置,包括通过符号链接的访问。
- **不保存、不中转任何密钥。** 服务商、模型和密钥都来自你的 pi 配置。本服务器不新增任何
端点、代理或遥测。
- **资源限制是提示性护栏,不是保证。** 内存下限和并发上限能避免明显的资源超用,但不会让
任务本身变得安全。
### 致谢
本项目基于以下两个 MIT 许可的作品衍生而来:
- [`howznguyen/pi-delegate-mcp`](https://github.com/howznguyen/pi-delegate-mcp) —— 基础
服务器、worker 与工具架构。
- [`Nyarlathoteppppp/pi-durabletask-mcp`](https://github.com/Nyarlathoteppppp/pi-durabletask-mcp) ——
工作目录守卫与凭据路径守卫(`src/workspace.ts`、`src/secrets.ts`)。
二者均在 MIT 许可下使用与再分发。原始版权声明见 [`LICENSE`](./LICENSE)。
### 许可证
MIT,见 [`LICENSE`](./LICENSE)。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues