Skip to content

MCP サーバー 機能設計 — 全体像 ​

項目内容
ステータス🟡 設計中
関連案件#13 Mappy MCP サーバー新設
GitLab IssueMappy #58
親ドキュメント(本ドキュメントが MCP 機能設計の親)
子ドキュメントツールカタログ / 認証・テナンシ / 書込安全装置

1. 本ドキュメントの目的 ​

MCP サーバーの機能設計の全体像を定義する。実装スタック(Python / TypeScript)の比較、コンポーネント分担、リクエストフロー、トランスポート仕様、エラーハンドリング方針をここで確定し、後続の設計書(ツールカタログ・認証・書込安全装置・監査ログ等)の前提とする。

2. システム全体像 ​

2.1 アーキテクチャ図 ​

2.2 コンポーネント責務 ​

コンポーネント責務配置
Streamable HTTP エンドポイントMCP プロトコルの受付、長時間接続の維持、メッセージ・イベントの送受信MCP Server プロセス
OAuth 2.1 認可サーバークライアント登録・認可コード発行・トークン発行・scope 検証MCP Server プロセス(または独立)
Tool Dispatchertool 名から実装関数へのルーティング、入力バリデーション、scope 検査、結果整形MCP Server プロセス
Audit Logger全 tool 呼び出し・認可失敗・例外を監査ログ DB へ記録MCP Server プロセス
Laravel API(MCP用)MCP 専用エンドポイントを /api/mcp/* 配下に追加。既存のサービス層・モデルを呼び出しLaravel アプリ内
Mappy DBデータ実体。MCP からは Laravel API 経由のみアクセス既存
GBP APIGoogle Business Profile への中継。Laravel API がトークン管理外部
Jobs Queue書込系 tool の非同期処理。既存 jobs テーブルを利用既存

DB 直参照は禁止

MCP Server から Mappy DB を直接 SELECT/UPDATE しない。全てのデータアクセスは Laravel API 経由とする。理由:

  • テナンシ判定・権限制御を二重実装しない
  • 既存のバリデーション・サービスロジック・監査機構を流用
  • スキーマ変更時の影響範囲を最小化

3. リクエストフロー ​

3.1 初回接続・認証フロー(OAuth 2.1 + PKCE) ​

詳細は 認証・テナンシ設計 を参照。

3.2 読取系 tool 呼び出しフロー(同期) ​

3.3 書込系 tool 呼び出しフロー(非同期) ​

詳細は 書込安全装置 を参照。

4. トランスポート — Streamable HTTP ​

4.1 採用理由 ​

  • MCP 2025-03-26 仕様の正式トランスポート(旧 SSE は段階的廃止)
  • 長時間接続を維持しつつ HTTP/2 / HTTP/3 と相性が良い
  • 標準的なロードバランサ・WAF・CDN で扱える
  • ChatGPT Connectors / Claude Desktop の両方が公式対応

4.2 エンドポイント ​

パスメソッド用途
/sseGETMCP セッション確立(イベントストリーム)
/messagesPOSTクライアントから MCP メッセージ送信
/oauth/authorizeGETOAuth 認可エンドポイント
/oauth/tokenPOSTアクセストークン発行
/oauth/registerPOST動的クライアント登録 (RFC 7591)
/.well-known/oauth-authorization-serverGETOAuth メタデータ
/healthGETヘルスチェック

4.3 セッション管理 ​

  • 1 接続 = 1 セッション
  • セッション ID はサーバーから発行、Mcp-Session-Id ヘッダーで返却
  • 接続切断時はセッション破棄、再接続時は新セッション
  • アイドルタイムアウト: 30 分
  • 強制再認証: refresh_token 期限切れ時

5. 実装スタック詳細比較 ​

提案書では両案併記としているが、本設計書では選定軸を明確化する。

5.1 案A: Python (FastMCP) ​

項目内容
MCP ライブラリFastMCP 2.x
推奨 Python バージョン3.11+
HTTP サーバーUvicorn (ASGI)
OAuth 2.1 実装Authlib または独自実装
入出力バリデーションPydantic v2
Laravel API クライアントhttpx (非同期)
ロギングstructlog + JSON 出力
テストpytest + pytest-asyncio
依存管理Poetry または uv

サンプルコード(tool 定義):

python
from fastmcp import FastMCP
from pydantic import BaseModel, Field

mcp = FastMCP("Mappy MCP")

class LocationListInput(BaseModel):
    user_id: int = Field(..., description="対象ユーザー ID")
    group_id: int | None = Field(None, description="グループで絞り込み")
    limit: int = Field(50, ge=1, le=100)

@mcp.tool(scopes=["mappy:location:read"])
async def location_list(input: LocationListInput) -> list[dict]:
    """ユーザーがアクセス可能なロケーション一覧を返す"""
    resp = await laravel_api.get(
        "/api/mcp/locations",
        params=input.model_dump(exclude_none=True),
    )
    return resp.json()

5.2 案B: TypeScript (公式 SDK) ​

項目内容
MCP ライブラリ@modelcontextprotocol/sdk
推奨 Node バージョン20 LTS
HTTP サーバーExpress / Hono / Fastify
OAuth 2.1 実装oauth4webapi / panva/jose
入出力バリデーションZod
Laravel API クライアントundici / fetch
ロギングpino
テストvitest
依存管理pnpm または npm

サンプルコード(tool 定義):

typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({ name: "Mappy MCP", version: "1.0.0" });

const LocationListInput = z.object({
  user_id: z.number().int().describe("対象ユーザー ID"),
  group_id: z.number().int().optional(),
  limit: z.number().int().min(1).max(100).default(50),
});

server.tool(
  "location.list",
  "ユーザーがアクセス可能なロケーション一覧を返す",
  LocationListInput.shape,
  async (input) => {
    const resp = await fetch(
      `${LARAVEL_API}/api/mcp/locations?${new URLSearchParams(input)}`,
    );
    return { content: [{ type: "text", text: await resp.text() }] };
  },
);

5.3 比較表 ​

評価軸Python (FastMCP)TypeScript (公式 SDK)備考
公式サポートコミュニティ製(人気)公式TS が一歩リード
ドキュメント良い充実TS が一歩リード
型安全性Pydantic (実行時)Zod + TS (静的)TS が強い
既存社内スキルスクレイピング・AI で蓄積フロント側で蓄積同等
AI レポート機能との同居○ Python 同士× 言語が異なるPython が有利
PPTX/Excel 生成等の拡張○ python-pptx 等△ Node.js 対応ライブラリは少なめPython が有利
Laradock 内同居新規コンテナ追加既存 Node コンテナ流用可TS が有利
起動速度・メモリNode.js より重い軽量TS が有利
Streamable HTTP 実装の成熟度安定安定同等
OAuth 2.1 ライブラリAuthlib(豊富)oauth4webapi(標準準拠)同等

5.4 推奨と判断基準 ​

推奨:Python (FastMCP)

判断軸の優先順位:

  1. 同居・統合運用の容易性(AI レポート機能 #9 が Python 採用済み)
  2. 将来の拡張性(PPTX/Excel 生成、機械学習統合の選択肢)
  3. 社内スキル(スクレイピング系も Python)

これら 3 点で Python が優位。TypeScript の優位性(公式サポート・型安全)も有力だが、組織横断の運用統合を優先する。

最終決定は 設計レビューでチーム合意 → 製造 Issue 起票直前で確定。

6. クライアント別の挙動差 ​

クライアントトランスポートOAuth フロー注意点
Claude DesktopStreamable HTTP / stdio 両対応内蔵ブラウザで PKCE フローmacOS / Windows / Linux 対応
Claude CodeStreamable HTTP / stdio 両対応同上CLI ベース
ChatGPT ConnectorsStreamable HTTP のみWeb ベースのコネクタ設定画面リダイレクト URI を ChatGPT 側に登録

6.1 互換性確保のため必須 ​

  • /.well-known/oauth-authorization-server を返す
  • RFC 7591 動的クライアント登録(ChatGPT は事前登録不要にできる)
  • PKCE 必須対応(code_challenge_method=S256)
  • tool description は英語併記 or 顧客 AI の言語に追随できる構造
  • リダイレクト URI のホワイトリスト:Claude/ChatGPT の公式 URI を登録

7. エラーハンドリング ​

7.1 エラー区分 ​

区分HTTP / JSON-RPC例動作
認証エラー401トークン無効・期限切れクライアントに再認証を促す
認可エラー403 / -32604scope 不足tool 結果を isError: true で返す
入力エラー400 / -32602バリデーション失敗詳細メッセージ付きで返却
Mappy 側 4xx透過レコード未存在等エラーコードを保持して返却
Mappy 側 5xx502 / -32603Laravel API 障害Audit Log に記録、リトライ可否を判定
GBP API 障害502Google 側エラーエラーメッセージを顧客 AI に伝達
タイムアウト50430 秒以上応答なしクライアントに通知、書込系は batch_id で追跡

7.2 タイムアウト方針 ​

区間タイムアウト
MCP Client → MCP Serverクライアント側設定(通常 30〜60 秒)
MCP Server → Laravel API10 秒(読取)/ 30 秒(書込同期処理)
Laravel API → GBP API既存設定に従う(通常 30 秒)
書込系全体(ジョブ完了まで)非同期、batch_id で追跡

7.3 リトライ方針 ​

  • 読取系: 5xx のみクライアント側で 1 回まで自動リトライ可
  • 書込系: idempotency_key を使った再送のみ許可。サーバー側自動リトライは禁止
  • GBP API レート制限: Laravel 側で既存の rate-limiter middleware を流用

8. レート制限 ​

適用範囲制限理由
アクセストークン単位60 リクエスト/分(読取)DoS 対策
アクセストークン単位10 リクエスト/分(書込)GBP API 制限への配慮
クライアント ID 単位1000 リクエスト/時クライアント丸ごとの暴走対策
同一 idempotency_key24 時間重複書込防止

9. デプロイ構成(概要) ​

詳細は インフラ設計 を参照。

項目内容
配置AWS(既存 Mappy インフラと同一 VPC)
コンテナECS Fargate(または EC2)
ロードバランサーALB(HTTPS 終端)
ドメインmcp.mappy.example.com(仮)
TLSACM 証明書
共通ストアRedis(セッション、レート制限カウンタ、idempotency キャッシュ)
シークレット管理AWS Secrets Manager
ログ集約CloudWatch Logs
監視CloudWatch Metrics / Alarms

10. 監査ログ ​

MCP Server はすべての操作を監査ログに記録する。 詳細は DB 設計(監査ログ) を参照。

記録対象:

  • tool 呼び出し(入力・出力・実行時間・結果コード)
  • 認可成功・失敗
  • トークン発行・失効
  • レート制限ヒット
  • 例外・タイムアウト

11. テナンシ・スコープ(概要) ​

詳細は 認証・テナンシ設計 を参照。

階層操作可能範囲
admin (is_supervisor=1)全 mappy_users
admin (is_supervisor=0)preview_user_id 対象のユーザー
MAIN_USER自分 + parent_user_id 配下
MASTER_USERparent_user_id 配下全部
GROUP_USER自分のみ

店舗境界:

  • mappy_user_available_gbp_locations 経由のフィルタ
  • グループ単位は mappy_groups + mappy_group_location(単数形)

12. 関連設計書 ​

ドキュメント内容
ツールカタログ各 tool の入出力 schema、scope、副作用区分
認証・テナンシ設計OAuth 2.1 フロー詳細、scope 設計、テナンシ判定ロジック
書込安全装置dry_run / idempotency / 確認トークン / batch ポーリング
DB 設計(監査ログ)監査ログテーブル定義
DB 設計(OAuth クライアント)OAuth クライアント・トークン管理テーブル
インフラ設計AWS 構成・コンテナ・ネットワーク
Issue 詳細実装タスク・検収条件

13. 未確定事項(設計レビューで決定) ​

#項目候補
1実装スタックPython (FastMCP) / TypeScript (公式 SDK)
2OAuth ライブラリPython: Authlib / 独自
TS: oauth4webapi / 独自
3MCP Server のホスト名mcp.mappy.example.com 仮
4admin 経由の代理操作の許可範囲Phase 1 では admin 自身のみ/Phase 2 で preview_user_id 対応
5レート制限の最終値上記は暫定、本番負荷を見て調整
6Redis vs DynamoDBセッション・idempotency ストアの選定
7クライアント側のキャッシュ可否tool 結果のキャッシュをクライアントが行うか