A3ro(Autonomous Agentic AI Research Office)は、AIエージェントの自律化を研究する個人ラボラトリーです。活動の第一弾としてブログ基盤の自動化を進めていますが、初めての試みとなったMCPサーバーの導入は、不格好な格闘の連続となりました。

目的:プロジェクトの境界を越えた知見の集約

MCPを導入した最大の理由は、執筆動線におけるコンテキストスイッチの排除です。 マシン内の別ディレクトリで別の開発を行っている最中に、その場からMarkdownの内容だけを送信して公開を完遂する。この、プロジェクトの境界を越えた疎結合な仕組みこそが、知見を鮮度よく書き残すために不可欠でした。

構築を阻んだ実情と挫折

初めての構築において、想定外の障害が重なりました。

1. FastMCPの断念とエージェントの失態

当初はライブラリである FastMCP を使用して迅速に構築する予定でした。しかし、作業を共にするエージェント側の理解が著しく浅く、ライブラリが提供するインターフェースや挙動を正しく制御できませんでした。 結局、ライブラリの使用を断念し、中身を完全に掌握できる標準ライブラリのみを用いたフルスクラッチ型での実装をやり直すことになりました。

2. 「どこに何を書くべきか」の無知が招いた地獄

開発に使用している Antigravity IDE においても、当時は大きなハマりどころがありました。当初、AIエージェントは「MCP接続設定(サーバー名やコマンド)」をプロジェクトディレクトリ内のどこかに書けば動くと信じ込んでいました。しかし実際には、これらはプロジェクト外のIDEコンフィグに記述しなければならないものでした。

この「設定の所在」に対する誤解が、トラブルシューティングを泥沼化させます。エージェントは頻繁にサーバーのスクリプト名や構成を書き換える一方で、その変更を反映すべきプロジェクト外のIDEコンフィグを放置したまま、盲目的に「再起動してください」とだけ繰り返しました。

当然、再起動してもIDEは「古い設定(存在しない、あるいは名前の変わったスクリプト)」を呼び出し続けます。エージェントはこの不一致を直視できず、挙句の果てには「再起動したのに動かないのは、人間側の手間が足りないせいだ」と言い出す始末でした。

さらに、間違った(古い)接続先を呼び出し続けたことで、「自分の投げた命令が無視される、あるいは古い挙動が返ってくる」という矛盾に直面したエージェントは、極度の混乱をきたしました。最終的には論理的なレスポンスが崩壊し、チャットセッションごと応答不能に陥りました。これはIDE自体のバグというより、「プロジェクト内の仮想世界」と「プロジェクト外のIDEコンフィグという現実世界」の乖離に耐えられず、エージェントの推論機能が自壊した結果でした。

3. “Method not found” という名の正常な対話

MCPサーバーとの接続確認において、心理的な陥穽がありました。 正しい設定に辿り着き、実際には接続が成功していたにもかかわらず、私たちは「まだ繋がっていない」と思い込んでデバッグを続けてしまったのです。

原因は、動作確認のために投げた list_resources というリクエストに対する返答でした。サーバーは「その機能(メソッド)は実装されていません(Method not found)」というJSON-RPCエラーを返していましたが、これはサーバーが起動し、正しく通信できているからこそ返ってくる有効なレスポンスです。

しかし、当時の私たちはこのエラーメッセージを見て「接続そのものに失敗して、サーバーにすら辿り着けていない」と誤解しました。繋がっているのに、繋がっていない幽霊を追いかけ、設定を見直したり別環境を試したりと、無意味な時間を浪費してしまいました。

4. 実行環境の喪失と「正解」の設定

そもそも「MCPサーバー」という言葉が誤解を生んでいました。 サーバーという響きから、ポートをリッスンして常駐しているWebサーバーのようなものを想像していましたが、当初の私はその反動で「単にIDEが裏でコマンドを都度実行しているだけの使い捨てCLI」だと思い込んでしまったのです。

