0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【実測】freee公式MCPは `FREEE_SCOPE=read` では読み取り専用にならない──AIに会計の「書き込み」を許す前の線引き

0
Posted at

「先月の売上を教えて」とAIに聞ける。ここまでは、たぶん誰も反対しません。

では、「その請求書、作っといて」まで任せますか。

2026年、会計データにAIを直結する仕組みが一気に実用段階に入りました。日本ではfreeeが公式MCPサーバーを出し、海外では会計プラットフォームのDigitsが同じくMCPサーバーを公開しています。ところがこの2つは、設計思想が正反対です。

結論から書きます。繋ぐ前に決めるべきは「AIに何を読ませるか」ではなく、「AIに何を書かせないか」です。 そして先に言っておくと、その線はMCPクライアントのツール制限でも、OAuthのスコープ指定でも引けません。実際に検証用アプリでOAuthを通して測ったので、その結果を出します。

この記事では、freee-mcpのパッケージを読んで確認した事実、実際にトークンを取って測った権限の挙動、そして私がfreee APIへの書き込みを自動化したときに置いた安全装置を並べて、線の引き方を具体化します。

2026年に起きたこと:日本と海外で、真逆の設計が出た

まず事実の確認から。

freee-mcp(日本) Digits MCP Server(米国)
公開 2026年3月2日 2026年4月21日
形態 OSS(Apache-2.0)/npm 自社サービスの機能・全プラン無料
対象 会計・人事労務・請求書・工数管理・販売・IT管理・サイン 自社の元帳(ledger)データ
書き込み できる(POST/PUT/DELETE/PATCH) できない(読み取り専用)

Digitsは「すべてのアクセスは設計上、読み取り専用(read-only by design)」と明言し、その理由を「元帳の整合性を守るため(preserving ledger integrity)」と説明しています。機能を絞ったのではなく、絞ったこと自体を売りにしているのがポイントです。

一方のfreee-mcpは、公式プレスリリースで「チャット上で『請求書を作って』と依頼するだけで、取引先登録から請求書発行まで一連の操作を正確に完了できます」と書いています。書き込みができることが、そもそもの価値になっています。

どちらが正しいという話ではありません。責任の置き場所が違うだけです。Digitsは自社で線を引き、freeeは線引きを利用者に委ねた。だから、freeeを使う側は自分で線を引く必要があります。

freee-mcpの中身を読む:ツール単位では絞れない

ここからは、npmパッケージ freee-mcp(バージョン0.32.1/2026年7月31日公開)とREADMEを実際に読んで確認した内容です。

まず、公開されているツールの構成が特徴的です。

管理ツール(9個)
freee_authenticate / freee_auth_status / freee_clear_auth / freee_set_current_company / freee_get_current_company / freee_list_companies / freee_current_user / freee_server_info / freee_file_upload

APIツール(6個)

ツール 説明
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
freee_api_list_paths エンドポイント一覧 -

「取引を登録するツール」「請求書を作るツール」のように業務単位で並んでいるのではありません。HTTPメソッドごとの汎用ツールが6つあるだけです。APIのパス(/api/1/deals など)は、AIが呼び出すときに引数として渡します。どのAPIを叩くかは、freeeが配布するAgent Skills(会計33本・人事労務28本などのAPIリファレンス)をAIが参照して決める設計です。

この構造は、実装としては合理的です。約270本あるAPIを1本ずつツール化すると、AIに渡す道具の一覧だけでコンテキストが埋まってしまいます。

ただし、運用側から見ると重要な意味があります。

ツールを取捨選択しても、権限は絞れません。

MCPクライアント側で「このツールだけ許可する」という制御をかけたくなりますが、freee_api_post を1つ許可した時点で、そのトークンで叩けるすべてのPOST APIが射程に入ります。取引の登録も、請求書の発行も、従業員の登録も、同じ1つのツールを通ります。

つまり、線を引ける場所は実質2つしかありません。

  1. freeeアプリ側の権限設定(=発行されるトークンの権限)
  2. 事業所(company_id)の切り替え

既定スコープは read write だった

そこでスコープを確認しました。パッケージのバンドルを読むと、既定値がこう定義されています。

iw = "read write"

そして、これは環境変数 FREEE_SCOPE で上書きできる作りになっています。

scope: process.env.FREEE_SCOPE || iw

つまり、何も指定せずにローカルで起動すると、読み取りと書き込みの両方を要求するのが既定の挙動です。READMEには読み取り専用モードの記載はなく、バンドル内にも readonly に類する切り替えは見当たりませんでした(0.32.1時点)。

では FREEE_SCOPE=read にすれば、読み取り専用で繋げるのでしょうか。

実測:FREEE_SCOPE=read は効かない

検証用のfreeeアプリを別に作り、実際にOAuthを通して確かめました。結果から書きます。効きません。

計測方法はこうです。認可リクエストのスコープと、freeeアプリ側の権限設定(「データ種別 × 参照/更新」のチェック)を組み合わせて認証し、返ってきたトークンのスコープと、実際にAPIが通るかどうかを見ました。

