課題:MCP経由での反復作業が招く「ディレクトリの乱立」
本プロジェクトで採用している「記事ごとに連番ディレクトリ(34-slug/など)を自動生成して管理する」という独自の運用ルールと、MCP(Model Context Protocol)によるエージェントの操作は、そのままでは非常に相性が悪いことが判明しました。
問題は、MCPツールの呼び出しが基本的にステートレス(状態を持たない)であることに起因します。
何が起きたか
本プロジェクトでは、AIエージェントが記事を執筆・入稿するための専用ツールとして、自作のMCPツール draft_post を使用しています。このツール本来の役割は、「外部の原稿(Seedファイル)を受け取り、プロジェクト内の適切なディレクトリに連番を振って配置する」という入稿の自動化でした。
しかし、以下のような作業フローにおいて、設計上の致命的な欠陥が露呈しました。
- 初回入稿: エージェントが
/path/to/seed.mdを作成し、draft_postでプロジェクト(例:2026-01)へ送信。 → サーバーは34-slug/article.mdを新規作成する。 - 修正指示: 人間が「タイトルを少し変えて」と指示。
- 修正・再送: エージェントは手元の
/path/to/seed.mdを編集し、再度修正版をdraft_postで送信する。
このとき、ツール側はリクエストが来るたびに「これは新しい入稿だ」と愚直に判断し、新しい連番を一つずつ増やして配置してしまいます。その結果、修正を重ねるほどリポジトリ内には実体のない「枝番」のようなディレクトリが乱立し、管理が即座に破綻してしまったのです。
/34-mcp-article/article.md(初稿)/35-mcp-article/article.md(1回目の修正)/36-mcp-article/article.md(2回目の修正)
これはAIの習性の問題ではなく、「連番というステートフルな管理体系」に対して、「一回限りの命令として設計されたツール」をぶつけたことによる設計の不整合です。
解決策:外部ファイルを「永続的な種(Seed)」として定義する
この不整合を解消するため、我々は外部にある原稿ファイルを、単なる一時的なデータではなく「プロジェクト内記事のアイデンティティを決定する種(Seed)」として再定義しました。
具体的には、送信元ファイル(外部ファイル)の絶対パスから一意な source_id を生成し、記事のFrontmatterに永続化させる仕組みを導入しました。
「パスをハッシュ化する」ことの意味
なぜ内容のハッシュではなく「パスのハッシュ」なのか。ここが設計の肝です。
- 執筆中の「場所」は変わらない: AIエージェントは、人間からの修正指示を受けるたびに、手元の原稿ファイル(例:
seed.md)に対して編集操作を行い、その最新状態をツールに渡します。 - 場所をIdentityにする: 内容がどれだけ書き換わっても、「その場所にあるファイル」である限り、ハッシュ(
source_id)は不変です。 - 不変の紐付け: プロジェクト側に一度この ID を書き込んでしまえば、外の世界(編集中の原稿)と中の世界(リポジトリの記事)の間に、堅牢な架け橋が架かります。
Upsertによる自動同期のフロー
サーバー側は、ツールが呼ばれるたびに以下の「紐付け確認」を自動で行います。
- パスの特定: ツールに渡された原稿パス(
FILE:path/to/seed.md)から絶対パスを取得。 - Identity計算: その絶対パスをハッシュ化して
source_idを算出。 - リポジトリスキャン:
projects/下の既存記事から、同じIDを持つ Frontmatter を探す。 - 自動的な振る舞いの切り替え:
- IDが見つかった: 「これは以前この
seed.mdから作られた記事の更新だ」と判断し、既存ディレクトリを上書き。 - IDが見つからない: 「これは新しい種(Seed)による新規記事だ」と判断し、新しい連番を発行。
- IDが見つかった: 「これは以前この
設計の教訓:ステートレスな命令を、場所の不変性でステートフルに繋ぐ
エージェントが「今これが新規か更新か」という状態を意識しなくても、サーバー側が「呼び出し元の場所」を見ることで、暗黙的に状態を復元(Upsert化)できます。 この「場所の不変性(Path as Identity)」を活用した設計によって、リポジトリの美しさを保ちつつ、エージェントには自由な執筆・修正環境を提供することが可能になりました。
まとめ
MCPを介したローカルリポジトリ操作において、ツールの冪等性は単なる「便利機能」ではなく、プロジェクトの整合性を保つための「必須要件」です。
source_id という単純な Identity 管理を挟むだけで、ステートフルなディレクトリ管理とステートレスなMCPツール呼び出しは、見事に調和させることができます。