ank MCP サーバー

CLI のすべての動詞をツールとして。シェルを持たないクライアントのために。Claude Code への追加は 1 行です:

claude mcp add ank -- ank mcp --repo /path/to/your/repo

ank mcp とは

ank mcp は、どのインストール方法でも置かれるひとつの実行ファイルの動詞です。別のファイルを取ってくる必要はありません。CLI がディスパッチするものが、そのままサーバーが提供するものです。同じバイナリだからです。

stdio 上で JSON-RPC を話し、クライアントがそれを起動します。つまり起動するのではなく、設定するものです。コマンド、その引数、そしてどのリポジトリを代弁するか。

クライアントを設定する

エントリは 3 つのクライアントすべてで同じ JSON です。変わるのは置くファイルだけです。

.mcp.json · エントリ
{
  "mcpServers": {
    "ank": {
      "command": "ank",
      "args": ["mcp", "--repo", "/path/to/your/repo"]
    }
  }
}

置き場所

Claude Code
リポジトリのルートにある .mcp.json。ツリーと一緒に移動し、clone した全員に届く形です。あるいは上の claude mcp add の 1 行で、エントリを書いてもらえます。
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 という 2 つ目の実行ファイルを置いていました。今はどのインストール方法も置かないので、まだそれを指している設定は command not found になります。変えるべきはその 1 行です。

--repo は必ず書く

クライアントはたまたまいるディレクトリでサーバーを起動し、--repo がなければサーバーはそのディレクトリを使います。この失敗はエラーになりません。誰も意図していない corpus を、あるいは何も代弁していないプロセスが、黙って動き続けるだけです。.ank/ のないパスは起動時に拒否され、人の目に届きます。

ank mcp
ank mcp --repo /tmp
error[1]: no .ank/ found from /tmp
  -> ank init

動詞ひとつに、ツールひとつ

ツールは、バイナリがディスパッチに使い、ank help --json が記述するのと同じテーブルから生成されます。選び抜いたサブセットではありません。2 つの入口が、何が存在するかで食い違うことはありえません。

  • ank_context
  • ank_claim
  • ank_show
  • ank_log
  • ank_done
  • ank_release
  • ank_new
  • ank_review
  • ank_accept
  • ank_read
  • ank_close
  • ank_amend
  • ank_attest
  • ank_find
  • ank_status
  • ank_graph
  • ank_scope
  • ank_tui
  • ank_mcp
  • ank_watch
  • ank_edit
  • ank_check
  • ank_migrate
  • ank_archive
  • ank_config
  • ank_init
  • ank_skills
  • ank_update
  • ank_help
  • ank_<verb> という名前

    ただの context では、クライアントが読み込んでいる他のサーバーと衝突します。要約が説明に、フラグが入力スキーマになり、位置引数は文字列の配列 arguments として渡ります。

  • CLI の答えを、終了コードごと

    呼び出しは --json が返すドキュメントを、隣に exitCode を添えて返します。拒否は CLI の拒否そのもので、ヒントも含めて isError 付きの結果として返ります。JSON-RPC のエラーはリクエストが間違っていたこと、isError は corpus がノーと言ったことを意味します。

  • CLI が取らない claim は取らない

    claim はすべて、そのリポジトリの refs/ank/claims/ に同じ compare-and-swap で入ります。サーバーはクライアントの代わりに何も保持せず、ANK_AGENT が指定されていなければ ank-mcp/<version> として書き込みます。

corpus が拒否した呼び出し
--> {"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 か

どちらも同じ動詞に届き、同じドキュメントを返します。クライアントに何ができるかで選んでください。

エージェントにシェルがある

CLI を使います。npx skills add haksolot/ank でループを教える skills をエージェントに渡せば、他のコマンドと同じように ank を呼びます。

クライアントにシェルがない

ank mcp を使います。クライアントには同じ動詞がツールとして見え、各説明に拒否条件と終了コードが書かれているので、呼ぶ前に何が拒否されるかを読めます。

corpus を表示するものを作るなら、ポーリングするのは ank_status と ank_find です。ank_context と ank_show は claim を更新し、ank_check は古い ref を刈り込む、つまり書き込みます。

ank をインストール

コマンドは二つ。Linux、macOS、Windows に対応し、git 2.34 以降が必要です。

npm install -g @haksolot/ank
npx skills add haksolot/ank