Skip to content

Mappy MCP サーバー新設(v3 — Laravel 内蔵版)

概要

項目内容
ステータス🔵 提案中
GitLab IssueMappy #58
対象プロダクトGMAC / GCOR / PIPIT (KingMeo) / 口コミONE の 4 製品(Phase 1 は GMAC のみ有効化)
想定工数(Phase 1)8.0 人日(AI 前提 — AIリテイク × レビュー時間で積算)
追加インフラコストほぼゼロ(既存 Laravel EC2 に相乗り、新規 AWS リソースなし)
実装スタックLaravel 内蔵(既存コードベースに追加)+ Bearer トークン認証

社内メンバーが各自の Claude / ChatGPT 等の AI エージェントから、Mappy 4 製品のデータを MCP (Model Context Protocol) 経由で参照できるようにする。実装は既存 Laravel アプリケーションへの機能追加のみで完結させる。

v2 からの方針転換について

旧提案 /projects/mcp-server-v2(Lambda + API Gateway + OAuth 2.1 + DynamoDB 構成)は、設計レビューの結果、Laravel 内蔵の軽量構成へ方針転換したためアーカイブ扱いとする。v2 で実施した DB 実スキーマ調査・SQL 記述(/design/mcp-tools-v2)は本設計に流用している。

背景・目的

  • 利用者(主に社内メンバー)は各自 Claude / ChatGPT 等の AI エージェントを持っているが、現状その AI から製品データにアクセスする手段がない
  • 代表ユースケースは「AI による月間レポート作成」— AI がローカルの PPTX テンプレートにデータを流し込むための、プログラマブルなデータ取得手段が必要
  • v2 提案では独立したサーバーレス構成(Lambda / OAuth 2.1 / DynamoDB)を検討したが、技術レビューの結果「管理画面で取れる情報を MCP でエージェント向けにインターフェース公開するだけ」という要件に対して構成が大きすぎると判断。既存 Laravel に内蔵する最小構成へ転換した

方針(技術レビューで確定した 4 機能)

大掛かりな独立システムは作らない。必要な機能は以下の 4 つのみ。

