概要

ローカルLLMエージェント向けに構築したMCPサーバー「shelpa」を「filesystem」に再利用して作り直した。名前の変更にとどまらず、パイプライン実行エンジンの完全撤去、undo/redo・ゴミ箱・ファイル追跡機能を備えたMCPファイルシステムサーバーへの全面改修となった。

shelpaの旧設計については仮想パイプラインの設計記録サンドボックス設計と教訓を参照。本稿はその後継として生まれ変わったfilesystemの設計と実装の記録である。

shelpaが抱えていた問題

shelpaはshelpa_pipe(パイプライン実行)とshelpa_write(ダイレクト書き込み)の2つのMCPツールを提供し、許可コマンドのみを実行できるミニマルな文法を強制するサンドボックスだった。書き込み操作はすべて.shelpa/ディレクトリにミラーコピーを保存し、トレーサビリティを確保していた。

しかし、パイプライン実行というコンセプト自体がLLMとの相性に限界があった。このライブラリを「filesystem」として作り直すにあたり、名前だけでなくアーキテクチャの根本を見直すことにした。

shelpaから使える実装だけを残してプロトタイプへ

最初の作業は「shelpa」から使える実装だけを残し、構想に不足していた機能をまず動く形へ全体を構成し、仮組みを行ってプロトタイプを作ることだった。

パイプライン実行関連のモジュール(parser.rsexecutor.rstypes.rsとそのテスト群)を削除し、パス安全性検証やワークスペーススコープの制限機構など再利用できるコアだけを残した。依存クレートもregexos_pipeshell-wordsthiserrorを削除してスリム化した。

パイプラインエンジンの撤去とMCPファイルシステムAPIへの移行

最も大きな設計変更として、shelpa由来のパイプライン実行エンジンを完全に撤去し、MCP公式のfilesystemサーバー(modelcontextprotocol/serverssrc/filesystem)を参考にした標準的なファイルシステム操作ツールに置き換えた。

公式リファレンス実装はTypeScriptで書かれている。これをRustベースのMCPサーバーとして再実装しつつ、shelpaの特徴だった.filesystem/ディレクトリによるトレーサビリティを発展させ、ゴミ箱・バージョン履歴・ファイル追跡を備えた設計に拡張した。

14ツール構成

最終的なツール構成は14個になった。

基本ファイル操作

ツール機能
read_text_fileファイル読み取り。head/tailで部分読み取り対応
create_file新規作成。既存ファイルがある場合はエラー
write_file作成・上書きの両方に対応
edit_fileoldText/newTextによる検索置換。diff出力、dryRun対応
create_directory再帰的ディレクトリ作成
list_directory[FILE]/[DIR]プレフィックス付き一覧
directory_treeJSON形式の再帰ツリー(除外パターン対応)
move_file移動・リネーム。移動先既存の場合はエラー

安全な削除と復元

ツール機能
delete_fileファイルを.filesystem/.trash/に移動(永久削除しない)
list_trashゴミ箱の内容一覧
restore_fileゴミ箱から元のパスに復元
search_fileファイルの状態検索。移動・削除の追跡結果を返す

バージョン履歴(--backupモード限定)

ツール機能
undo_filenバージョン前の状態に復元
redo_fileundo後にnバージョン先に進める

書き込みを伴う操作(create_filewrite_fileedit_filemove_file)は自動的に.filesystem/への記録を実行する。move_file.filesystem/.movesにログを追記し、delete_file.filesystem/.deletesにログを残す。

デュアルモードMCPサーバー

filesystem--mcp--serverの2つの起動モードを持つ。同じMCPツールキット内のctreeやpathfinderとCLIインターフェースを統一するための設計である。

  filesystem --mcp [--root <ROOT>]    # シングルプロジェクト
filesystem --server                  # グローバルデーモン
  
観点--mcp--server
--root(起動時)任意(デフォルト: cwd)受け付けない
ツール呼び出しのroot無視必須
マルチプロジェクト不可
用途CLI / スタンドアロンagent-gatewayデーモン

