おはようございます。まさきんです。
家族用のチャットボットから、買い物リストに書き込めない問題がありました。裏で動かしている claude -p が、MCPツールを必ず拒否していたんです。原因と直し方を、公式ドキュメントで確かめながらメモしておきます。
※記事公開時点の情報です。最新の条件は公式サイトでご確認ください。
claude -pの無人実行では、確認が必要な操作は拒否されます--permission-mode acceptEditsが通すのは、ファイル編集と一部のファイル操作コマンドです- MCPツールは
--allowedToolsかpermissions.allowで明示すると通ります - 書式は
mcp__<サーバー名>__<ツール名>で、サーバー単位の指定もできます - 僕は Notion の検索・取得・クエリ・作成・更新の5操作だけを許可しました
買い物リストに書けなかった
我が家には、家族で使うメッセージアプリのボットがあります。自作のもので、裏では claude -p を呼んでいます。Claude Code をヘッドレスで動かす形ですね。
このボットに、買い物リストの読み書きをさせようとしました。買い物リストは Notion のデータベースです。家族が「これ買っておいて」と送ると、ボットがリストに足す。そんな使い方を考えていました。
ところが、何度やっても書き込めませんでした。Notion のツールを呼ぶたびに、必ず拒否されます。手元の対話セッションでは動くのに、ボット経由だけが通りません。
原因は許可が無かったこと
結論はシンプルでした。ボットが呼ぶ claude -p に、Notion コネクタの許可が無かったんです。
ボットは --permission-mode acceptEdits で動いています。ファイルの編集は自動で通る設定です。なので「ある程度は任せている」つもりでいました。ただ、MCPツールはその範囲に入っていませんでした。
僕の環境では、無人実行のMCPツールは必ず拒否されました。--allowedTools で明示するまで、ずっとです。ここが今回の出発点です。
無人実行では答える人がいない
仕組みを整理しておきます。Claude Code は、操作の前に許可を確認することがあります。対話セッションなら、画面に確認が出て人が答えます。
-p を付けた実行は、非対話モードです。公式ドキュメントでは「Run Claude Code programmatically」というページで説明されています。確認に答える相手を用意していない -p 実行では、確認が必要な操作は拒否されると書かれています。
つまり「聞かれて止まる」のではなく「聞かれずに断られる」わけですね。ボットの裏側では、この違いがそのまま「必ず拒否」という見え方になります。仕組みがわかると、なるほどという感じでした。
権限モードの比較
次に、権限モードです。公式の「Choose a permission mode」には、確認なしで実行できる範囲がモードごとに載っています。
| モード | 確認なしで実行できるもの | 公式が挙げる用途 |
|---|---|---|
| default | 読み取りのみ | すべての操作を自分で確かめる作業 |
| acceptEdits | 読み取り・ファイル編集・一部のファイル操作コマンド | コードを確認しながら進める作業 |
| plan | 読み取り中心(編集は承認が必要) | 変更前の調査 |
| auto | 分類器が操作を審査して判断 | 長い作業 |
| dontAsk | 読み取りと事前に許可したツールのみ | 絞り込んだCIやスクリプト |
| bypassPermissions | ほぼすべて | 隔離されたコンテナやVMのみ |
default は、画面上では Manual という名前で表示されます。設定値としては default のままです。
モードは土台です。その上に、許可ルールと拒否ルールを重ねる形になっています。公式には、拒否ルールは bypassPermissions を含むどのモードでも効くと書かれています。
acceptEdits が通す範囲
acceptEdits が自動で通すのは、作業ディレクトリ内のファイル編集です。加えて mkdir や mv といったファイル操作のコマンドも通ります。
一方で、それ以外のシェルコマンドやネットワークへのアクセスは対象外です。公式には、--allowedTools か permissions.allow のルールが必要だと書かれています。自動承認の一覧に、MCPツールは入っていません。
acceptEdits は「編集を任せるモード」であって「外部サービスの操作を任せるモード」ではない。そう読むのが自然かなと思います。
bypassPermissions が効かなかった
実は、設定ファイルには bypassPermissions を書いていました。場所は ~/.claude/settings.json です。なので「全部通るはず」と思い込んでいたんです。ただ、ボットでは効きませんでした。
理由は公式に書かれていました。開始時のモードは、最初に当てはまるものが使われます。
--permission-modeフラグ(または--dangerously-skip-permissions)- 設定ファイルの
permissions.defaultMode
CLIリファレンスにも同じことが書かれています。--permission-mode は、設定ファイルの defaultMode を上書きします。ボットは --permission-mode acceptEdits を付けて起動しています。なので、設定ファイルの bypassPermissions は使われなかったわけです。
フラグと設定ファイルの関係は、モード以外では細かく確かめていません。ここは僕の環境での事実に留めておきます。
MCPツール名の書き方
許可ルールに書くMCPツールの名前には、決まった形があります。公式の「Configure permissions」に載っている書式は次のとおりです。
| 書き方 | 対象 |
|---|---|
mcp__puppeteer | puppeteer サーバーのすべてのツール |
mcp__puppeteer__* | 同じく、サーバーのすべてのツール(ワイルドカード) |
mcp__puppeteer__puppeteer_navigate | puppeteer サーバーの puppeteer_navigate だけ |
mcp__github__get_* | github サーバーの get_ で始まるツール |
サーバー単位でも、ツール単位でも指定できます。ただ、許可ルールのワイルドカードには条件があります。mcp__<サーバー名>__ のあとにしか使えません。mcp__* のようにサーバー名までぼかした許可は、警告つきで無視されると書かれています。
もう一つ注意したいのは、コネクタの名前です。Claude Code が自分で取得するコネクタのツールは、少し形が違います。mcp__claude_ai_<サーバー名>__<ツール名> になるとされています。実際の名前を確かめてから書くのが安全です。
—allowedTools で明示する
直し方は、使うツールを --allowedTools で並べるだけでした。公式では「確認なしで実行するツール」を指定するフラグと説明されています。
形はこうなります。サーバー名とツール名は例示です。実際の名前は環境で違うので、置き換えてください。
claude -p "買い物リストに牛乳を足して" \
--permission-mode acceptEdits \
--allowedTools \
"mcp__notion__search" \
"mcp__notion__fetch" \
"mcp__notion__query" \
"mcp__notion__create_pages" \
"mcp__notion__update_page"
僕の場合、この許可リストはボットのコードの中に持たせています。ボットが claude -p を呼ぶたびに、同じリストを渡す形です。
設定ファイルに書く方法もあります。settings.json の permissions.allow に同じ書式で並べます。
{
"permissions": {
"allow": ["mcp__notion__search", "mcp__notion__fetch"],
"deny": ["mcp__notion__delete_page"]
}
}
こちらもツール名は例示です。どちらに置くかは好みかもしれません。僕は「このボットが何をできるか」をコードで読めるほうが安心なので、コード側にしました。
許可した5操作
サーバーごと許可すれば、設定は1行で済みます。ただ、僕はそうしませんでした。許可したのは 5操作 だけです。
| 操作 | 許可 | 買い物リストでの用途 |
|---|---|---|
| 検索 | した | リストや品目を探す |
| 取得 | した | ページの中身を読む |
| クエリ | した | データベースを条件で絞る |
| 作成 | した | 新しい品目を足す |
| 更新 | した | 「次回買う」などの状態を変える |
| 削除 | していない | 使わない |
| 上の5つ以外の操作 | していない | 使わない |
買い物リストの読み書きは、この5つで足ります。削除は入れていません。品目を消したいときは、状態を更新すれば済むからです。
許可を入れたあと、ボットは動くようになりました。家族からリクエストされた品を、買い物リストの「次回買う」に入れて報告できています。
道具に渡す権限を使う分だけに絞る感覚は、固定費の見直しに近いと感じています。スマホ代も、使っている分に合わせると無駄が見えやすいですね。
許可を最小限に絞る考え方
なぜ絞るのか。理由は、ボットの入力が僕だけのものではないからです。
家族が自由に文章を送ってきます。言い間違いもありますし、意図と違う解釈をされることもあります。そのとき、削除まで許可していると取り返しがつきません。作成と更新だけなら、間違えても直せます。
考え方を並べると、次のようになります。
- まず「読む操作」と「書く操作」に分ける
- 書く操作は「足す・変える」と「消す」に分ける
- 消す操作は、必要になるまで入れない
- サーバー単位の許可は、ツールが増えたときに範囲も広がると意識する
公式には、ルールの評価順も書かれています。順番は deny(拒否)、ask(確認)、allow(許可)です。最初に当たったものが結果になります。なので、絶対に使わせたくないツールは deny に書くのが確実です。--disallowedTools にツール名をそのまま書く方法もあります。そのツールは Claude から見えなくなるとされています。
秘密情報の扱いでも、同じ「形だけで安心しない」感覚が大事でした。そちらはgitleaksで見逃した2件の記事に書いています。
dontAsk という選択肢
公式ドキュメントを読んでいて、もう一つ気になるモードがありました。dontAsk です。
dontAsk は、確認が必要な操作をすべて拒否するモードです。通るのは、読み取りと事前に許可したものだけ。公式でも、許可リストを厳密に決めたCI向けとして例が載っています。
claude -p "run the test suite" --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read"
僕のボットは、いまのところ acceptEdits のままです。ファイル編集も任せたい場面があるからです。ただ、外部サービスの操作だけなら dontAsk のほうが合うのかもしれません。
なお、権限モードを指定しない -p 実行は注意が必要です。開始モードが環境やバージョンで変わります。公式にも、使いたいモードを明示するよう書かれています。
設定の手順
これから同じことをする場合の流れです。
- ボットにさせたい操作を、言葉で書き出す
- その操作に必要なMCPツールを選ぶ
- 実際のツール名を
mcp__<サーバー名>__<ツール名>の形で確かめる --allowedToolsかpermissions.allowに並べる- 使わせたくないツールがあれば deny に書く
claude -pで実際に呼び、拒否が出ないか見る- 許可リストは、操作が増えたときだけ足す
ツール名と拒否の確かめ方
ツール名は、推測で書くと当たりません。公式には system/init というイベントが紹介されています。--output-format stream-json の最初に出るものです。ここにモデルやツール、MCPサーバーの情報が入ります。
拒否も同じ出力で追えます。拒否は permission_denied というシステムメッセージで出ます。最後の結果メッセージにも permission_denials として一覧が載るとされています。ボットのログにこれを残しておくと、原因探しが早くなりそうです。
よくある失敗
- acceptEdits にすれば、MCPツールも通ると思い込む
- 設定ファイルの bypassPermissions が、フラグより強いと思い込む
- ツール名を推測で書き、実際の名前と合っていない
mcp__*のような広い許可を書き、無視されていることに気づかない- 面倒になって、サーバーごと全部を許可する
- 無人実行で bypassPermissions を使い、何でも通る状態にする
上の2つは、まさに僕がやったことです。モードの名前から受ける印象と、実際に通る範囲は少し違いました。
bypassPermissions については、公式が強く注意しています。隔離されたコンテナやVMでの利用が前提とされています。家族の入力がそのまま届くボットには、ちょっと合わないと思います。
始める前に確認すること
- ボットがどの権限モードで起動しているか
- 起動フラグと設定ファイルのどちらでモードが決まっているか
- 使わせたい操作を言葉で書き出したか
- MCPツールの実際の名前を確かめたか
- 削除など取り返しのつかない操作を外したか
- 拒否されたツールをログで追えるか
- 許可リストの置き場所を1か所に決めたか
よくある質問
Q. claude -p でMCPツールが拒否されるのはなぜですか?
-p は非対話の実行です。確認に答える相手を用意していない場合、確認が必要な操作は拒否されると公式に書かれています。僕の環境では、MCPツールを明示して許可するまで必ず拒否されました。
Q. acceptEdits にすればMCPツールも通りますか?
通りませんでした。公式の説明では、acceptEdits が自動で通すのはファイル編集と一部のファイル操作コマンドです。それ以外は --allowedTools か permissions.allow が必要とされています。
Q. settings.json に bypassPermissions を書いたのに効きません。
起動時に --permission-mode を付けていないか確かめてください。公式には、このフラグが設定ファイルの defaultMode を上書きすると書かれています。僕のボットも、ここで引っかかりました。
Q. サーバー単位でまとめて許可できますか?
できます。mcp__<サーバー名> か mcp__<サーバー名>__* と書くと、そのサーバーの全ツールが対象です。ただ、削除なども含まれます。僕は必要な操作だけを個別に書きました。
Q. —allowedTools と —tools は何が違いますか?
--allowedTools は、確認なしで実行するツールの指定です。--tools は、使える組み込みツールを絞るフラグです。公式には、--tools はMCPツールに影響しないと書かれています。
Q. 許可ルールを書いても通らないことはありますか?
あるようです。組織が ask に設定したコネクタのツールには、許可ルールが効かないと公式に書かれています。ユーザーの操作が必須とされたMCPツールも同じです。dontAsk モードでは、これらは拒否されます。
Q. —bare を付けるとどうなりますか?
--bare は、MCPサーバーなどの自動読み込みを省くモードです。公式には、MCPサーバーは --mcp-config で渡したものだけが接続されるとあります。認証も APIキーなどが前提になるので、付ける前に確かめたほうがよさそうです。
Q. 確認に答える人がいないと明示する方法はありますか?
公式には --permission-prompts none というフラグが載っています。確認が必要な操作を拒否し、Claude に再試行しないよう伝えるものです。v2.1.259 以降が必要とされています。僕はまだ使っていません。
参考にした公式情報
- Run Claude Code programmatically(Claude Code Docs)
- Choose a permission mode(Claude Code Docs)
- Configure permissions(Claude Code Docs)
- CLI reference(Claude Code Docs)
- All settings(Claude Code Docs)
- Configure permissions - Agent SDK(Claude Code Docs)
まとめ
claude -p でMCPツールが拒否されたのは、許可が無かったからでした。acceptEdits はファイル編集のためのモードです。外部サービスの操作は、別に明示する必要がありました。
許可は、使う操作だけに絞るのがよさそうです。僕は5操作から始めました。自作ボットを続けるかどうかの見合いは、Claude Max の使用率の記事で整理しています。通知からAIに相談する仕組みは、Claudeに投げるボタンの記事にも書いています。ボットが動かないときは、まず起動フラグを眺めてみてください。
本記事にはアフィリエイト広告を含みます。当サイトのリンクを経由して商品・サービスへお申し込みいただいた場合、提携先企業から成果報酬を受け取ることがあります。 また、運営者は楽天グループに所属する社員であり、紹介プログラムを通じた報酬を受け取る場合があります。記事内容・評価は広告の有無にかかわらず、運営者の実体験と調査に基づき作成していますが、 上記の関係性をご理解のうえお読みください。詳しくは免責事項・アフィリエイト表記をご覧ください。
楽天モバイルの通信エリア・電波状況について気になることがある方は、公式の電波改善・調査依頼フォームからご相談いただけます。