Skip to content

MCP サーバー ツールカタログ

項目内容
ステータス🟡 設計中
関連案件#13 Mappy MCP サーバー新設
親ドキュメントMCP サーバー 全体像
関連設計認証・テナンシ / 書込安全装置

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

MCP サーバーが提供する全 tool の仕様を一覧化する。 各 tool について以下を確定する:

  • 名前・説明
  • 必要 scope
  • 入力スキーマ(型・必須/任意・制約)
  • 出力スキーマ
  • 副作用(読取/書込/非同期)
  • エラー時の挙動

実装スタック(Python / TypeScript)に依存しない言語非依存の定義とする。 スキーマは JSON Schema 風で記述(Python なら Pydantic、TS なら Zod に変換)。

2. ツール命名規則

<domain>.<action>
部分
<domain>location / posts / reviews / ranking / insight / report / keyword / group / media / sms / questionnaire / sns / notification / batch
<action>list / get / create / update / delete / summary / status

: location.list, review.reply, report.create, batch.status

3. 共通仕様

3.1 共通入力パラメータ

すべての tool で以下のオプション入力を許容する:

パラメータ説明
user_idint?対象ユーザー ID(省略時は認証ユーザー自身)。supervisor admin のみ任意指定可
dry_runbool?true で実行せず、想定される副作用のサマリーを返す(書込系のみ)
idempotency_keystring?UUID 推奨。同一キーは 24h 重複拒否(書込系のみ)

3.2 共通出力ラッパー

json
{
  "data": <tool 固有のペイロード>,
  "meta": {
    "request_id": "01HVABC...",
    "elapsed_ms": 123,
    "next_cursor": "..." // ページング時
  }
}

3.3 ページング

カーソル方式を採用(offset/limit ではなく)。理由:大規模テーブル(mappy_search_rankings 1,000 万行)でも安定動作するため。

パラメータ説明
cursorstring?前ページレスポンスの next_cursor
limitint?1〜100、デフォルト 50

レスポンスの meta.next_cursornull でないなら次ページあり。

3.4 エラー形式

MCP の isError: true を返し、content[0].text に JSON でエラー詳細を載せる:

json
{
  "error_code": "FORBIDDEN_LOCATION",
  "message": "対象ロケーションへのアクセス権限がありません",
  "details": {
    "location_id": 8802,
    "user_id": 1435
  }
}

4. ツール一覧マトリクス

凡例:

  • 副作用: 🔵 読取 / 🟠 書込同期 / 🔴 書込非同期
  • Phase: 1/2/3
  • DB レート: 高負荷想定テーブル

Phase 1(MVP)— 認証 + 読取系

#tool 名副作用scopeDB 主参照説明
1location.list🔵mappy:location:readmappy_gbp_locations + mappy_user_available_gbp_locationsアクセス可能なロケーション一覧
2location.get🔵mappy:location:readmappy_gbp_locationsロケーション詳細(raw_json 含む)
3review.list🔵mappy:reviews:readmappy_gbp_reviews (28 万行)口コミ一覧
4ranking.list🔵mappy:ranking:readmappy_search_rankings (1,000 万行)検索順位
5insight.summary🔵mappy:insight:readmappy_gbp_insights (420 万行)インサイト集計

Phase 2 — 書込系拡張

#tool 名副作用scope説明
6post.list🔵mappy:posts:read投稿一覧
7post.create🔴mappy:posts:write投稿作成(複数店舗一括対応)
8post.delete🟠mappy:posts:write投稿削除
9review.reply🟠mappy:reviews:write口コミ返信
10review.template.list🔵mappy:reviews:read返信テンプレート一覧
11review.template.create🟠mappy:reviews:write返信テンプレート登録
12media.list🔵mappy:media:readメディア一覧
13media.upload🔴mappy:media:writeメディアアップロード(一括対応)
14media.delete🟠mappy:media:deleteメディア削除
15location.update🟠mappy:location:writeロケーション属性更新
16batch.status🔵(Phase 1〜認証済み)非同期処理の状態確認

Phase 3 — レポート・分析

#tool 名副作用scope説明
17report.list🔵mappy:report:readレポート一覧
18report.get🔵mappy:report:readレポート取得(HTML / PDF パス)
19report.create🔴mappy:report:writeレポート生成リクエスト
20keyword.list🔵mappy:keyword:readキーワード一覧・流入
21group.list🔵mappy:group:readグループ一覧
22group.compare🔵mappy:group:read + mappy:ranking:readグループ間の順位・インサイト比較
23questionnaire.list🔵mappy:questionnaire:readアンケート一覧
24questionnaire.answers🔵mappy:questionnaire:read回答取得
25sms.list🔵mappy:sms:readSMS ログ

