🐦

Public API を MCP化するとき Agent Skill 併用が良さそう with freee-mcp

に公開

freee を MCP からいろいろ操作できると便利そうという単純な思いつきで freee-mcp を作っている人です。freee-mcp は現在 MCP と Agent Skill を組み合わせた形で動作し、Claude系や Codex から freee会計並びに freee の public API が提供されているすべてのサービスを操作することができます。初期の構想では MCP だけを提供することを考えていましたが、MCP のコンテキスト圧迫の問題にぶつかり、Agent Skill と併用する形での提供でうまく動作できる様になりました。

この記事では、この構成に至った設計上の判断と背景を説明します。
https://github.com/him0/freee-mcp

Claude にリアルタイムに試算表を見てもらってレポートを作っている様子

freee-mcp がうまく動作すれば

  • freee請求書の tool を使うことで、先月と同じ請求書を発行する
  • レシートの内容で経費精算する
  • 勤怠付ける

などなど、何でもできるはず(理論的には)

MCP 単体構成で直面した問題

freee-mcp は Public API を叩くにあたり認証を行う必要があるので、MCP Server はローカルでホストする構成を取っています。またfreee の Public API は Open API の定義が公開されているので、こちらから、機械的に実装を生成することで、更新があってもほぼ自動で対応ができる構成になっています。

Open API の定義から MCP を作成するコンセプトはjanwilmake/openapi-mcp-server というプロジェクトにインスパイアを受けています。こちらは API をそれぞれ Tool にするアプローチが取られています。一方で、Open API に定義されていない Tool を追加で増やすことができないという問題点もありました。freee-mcp では認証を行うというフローがどうしても必要になってしまうので、janwilmake/openapi-mcp-server を活用するだけでは、目的を達成できませんでした。

Public API 自体を Tool にしつつ、追加の Tool を生やしたということで janwilmake/openapi-mcp-server をライブラリとして活用し Tool を作成しつつ追加の認証系の Tool を入れることで初期のバージョンは完成、MCPとして呼び出せるようになりました。

実装が一通り動いた段階で、Claude Sonnet で実際に試してみましたが、ここで大きな壁にぶつかりました。freee の API は数が非常に多く、それらをすべて Tool として公開すると、Tool 定義だけでコンテキストウィンドウを圧迫してしまいます。

Toolが多すぎる

また、コンテキストウィンドウの問題だけでなく OpenAPI 由来の情報を素直に使うと Tool 名が長くなりやすく、結果として MCP 側の命名制約に引っかかるケースも頻発しました。

さらに、実際の利用時には「この Tool は使わない」「この API だけ使いたい」といった前提条件を毎回かなり丁寧に指示する必要がありました。その調整コストを考えると、結局は人間が直接 API を叩いた方が早い、という感覚になってしまいました。

Claude に Agent Skill が登場した

freee-mcp は、実用が難しいと判断してから数カ月ほどプロジェクトを放置していました。しかし、Anthropic から Claude に Skill 機能がリリースされたことで、状況は一変しました。

https://claude.com/blog/skills

Agent Skill は、MCP におけるコンテキストの無駄遣いを根本的に解消するための仕組みとして設計されています。すべての Tool 定義を常時コンテキストに載せるのではなく、必要な情報だけを段階的に投入できる点は、freee-mcp が抱えていた問題と非常に相性が良いものでした。

この Agent Skill の登場により、freee-mcp には大きな構成変更の余地が生まれました。その結果、MCP と Agent Skill を組み合わせた形であれば、実用に耐えるレベルまで持っていける、という手応えを得ることができました。

再設計にあたっては、「API をすべて Tool として公開する」という従来の前提を捨てました。代わりに、API に関する情報は Agent Skill 側に集約し、必要になったタイミングで参照・展開する、というフローを採用しています。

この構成であれば MCP 側の Tool は最小限に留まり、Tool の数も Description の量も大幅に削減できます。実際に動かしてみると、Agent Skill によるコンテキストの逐次投入が非常にうまく噛み合い、以前問題になっていたコンテキスト不足や Tool 選択の迷いはほぼ解消されました。以下に動作のフローを示します。

具体的に定義している Tool は、HTTP Method ごとに個別に定義する形にして、削除を許可したくない場合に Delete だけオフにするといった使い方に対応できるようになっています。

ツール 説明
freee_api_get データ取得 /api/1/deals
freee_api_post 新規作成 /api/1/deals
freee_api_put 更新 /api/1/deals/123
freee_api_delete 削除 /api/1/deals/123
freee_api_patch 部分更新 /api/1/deals/123

Agent Skill の構成

Agent Skill についても初期のコンセプトを維持し、freee の OpenAPI 定義から自動的に生成する方式を採用しています。Open API の json を parse して、Markdown に書き出すという方式を取っていますが、最低限の情報しか現在は書き出していないので、改良の余地がまだある様に思います。

$ tree ./skills/freee-api-skill
./skills/freee-api-skill
├── references
│   ├── accounting-account-groups.md
│   ├── accounting-account-items.md
│   ├── accounting-approval-flow-routes.md
...
│   ├── invoice-quotations.md
│   ├── pm-users.md
│   └── troubleshooting.md
└── SKILL.md

今後の展望

動くかどうか分からない試行錯誤の状況から脱したので、vibe coding 過ぎるコードを時間を見つつ質をあげていきたいと思います。また SKILL.md の内容の整理や、よくある作業パターンを referer に追加し、Agent が成功できるタスクを増やしていきたいと思います。

何かあれば、Github Issue や X で連絡ください

https://x.com/him0net

Discussion