--serverモードはagent-gatewayから常駐プロセスとして起動される前提で、ゲートウェイがすべてのツール呼び出しにrootを注入する。

  ServerConfig{
    Name:    "filesystem",
    Command: "filesystem",
    Args:    []string{"--server"},
    Scope:   "global",
}
  

ワイヤプロトコルは最初のメッセージから自動検出される。先頭バイトが{ならLine JSON、Content-Length:ヘッダならHTTPスタイルフレーミング(LSP互換)として処理する。

.filesystem/のヒストリモデル

.filesystem/ディレクトリはshelpa時代の単純なミラーから、構造化された履歴システムに進化した。

--backupモード時の構造

  .filesystem/
  src/
    main.rs/            # src/main.rsの履歴
      00001             # バージョン1(全文スナップショット)
      00002             # バージョン2
      .head             # 現在のバージョンポインタ
  .moves                # append-onlyのリネームログ(タブ区切り)
  .trash/
    00001               # 削除されたファイル内容
    00001.history/      # 削除されたファイルのバージョン履歴
  .deletes              # append-onlyの削除・復元ログ
  

各書き込みはdiffではなく全文スナップショットを追記する。シンプルで高速、リスクが低い。.headが現在のバージョンを追跡し、undoでデクリメント、redoでインクリメントする。undo後に新しい書き込みが発生するとredoスタックはクリアされる(一般的なエディタと同じ挙動)。

move_fileは履歴ディレクトリごと移動し.movesに追記する。delete_fileはファイルと履歴を.trash/に移動して.deletesにログを残す。ゴミ箱IDは単調増加で再利用されない。

--backupなしの場合

.moves.trash/.deletesのみを使用する。バージョンスナップショット、.head、undo/redoは無効。最小限のフットプリントで動作する。

パス安全性とサンドボックス

shelpaから引き継いだワークスペーススコープの制限は維持・強化した。

  • パスはファイルシステムアクセスなしで正規化(...を折りたたむ)
  • 絶対パスもワークスペースルート内でなければPathEscapeエラー
  • シンボリンクは起動時に解決(macOSの/tmp/private/tmpに対応)
  • シェル実行なし。コマンドインジェクションの攻撃面がない

list_directorydirectory_tree.filesystem.gitnode_modulestarget__pycache__など一般的なビルド・キャッシュディレクトリをデフォルトで除外し、ワークスペースルートの.gitignoreパターンも適用する。

エラーモデル

すべてのエラーはisError: trueのMCPツール結果として返る。

エラー種別発生条件
PathEscapeパスがワークスペースルートを逸脱
NotFoundファイル/ディレクトリが見つからない、edit_fileoldText不一致
AlreadyExistscreate_fileの対象が既存、move_file/restore_fileの移動先が既存
IoErrorファイルシステムI/Oエラー
InvalidArgument不正なパラメータ(headtailの同時指定、undoの超過など)

まとめ

この改修で達成した主要な成果を整理する。

  1. shelpaからfilesystemへの再設計 — パイプライン実行エンジンを完全撤去し、標準的なファイルシステムAPIに移行
  2. 14ツールのMCPサーバー — 基本ファイル操作8種、安全な削除/復元4種、バージョン履歴2種の構成
  3. デュアルモード--mcp(シングルプロジェクト)と--server(マルチプロジェクトデーモン)でctree・pathfinderとCLIパターンを統一
  4. .filesystem/ヒストリモデル — 全文スナップショットによるundo/redo、ゴミ箱による安全な削除、リネーム/削除の追跡ログ
  5. --backupフラグによる段階的な機能選択 — バージョン履歴が不要な場合は最小フットプリントで動作

このfilesystemを作り直した直接の動機は、agent-gatewayを自作エージェントに改良したことにある。ワーカーとして動くローカルLLMがファイルを誤って削除・破壊しても、ゴミ箱とバージョン履歴から容易に復旧・検証できる仕組みが必要だった。shelpaのワークスペーススコープとミラーリングの設計思想は、この要件にそのまま再利用できた。