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 結果のキャッシュをクライアントが行うか