Skip to main content
Glama
mako10k

MCP Async Bridge Server

by mako10k
README.md
# MCP Async Bridge Server

MCPサーバをブリッジし、非同期処理機能を追加するMCPサーバです。

## 機能

- **非同期化**: 既存のMCPサーバのすべてのツールに `sync` パラメータを追加(デフォルト:async)
- **タイムアウト処理**: 1秒で応答がない場合、実行制御用ハンドルを返却
- **状況確認**: 非同期ツールの実行状況管理とキャンセル機能
- **リソース/サブスクリプション**: `task://{taskId}` でタスクの状態/結果をリソースとして公開。`resources/subscribe` で更新を購読可能

## セットアップ

### 1. 依存関係のインストール

```bash
npm install
```

### 2. ビルド

```bash
npm run build
```

### 3. 実行

```bash
npm start
```

### 4. 開発モード

```bash
npm run dev
```

## 設定

### 環境変数

- `MCP_TARGET_SERVER`: ブリッジ先MCPサーバのコマンド(例:`python server.py`)
- `MCP_TIMEOUT_MS`: タイムアウト時間(ミリ秒、デフォルト:1000)
- `MCP_ENV`: ターゲットMCPプロセスへ渡す環境変数の宣言(空白区切り)。
    - 形式: `<ENV_ITEM> ::= NAME | NAME=VALUE` を空白で列挙
    - VALUE はシェル風にクオート/展開可能('...' はリテラル、"..."/非クオートは `$VAR` `${VAR}` 展開、\" \\ \$ をエスケープ)
    - 値省略時は `NAME="$NAME"` と等価(現在の環境からコピー)
    - 宣言順にカスケード展開(前に定義した変数を後段で参照可能)
    - 例: `MCP_ENV='FOO=abc BAR="$FOO-suf" BAZ=${BAR}-end'`
- `MCP_WORKDIR`: ターゲットMCPプロセスの作業ディレクトリ(未指定時は継承)

既定で未指定でも引き継ぐ環境変数: `PATH`, `HOME`, `SHELL`(安全のため値はログ表示しません)。

### VS Codeでのデバッグ

このプロジェクトにはMCP設定が含まれています(`.vscode/mcp.json`)。VS CodeでMCPサーバとしてデバッグできます。

## アーキテクチャ

### コンポーネント

1. **AsyncBridgeServer**: メインのMCPサーバ
2. **TargetServerProxy**: 既存MCPサーバへのプロキシ
3. **AsyncTaskManager**: 非同期タスクの管理
4. **TimeoutHandler**: タイムアウト処理

### 提供ツール

#### ブリッジツール
- 既存MCPサーバのすべてのツールに `sync` パラメータを追加
- デフォルトで非同期実行、`sync: true` で同期実行

#### リクエストペイロード形式

Model Context Protocol の仕様に合わせ、ブリッジ経由のツール呼び出しは次のように
`arguments` オブジェクト内へ元のパラメータを格納してください。

```jsonc
{
    "arguments": {
        "a": 1,
        "b": 2
    },
    "sync": false // 省略時は false(非同期実行)
}
```

既存クライアントとの互換性のため、トップレベルに置かれたパラメータ
(例: `{ "a": 1, "b": 2 }`)も自動的に `arguments` にラップされますが、
仕様準拠のため上記形式での利用を推奨します。

#### 管理ツール
- `async_list_pending_tasks`: 未完了の非同期タスク一覧
- `async_get_task_result`: タスク結果の取得(完了時にハンドル開放)
- `async_cancel_task`: 実行中タスクのキャンセル

### 応答取得用リソースとサブスクリプション

- ブリッジは `resources` 機能を公開し、`task://{taskId}` でタスクの状態と結果を読み取れます。
- 非同期ツール開始時の応答には `ResourceLink`(`task://{taskId}`)が含まれます。
- クライアントは以下の流れで最新状態を追跡します。

1) `resources/subscribe` で `task://{taskId}` を購読
2) サーバーから `notifications/resources/updated` が届いたら
3) `resources/read` で `task://{taskId}` を取得(JSON: `status`, `result`)

例(概念):

```jsonc
// リソース購読
{
    "method": "resources/subscribe",
    "params": { "uri": "task://<taskId>" }
}

// 更新通知(サーバー→クライアント)
{
    "method": "notifications/resources/updated",
    "params": { "uri": "task://<taskId>" }
}

// リソース読み取り
{
    "method": "resources/read",
    "params": { "uri": "task://<taskId>" }
}
```

## 使用例

```typescript
// 非同期実行(デフォルト)
const handle = await callTool('some_tool', { param: 'value' });

// 同期実行
const result = await callTool('some_tool', { param: 'value', sync: true });

// 非同期結果の確認
const tasks = await callTool('async_list_pending_tasks');
const result = await callTool('async_get_task_result', { taskId: handle });
```

## 開発

### プロジェクト構造

```
src/
├── index.ts                 # エントリーポイント
├── server/
│   ├── AsyncBridgeServer.ts # メインサーバー
│   └── TargetServerProxy.ts # プロキシ実装
├── async/
│   ├── TaskManager.ts       # タスク管理
│   └── TimeoutHandler.ts    # タイムアウト処理
├── types/
│   └── index.ts            # 型定義
└── utils/
    └── logger.ts           # ログ機能
```

### テスト

```bash
npm test
```

## ライセンス

MIT