# 通知設計書 43-ページメタデータリクエスト通知

## 概要

本ドキュメントは、Next.jsの開発サーバーにおけるページメタデータリクエスト通知の設計について記述する。MCP（Model Context Protocol）等の外部ツールからページメタデータの問い合わせがあった際に、サーバーがブラウザへWebSocket経由でHMRメッセージ（`REQUEST_PAGE_METADATA`）を転送し、ブラウザ側の現在のページレンダリングに関するメタデータ（セグメントツリー情報等）を収集する仕組みを定義する。

### 本通知の処理概要

ページメタデータリクエスト通知は、MCPツール（get_page_metadata）がNext.js開発サーバーを通じてブラウザに現在のページレンダリング情報を問い合わせるためのHMR通知メッセージである。サーバーはリクエストIDを生成し、`REQUEST_PAGE_METADATA`メッセージをWebSocket経由で全接続ブラウザに送信する。ブラウザはセグメントツリーデータ（`SegmentTrieData`）を取得し、`MCP_PAGE_METADATA_RESPONSE`メッセージとしてサーバーに返送する。サーバーは応答をページメタデータ形式に変換し、MCPクライアントに結果を返す。

**業務上の目的・背景**：AI支援開発ツール（Claude Code等）がNext.jsアプリケーションの現在のページ構造を把握するために必要な通知である。App Routerのセグメント構造（レイアウト、ページ、バウンダリなど）をプログラマティックに取得することで、外部ツールがページの構成要素を理解し、より的確な開発支援を提供できる。ルーターの種類（App Router / Pages Router）も識別可能。

**通知の送信タイミング**：MCPクライアントが`get_page_metadata`ツールを呼び出したタイミングで発生する。サーバーは接続中のブラウザセッション数を確認し、少なくとも1つの接続がある場合にのみメッセージを送信する。

**通知の受信者**：WebSocket経由で開発サーバーに接続されているすべてのブラウザセッション。各ブラウザセッションが個別にセグメントツリーデータを含む応答を返す。

**通知内容の概要**：メッセージには`type`（`requestPageMetadata`）と一意の`requestId`（`mcp-requestPageMetadata-{nanoid}`形式）が含まれる。ブラウザはこのリクエストIDに対応する応答として、`SegmentTrieData`（セグメントツリーのルートノードとルーター種別）を返す。

**期待されるアクション**：ブラウザはリクエストを受信すると、現在のセグメントツリーデータ（`getSegmentTrieData()`）を取得し、`MCP_PAGE_METADATA_RESPONSE`イベントとしてWebSocket経由でサーバーに応答を返す。サーバーは応答をPageMetadata形式に変換し、セグメント情報（パス、タイプ、バウンダリ状態）を整形してMCPクライアントに返却する。

## 通知種別

WebSocket HMRメッセージ（開発サーバー → ブラウザ、JSON形式）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（WebSocket HMR経由、リクエスト-レスポンスパターン） |
| 優先度 | 中（開発支援用途） |
| リトライ | 無（タイムアウト5秒後に部分的な応答を返す or エラー） |

### 送信先決定ロジック

開発サーバーに現在WebSocket接続されているすべてのブラウザセッションにブロードキャストする。`getActiveConnectionCount()`で接続数を取得し、0の場合はメッセージを送信せずにエラーメッセージを返す。接続がある場合は`sendHmrMessage()`を通じて全クライアントに送信する。

## 通知テンプレート

### メール通知の場合

本通知はメール通知ではない。WebSocket HMRメッセージである。

### 本文テンプレート

