はじめに / 対象と前提
Claude Code で MCP サーバーをいくつか使い始めると、次に必ずぶつかるのが「この設定、チームメンバーにどう配るか」だ。自分の手元では claude mcp add で動いていたのに、リポジトリを clone した同僚の環境では MCP ツールが一切見えない。あるいは .mcp.json をコミットしたら API キーまで一緒に push しそうになった。
この記事はそのあたりを、どこに保存されているか → どう配るか → どこでハマるか の順で整理する。
- 想定読者:Claude Code を個人で使えていて、MCP サーバーの設定をリポジトリ経由でチームに共有したい Web エンジニア
-
前提知識:MCP(Model Context Protocol、Claude に外部ツールを渡す共通規格)の概念と、
claude mcp addを一度は叩いたことがある程度 -
検証環境:macOS 15 / Claude Code 2.x 系(2026 年 10 月時点)/ Node.js 22.x。MCP サーバーのサンプルは
@modelcontextprotocol/server-filesystemと自作の stdio サーバー
TL;DR
- MCP サーバー設定には local / project / user の 3 スコープ があり、保存先ファイルが違う。チーム共有は project スコープ = リポジトリ直下の
.mcp.json一択 -
.mcp.jsonに秘密情報を直書きせず${VAR}展開 を使う。ただし 未定義かつデフォルト無し の変数があると設定ファイル全体の読み込みに失敗する - project スコープのサーバーは 初回に承認プロンプト が出る。一度「拒否」を選ぶとそのサーバーは黙って無効になり、
claude mcp reset-project-choicesを叩くまで復活しない
手順 / 動かし方
1. まず今どこに何が入っているか確認する
claude mcp list
実行結果(自分の環境):
Checking MCP server health...
filesystem: npx -y @modelcontextprotocol/server-filesystem /Users/me/work - ✓ Connected
notion: npx -y @notionhq/notion-mcp-server - ✓ Connected
ここで注目すべきは どのスコープに入っているかは list では分からない こと。個別に get で見る。
claude mcp get filesystem
filesystem:
Scope: Local config (private to you in this project)
Status: ✓ Connected
Type: stdio
Command: npx
Args: -y @modelcontextprotocol/server-filesystem /Users/me/work
Scope: Local config と出ている時点で、この設定は 同僚の環境には存在しない。
2. 3 スコープの保存先と優先順位
| スコープ | 指定方法 | 保存先 | 共有範囲 |
|---|---|---|---|
| local(既定) |
--scope local または省略 |
~/.claude.json 内の「そのプロジェクトパス」の項 |
自分のみ・そのディレクトリのみ |
| project | --scope project |
リポジトリ直下の .mcp.json
|
git に乗る=チーム全員 |
| user | --scope user |
~/.claude.json のグローバル項 |
自分のみ・全プロジェクト |
同じ名前のサーバーが複数スコープにあるときは local > project > user の順で勝つ。つまり「チームの .mcp.json にある github サーバーを、自分だけ別トークンで動かしたい」なら、同名で local に登録すれば個人側が優先される。
3. project スコープで登録して .mcp.json を生成する
claude mcp add --transport stdio --scope project filesystem \
-- npx -y @modelcontextprotocol/server-filesystem ./docs
生成された .mcp.json:
{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./docs"],
"env": {}
}
}
}
ポイントは パスを相対で書いていること。local スコープのときに /Users/me/work と絶対パスで書いていたものをそのまま project に移すと、他人の環境では存在しないパスになる。相対パスは Claude Code を起動したカレントディレクトリ基準で解決される。
4. 秘密情報は ${VAR} で外出しする
API キーが必要なサーバーはこう書く。
{
"mcpServers": {
"notion": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@notionhq/notion-mcp-server"],
"env": {
"NOTION_TOKEN": "${NOTION_TOKEN}",
"NOTION_API_VERSION": "${NOTION_API_VERSION:-2025-09-03}"
}
}
}
}
-
${VAR}:シェルの環境変数をそのまま埋め込む -
${VAR:-default}:未定義ならデフォルト値を使う
展開が効くのは command / args / env / url / headers の各フィールド。HTTP 型のリモート MCP なら "headers": {"Authorization": "Bearer ${MY_TOKEN}"} と書ける。
5. 同僚側での動作確認
clone 直後に claude を起動すると、次のプロンプトが出る。
This project contains MCP servers defined in .mcp.json.
Do you want to use them?
❯ Yes, use these servers
No, skip
ここで Yes を選び、セッション内で /mcp を打つと接続状態が一覧で出る。✓ connected になっていれば完了。
ハマりどころ
ハマりどころ 1:${VAR} が未定義だと .mcp.json 全体が読まれない
症状:.mcp.json に 3 つサーバーを書いたのに、/mcp に 1 つも出てこない。エラーも特に見えない。
原因:${NOTION_TOKEN} を書いた同僚の環境でその変数が未定義だった。Claude Code は デフォルト値のない未定義変数を含む設定ファイルをパースできない 扱いにするので、その 1 行のために ファイル全体 が無効になる。巻き添えで他のサーバーも消える。
回避策:
- 秘密情報以外の変数には必ず
${VAR:-default}でデフォルトを付ける - 秘密情報は README に「
export NOTION_TOKEN=...を.zshrcに書け」と明記する。.envファイルは読まれない(Claude Code 自身は dotenv を読まない。シェルの環境変数だけが見える) - 詰まったら
claude --debugで起動し、MCP 関連のログを確認する。パース失敗はここに出る
ハマりどころ 2:一度「No」を選ぶと、そのサーバーは黙って無効のまま
症状:初回プロンプトで間違えて「No, skip」を押した。以降 .mcp.json を直しても claude を再起動しても一切出てこない。
原因:project スコープの承認結果は プロジェクト単位で ~/.claude.json に記憶 される。拒否はそのまま永続化され、再プロンプトは出ない。
回避策:
claude mcp reset-project-choices
を叩いて次回起動時にプロンプトを出し直す。CI や共有マシンで毎回プロンプトを出したくない場合は、.claude/settings.json に明示的に書く。
{
"enableAllProjectMcpServers": true
}
逆に「この 1 つだけは使いたくない」なら disabledMcpjsonServers: ["notion"]、「この 2 つだけ許可」なら enabledMcpjsonServers: ["filesystem", "github"] と書ける。チーム用途は enabledMcpjsonServers でホワイトリストにしておくのが安全。
ハマりどころ 3:-- を忘れるとサーバー側の引数を claude が食う
症状:
claude mcp add --scope project filesystem npx -y @modelcontextprotocol/server-filesystem ./docs
と打ったら、error: unknown option '-y' で止まる。あるいは止まらずに登録されたが、起動すると npx が対話プロンプトで固まる。
原因:claude mcp add は -- より後ろをサーバーコマンドとして丸ごと扱う。-- が無いと -y を自分のオプションだと解釈する。
回避策:サーバーコマンドの前には必ず -- を置く。環境変数を渡すときの -e KEY=value と HTTP ヘッダの --header は -- の 前 に置く。
claude mcp add --transport stdio --scope project -e NOTION_TOKEN='${NOTION_TOKEN}' notion \
-- npx -y @notionhq/notion-mcp-server
シングルクォートで囲わないとその場でシェルが展開してしまい、.mcp.json に 実トークンが直書き される。commit 前に git diff .mcp.json で ${ が残っているか必ず目視すること。
背景・補足
なぜ project スコープだけ承認プロンプトが入るのか。.mcp.json は リポジトリに同梱される=第三者が書いた設定を自分のマシンで実行する ことになるため、悪意ある command が仕込まれていても自動実行されないようにしている。OSS を clone して claude を起動した瞬間に任意コマンドが走る、を防ぐための安全装置だ。
逆に local / user スコープは自分で claude mcp add した前提なのでプロンプト無しで即有効になる。この非対称性を知っていると「自分の環境では動くのに同僚で動かない」の 9 割は説明がつく。
まとめ
- チーム共有は project スコープ(
.mcp.json)、個人上書きは local スコープ。同名なら local が勝つ - 秘密情報は
${VAR}、それ以外は${VAR:-default}。未定義変数 1 つでファイル全体が無効になる - 初回承認で「No」を押したら
claude mcp reset-project-choices。チームではenabledMcpjsonServersでホワイトリスト化 -
claude mcp addは--の後ろがサーバーコマンド。-eでトークンを渡すときはシングルクォートで展開を防ぐ - 詰まったら
claude mcp get <name>でスコープ確認、claude --debugでパースエラー確認