ank MCP 服务器
CLI 的每个动词都是一个工具,给没有 shell 的客户端用。添加到 Claude Code 只要一行:
claude mcp add ank -- ank mcp --repo /path/to/your/repo
ank mcp 是什么
ank mcp 是那个可执行文件的一个动词,每种安装方式装的都是它。不需要再取第二个文件:CLI 分发什么,服务器就提供什么,因为它们是同一个二进制。
它通过 stdio 说 JSON-RPC,由客户端来启动。所以你不用启动它,而是配置它:一条命令、它的参数,以及它代表的仓库。
配置客户端
三个客户端里的配置项是同一段 JSON,只是放的文件不同。
{
"mcpServers": {
"ank": {
"command": "ank",
"args": ["mcp", "--repo", "/path/to/your/repo"]
}
}
}放在哪里
- Claude Code
- 仓库根目录下的
.mcp.json,这种形式会随工作树一起走,所有 clone 的人都能用上。或者用上面那行claude mcp add,它会替你写好配置项。 - Claude Desktop
claude_desktop_config.json,macOS 上在~/Library/Application Support/Claude/,Windows 上在%APPDATA%\Claude\。- Cursor
- 仓库旁边的
.cursor/mcp.json,或者用~/.cursor/mcp.json一次覆盖所有项目。
命令是 ank,mcp 是第一个参数
0.6.0 及以前的版本会额外安装一个名为 ank-mcp 的可执行文件。现在任何安装方式都不再提供它,所以还在用它的配置会得到 command not found。只需要改这一行。
一定要写 --repo
客户端会在它恰好所在的目录里启动服务器,没有 --repo 时,服务器就用那个目录。这种失败不会报错:它只是一个进程,悄悄地代表一个谁也没想要的 corpus 说话,或者什么都不代表。没有 .ank/ 的路径会在启动时被拒绝,让人能看到。
ank mcp --repo /tmp
error[1]: no .ank/ found from /tmp
-> ank init
每个动词,一个工具
这些工具由二进制分发所用的同一张表生成,ank help --json 描述的也是这张表。不是精选的子集:两个入口不可能在“有哪些东西”上不一致。
ank_contextank_claimank_showank_logank_doneank_releaseank_newank_reviewank_acceptank_readank_closeank_amendank_attestank_findank_statusank_graphank_scopeank_tuiank_mcpank_watchank_editank_checkank_migrateank_archiveank_configank_initank_skillsank_updateank_help
命名为 ank_<verb>
光叫
context会和客户端加载的其他服务器撞名。摘要变成工具描述,flag 变成输入 schema,位置参数放在arguments里,是一个字符串数组。CLI 的回答,连同退出码
一次调用返回的就是
--json返回的文档,旁边附上exitCode。拒绝就是 CLI 的拒绝,连提示一起,作为带isError的结果返回。JSON-RPC 错误表示请求本身有误;isError表示 corpus 说了不。CLI 不会做的 claim,它也不做
每个 claim 都落在对应仓库的
refs/ank/claims/里,走同样的 compare-and-swap。服务器不替任何客户端持有什么,写入时的身份是ank-mcp/<version>,除非ANK_AGENT指定了身份。
--> {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ank_show","arguments":{"arguments":["TASK-9999"]}}}
<-- {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"error[2]: entity not found: TASK-9999\n -> ank find TASK-9999"}],"isError":true,"exitCode":2,"stderr":"error[2]: entity not found: TASK-9999\n -> ank find TASK-9999"}}
多个仓库,一个服务器
每个工具都有一个可选参数 corpus:即 ank status --json 在 "corpus" 下打印的根提交,绝不是路径。用 ank config --user corpora.<root> <path> 把每个仓库声明一次,客户端配置一个字都不用改。一个服务器可以面向多个 corpus,但绝不会合并它们的 claim。
ank_accept 和其他动词一样存在,在默认分支之外照样拒绝。批准一项决策,仍然是人的行为。
MCP 还是 CLI
两者调用的是同样的动词,返回同样的文档。按你的客户端能做什么来选。
你的智能体有 shell
用 CLI。npx skills add haksolot/ank 会给智能体装上教它这套流程的 skills,它像调用其他命令一样调用 ank。
你的客户端没有 shell
用 ank mcp。客户端会把同样的动词看作工具,每个描述里都写明了拒绝情形和退出码,所以调用之前就能知道它会拒绝什么。
在做展示 corpus 的东西?轮询 ank_status 和 ank_find。ank_context 和 ank_show 会续约 claim,ank_check 会清理过期的 ref,也就是会写入。