```json
{
  "type": "requestPageMetadata",
  "requestId": "mcp-requestPageMetadata-{nanoid}"
}
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | メッセージタイプ | HMR_MESSAGE_SENT_TO_BROWSER.REQUEST_PAGE_METADATA | Yes |
| requestId | リクエスト識別子 | nanoid()による自動生成（`mcp-requestPageMetadata-{id}`形式） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API | MCPクライアントが`get_page_metadata`ツールを呼び出し | ブラウザ接続数 > 0 | MCPプロトコル経由のリクエスト |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ブラウザ接続なし | `getActiveConnectionCount() === 0`の場合、メッセージ送信をスキップしエラーを返却 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[MCPクライアントがget_page_metadataを呼び出し] --> B[接続数チェック]
    B -->|接続なし| C[エラーメッセージ返却]
    B -->|接続あり| D[requestId生成 - nanoid]
    D --> E[createBrowserRequest実行]
    E --> F[REQUEST_PAGE_METADATA HMRメッセージ送信]
    F --> G[ブラウザがgetSegmentTrieData取得]
    G --> H[MCP_PAGE_METADATA_RESPONSE送信]
    H --> I[handlePageMetadataResponse処理]
    I --> J{全セッション応答受信?}
    J -->|Yes| K[応答集約]
    J -->|タイムアウト| L[部分応答集約]
    K --> M[convertSegmentTrieToPageMetadata処理]
    L --> M
    M --> N[formatPageMetadata処理]
    N --> O[MCPクライアントへJSON返却]
    C --> P[終了]
    O --> P
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし。本通知はメモリ内の状態管理のみで動作する。

### 更新テーブル一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 接続なしエラー | ブラウザセッションが0件 | エラーメッセージ「No browser sessions connected...」をMCPに返却 |
| タイムアウト | 5秒以内にブラウザから応答がない | 部分的な応答があればそれを返す、なければタイムアウトエラー |
| 空レスポンス | ブラウザから応答があるがデータがnull | 空のsessions配列を返す |
| 一般エラー | その他の例外 | error.messageをJSON形式でMCPに返却 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A（タイムアウト時は部分応答を返す） |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（MCPリクエスト頻度に依存） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。開発サーバーが稼働中であればいつでも利用可能。

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

- 本通知は開発環境でのみ動作し、本番環境では利用不可
- MCPプロトコル経由でのアクセスのみを想定し、認証はMCPサーバーの接続管理に依存
- ページメタデータにはファイルパス情報が含まれるため、開発環境限定で使用すること
- `requestId`にnanoidを使用して一意性を確保し、リクエストの混同を防止
- テレメトリトラッキング（`mcpTelemetryTracker.recordToolCall`）が行われる

## 備考

- `DEFAULT_BROWSER_REQUEST_TIMEOUT_MS`は5000ms（5秒）に設定されている
- 複数のブラウザセッションが接続されている場合、すべてのセッションから応答を収集し、セッション単位でメタデータを返す
- App Routerのhot-reloaderのみが`REQUEST_PAGE_METADATA`を処理する（行499-508）
- セグメントの表示パスは加工される：`@boundary`サフィックスの除去、`__next_builtin__`プレフィックスの除去、`app/`プレフィックスの自動付加
- セグメントはタイプ順（layout → boundary → page → その他）にソートされる
- `routerType`フィールドによりApp Router / Pages Routerの判別が可能
- セグメントのバウンダリタイプは`boundary:`プレフィックスで識別される

---

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

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

### 推奨読解順序

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

HMRメッセージの型定義とPageMetadata、SegmentTrieDataの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | `REQUEST_PAGE_METADATA`の定義（行39）、`RequestPageMetadataMessage`インターフェース（行171-174） |
| 1-2 | mcp-page-metadata-types.ts | `packages/next/src/shared/lib/mcp-page-metadata-types.ts` | `PageMetadata`、`PageSegment`、`SegmentTrieData`型定義 |

**読解のコツ**: `SegmentTrieData`はブラウザからの生データであり、`PageMetadata`はサーバー側で変換後の整形データである。`convertSegmentTrieToPageMetadata()`がこの変換を担当する。

#### Step 2: エントリーポイントを理解する（サーバー側）

MCPツールの`get_page_metadata`登録とリクエスト処理の起点を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | get-page-metadata.ts | `packages/next/src/server/mcp/tools/get-page-metadata.ts` | `registerGetPageMetadataTool()`（行19-118）、`createBrowserRequest`呼び出し（行51-56） |

**主要処理フロー**:
1. **行31-33**: MCPリクエスト受信、テレメトリ記録
2. **行36-49**: 接続数チェック（0の場合はエラー返却）
3. **行51-56**: `createBrowserRequest`でブラウザにリクエスト送信
4. **行73-78**: 応答をPageMetadataに変換
5. **行94-103**: `formatPageMetadata`で整形処理

#### Step 3: セグメントツリー変換ロジックを理解する

ブラウザからのSegmentTrieDataをPageMetadataに変換する処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | get-page-metadata.ts | `packages/next/src/server/mcp/tools/get-page-metadata.ts` | `convertSegmentTrieToPageMetadata()`（行132-160）、`formatPageMetadata()`（行179-239） |

**主要処理フロー**:
- **行137-153**: ツリーの再帰的トラバース（type, pagePath, boundaryTypeを収集）
- **行194-206**: セグメントのソート（layout → boundary → page → その他）
- **行208-229**: 表示パスの加工（`@boundary`除去、`__next_builtin__`除去、`app/`付加）

#### Step 4: ブラウザ側の応答処理を理解する

ブラウザ側でのメッセージ受信と応答送信を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | `REQUEST_PAGE_METADATA`ハンドラ（行499-508） |

**主要処理フロー**:
- **行500**: `getSegmentTrieData()`でセグメントツリーデータ取得
- **行501-506**: 応答メッセージ構築（requestId, segmentTrieData, url）
- **行507**: `sendMessage()`でサーバーに応答送信

#### Step 5: ブラウザ通信基盤を理解する

リクエスト-レスポンスパターンの共通実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | browser-communication.ts | `packages/next/src/server/mcp/tools/utils/browser-communication.ts` | `createBrowserRequest()`（行30-75）、`handleBrowserPageResponse()`（行77-97） |

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

```
MCPクライアント (get_page_metadata呼び出し)
    │
    ├─ registerGetPageMetadataTool() [get-page-metadata.ts:19]
    │      ├─ mcpTelemetryTracker.recordToolCall() [行33]
    │      ├─ getActiveConnectionCount() [行36]
    │      ├─ createBrowserRequest() [browser-communication.ts:30]
    │      │      ├─ nanoid() → requestId生成
    │      │      ├─ pendingRequests.set()
    │      │      └─ sendHmrMessage() → WebSocket送信
    │      │
    │      │  [ブラウザ側]
    │      │  └─ hot-reloader-app.tsx ハンドラ [行499-508]
    │      │         ├─ getSegmentTrieData()
    │      │         └─ sendMessage() → MCP_PAGE_METADATA_RESPONSE
    │      │
    │      ├─ handlePageMetadataResponse() [get-page-metadata.ts:120]
    │      │      └─ handleBrowserPageResponse() [browser-communication.ts:77]
    │      │
    │      ├─ convertSegmentTrieToPageMetadata() [行132]
    │      │      └─ traverseTrie() 再帰処理 [行137]
    │      │
    │      └─ formatPageMetadata() [行179]
    │             └─ セグメントソート・パス加工
    │
    └─ MCPクライアントへJSON応答