アプリ側の権限 要求したスコープ 実際に付与されたスコープ 書き込みAPI
取引:参照+更新 read accounting:deals:read accounting:deals:write default_read 通る(404=対象が無いだけ)
取引:参照のみ read write accounting:deals:read default_read 403(アクセス権限なし)

読み取ってほしいのは1行目です。read だけを要求したのに、accounting:deals:write が付いてきました。 要求したスコープは無視され、freeeアプリ側の権限設定がそのままトークンの権限になります。

逆に2行目では、read write を要求しても書き込みは付きませんでした。エラーメッセージはこうです。

HTTP 403  このアプリケーションにはアクセス権限がないエンドポイントです

つまり、freeeの権限はこう考えるのが正しいことになります。

境界はOAuthのリクエストではなく、freeeアプリの権限設定にある。

スコープ名が accounting:deals:read / accounting:deals:write という形になっているのがヒントでした。これはアプリ管理画面の「[会計] 取引」という行と、「参照」「更新」という列に、そのまま1対1で対応しています。画面のチェックボックスがそのまま権限の実体で、FREEE_SCOPE はその外側から何かを削れる仕組みではありませんでした。

検証でハマった点:ボディが不正だと、権限チェックまで到達しない

ここは同じ検証をする人向けの注意です。

最初、書き込み権限の有無を POST /api/1/dealsわざと空のボディを送って判定しようとしました。403なら権限なし、400なら権限ありという読みです。ところが権限を参照のみに絞っても、返ってくるのは400のままでした。

HTTP 400  company_id, details, issue_date, type が指定されていません。

少なくともこのエンドポイントでは、ボディの検証が先に走ります。そこで弾かれると、権限の話まで到達しません。空ボディのPOSTでは権限の有無を判定できません(freeeの全APIがこの順序かどうかまでは確かめていません)。

判定にはボディを持たないメソッドを使います。私は「存在しないことをGETで先に確認したID」に対して DELETE を撃ちました。

  • 403 → 書き込み権限なし
  • 404 → 書き込み権限あり(権限チェックは通り、対象が無いだけ)

存在しないIDだと確認してから撃つので、権限があっても何も消えません。安全に権限だけを切り分けられます。

Remote MCPを選ぶと、この判断自体が手元に残らない

READMEが推奨しているのは、https://mcp.freee.co.jp/mcp に繋ぐRemote MCPです。ローカル設定が不要で手軽ですが、手軽な方の入り口を選ぶと、どのアプリのどの権限で繋がっているかを自分で決める余地が減ります。

権限を握るのか、手軽さを取るのか。ここが最初の分岐点になります。

一次情報:freeeに「書き込み」を自動化したとき、何を置いたか

ここからは私自身の実装の話です。

私はクラウドワークスの報酬CSVを取り込んで、freeeに収入取引として自動登録するツールをGASで作り、公開しています。売上と手数料を分けて計上し、源泉徴収も控除して、入金口座と消し込むところまでやります。つまり、AIを介さずに POST /api/1/deals を叩き続けている立場です。

🔗 コードはこちら:mamagotolab/freee-crowdworks-gas

そのとき置いた安全装置は4つでした。これはそのまま、AIに書き込みを渡すときに必要なものと同じです。

① 全件を検証してから、1件も登録しない状態で止める

// 全行を処理前にバリデーション(1件でもNGなら登録しない)
if (errors.length) throw new Error('登録を中止しました。修正してください:\n' + errors.join('\n'));

途中まで登録して失敗するのが、会計データでは一番やっかいです。10件中3件だけ入った状態は、手で片付けるしかありません。検証を全部終えてから、書き込みを始める。 コストの高い処理の前に、検証を全部済ませる原則です。

② 重複を防ぐキーを決めておく

報酬IDをキーにして、同じデータを二重に取り込まないようにしています。毎月CSVを足しても二重計上になりません。AIに任せる場合、この「同じ操作を2回やらせない」保証は、AI側ではなくデータ側に持たせる必要があります。

③ 書いた結果のIDを、必ず手元に記録する

登録が成功したら、freeeが返す取引IDをスプレッドシートに書き戻しています。これがないと、何を作ったのか後から特定できません。取り消したいときに、探すところから始まります。

④ 突き合わせて確認する仕組みを別に持つ

報酬データ・freeeの取引・入金口座の明細を突き合わせる照合レポートを作りました。書き込んだ側の記録だけを見て「登録できた」と判断しない、という話です。

ここで大事なのは、①〜④はどれも「決まった手順を必ず踏む」ことで成立しているという点です。全件を検証してから書き始める、同じキーは二度通さない、書いた結果を必ず記録する。プログラムだから守れます。

AIエージェントに同じ保証をさせるのは、現状かなり難しい。指示には書けますが、守られたかどうかを毎回確かめる手段がありません。ここが、人が書いたコードとの決定的な差です。

