MCP Fusion/Protocol and runtime/ランタイムアーキテクチャ
ランタイムアーキテクチャ
MCP Fusion の実際の動作:ビルド時のコンパイル、O(1) のリクエストルーティング、リクエスト単位のコンテキスト、Result モナド、実行パイプライン、そしてトランスポート。
このページでは、Tools で説明しているフルエント API の土台となるエンジンについて解説します。これは packages/core でコンパイルされる、リクエストライフサイクルの技術詳細リファレンスです。
2つのレイヤー:一度ビルドし、多数をさばく
MCP Fusion は、ビルド時に属する作業と、リクエストごとに必ず行うべき作業を分離します。
ビルド時。 registry.register(builder) は builder.buildToolDefinition() を即座に呼びます。このコンパイル処理が、プロセスの生存期間中にサーバーが必要とするすべてを生み出します:
- 判別フィールドとアクションごとの必須注釈を備えた、マージ後の入力スキーマ
<tool_error>対応の検証スキーマ、アクションごとに 1 つのstrictな Zod スキーマ- 事前コンパイル済みのミドルウェアチェーン、アクションごとに 1 つのクロージャ、グローバルミドルウェアが最も外側、アクション別ミドルウェアが最も内側
- アクションマップ、アクションキーからコンパイル済みコンテキストを引く O(1) の
Map
buildToolDefinition() の後、ビルダーは凍結されます。アクションに対する Object.freeze、そしてすべての変更メソッドに対するガードです。うっかりビルド済みの tool を変更することはできません。mergeActions() がアクションを追加できる唯一の正規の方法で、再ビルドのために明示的に凍結を解きます。
リクエスト時。 ランタイムの経路は固定で、組み立てステップが存在しません:
contextFactory → discriminator parse → action resolve (Map)
→ arg validation (cached strict schema) → middleware chain (precompiled)
→ handler → Presenter (postProcess) → guards → response各ステップは事前コンパイル済みの構造体から読み取ります。リクエスト経路上でスキーマの再構築も、チェーンの合成も、検索のスキャンも行われません。
Registry、tool 名とアクション
ドット付きのビルダー名はフラットな tool 名ではありません。f.query('billing.get_invoice') は tool billing にアクション get_invoice を登録します。ビルド時にドットを含む 2 つの名前はエラーです。ネストには f.router('support.tickets') を使います。同じ名前空間を共有するビルダーはマージされます。compliance.scan、compliance.report、compliance.status をエクスポートする 3 つのファイルは、3 つのアクションを持つ 1 つの compliance tool になります。ディレクトリ単位でコネクタを構成しても、エージェントには引き続き一貫した表面が見えます。
contextFactory:リクエスト単位のエントリー
attachToServer(server, { contextFactory }) はルーティング前に contextFactory(extra) をリクエストごとに 1 回実行します。extra は MCP SDK の生のリクエストコンテキストです:セッション ID、_meta オブジェクト(プログレットークン)、キャンセル用の AbortSignal、エリシテーション用の sendRequest チャンネル。新しいオブジェクトを返してください。ミドルウェアが内容を充実させながら、フレームワークはこのオブジェクトをその場で変更します。データベースハンドル、テナント ID、abort シグナルが ctx に加わるのはこの場所です。そのため stateless なデプロイでは、構造上リクエスト間の漏れが起こり得ません。
contextFactory を省略すると、ctx に触れたとき原因不明の失敗ではなく明確なエラーが投げられます。
トランスポート
startServer() は 3 つのトランスポートをサポートします:
| トランスポート | セッション | 用途 |
|---|---|---|
stdio | なし | ローカルクライアント、デスクトップアプリ、mcpfusion dev |
http | UUID のセッション ID、TTL リーパー、ボディ上限、セッション単位のトークンバケット | 永続的な HTTP MCP サーバー |
stateless | なし | MCP 2.0 モード:リクエストごとに新しい Server を生成し、任意のロードバランサーの後ろで動作 |
Stateless はスケーリングの既定です。initialize のハンドシェイクがなく、リクエストは Mcp-Method と Mcp-Name ヘッダーでルーティングされ、Vercel と Cloudflare のアダプターは SSE もセッション状態もない JSON レスポンスを返します。Vinkius Edge はこのモデルを使っています。StartServerOptions.state は isolate が破棄される前にシリアライズされ、次のコールドリクエストで透過的に復元されます。
Result モナド:例外を使わない制御フロー
内部的にパイプラインは Result ベースです。Success か Failure で、各ステップは Failure で短絡します。ハンドラーは Result を見ません。データを返すか succeed()/toolError() を使います。Result がもたらすのは予測可能性です。検証、判別子解析、ディスパッチは例外の送出ではなく値を返すので、スタックトレースの中で失われるものがありません。ToolResponse の throw はそのまま通過します(つまり throw toolError('NOT_FOUND', ...) は機能します)。その他の throw は「安易に再試行しないこと」という復旧指示付きの INTERNAL_ERROR としてラップされます。
ハンドラーの周りのガード
3 つの独立したガードが実行を囲み、設定されていない場合はゼロコストです:
- 並行数:有界キューを持つセマフォ。容量を超えると、性能を落とす代わりにリトライのヒント付きで
SERVER_BUSYを返します。 - ミューテーションの直列化:破壊的なアクションにはアクション単位の FIFO ミューテックスが自動的に与えられるので、2 つのエージェントが同じ書き込みを競うことはできません。
- エグレス上限:レスポンスに対するバイト数の予算。大きすぎるテキストは、モデルにページネーションを促すシステムメッセージ付きで切り詰められます。構造化された
structuredContentは保持され、isErrorが反転することは決してありません。
入力側のガードについては Security pipeline、キャッシュと鮮度のシグナルについては State sync を参照してください。
観測性のフック
registry.enableDebug(observer)、enableTracing(tracer)、enableTelemetry(sink) は同じダックタイピングのインターフェースを通じてすべてのビルダーに伝播します。各フックは設定されるまで不活性です。サブシステムが静かな限り、タイマーもラッパーもアロケーションもありません。同じ 3 つのシンクが mcpfusion inspect、OTel パイプライン、そしてロックファイル内のミドルウェアカバレッジの証跡を支えています。
次のステップ
- Security pipeline:ファイアウォールとその層
- State sync:キャッシュディレクティブ、無効化、購読
- Testing:このパイプラインをメモリ上で試す