```

### データフロー図

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

MCPクライアント ──────▶ get_page_metadata ──────▶ requestId生成
                                                      │
                                                      ▼
                        WebSocket HMR ◀───── REQUEST_PAGE_METADATA
                              │
                              ▼
                      ブラウザ Dev Overlay
                     getSegmentTrieData()
                              │
                              ▼
                 MCP_PAGE_METADATA_RESPONSE ──────▶ サーバー
                  (SegmentTrieData)                    │
                                                       ├─ convertSegmentTrieToPageMetadata()
                                                       ├─ formatPageMetadata()
                                                       │    ├─ セグメントソート
                                                       │    └─ パス加工
                                                       │
                                                       ▼
                                                MCPクライアントへ
                                                JSON応答返却
                                                (sessions[].url,
                                                 routerType,
                                                 segments[])
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| get-page-metadata.ts | `packages/next/src/server/mcp/tools/get-page-metadata.ts` | ソース | MCPツール登録、メタデータ取得・変換メイン処理 |
| browser-communication.ts | `packages/next/src/server/mcp/tools/utils/browser-communication.ts` | ソース | ブラウザ通信基盤（リクエスト-レスポンスパターン） |
| hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | ソース | HMRメッセージ型定義 |
| mcp-page-metadata-types.ts | `packages/next/src/shared/lib/mcp-page-metadata-types.ts` | ソース | PageMetadata、PageSegment、SegmentTrieData型定義 |
| hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | ソース | ブラウザ側メッセージハンドラ |
| segment-explorer-trie.ts | `packages/next/src/next-devtools/dev-overlay/segment-explorer-trie.ts` | ソース | セグメントツリーデータ構造・操作 |
| mcp-telemetry-tracker.ts | `packages/next/src/server/mcp/mcp-telemetry-tracker.ts` | ソース | MCPテレメトリ追跡 |
