🤑

freee を CLI から操作するツールと Agent Skill を作り、トークン効率を75%改善した

に公開

こんにちは、@yamitzkyです。

freee が公式に公開している MCP サーバーと Agent Skill freee/freee-mcp を fork して、freee CLIと、それを使う Agent Skill という構成に再構築したものを公開しました。

https://github.com/yamitzky/freee-cli

念の為記載しますが、あくまで非公式なフォークです。

使い方

freee CLI 単独でも、エージェントスキル経由でも使えます。

たとえば稟議申請一覧を取得する場合、

npx @yamitzky/freee accounting get approval_requests

# または
npm install -g @yamitzky/freee
freee accounting get approval_requests

Agent Skill 経由で、Claudeなどから取得する場合は、

npx skills add yamitzky/freee-cli

claude
# freeeの最新の稟議一覧を取得して

Why not freee MCP?

freee からは、公式の MCP(Model Context Protocol)サーバーと、それに対応する Agent Skill が公開されています。会計・人事労務・請求書・工数管理・販売の 5 つの API に対応しており、Claude などから freee の操作ができるようになっています。このような取り組みをオフィシャルに公開している点が非常に素晴らしいと思います。

https://github.com/freee/freee-mcp

ただ、以下3つの観点で、現状の MCP + Agent Skills というオフィシャルな設計に課題を感じています。いずれも、個別個別に見れば解決策はあるかもしれませんが...

トークン効率が悪い可能性

MCP サーバーは、ツール定義(ツール名・パラメータスキーマ)をエージェントのコンテキストに公開します。ツール定義だけでかなりのトークンを消費します。さらに、API レスポンスは JSON がそのままエージェントに返るため、大量のフィールドを含む freee API のレスポンスはコンテキストウィンドウを圧迫します。

権限設定の柔軟さの不足

Claude Code では、外部ツールの実行を permission wildcards で制御できます。たとえば以下の設定のように、特定パターンのコマンドだけを許可できます。

{
  "permissions": {
    "allow": [
      "Bash(find:*)"
    ]
  }
}

しかし現状の freee-mcp の場合、以下の7つのツールにまとめられています。

ツール名 HTTPメソッド 必須パラメータ オプションパラメータ 説明
freee_api_get GET service, path query データ取得
freee_api_post POST service, path, body query データ作成
freee_api_put PUT service, path, body query データ更新
freee_api_delete DELETE service, path query データ削除
freee_api_patch PATCH service, path, body query データ部分更新
freee_api_list_paths - なし なし エンドポイント一覧表示
freee_file_upload POST file_path description, partner_name, issue_date, amount, qualified_invoice, document_type ファイルボックスにアップロード

そのため、「経費精算はAIが自動でやっていいけど、支払い依頼はダメ」といったような権限指定ができないのではと思います

ツールとしてのポータビリティ不足

MCP は、Claude Code のような AI が使うには使いやすい仕組みです。

ですが、シェルスクリプトから使いたい、AI 以外で自動化・定期タスクにしたい、といったモチベーションがある場合には使いづらい仕組みで、結局 API を直接扱う必要が出てきてしまいます。認証の仕組みの理解も必要になってしまいます。

CLI + Agent Skill という選択肢

おそらくは似たような課題感だと思いますが、最近では CLI + スキルという構成で作られたAgent Skills が出てきています。

例えば Notion からは元々 MCP が公開されていましたが、記事執筆の5日前に makenotion/skills が公開されました。これは ntn という CLI と、87行程度の SKILL.md という構成です。

記事執筆の17日前に公開された、Google Workspace の公式 CLI googleworkspace/cli も(こちらは細かく SKILL.md が別れていますが) 似たような構成です。

今回作った、yamitzky/freee-cli も似たような構成になっています。

  • Skill(SKILL.md): CLI の使い方を51行の SKILL.md で記述。エージェントのコンテキストに最小限の情報だけを注入する
  • CLI(freee コマンド): 実際の API 呼び出しは CLI 経由で行う。--help, --spec で API 仕様をオンデマンドで取得できる