#機能実装先
1ログインユーザー毎のトークン払い出し管理画面(既存ユーザー詳細画面にタブ追加)
2MCP 用 API 作成Laravel(既存 Service 層を流用)
3MCP 用エンドポイント用意Laravel(POST /api/mappy/mcp の 1 ルート)
4トークン認証Laravel(専用ミドルウェア + 独自テーブル mappy_mcp_tokens

OAuth 認可サーバー・Lambda・API Gateway・DynamoDB 等の新規 AWS リソースは一切追加しない。ホスティングは既存 Laravel EC2 に相乗りする。

スコープ

対象プロダクト(4 製品)

4 製品は同一 Laravel コードベースの env 切替で運用されており、DB は製品ごとに別 Aurora クラスターだが同一スキーマ。コードは 4 製品共通で実装し、env フラグ MCP_ENABLED で製品別に ON/OFF する。

製品ドメインAurora クラスターPhase 1
GMACgmac-g.comgmac-db-production-cluster-1有効MCP_ENABLED=true
GCORg-cor-m.comgcor-db-production-cluster無効(env で false)
PIPIT (KingMeo)king-meo.comkingmeo-db-production-cluster無効(env で false)
口コミONEkuchikomione.comkuchikomi-one-db-production-cluster無効(env で false)

Phase 2 以降の他製品展開は「env を true にする + migration 適用確認」のみで完了する。

Phase 1 の範囲

  • GMAC のみ有効化読取専用 7 tool(下表)
  • トランスポートは MCP Streamable HTTP の単発 request/response モード(SSE 不使用)、JSON-RPC 2.0
  • トークン発行は管理者のみ(管理画面から。セルフ発行は Phase 2 検討)

対象外

項目理由
書込み系 tool(投稿・口コミ返信等)Phase 1 は読取専用に限定
PPTX 生成MCP サーバーはデータ提供のみ。レポート生成は AI クライアント側(#9 案件と並行・独立)
ChatGPT 対応ChatGPT コネクタは「認証なし」or「OAuth 2.1 認可サーバー」の二択で静的 Bearer トークンに未対応。OAuth 2.1 実装が必要なため Phase 2 以降
OAuth / 新規 AWS リソース / 監査 DB テーブル / キャッシュ層 / 承認フロー最小構成方針によりスコープ外
マッピーログイン回数の提供レポート項目の対象外と決定済

Phase 1 で提供する 7 tool(確定)

#tool 名データ源主要出力備考
1location_listmappy_gbp_locations (境界: mappy_integrated_gbp_locations、GROUP は mappy_group_location 経由)店舗一覧: id / title(店舗名) / address / primary_category_display_name / store_code / statusモデル GbpLocation。status は 0=normal〜6=disabled。境界は integratedLocations 準拠 (available は不採用、D-3 参照)
2review_listmappy_gbp_reviews口コミ一覧 (star_rating / comment / create_time / reviewer_display_name / reply_comment) + 集計 (件数 / 平均評価 / 評価分布 / 返信率)type=1 (REVIEW_TYPE) で必ず絞る。期間フィルタは create_time。ReviewService::getReviewCountOfLocations / getAverageRatingOfLocations / getReviewCountGroupByRating + calculateReplyRateForLocations 流用。star_rating は varchar だが数値保存済みで AVG 可
3ranking_listmappy_search_rankings JOIN mappy_keywordsキーワード別の平均検索順位・日次順位推移 (keyword 文字列 / ranking / ranking_at)ranking NULL/0/>=61 は圏外 (OUT_OF_RANGE_VALUE=61)。JOIN 時 mappy_keywords.deleted_at IS NULL (レポート互換は withTrashed)。期間列は ranking_at (IDX あり)。RankingService::getAverageRankingInPeriod / getRankingChartData 流用。search_ranking_enabled=0 のユーザーは業務エラー
4insight_summarymappy_gbp_insights期間 SUM: 表示回数 (all_views / search / map 別) / 行動数 action_count (website+route+call 内訳含む) / action_rate期間列は insight_at (unique[gbp_location_id, insight_at]、日次 1 行/店舗)。InsightService::getInsightCountOfLocations (月間レポートの正解クエリ) ほぼそのまま流用
5post_listmappy_gbp_posts投稿一覧 (title / summary / topic_type / gbp_state / create_time / gbp_search_url) + 期間投稿記事数期間列は create_time。件数集計は StatisticService::getPostOperationRanking と同形 (state フィルタなし)。gbp_state='LIVE' フィルタはオプションパラメータとして提供。現行 DownloadableReport に投稿数セクションは無く、分析(統計)機能が集計の正
6media_listmappy_gbp_media_updated_locations写真一覧 (gbp_media_url / gbp_media_thumbnail_url / category / gbp_state / created_at) + 期間投稿写真数期間列は created_at。StatisticService::getPictureOperationRanking と同形。gbp_state='LIVE' フィルタはオプション。mappy_gbp_media_schedules は予約メタであり主データ源にしない。originates_from_gbp 等の削除済み列は使用不可
7keyword_listGBP Performance API 直呼び (GET {locationName}/searchkeywords/impressions/monthly)。恒久テーブルなし月次流入キーワードと表示回数 / 上位 10 / unique 流入キーワード数KeywordService::retrieveMonthlyKeywordsImpressions + BusinessProfileApiService::getMonthlyKeywordsImpressions 流用。Google トークンは getApiUser() (root MAIN) で解決。insightsValue.value 空は threshold 値代替。mappy_report_keywords は鮮度保証のない使い捨てキャッシュのため使わない。mappy_keywords (順位計測用登録キーワード) は流入キーワードではない (ranking_list 側専用)

tool 名はアンダースコア区切りで統一する。AI クライアント側のツール名制約(Anthropic Messages API: ^[a-zA-Z0-9_-]{1,64}$)にドット入り名が適合しないため(詳細は技術設計書 §4.1)。

月間レポート必要項目とのカバレッジ

代表ユースケース(AI が月間レポートをローカル PPTX テンプレートで生成)に必要な項目は、7 tool ですべて取得できる。

月間レポート必要項目取得 tool
表示回数(検索 / マップ別含む)#4 insight_summary
行動数(Web サイト / 経路 / 電話の内訳含む)#4 insight_summary
平均検索順位#3 ranking_list
口コミ評価・評価分布・返信率#2 review_list
キーワード上位 10#7 keyword_list
流入キーワード数#7 keyword_list
投稿記事数#5 post_list
投稿写真数#6 media_list
店舗基本情報#1 location_list
マッピーログイン回数対象外(決定済)

アーキテクチャ概要

すべて既存リソースの中で完結する。新規 AWS リソースは追加しない

  • 認証: 独自テーブル mappy_mcp_tokens(SHA-256 ハッシュのみ保存、平文は発行時に一度だけ表示)+ 専用ミドルウェアによる Bearer トークン検証。Laravel 5.7 のため Sanctum は使えず、Sanctum 方式を模倣した最小実装とする
  • エンドポイント: POST /api/mappy/mcp の 1 ルートのみ。外部 MCP SDK は PHP 8.1+ 必須でインストール不能のため、自前の軽量 JSON-RPC ハンドラで実装(外部 Composer パッケージ追加なし)
  • テナンシ: トークン → ユーザー → 参照可能店舗(mappy_integrated_gbp_locations 準拠)の境界を全 tool で強制。月間自動レポートと同じスコープ解決
  • レート制限・ログ: ユーザー単位 60 req/分 + 専用ログチャネル(storage/logs/mcp-*.log)で利用状況を記録

詳細な設計判断(テーブル DDL、JSON-RPC メソッド仕様、エラー表、クライアント互換性)は 技術設計書 を参照。

利用イメージ

  1. 管理者: 管理画面 → アカウント管理 → 対象ユーザー編集 → MCPトークンタブ → 「発行」→ モーダルに一度だけ表示される平文トークンをコピーし、利用者へ安全な手段で受け渡し
  2. 利用者: 自分の AI クライアントにトークンを設定(Claude Code なら 1 コマンド)
bash
claude mcp add --transport http mappy https://gmac-g.com/api/mappy/mcp \
  --header "Authorization: Bearer <token>"
  1. 日常利用: AI に「先月の月間レポートを作って」と依頼すると、AI が location_listinsight_summaryreview_listranking_listkeyword_listpost_listmedia_list を組み合わせてデータを取得し、ローカルの PPTX テンプレートにレポートを生成する

クライアント互換性

Claude Code は標準対応(推奨・最も簡単)。Claude Desktop / claude.ai は mcp-remote プロキシ経由で接続可(クライアント PC に Node.js が必要)。ChatGPT は静的 Bearer トークン未対応のため Phase 1 では接続不可(OAuth 2.1 実装が必要、Phase 2 以降)。

画面モック

Phase 1 で追加する画面は既存ユーザー詳細画面への「MCPトークン」タブ 1 つのみ(新規独立画面なし。詳細は技術設計書 §7)。タブのインタラクティブモック(一覧 / 発行モーダル(平文一度だけ表示)/ 失効確認)は製造前レビュー時に追加予定とし、技術設計書の未確定事項(§12)で追跡する。

概算工数(AI前提)

体制

役割人数担当内容
設計者1名要件確認 → AIに設計書作成指示 → レビュー → 製造へ指示
製造者1名ISSUEを元にAIに作成指示 → コードレビュー → テスト実施 → デプロイ

工数内訳

#作業項目AIリテイクレビュー工数(人日)担当
1技術設計書レビュー・製造指示(設計書の最終確認 → 製造者への着手指示)1回0.5日/回0.5設計者
2DB・モデル(migration mappy_mcp_tokens + モデル McpToken)1回0.5日/回0.5製造者
3トークン管理 API(一覧 / 発行 / 失効の 3 本、auth:admin_api グループ)1回0.5日/回0.5製造者
4管理画面 UI(トークンタブ追加 + 平文一度だけ表示モーダル + 失効確認 + 出し分け)2回0.5日/回1.0製造者
5認証ミドルウェア(Bearer 検証 / 有効性確認 / 最終使用日時更新 / 401 応答)1回0.5日/回0.5製造者
6MCP エンドポイント(JSON-RPC 2.0 ハンドラ + ツール定義層分離 + エラー表準拠)2回0.5日/回1.0製造者
7tool 実装(DB 系 6 本 — 既存 Service 流用 + テナンシ境界 + ページング)3回0.5日/回1.5製造者
8tool 実装(API 系 1 本 — keyword_list、GBP Performance API 直呼び)1回0.5日/回0.5製造者
9env・設定(MCP_ENABLED を 4 製品 env + config、無効製品 404、ログチャネル)1回0.5日/回0.5製造者
10結合テスト(Claude Code / Claude Desktop 実接続、7 tool の tools/call 実行確認、値を管理画面表示と突合)2回0.5日/回1.0製造者
11ドキュメント(利用者向け接続手順書 + 運用手順(発行 / 失効))1回0.5日/回0.5設計者
合計8.0設計者 1.0日 / 製造者 7.0日
  • 目標レンジ 5〜8 人日内。バッファは各項目のリテイク分に内包済み(別途バッファ行は設けない)
  • 前提: PHP 7.1 互換構文 / 外部パッケージ追加なし / 既存 Service 流用のため集計ロジックの新規設計工数は含まない
  • スコープ外(工数 0): OAuth・新規 AWS リソース・監査テーブル・書込み tool・ChatGPT 対応・PPTX 生成

スケジュール

開始日は仮置き(着手日確定後に更新)。

タスク担当日数7/67/77/87/97/107/117/127/137/147/15
技術設計書レビュー・製造指示設計者1d
DB・モデル / トークン管理API製造者1d
認証ミドルウェア / env・設定製造者1d
MCPエンドポイント(JSON-RPC ハンドラ)製造者1d
tool 実装(7 tool)製造者2d
管理画面トークンUI製造者1d
接続手順書・運用手順作成設計者1d
結合テスト・実クライアント接続確認製造者1d
  • ガントチャートの最小粒度は 1 日のため、設計者タスク des1(工数内訳 #1 = 0.5 人日)と des2(工数内訳 #11 = 0.5 人日)は各 1 日枠で表示している(設計者計 1.0 人日)
  • 製造者タスク dev1〜dev6 は計 7 日 = 7.0 人日で、工数内訳の担当別合計(設計者 1.0日 / 製造者 7.0日 = 8.0 人日)と対応する

#9 レポート AI 案件との関係

本件と #9 レポート AI 案件並行・独立で進める。

  • 本件(MCP サーバー): データ提供のみ。PPTX 生成はしない
  • #9 レポート AI: レポート生成側の案件。MCP 経由のデータ取得を前提にできるが、依存関係は持たせない(どちらが先にリリースされても他方に影響しない)

リスク・未確定事項

#項目内容・対策
1Laravel 5.7 / PHP 7.1 制約外部 MCP SDK・Sanctum が使えず自前実装となる。単発 request/response モードの最小実装に絞り、ツール定義層を分離して将来の SDK 移行に備える
2AI クライアント互換性Claude Code の Authorization ヘッダ欠落の既知バグ事例があるため、結合テストでサーバーアクセスログによるヘッダ到達確認を必須とする。Claude Desktop は mcp-remote 経由(Node.js 必要)
3ChatGPT 非対応静的 Bearer トークンでは接続不可(OAuth 2.1 必須)。利用者への事前周知と手順書への明記で誤解を防ぐ
4既存 EC2 への負荷mappy_search_rankings は 1,000 万行級。ユーザー単位 60 req/分のレート制限 + 期間上限 13 ヶ月 + 既存レポートと同等クエリの流用で抑制する
5トークン運用Phase 1 は無期限トークン(発行は管理者のみ)。最終使用日時を記録し、定期棚卸し・漏洩時の即時失効を運用手順書に含める
6keyword_list の外部 API 依存GBP Performance API 直呼びのため、Google アクセストークン失効時は当該 tool のみ業務エラーとなる(他 6 tool には影響しない)

関連リンク