Filesystem MCPサーバーの使い方 — 読み書きできるディレクトリを絞る権限設計
Filesystem MCPサーバーの導入手順と、アクセス可能なディレクトリを決める2つの方式(コマンドライン引数とMCP Roots)の違いを扱います。Claude Codeでの権限設計の判断基準も示します。
Filesystem MCPサーバーは、指定したディレクトリだけに読み書きを絞ってファイル操作をツール化する公式MCPサーバーです。Claude Codeにはファイルを読み書きするネイティブなツールがもともとあります。そのため、まず気になるのは「なぜ別のMCPサーバーが要るのか」でしょう。
この記事では、導入から動作確認までを手元のClaude Code(v2.1.287)で試した出力つきで示します。そのうえで、許可ディレクトリを決める2つの方式がClaude Codeでは実際にどう効くかと、ツール単位で権限を分ける設定を扱います。
MCPプロトコル自体の仕組みはMCPとはが対応します。権限ルールの一般的な書き方はMCPセキュリティガイドにあります。
Filesystem MCPサーバーとは
npmで@modelcontextprotocol/server-filesystemとして公開されているNode.js製の公式MCPサーバーです。Model Context Protocolの公式リポジトリmodelcontextprotocol/serversに含まれるリファレンス実装の1つです。ファイルの読み書き・ディレクトリの作成や一覧・移動・検索・メタデータ取得を、ツールとして提供します。
設計の中心は、アクセスを許可するディレクトリの制御です。操作はすべて許可ディレクトリの範囲内に制限されます。許可ディレクトリが1つも無いと、サーバーは動作しません。
用意されているツール
ツールは13種類です。READMEは各ツールにMCPのToolAnnotationsを設定しており、右の列はその区分です。
| ツール | できること | 区分 |
|---|---|---|
read_text_file | できることUTF-8テキストとして読む(head / tailで先頭・末尾N行のみ指定可) | 区分読み取り専用 |
read_media_file | できること画像・音声などをBase64で返す | 区分読み取り専用 |
read_multiple_files | できること複数ファイルを一括で読む(一部失敗しても他は続行) | 区分読み取り専用 |
list_directory / list_directory_with_sizes | できること一覧。後者はサイズと件数の集計つき | 区分読み取り専用 |
directory_tree | できることディレクトリ構造をJSONツリーで返す | 区分読み取り専用 |
search_files | できることグロブ形式のパターンで再帰検索 | 区分読み取り専用 |
get_file_info | できることサイズ・作成日時・更新日時・権限などのメタデータ | 区分読み取り専用 |
list_allowed_directories | できること現在の許可ディレクトリの一覧 | 区分読み取り専用 |
create_directory | できることディレクトリ作成(既存なら何もしない) | 区分書き込み(べき等) |
write_file | できること新規作成・上書き | 区分書き込み(べき等・破壊的) |
edit_file | できることパターンマッチによる部分編集。dryRunで適用前にdiffを確認できる | 区分書き込み(破壊的) |
move_file | できること移動・リネーム。移動先が存在すると失敗する | 区分書き込み(破壊的) |
全ツールがopenWorldHint: falseで、READMEの説明では許可ディレクトリの外の世界には出ない設計です。
使い分けで引っかかりやすい点がいくつかあります。read_text_fileは拡張子に関係なくUTF-8のテキストとして読み、headとtailは同時に指定できません。画像や音声はread_media_fileを使い、画像・音声以外のファイルは埋め込みリソースとして返ります。move_fileは移動先にすでにファイルがあると失敗するので、上書きしたいときは別の手順が要ります。write_fileは既存ファイルを確認なしで上書きします。READMEも取り扱いに注意するよう書いています。
導入から動作確認まで
追加するコマンドは1本です。許可ディレクトリを引数で渡すか、省略してRootsに任せるかで、次の節の挙動が分かれます。
Claude Codeに追加して使えるようにする
- 1
サーバーを追加する
claude mcp addで追加します。チームで共有するなら--scope projectを付けると、プロジェクト直下の.mcp.jsonに書き込まれます。 - 2
承認する
.mcp.jsonのサーバーは、承認するまで接続されません。claude mcp getはPending approvalと表示し、claudeを起動して承認するよう案内します。 - 3
許可範囲を確かめる
セッション内でClaudeに
list_allowed_directoriesを呼ばせ、想定したディレクトリだけが返るかを見ます。ここが食い違っていたら、次の節の挙動が原因です。
v2.1.287の作業ディレクトリで実際に実行すると、次のように返りました(ここではサーバーを起動せず、設定の書き込みと状態表示だけを確かめています)。
claude mcp add --scope project filesystem -- npx -y @modelcontextprotocol/server-filesystem .
claude mcp get filesystemaddは次の行を表示し(続けて書き込んだファイルのパスも出ます)、.mcp.jsonに下の内容を書きました。
Added stdio MCP server filesystem with command: npx -y @modelcontextprotocol/server-filesystem . to project config{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
"env": {}
}
}
}.は絶対パスに展開されず、書いたとおりに保存されます。claude mcp get filesystemの表示は次のとおりです(主要な行のみ)。
filesystem:
Scope: Project config (shared via .mcp.json)
Status: ⏸ Pending approval (run `claude` to approve)
Type: stdio
Command: npx
Args: -y @modelcontextprotocol/server-filesystem .同じ名前でもう一度addすると、MCP server filesystem already exists in .mcp.jsonで止まります。上書きしたいときは、先にclaude mcp remove filesystem -s projectで消します。
--scopeを省くと、既定はlocalです。自分だけが使う設定なら、こちらで足ります。
Windowsでは、READMEの設定例がnpxをcmd /c経由で起動しています。.mcp.jsonに書くなら、commandをcmd、argsの先頭を/cとnpxにします。パスにプロジェクトのルートを使いたいときは、${CLAUDE_PROJECT_DIR:-.}のように既定値を付けて書きます。CLAUDE_PROJECT_DIRは、作業ディレクトリを途中で足し引きしても変わらないプロジェクトの根を指します。
許可ディレクトリを決める2つの方式
アクセスを許可するディレクトリは、コマンドライン引数かMCP Rootsで決まります。READMEは後者を推奨しています。
引数で渡す方式と、Rootsで任せる方式
コマンドライン引数
サーバー起動時に渡したパスが、そのまま初期の許可リストになります。変えるにはサーバーの再起動が要ります。Rootsに対応しないクライアントでは、この値が最後まで使われます。
MCP Roots
クライアントがroots/listで返したディレクトリに置き換わります。notifications/roots/list_changedを受けるたびに、サーバーは許可リストを入れ替えます。
引数を省略するとサーバーは空の許可リストで起動します。接続時にクライアントへroots/listを要求し、返ってきた一覧を許可リストにします。省略する場合のコマンドは次のとおりです。
claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystemなお、RootsはMCP仕様2026-07-28で非推奨に指定されました。非推奨の期間中も機能は動きます。経緯はMCP Roots非推奨にあります。
Claude Codeでは引数がRootsに置き換わる
READMEは、Rootsが届くとサーバー側の許可ディレクトリを完全に置き換えると書いています。Claude Codeはroots/listに、セッションの起動ディレクトリを返します。加えて、--add-dir・/add-dir・additionalDirectoriesで追加した全ディレクトリも返します。追加や削除があればnotifications/roots/list_changedも送ります。
この2点を合わせると、Claude Codeでは引数で渡した別パスが、接続後に作業ディレクトリ側の一覧へ入れ替わると読めます。/path/to/shared-dataのようなパスを渡しても同じです。v2.1.203より前も起動ディレクトリだけは返していたため、入れ替わり自体は版に依存しません。v2.1.203で変わったのは、追加ディレクトリが含まれ、変更が通知されるようになった点です。ただし、この置き換えをClaude Codeの実機で確かめたわけではありません。サーバーを起動するとパッケージの取得が走るため、今回は設定の書き込みと状態表示までに留めています。意図した範囲を保証したいときは、接続後にlist_allowed_directoriesの結果を直接見てください。
引数もRootsも無い状態では、サーバーは初期化時にエラーで停止します。READMEは、許可ディレクトリが少なくとも1つ必要だと定めています。
作業ディレクトリと別の境界は引数だけでは作れない
Rootsの置き換えが効くなら、Claude Codeの作業ディレクトリと切り離した固定境界を、引数だけで作るのは難しいことになります。その用途が必要な場合は、サーバーの外側で絞る方法を検討することになります。たとえばREADMEにはDockerで/projectsにマウントし、読み取り専用のroを付ける構成の例があります。ただしRootsとの組み合わせでどうなるかは、READMEからは読み取れません。
一方、作業ディレクトリに追随させる使い方は、引数なしの方式でそのまま成立します。/add-dirでディレクトリを足せば、MCPサーバー側の許可範囲も同じ一覧に揃います。ネイティブツールとMCPツールの届く範囲を一致させたい運用では、この追随が目的そのものです。
このサーバーが役に立つ場面
単に「Claude Codeでファイルを読み書きしたい」だけなら、ネイティブツールで足ります。追加する価値が出る場面は次の2つです。
導入を検討する場面
ツール単位で許可を分けたい
権限ルールを
mcp__filesystem__write_fileのようにツール名で書けます。読み取り系だけ自動許可し、書き込み系は確認に回す構成が、ネイティブのWriteとは独立に作れます。ファイル操作を持たないクライアントと揃えたい
内蔵のファイル操作ツールを持たないMCPクライアントと併用するなら、同じツール名で同じ操作を呼べます。
ツール単位で権限を分ける設定
MCPツールの権限ルールはmcp__<サーバー名>__<ツール名>の形で書きます。サーバー名filesystemで追加したなら、mcp__filesystem__write_fileが書き込みツール、mcp__filesystem__*が全ツールを指します。Allowルールのワイルドカードは、mcp__<サーバー名>__の接頭辞を固定した形でだけ有効です。mcp__*のような接頭辞なしの許可ルールは、警告つきで無視されます。
先のツール表の区分をそのまま写すと、次のような構成になります。
{
"permissions": {
"allow": [
"mcp__filesystem__read_text_file",
"mcp__filesystem__list_directory",
"mcp__filesystem__search_files",
"mcp__filesystem__list_allowed_directories"
],
"ask": [
"mcp__filesystem__write_file",
"mcp__filesystem__edit_file",
"mcp__filesystem__move_file"
]
}
}注意点が2つあります。まず、括弧つきのmcp__ルール(mcp__filesystem__write_file(path:...)のような引数指定)は、設定ファイルでは読み込み時にスキップされます。パスで絞りたいときは、許可ディレクトリの側で絞ります。引数指定のdenyルールは、起動時に--disallowedToolsで渡す方法もあります。
次に、ReadとEditのdenyルールの適用先は、組み込みのファイルツールと、catやsedなど認識されたBashコマンドです。MCPのファイル操作ツールは、その対象として挙がっていません。Edit(./secrets/**)をdenyに入れていても、Filesystem MCPサーバーが同じパスを許可していれば別系統で届くことがあります。禁止したい場所があるなら、mcp__filesystem__*側のルールか、許可ディレクトリ自体からも外します。権限ルール全般の書き方はMCPセキュリティガイドに詳しくあります。
大きなディレクトリを扱うときの下見
list_directory_with_sizesは、ファイル数の多いディレクトリを扱う前の下見に向いています。sortByで名前順かサイズ順を選べ、合計サイズ・ファイル数・ディレクトリ数の集計が一度で返ります。全体をdirectory_treeで読み込むより、返ってくる量を抑えやすい操作です。
ログディレクトリや生成物の置き場のように、中身の量が読めない場所を最初に触るときは、list_directoryより先にこちらを呼ぶと見通しが立ちます。directory_treeにもexcludePatternsがあるので、node_modulesのような重い場所を外せます。
データベース接続用のMCPサーバーと組み合わせる構成もあります。読み取り専用のデータベース接続と並べ、抽出したレポートをファイルに書き出す使い方です。接続側はMCPからデータベースに接続する方法を参照してください。この場合は、許可ディレクトリを出力先だけに絞り、データベース側とは別の権限として設計します。
つまずいたときの切り分け
許可範囲が想定と違うとき
意図した範囲の外が見えている、あるいは想定より狭いときは、まずlist_allowed_directoriesで現在の許可リストを見ます。引数とRootsのどちらが効いているかで結果が変わるため、原因の切り分けに直結します。引数で渡した別パスが見当たらなければ、「Claude Codeでは引数がRootsに置き換わる」で触れた置き換えを疑います。
初期化エラーで止まるとき
引数を省略したのにサーバーが初期化エラーで止まるときは、クライアントがRootsに対応していないか、空のroots応答を返しています。Claude Codeで起きたときは、claude mcp get <名前>で接続状態を見ます。接続できていれば、list_allowed_directoriesの結果を確認します。なお、v2.1.203より前は/add-dirで足したディレクトリが反映されない、という形で差が出ます。
edit_fileは先にdryRunで確認する
edit_fileはパターンマッチで複数箇所を同時に書き換えられます。そのぶん、意図しない箇所まで一致することがあります。READMEは、先にdryRun: trueでdiffを確認する運用をベストプラクティスとしています。askで確認を挟む構成でも、dryRunは別の防御として残せます。
まとめ
Claude Codeの標準のファイル操作で足りるなら、このサーバーは要りません。入れるなら、Claude Codeでは許可範囲がRootsで決まる前提で、開くディレクトリを先に決めます。追加する理由がツール単位の権限分けなら、mcp__filesystem__write_fileなどのルールを先に決めておきます。ローカルファイルを扱う他のMCPサーバーの選定はおすすめMCPサーバー10選も参考になります。スコープの扱いはClaude Code MCP設定ガイドが詳しく扱っています。