The ank MCP server
Every verb of the CLI as a tool, for a client that has no shell. One line to add it to Claude Code:
claude mcp add ank -- ank mcp --repo /path/to/your/repo
What ank mcp is
ank mcp is a verb of the one executable every install route places. There is no second file to fetch: what the CLI dispatches is what the server serves, because they are the same binary.
It speaks JSON-RPC over stdio, and the client spawns it. So you do not start it, you configure it: a command, its arguments, and the repository it speaks for.
Configure a client
The entry is the same JSON in all three clients. Only the file it goes in changes.
{
"mcpServers": {
"ank": {
"command": "ank",
"args": ["mcp", "--repo", "/path/to/your/repo"]
}
}
}Where it goes
- Claude Code
.mcp.jsonat the root of the repository, the form that travels with the tree and reaches everyone who clones it. Or the one-lineclaude mcp addabove, which writes the entry for you.- Claude Desktop
claude_desktop_config.json, in~/Library/Application Support/Claude/on macOS and%APPDATA%\Claude\on Windows.- Cursor
.cursor/mcp.jsonbeside the repository, or~/.cursor/mcp.jsonfor every project at once.
The command is ank, and mcp its first argument
Releases up to 0.6.0 placed a second executable named ank-mcp. No route places it any more, so a configuration still naming it gets command not found. That is the one line to change.
Always write --repo
A client spawns the server in whatever directory it happens to be in, and without --repo the server takes that directory. The failure is not an error: it is a process quietly speaking for a corpus nobody meant, or for none. A path with no .ank/ under it is refused at startup, where a person sees it.
ank mcp --repo /tmp
error[1]: no .ank/ found from /tmp
-> ank init
Every verb, one tool each
The tools are generated from the same table the binary dispatches from and ank help --json describes. Not a curated subset: the two surfaces cannot disagree about what exists.
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
Named ank_<verb>
A bare
contextwould collide with every other server a client has loaded. The summary becomes the description, the flags become the input schema, and positionals arrive asarguments, an array of strings.The CLI’s answer, exit code included
A call returns the document
--jsonreturns, withexitCodebeside it. A refusal is the CLI’s refusal, hint and all, returned as a result withisError. A JSON-RPC error means the request was wrong;isErrormeans the corpus said no.No claim the CLI would not take
Every claim lands in
refs/ank/claims/of that repository, under the same compare-and-swap. The server holds nothing on a client’s behalf and writes asank-mcp/<version>unlessANK_AGENTnames an identity.
--> {"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"}}
Several repositories, one server
Every tool takes an optional corpus argument: the root commit ank status --json prints under "corpus", never a path. Declare each repository once with ank config --user corpora.<root> <path> and the client configuration does not change by a character. One server may address several corpora; it never merges their claims.
ank_accept is there like every other verb, and still refuses off the default branch. Ratifying a decision stays a human act.
MCP or the CLI
Both reach the same verbs and return the same documents. Pick by what your client can do.
Your agent has a shell
Use the CLI. npx skills add haksolot/ank gives the agent the skills that teach it the loop, and it calls ank like any other command.
Your client has no shell
Use ank mcp. The client sees the same verbs as tools, with the refusals and exit codes written into each description, so it can read what a call will refuse before making it.
Building something that shows a corpus? Poll ank_status and ank_find. ank_context and ank_show renew a claim, and ank_check prunes stale refs, so it writes.
Install ank
Two commands. Linux, macOS and Windows, with git 2.34 or newer.
npm install -g @haksolot/ank
npx skills add haksolot/ank