5. Phase 1 ツール詳細

5.1 location.list

ユーザーがアクセス可能なロケーション一覧を返す。

scope: mappy:location:read副作用: 🔵 読取 DB: mappy_gbp_locations JOIN mappy_user_available_gbp_locations

入力スキーマ:

json
{
  "type": "object",
  "properties": {
    "user_id": { "type": "integer", "description": "対象ユーザー ID(省略時は認証ユーザー)" },
    "group_id": { "type": "integer", "description": "グループで絞り込み" },
    "store_code": { "type": "string", "description": "店舗コードで完全一致絞り込み" },
    "q": { "type": "string", "description": "店舗名の部分一致検索" },
    "cursor": { "type": "string" },
    "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }
  }
}

出力スキーマ:

json
{
  "data": {
    "locations": [
      {
        "id": 8802,
        "name": "locations/8802235673275682965",
        "title": "渋谷店",
        "address": "東京都渋谷区...",
        "store_code": "SHIBUYA001",
        "primary_category": "美容室",
        "data_source": "places_api_app",
        "new_review_uri": "https://..."
      }
    ]
  },
  "meta": { "next_cursor": "...", "request_id": "...", "elapsed_ms": 123 }
}

エラー:

code条件
FORBIDDEN_USERtarget_user_id が階層外
INVALID_GROUPgroup_id が対象ユーザーのグループでない

5.2 location.get

ロケーションの詳細情報を返す。GBP raw_json も含む(要求時)。

scope: mappy:location:read副作用: 🔵 読取

入力:

json
{
  "type": "object",
  "required": ["location_id"],
  "properties": {
    "location_id": { "type": "integer" },
    "include_raw": { "type": "boolean", "default": false, "description": "GBP raw_json を含める(大きいので明示要求のみ)" }
  }
}

出力:

json
{
  "data": {
    "id": 8802,
    "name": "locations/8802235673275682965",
    "title": "渋谷店",
    "address": "...",
    "primary_category": "美容室",
    "categories": ["美容室", "ヘアサロン"],
    "phone_numbers": ["03-1234-5678"],
    "website_uri": "https://...",
    "regular_hours": { ... },
    "latlng": { "latitude": 35.65, "longitude": 139.70 },
    "data_source": "places_api_app",
    "raw": { ... }  // include_raw=true のときのみ
  }
}

エラー:

code条件
FORBIDDEN_LOCATION対象ユーザーが location_id にアクセス不可
NOT_FOUNDlocation_id が存在しない

5.3 review.list

口コミ一覧を返す。

scope: mappy:reviews:read副作用: 🔵 読取 DB: mappy_gbp_reviews(28 万行、必ず期間絞り込み推奨)

入力:

json
{
  "type": "object",
  "properties": {
    "user_id": { "type": "integer" },
    "location_id": { "type": "integer", "description": "未指定なら全アクセス可能店舗から" },
    "since": { "type": "string", "format": "date-time", "description": "ISO8601、デフォルト過去 30 日" },
    "until": { "type": "string", "format": "date-time" },
    "min_rating": { "type": "integer", "minimum": 1, "maximum": 5 },
    "max_rating": { "type": "integer", "minimum": 1, "maximum": 5 },
    "has_reply": { "type": "boolean" },
    "cursor": { "type": "string" },
    "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }
  }
}

出力:

json
{
  "data": {
    "reviews": [
      {
        "id": 12345,
        "location_id": 8802,
        "reviewer_name": "山田 太郎",
        "rating": 5,
        "comment": "...",
        "reply_comment": "...",
        "create_time": "2026-05-01T10:00:00Z",
        "update_time": "2026-05-02T09:00:00Z"
      }
    ]
  },
  "meta": { "next_cursor": "...", ... }
}

期間制約

過去 90 日を超える期間は明示的な許可が必要(負荷対策)。未指定時は過去 30 日。

5.4 ranking.list

検索順位データを返す。