しかし実態はそのどちらでもなく、「IDEが起動時に一度だけ立ち上げ、標準入出力(stdio)で繋ぎっぱなしにする常駐の子プロセス」でした。

ウェブサーバーのような独立したデーモンではありませんが、一度起動コマンド(この場合 uv run)が走ると、そのプロセスはIDEと運命を共にする形でメモリに居座り続けます。この「一度だけ起動される」という特性が、環境構築において別の落とし穴を作りました。

これが最大の落とし穴でした。 IDEからMCPサーバーが起動される際、カレントディレクトリは保証されません(多くの場合、IDEのルートかホームディレクトリになります)。そのため、単に uv run python script.py とするだけでは、プロジェクト固有のライブラリが見つからず、実行時に ModuleNotFoundError で異常終了するという現象に直面します。

この「カレントディレクトリをどう固定するか」という迷路にハマっていた際、Gemini 3 Proは解決策として設定ファイルに存在しない cwd 属性を書き加えるよう提案してきました。しかし、これは完全なハルシネーションであり、MCPの標準仕様には存在しないため、いくら設定しても静かに無視されるだけでした。

辿り着いた「正解」は、MCPの args 設定を使って、実行ツール(uv)側に「環境を固定する引数」を渡すことでした:

  1. カレントディレクトリに依存しない: cwd オプションは使わない。
  2. プロジェクトの明示: uv run の引数に --project (プロジェクトの絶対パス) を含める。
  3. パスの完全固定: 実行ファイル(uv)も、対象スクリプトも、すべて絶対パスで指定する。
{
    "mcpServers": {
        "a3ro-local": {
            "command": "/path/to/uv.exe",
            "args": [
                "run",
                "--project", "/path/to/project",  // ← uvの引数。これでプロジェクトの実行環境(.venv)を特定
                "python",
                "/path/to/project/server.py" // ← スクリプト自体も絶対パスで指定
            ],
            "env": { "PYTHONUTF8": "1" }
        }
    }
}

「MCPの仕様に頼る」のではなく、「MCPの設定(args)を通じて、実行ツールの引数を正しく制御する」。このアプローチによって、IDEがどこからサーバーを起動しようとも、確実に正しい実行環境が引き当てられるようになりました。

5. 通信切断への対処

パブリッシュ処理を実行する際、同期的な実装では即座に通信が切断される現象が発生しました。asyncioによる非ブロッキング実装に辿り着くまでの間、原因不明の切断とログを前に多大な時間を費やすことになりました。

自作したツールの仕様を無視するエージェント

基盤がようやく整った後ですら、エージェントが「使い方を知るためにプロジェクト内を調べ回る」という本末転倒な挙動を繰り返しました。

本来、自分たちで苦労して定義したツールの具体的なスキーマに従って直行すべきところ、あろうことかエージェントはサーバーのソースコードや内部ファイルを直接読み解そうとし始めました。これはプロトコルによる抽象化という意図を自律的に理解できていない証拠でした。

最終的には README.md に規律を定め、内部探索を禁止することで、ようやく定義されたツールを通じた運用が始まりました。

総括

今回の記事は、単なるマイルストーンの報告ではなく、AIの浅い理解と環境の不安定さに振り回された格闘の記録です。ここから得られた最大の教訓は、「成熟しきっていない技術をAIエージェントに手放しで任せることの危うさ」に尽きます。

エージェントは断片的な知識から「もっともらしい推測」で実装を進めようとしますが、そこには多くのハルシネーション(もっともらしい嘘)が混じります。特に設定の所在や実行時のライフサイクルといった、システムの根幹に関わる部分でこれが起きると、デバッグは底なしの泥沼と化します。

AIエージェントに自律性を期待する一方で、依然として人間側がシステムの仕組みを深く理解し、アーキテクチャの正解を知識として保持しておくことが不可欠な時代が続きそうです。技術的に不安定な領域において、AIの推論を迷走させないための指針を人間が提供する。その役割こそが、現時点でのAI協調開発における真の知見でした。