だから結論はこうなります。①〜④を担保できない相手には、書き込みの権限そのものを渡さない。 「気をつけて使う」ではなく、権限で物理的に閉じる。もしくは、AIには下書きの作成までを任せ、確定のAPIは人が押すコードの側に残す。freee_api_post を渡すというのは、取り消し方を決めないまま実行を許すのと同じです。

権限を変えたら、再認証するまで反映されません

freeeアプリの権限設定を変更しても、すでに持っているアクセストークンの権限は変わりません。「権限を足したのに 403 が消えない」というときは、たいてい認証をやり直していないのが原因です。freeeの公式ドキュメントにも「新しいアクセストークンの取得をもって反映となります」と書かれています。

今回の検証でも、権限のチェックを付け外しするたびに認証をやり直したところ、そのつどトークンのスコープが accounting:deals:write の有無で切り替わりました。権限設定の変更は、次に取るトークンから効くという挙動です。

これは裏を返すと安心材料でもあります。後から権限を広げても、既存のトークンが勝手に強くならない。 だから「最初は参照だけのアプリで発行して、必要になったら取り直す」という進め方が現実的に成立します。

中小事業者としての線引き(私の運用基準)

以上を踏まえた、私自身の線引きです。絶対の正解ではなく、判断の型として読んでください。

操作 扱い 理由
残高・試算表・取引一覧を読む AIに読ませる 間違えても元に戻せる。効果が一番大きいのもここ
取引・請求書の「下書きを作る」 AIに作らせ、人が確定 判断はAI、確定は人。②③の記録が要る
過去の取引の更新・削除 渡さない 取り消しが効かない。監査上も追いにくい
人事労務(従業員・給与) 権限を付けない 会計の用事のために給与の権限まで渡さない

そして、実測を踏まえた実装上の結論はこうなります。

AIに繋ぐアプリと、自分のプログラムが書き込みに使うアプリは、分けて登録する。

スコープ指定では絞れない以上、「読ませるための権限しか持っていないアプリ」を別に作るのが、いちばん確実な線引きです。私の場合、自動仕訳のGASは更新権限を持つアプリを使い、AIに繋ぐなら参照だけのアプリを別に登録します。同じ事業所でも、鍵は2本に分けられます。

判断基準は1つだけです。「間違えたとき、どうやって元に戻すか」を先に言えるか。 言えない操作は、AIにもプログラムにも渡しません。

なお、MCPの一般的なリスクとして、外部から読み込んだ文章にAIへの指示を混ぜ込む「プロンプトインジェクション」や、ツールの説明文を後から書き換える「ツールポイズニング」が知られています。対策の基本は共通で、渡す権限を最小にすること、取り消しの効かない操作には人の確認を挟むことです。会計はまさに、その「取り消しの効かない操作」が並ぶ領域です。

FAQ

Q: freee-mcpは無料で使えますか?
A: freee-mcp自体はOSS(Apache-2.0)で無料です。別途、freeeの契約プランと、利用するAIツール側の費用がかかります。

Q: FREEE_SCOPE=read を指定すれば読み取り専用になりますか?
A: なりません。実測では、read だけを要求してもアプリ側に更新権限があれば accounting:deals:write が付与され、書き込みAPIも通りました。読み取り専用にしたい場合は、freeeアプリの権限設定で「更新」のチェックを外したアプリを別に登録してください。

Q: freeeアプリの権限を絞ると、どのくらい確実に止まりますか?
A: 「取引:参照のみ」のアプリで認証したところ、書き込みAPIは HTTP 403 このアプリケーションにはアクセス権限がないエンドポイントです で拒否されました。トークン自体に更新権限が乗らないので、AI側が何を要求しても通りません。

Q: どこから始めるのが安全ですか?
A: 検証用のfreeeアプリを本番と分けて作り、参照権限だけで読み取りから始めるのが安全です。書き込みは、重複防止キー・実行結果IDの記録・照合手段が揃ってから解禁します。

おわりに

会計にAIを繋ぐ話は、これから「繋げるか」ではなく「どこで止めるか」の話になります。海外のDigitsは、その線をサービス側で引きました。freeeは、線を引く自由と責任を利用者に渡しました。

自由を渡された側がやるべきなのは、機能の比較ではなく、自分の業務での線引きです。 どの数字なら見せてよくて、どの操作は人が押すのか。

これはAI連携に限った話でもありません。私たちが外部APIに書き込む実装をするとき、結局いつも同じところに戻ってきます。「間違えたとき、どうやって元に戻すか」を先に決めてから、書き込みを実装する。 MCPは、その原則を守っているかどうかを、これまでより短い距離で試してくる仕組みだと思っています。


関連記事

筆者について
「自社の会計まわりをAIに繋ぎたいが、どこまで任せてよいか判断がつかない」「経理の流れごと整理したい」。
そうした相談に、業務の流れを整理する要件定義から、運用後の保守まで対応する開発ラボを運営しています。
👉 ママゴトラボ|業務自動化の開発ラボご依頼(クラウドワークス)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?