scope: mappy:ranking:read + mappy_users.search_ranking_enabled = 1副作用: 🔵 読取 DB: mappy_search_rankings(1,000 万行、期間絞り込み必須

入力:

json
{
  "type": "object",
  "required": ["since", "until"],
  "properties": {
    "user_id": { "type": "integer" },
    "location_id": { "type": "integer" },
    "keyword": { "type": "string" },
    "since": { "type": "string", "format": "date-time" },
    "until": { "type": "string", "format": "date-time" },
    "aggregate": { "type": "string", "enum": ["daily", "weekly", "raw"], "default": "daily" },
    "cursor": { "type": "string" },
    "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }
  }
}

必須制約

  • since / until 必須
  • 期間は最大 365 日
  • location_id 未指定の場合、ユーザーの全店舗を返すが、その場合は最大 100 店舗まで

出力:

json
{
  "data": {
    "rankings": [
      {
        "location_id": 8802,
        "keyword": "美容室 渋谷",
        "date": "2026-05-01",
        "rank": 3,
        "search_volume": 1234
      }
    ],
    "summary": {
      "avg_rank": 3.2,
      "best_rank": 1,
      "worst_rank": 8,
      "total_records": 1234
    }
  },
  "meta": { ... }
}

5.5 insight.summary

GBP インサイトの集計を返す。

scope: mappy:insight:read副作用: 🔵 読取 DB: mappy_gbp_insights(420 万行)

入力:

json
{
  "type": "object",
  "required": ["since", "until"],
  "properties": {
    "user_id": { "type": "integer" },
    "location_id": { "type": "integer" },
    "group_id": { "type": "integer", "description": "グループ集計" },
    "since": { "type": "string", "format": "date" },
    "until": { "type": "string", "format": "date" },
    "metrics": {
      "type": "array",
      "items": { "type": "string", "enum": ["views", "actions_website", "actions_phone", "actions_directions", "search_count"] },
      "description": "未指定なら全 metric"
    },
    "aggregate": { "type": "string", "enum": ["daily", "weekly", "monthly", "total"], "default": "monthly" }
  }
}

出力:

json
{
  "data": {
    "summary": {
      "period": { "since": "2026-04-01", "until": "2026-04-30" },
      "metrics": {
        "views": 15234,
        "actions_website": 1234,
        "actions_phone": 456,
        "actions_directions": 789,
        "search_count": 2345
      },
      "previous_period_diff": {
        "views": { "value": 1820, "percent": 13.6 }
      }
    },
    "series": [
      { "date": "2026-04-01", "views": 500, "actions_website": 40 }
    ]
  }
}

6. Phase 2 ツール詳細(抜粋)

6.1 post.create

投稿を作成する(複数店舗一括対応、非同期)。

scope: mappy:posts:write副作用: 🔴 書込非同期 DB: 既存 Jobs キュー経由 戻り値: batch_id → 状態確認は batch.status

入力:

json
{
  "type": "object",
  "required": ["location_ids", "post"],
  "properties": {
    "location_ids": {
      "type": "array",
      "items": { "type": "integer" },
      "minItems": 1,
      "maxItems": 100,
      "description": "一括対象店舗"
    },
    "post": {
      "type": "object",
      "required": ["summary"],
      "properties": {
        "summary": { "type": "string", "maxLength": 1500 },
        "topic_type": { "type": "string", "enum": ["STANDARD", "EVENT", "OFFER"] },
        "event": {
          "type": "object",
          "properties": {
            "title": { "type": "string", "maxLength": 58 },
            "start_time": { "type": "string", "format": "date-time" },
            "end_time": { "type": "string", "format": "date-time" }
          }
        },
        "call_to_action": {
          "type": "object",
          "properties": {
            "action_type": { "type": "string", "enum": ["BOOK", "ORDER", "SHOP", "LEARN_MORE", "SIGN_UP", "CALL"] },
            "url": { "type": "string", "format": "uri" }
          }
        },
        "media_urls": { "type": "array", "items": { "type": "string", "format": "uri" } }
      }
    },
    "dry_run": { "type": "boolean", "default": false },
    "idempotency_key": { "type": "string" },
    "confirm_token": { "type": "string", "description": "5 店舗超の一括反映時に必須(書込安全装置参照)" }
  }
}

出力(dry_run=false):

json
{
  "data": {
    "batch_id": "01HVABC...",
    "status": "processing",
    "queued_at": "2026-05-25T10:00:00Z",
    "target_count": 12,
    "estimated_completion_seconds": 60
  }
}

出力(dry_run=true):

json
{
  "data": {
    "would_execute": true,
    "target_locations": [...],
    "validation_warnings": [
      { "location_id": 8802, "warning": "前回投稿から 1 時間未満" }
    ]
  }
}

確認トークン必須ケース

  • location_ids の長さが 5 以上 → confirm_token 必須
  • 詳細は 書込安全装置 を参照

6.2 review.reply

口コミに返信する。

scope: mappy:reviews:write副作用: 🟠 書込同期(GBP API 経由) DB: mappy_gbp_reviews

入力:

json
{
  "type": "object",
  "required": ["review_id", "reply"],
  "properties": {
    "review_id": { "type": "integer" },
    "reply": { "type": "string", "maxLength": 4000 },
    "dry_run": { "type": "boolean", "default": false },
    "idempotency_key": { "type": "string" }
  }
}

出力:

json
{
  "data": {
    "review_id": 12345,
    "reply_comment": "...",
    "reply_at": "2026-05-25T10:00:01Z"
  }
}

6.3 batch.status

非同期処理(post.create / media.upload 等)の状態確認。

scope: ベース認証のみ(特定 scope 不要、ただし当該 batch の発行ユーザーと一致が必要) 副作用: 🔵 読取

入力:

json
{
  "type": "object",
  "required": ["batch_id"],
  "properties": {
    "batch_id": { "type": "string" }
  }
}

出力:

json
{
  "data": {
    "batch_id": "01HVABC...",
    "status": "done", // queued / processing / done / failed / partial
    "queued_at": "...",
    "started_at": "...",
    "completed_at": "...",
    "target_count": 12,
    "success_count": 11,
    "failure_count": 1,
    "failures": [
      { "location_id": 8802, "error_code": "GBP_PERMISSION_DENIED", "message": "..." }
    ]
  }
}

7. Phase 3 ツール詳細(抜粋)

7.1 report.create

レポート生成リクエスト。

scope: mappy:report:write副作用: 🔴 書込非同期 DB: mappy_reports の status/progress 内包パターンを利用

入力:

json
{
  "type": "object",
  "required": ["template", "period"],
  "properties": {
    "user_id": { "type": "integer" },
    "location_id": { "type": "integer" },
    "group_id": { "type": "integer" },
    "template": { "type": "string", "enum": ["monthly", "yearly"] },
    "period": {
      "type": "object",
      "required": ["since", "until"],
      "properties": {
        "since": { "type": "string", "format": "date" },
        "until": { "type": "string", "format": "date" }
      }
    },
    "include_ai_advice": { "type": "boolean", "default": true },
    "output_format": { "type": "string", "enum": ["html", "pdf"], "default": "html" }
  }
}

出力:

json
{
  "data": {
    "report_id": 59,
    "status": "queued",
    "estimated_completion_seconds": 30
  }
}

完了状態は report.get で確認。

7.2 report.get

レポート取得。

scope: mappy:report:read副作用: 🔵 読取

入力:

json
{
  "type": "object",
  "required": ["report_id"],
  "properties": {
    "report_id": { "type": "integer" }
  }
}

出力:

json
{
  "data": {
    "report_id": 59,
    "status": "done", // pending / processing / done / failed
    "progress": 100,
    "file_url": "https://...?signed=...",
    "format": "html",
    "generated_at": "2026-05-25T11:00:00Z",
    "ai_advice": "..."
  }
}

7.3 group.compare

グループ間の比較データを返す。

scope: mappy:group:read + mappy:ranking:read + mappy:insight:read副作用: 🔵 読取

入力:

json
{
  "type": "object",
  "required": ["group_ids", "since", "until"],
  "properties": {
    "group_ids": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 10 },
    "since": { "type": "string", "format": "date" },
    "until": { "type": "string", "format": "date" },
    "metrics": { "type": "array", "items": { "type": "string", "enum": ["avg_rank", "views", "actions"] } }
  }
}