この設計の肝は、API スキーマ全体をエージェントのコンテキストに載せないことです。必要な情報は CLI の自己文書化コマンドでその都度取得する。これにより初期コンテキストが軽くなり、トークン消費を大幅に削減できます。

実装のポイント

コマンド体系と権限制御

コマンド体系を freee <service> <method> <path> に設計しました。これは ntn CLIgogcli を参考にしました。

freee accounting get deals          # 取引一覧を取得
freee accounting post deals key=val # 取引を作成
freee hr get employees              # 従業員一覧を取得

service は accounting, hr, invoice, pm, sm の 5 つに対応しています。

この設計により、Claude Code の permission wildcards で細かい制御が可能になります:

freee accounting get:*    → 会計の参照系を自動許可
freee accounting post:*   → 会計の作成系は都度確認
freee hr:*                → 人事労務系はすべて都度確認

コンパクト出力

MCP では API レスポンスの JSON がそのままエージェントに渡されますが、CLI ではコンパクトなテーブル形式(TSV)に変換して出力します。

# MCP(JSON そのまま)
{"deals": [{"id": 1, "company_id": 12345, "issue_date": "2025-01-15", "type": "income", "ref_number": "", "status": "settled", ...(数十フィールド)}, ...]}

# CLI(テーブル出力)
id    issue_date  type    amount   partner
1     2025-01-15  income  100000   株式会社A
2     2025-01-20  expense 50000    株式会社B

これにより、同じ情報を得るのに消費するトークン数が減ることが期待できます。必要に応じて --json フラグで生の JSON を取得することもできます。

セルフドキュメント

CLI 自身が API ドキュメントを持っているため、エージェントは必要に応じて仕様を確認できます。

freee accounting ls                 # エンドポイント一覧
freee accounting ls deals           # キーワードで絞り込み
freee accounting get deals --help   # コンパクトな CLI のヘルプ
freee accounting get deals --spec   # 生の OpenAPI フラグメント

エージェントは最初にすべての API 仕様を読み込む必要はなく、必要なエンドポイントの仕様だけをその都度取得できます。

例えば ls コマンドでは、以下のように絞り込んだコマンド一覧が出力されます。

❯ freee accounting ls deal
RESOURCE                          OPERATIONS
deals                             get(取引(収入・支出)取得) | post(取引(収入・支出)の作成)
deals/{id}                        get(取引(収入・支出)の取得) | put(取引(収入・支出)の更新) | delete(取引(収入・支出)の削除)
deals/{id}/payments               post(取引(収入・支出)の支払行の作成)
deals/{id}/payments/{payment_id}  put(取引(収入・支出)の支払行の更新) | delete(取引(収入・支出)の支払行の削除)
deals/{id}/renews                 post(取引(収入・支出)の+更新の作成)
deals/{id}/renews/{renew_id}      put(取引(収入・支出)の+更新の更新) | delete(取引(収入・支出)の+更新の削除)

--help をつけると OpenAPI の定義を元にして、以下のように出力されます。元となった OpenAPI にはレスポンスのスキーマもありますが、AI にはいらないのではという判断から削っています。

❯ freee accounting get deals --help
freee accounting get deals
取引(収入・支出)一覧の取得

使い方:
  freee accounting get deals
  freee accounting get deals partner_id==... account_item_id==...

