# 機能設計書 37-MCPツール実行

## 概要

本ドキュメントは、OpenCodeにおけるMCPサーバーから取得したツールの実行機能について記載する。この機能により、AIアシスタントはMCPサーバーが提供するツールをAI SDK互換の形式で実行できる。

### 本機能の処理概要

**業務上の目的・背景**：MCPサーバーは様々なツール（データベースクエリ、API呼び出し、ファイル操作等）を提供する。これらのツールをAIアシスタントが利用可能にするためには、MCPプロトコルのツール定義をAI SDK（Vercel AI SDK）の形式に変換し、統一的なインターフェースで実行できるようにする必要がある。

**機能の利用シーン**：
- AIアシスタントがMCPサーバーから提供されるカスタムツールを呼び出す
- 複数のMCPサーバーから取得したツールを統合的に管理する
- ツール実行時のタイムアウトと進捗通知を制御する

**主要な処理内容**：
1. 接続済みMCPサーバーからのツール一覧取得（listTools）
2. MCPツール定義からAI SDKツール形式への変換
3. ツール実行（callTool）とレスポンス処理
4. タイムアウト制御と進捗時のタイムアウトリセット
5. ツール名のサニタイズ（クライアント名_ツール名形式）

**関連システム・外部連携**：
- Model Context Protocol SDK（ツール定義・実行）
- Vercel AI SDK（dynamicTool形式）
- MCPサーバー（ツール提供元）

**権限による制御**：各ツールの実行権限はMCPサーバー側で制御。OpenCodeはMCPツールへの呼び出しを中継する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | セッション | 補助機能 | MCPツールの実行結果表示 |

## 機能種別

外部連携 / ツール実行

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| toolName | string | Yes | 実行するツール名（サニタイズ済み） | 存在するツールであること |
| arguments | object | No | ツール引数 | ツールのスキーマに準拠 |

### 入力データソース

- MCPサーバー: ツール定義（inputSchema）
- エージェント: ツール引数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | CallToolResult | ツール実行結果 |
| result.content | array | 結果コンテンツ配列 |
| result.isError | boolean | エラーフラグ |

### 出力先

- エージェントへの応答: ツール実行結果

## 処理フロー

### 処理シーケンス

```
1. ツール一覧取得（tools）
   └─ 接続済みクライアントのフィルタリング
   └─ 各クライアントからlistTools取得
   └─ ツール定義をAI SDK形式に変換
   └─ サニタイズ済みツール名をキーにマップ作成

2. ツール変換（convertMcpTool）
   └─ inputSchemaのJSONSchema7形式への変換
   └─ dynamicTool関数でラップ
   └─ execute関数の定義

3. ツール実行
   └─ dynamicTool.execute呼び出し
   └─ client.callTool実行
   └─ resetTimeoutOnProgress: true設定
   └─ 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[ツール一覧取得] --> B[接続済みクライアント取得]
    B --> C[各クライアントでlistTools]
    C --> D{取得成功?}
    D -->|No| E[エラー記録、クライアント削除]
    D -->|Yes| F[convertMcpTool変換]
    F --> G[ツール名サニタイズ]
    G --> H[ツールマップに追加]
    H --> I[ツールマップ返却]

    J[ツール実行] --> K[dynamicTool.execute呼び出し]
    K --> L[client.callTool実行]
    L --> M[CallToolResultSchema検証]
    M --> N[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-01 | ツール名サニタイズ | クライアント名とツール名の特殊文字を_に置換し、_で連結 | ツール登録時 |
| BR-37-02 | 進捗タイムアウトリセット | resetTimeoutOnProgress: trueにより進捗通知でタイムアウトをリセット | ツール実行時 |
| BR-37-03 | 接続済みクライアントのみ | status === "connected"のクライアントのみからツールを取得 | ツール一覧取得時 |
| BR-37-04 | スキーマ強制object型 | inputSchemaのtypeを常に"object"に設定 | ツール変換時 |
| BR-37-05 | 空引数のデフォルト | arguments未指定時は空オブジェクト{}を使用 | ツール実行時 |

### 計算ロジック

**ツール名生成**:
```javascript
const sanitizedClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "_")
const sanitizedToolName = mcpTool.name.replace(/[^a-zA-Z0-9_-]/g, "_")
const toolKey = sanitizedClientName + "_" + sanitizedToolName
```

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ListToolsError | 取得エラー | listToolsが失敗 | failedステータス設定、クライアント削除 |
| CallToolError | 実行エラー | callToolが失敗 | エラー結果を返却 |
| TimeoutError | タイムアウト | ツール実行がタイムアウト | タイムアウトエラーを返却 |

### リトライ仕様

- ツール実行失敗時の自動リトライは行わない

## トランザクション仕様

該当なし

## パフォーマンス要件

- ツール一覧取得は全クライアントに並列でリクエスト
- タイムアウトはMCP設定または実験的設定から取得

## セキュリティ考慮事項

- ツール実行はMCPサーバー側の認可に依存
- inputSchemaによる引数検証

## 備考

dynamicToolの仕様:
- AI SDK（Vercel AI SDK）のdynamicTool関数を使用
- description、inputSchema、executeを定義
- executeは非同期関数でcallToolを呼び出し

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

MCPツール関連の型を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/opencode/src/mcp/index.ts` | インポート部のTool型（1行目） |
| 1-2 | index.ts | `packages/opencode/src/mcp/index.ts` | MCPToolDef型（9行目） |