8. レート制限・リソース保護

tool特殊制限
ranking.list期間 365 日超は拒否
review.list期間 90 日超は明示確認必要
post.createlocation_ids 5 以上で confirm_token 必須
media.upload1 リクエスト 10 メディアまで
report.create同一ユーザー 1 時間 5 回まで
batch.statusポーリング推奨間隔 5 秒、最大 1 req/sec

9. ペイロード制限

種別上限
入力 JSON サイズ256 KB
出力 JSON サイズ1 MB(超える場合はページング)
raw_json 含む output5 MB
一括対象数 (location_ids)100

10. tool description の書き方

LLM が tool を選択しやすくするため、description は以下を含める:

  1. 何をするか (1 行)
  2. いつ使うか (1〜2 行、利用シーン)
  3. 入力の必須・任意の要点
  4. 副作用の有無

例:

location.list: ユーザーがアクセス可能な店舗の一覧を返します。
店舗の検索・絞り込み・グループ別の確認に使用します。
副作用なし。user_id 省略時は認証ユーザー自身の店舗を返します。

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

#項目候補
1tool 命名のドット vs アンダースコアlocation.list / location_list(MCP 仕様では両方可)
2cursor の暗号化要否base64(JSON) / 暗号化 / 完全 opaque
3raw_json 出力時のフィルタリング機微情報除外フィルタの要否
4tool description の言語日本語 / 英語 / 両方
5一括処理の最大サイズ(100 vs 500)DB / GBP API 負荷次第
6report.get の file_url の署名期限1h / 24h / 7d
7group.compare の group_ids 上限5 / 10 / 20
8metrics の追加(CTR 等)Phase 3 以降で追加

12. 関連ドキュメント