パラメータ:
  company_id                事業所ID(デフォルト: 現在の事業所)
  partner_id                取引先IDで絞込
  account_item_id           勘定科目IDで絞込
  partner_code              取引先コードで絞込
  status                    決済状況で絞込 (未決済: unsettled, 完了: settled)
  type                      収支区分 (収入: income, 支出: expense)
  start_issue_date          発生日で絞込:開始日(yyyy-mm-dd)
  end_issue_date            発生日で絞込:終了日(yyyy-mm-dd)
  start_due_date            支払期日で絞込:開始日(yyyy-mm-dd)
  end_due_date              支払期日で絞込:終了日(yyyy-mm-dd)
  start_renew_date          +更新日で絞込:開始日(yyyy-mm-dd)
  end_renew_date            +更新日で絞込:終了日(yyyy-mm-dd)
  offset                    取得レコードのオフセット (デフォルト: 0)
  limit                     取得レコードの件数 (デフォルト: 20, 最大: 100)
  accruals                  取引の債権債務行の表示(without: 表示しない(デフォルト), with: 表示する)

トークン消費の比較

同じ操作「(会社のメールアドレス)が2026年3月に提出した支払い依頼一覧を出して」という指示、MCP 版と CLI 版で実行し、Claude Code のセッショントークン消費を比較しました。

MCP 版 CLI 版
トークン消費 38,137 27,500
削減率 - -27.9%

約 28% のトークン削減が確認できました。「1+1は?」と聞くだけでも23,930 tokensは消費されるので(必ず消費されるトークン数)、そこと比較すると、75%ほどのトークン削減になっています。

とはいえ、より現実的/実践的なシナリオ(〜で稟議申請して、など)で検証できているわけではありません。

なぜ差が出るのか

MCP 版のツール呼び出し(6ステップ)は、

  1. Skill ロード
  2. freee_get_current_company(MCP ツール)で事業所取得
  3. references ディレクトリを検索
  4. accounting-payment-requests.md を80行読み込み
  5. freee_api_get で users 取得 → JSON 全量(約20フィールド x 34人)
  6. freee_api_get で payment_requests 取得 → JSON 全量(約20フィールド x 6件)

CLI 版のツール呼び出し(4ステップ)は、

  1. Skill ロード
  2. freee accounting docs payment_requests → コンパクトなパラメータ一覧
  3. freee accounting get users → テーブル出力(6フィールド x 10件 + 残件数)
  4. freee accounting get payment_requests ... → テーブル出力(6フィールド x 6件)

でした。主な差分のポイントとしては、

  • references ファイルの読み込みが不要(CLI の docs コマンドで代替)
  • company_id の自動注入により freee_get_current_company が不要
  • レスポンスがコンパクトテーブル形式(トップレベルのスカラーフィールドのみ、デフォルト10件)
  • MCP のツール定義スキーマがコンテキストに載らない

などが上げられます。SKILL.md 内での指示の違いなどもあるため、必ずしもアーキテクチャの差分(MCP+Skill→CLI+Skill)とは言えないことに注意してください。あくまで簡易的な検証をしているに過ぎないです。

ライセンスについて

今回作ったリポジトリに関しては、

freee K.K. による freee/freee-mcp のコードが含まれており、当該コードは Apache License 2.0 に基づいて提供されています。法令上許容される限りにおいて、私がこのフォークに加えた独自の変更および追加部分については、著作権が発生するとは考えておらず、CC0 1.0 に基づき、著作権その他の関連する権利を放棄します。

という記載をしています。

https://github.com/yamitzky/freee-cli

これは「freee-mcpおよびAPI仕様書の貢献がソースコードの大部分を占めており、それをCLI化した程度の私の変更については、私は著作権があるとも考えていないし、それを主張もしない」ということです。API利用規約に従って正しく使ってください。

現状と今後の展望

今のところは、稟議一覧の取得や、稟議申請など、一部のユースケースしか検証していません。そもそも、私が業務で使っていない freee 会計以外はテストしてすらいないです。

とはいえ、あまり長期的にメンテしたいと考えてはいません。非公式なツールであるということは、利用者にとってもリスクがあると感じることでしょう。

今回作った CLI+Agent Skills 構成が合理的なものであれば、freee-mcp 本体で対応してくれたらいいな...

Discussion