**読解のコツ**: Toolはai（Vercel AI SDK）からのインポート。MCPToolDefはMCP SDKのツール定義型。

#### Step 2: ツール変換ロジックを理解する

MCPツールからAI SDKツールへの変換。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/opencode/src/mcp/index.ts` | convertMcpTool関数（120-148行目） |

**主要処理フロー**:
- **121行目**: inputSchemaの取得
- **124-129行目**: JSONSchema7形式への変換（type: "object"強制）
- **131-147行目**: dynamicTool関数によるラップ
- **134-145行目**: execute関数の定義（client.callTool呼び出し）

#### Step 3: ツール一覧取得を理解する

接続済みクライアントからのツール収集。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/opencode/src/mcp/index.ts` | tools関数（566-606行目） |

**主要処理フロー**:
- **574-576行目**: status === "connected"でフィルタリング
- **578-591行目**: 各クライアントでlistTools取得（並列）
- **594-603行目**: convertMcpToolで変換、ツール名サニタイズ
- **600-602行目**: ツールキー生成（client_tool形式）

#### Step 4: ツール名サニタイズを理解する

特殊文字の置換ロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.ts | `packages/opencode/src/mcp/index.ts` | サニタイズ処理（600-601行目） |

**主要処理フロー**:
- **600行目**: クライアント名のサニタイズ（正規表現置換）
- **601行目**: ツール名のサニタイズ
- **602行目**: アンダースコアで連結

### プログラム呼び出し階層図

```
MCP.tools()
    │
    ├─ state() - 状態取得
    │
    ├─ clients() - クライアント一覧取得
    │
    └─ Promise.all([...connectedClients.map(...)])
           │
           └─ client.listTools()
                  │
                  └─ convertMcpTool(mcpTool, client, timeout)
                         │
                         ├─ dynamicTool({
                         │      description,
                         │      inputSchema: jsonSchema(schema),
                         │      execute: async (args) => {
                         │          return client.callTool({
                         │              name: mcpTool.name,
                         │              arguments: args
                         │          }, CallToolResultSchema, {
                         │              resetTimeoutOnProgress: true,
                         │              timeout
                         │          })
                         │      }
                         │  })
                         │
                         └─ sanitizedClientName + "_" + sanitizedToolName
```

### データフロー図

```
[入力]                    [処理]                         [出力]

MCPクライアント ──────▶ listTools取得 ────────────▶ MCPToolDef[]
                            │
                            ▼
                    convertMcpTool変換
                            │
                            ├─ inputSchema解析
                            │
                            ├─ JSONSchema7変換
                            │
                            └─ dynamicTool作成
                                   │
                                   ▼
ツール名 ──────────────▶ サニタイズ ──────────────▶ client_tool形式
                                   │
                                   ▼
                            ツールマップ
                                   │
                                   ▼
[ツール実行時]
引数 ──────────────────▶ callTool実行 ───────────▶ CallToolResult
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/opencode/src/mcp/index.ts` | ソース | tools関数、convertMcpTool関数 |
| @modelcontextprotocol/sdk | 外部 | ライブラリ | MCPプロトコル実装、callTool |
| ai | 外部 | ライブラリ | Vercel AI SDK、dynamicTool |
