← nocci に戻るMCP Server Spec v0.4.1

nocci MCP Server Specification (Draft v0.5)

最終更新: 2026-09-22 ステータス: Draft(実装着手) 準拠: Model Context Protocol 対応コードベース: nocci main branch (Next.js 15 + AWS CDK + DynamoDB 単一テーブル)


1. 概要

nocci MCP サーバーは、ユーザー自身の美容/ウェルネスログ(コスメ・サプリ・体調記録)を、Claude Desktop / その他 MCP 対応 AI アシスタントから安全に参照できるようにするインターフェースです。

「ユーザーが nocci に記録したデータを、ユーザーの AI アシスタントが読み取り、文脈に合った美容アドバイスや振り返りを返す」というユースケースを想定しています。

2. なぜ nocci が MCP を提供するのか

既存の美容/ウェルネスアプリは、ユーザーのデータをアプリ内に閉じ込めてきました。一方、ユーザーは Claude や ChatGPT と日常的に会話しており、そこで美容相談もしています。しかし AI アシスタントには「そのユーザーが実際に何を使い、肌の調子がどう変動したか」のコンテキストがありません。

nocci MCP は、このコンテキストの分断を解消する規格です。ユーザーがログを記録する場所(nocci)と、相談する場所(AI アシスタント)を、ユーザー自身のコントロール下で接続します。

3. 設計原則

  1. Read-only first:v1.0 では参照のみ。書き込みは将来検討。
  2. User-scoped:認証トークンに紐づく actorId(GUEST#{uuid} または USER#{cognitoSub})のデータのみ返す。
  3. Privacy-first:他人のデータには絶対にアクセスできない。
  4. Stateless:サーバー側で AI クライアントの会話状態を保持しない。
  5. Narrative over score:レポートは数値スコアではなく文章として返す(nocci の差別化②)。
  6. 薬機法準拠:医療的アドバイスや断定表現を含めない(後述)。
  7. JST 統一:日付境界はすべて JST(UTC+9)。既存実装と整合。

4. アーキテクチャ上の位置づけ

nocci の既存コードベースに対する変更点:

infra/functions/
  mcp/                       ← 新規追加
    index.ts                   MCP HTTP エンドポイント (Streamable HTTP)
    protocol.ts                JSON-RPC 2.0 ルーティング
    tools/
      get_recent_logs.ts
      get_latest_weekly_report.ts
      get_correlations.ts
      list_items.ts
  _shared/
    db.ts                    既存 listLogs / listItems / getLatestAiReport を再利用
    report.ts                既存 generateWeeklyReport を correlations 抽出に再利用
    auth.ts                  既存 verifyToken を再利用(JWT)
    rate-limit.ts            既存 isUserRateLimited を MCP にも適用

DynamoDB 側の追加は v0.1 ではなし(既存のキー設計をそのまま参照)。将来的に MCP 専用の長寿命 API キーを実装する場合は MCP_KEY#{keyHash} の SK パターンを追加。

5. 認証

v0.1: 既存 JWT を流用

ユーザーは nocci アプリ内「設定 → MCP連携」画面で自分の JWT を表示・コピーできる。AI アシスタント側の MCP クライアント設定に Authorization: Bearer <jwt> ヘッダとして貼り付け。

  • ゲストトークン(HS256):発行から 1 年間有効(issueGuestToken の挙動)
  • Cognito トークン(RS256):短命(要 refresh)。v0.1 ではゲスト想定が中心。

v1.0 以降: 専用 MCP API キー

DynamoDB に MCP_KEY#{sha256(key)} を追加し、ユーザー単位で複数発行・個別失効可能に。Authorization: Bearer mcp_<base64key> 形式。

6. エンドポイント

POST https://nocciapp.com/mcp
Transport: Streamable HTTP (MCP 標準)
Content-Type: application/json
Accept: application/json, text/event-stream

レート制限:既存 isUserRateLimited を流用(5分ウィンドウあたり 60 回)。

6.1 Claude Desktop からの接続 (mcp-remote ブリッジ)

Claude Desktop は現時点で MCP の HTTP transport を直接サポートしていないため、 mcp-remote ブリッジを介して接続する。 npx が初回実行時に自動でダウンロードするので、ユーザー側の事前準備は不要。

claude_desktop_config.json への記述例:

{
  "mcpServers": {
    "nocci": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://nocciapp.com/mcp",
        "--header",
        "Authorization: Bearer mcp_<上で発行したキー>"
      ]
    }
  }
}

設定ファイルの場所:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

将来 Claude Desktop が MCP の HTTP transport を直接サポートした時点で、 ブリッジ無しの { url, headers } 形式へ切り替え可能。サーバー側の API は変えない。

7. ツール

7.1 get_recent_logs

ユーザーが記録した最近の日次ログを返す。AI 側の文脈把握の起点。itemId は denormalize してアイテム名・種別・ブランド情報をインライン展開する(追加クエリを不要にするため)。

パラメータ:

名前 型 必須 デフォルト 説明
days integer (1–30) No 7 過去何日分
include_items boolean No true アイテム情報を denormalize するか

返り値:

{
  "generated_at": "2026-05-04T05:00:00.000Z",
  "period": { "from": "2026-04-27", "to": "2026-05-04" },
  "user_timezone": "Asia/Tokyo",
  "tier": "free",
  "logs": [
    {
      "date": "2026-05-04",
      "condition": "good",
      "skin": "good",
      "sleep": "6-7",
      "memo": "肌の調子が安定している",
      "usedItems": [
        {
          "itemId": "item_abc123",
          "name": "ビタミンC 1000mg",
          "type": "supplement",
          "brand": "Now Foods",
          "category": null,
          "timeSlots": ["morning"],
          "dose": 1,
          "doseUnit": "粒"
        }
      ]
    }
  ]
}

include_items: false の場合、usedItems は {itemId, timeSlots, dose?, doseUnit?} のみ。

enum 制約(既存スキーマと完全一致):

  • condition, skin: "good" | "ok" | "bad"
  • sleep: "<5" | "5-6" | "6-7" | "7+"
  • timeSlots[i]: "morning" | "noon" | "evening" | "night"
  • type: "cosmetic" | "supplement"
  • doseUnit: "錠" | "粒" | "包" | "ml" | "g" | "滴" | "本" | "回"

旧データの sleep: "<6" 等は DB レイヤーで <5 に自動マイグレーション済み。MCP は新形式のみを返す。

7.2 get_latest_weekly_report

直近の週次 AI レポートを返す。nocci 差別化②「narrative型レポート」をそのまま AI クライアント側にコンテキストとして渡す。

無料ユーザーは月曜生成の7日分析、有料ユーザーは日次生成の30日分析。

パラメータ:なし

返り値:

{
  "generated_at": "2026-05-04T05:00:00.000Z",
  "result_hash": "a1b2c3d4e5f60708",
  "available": true,
  "report": {
    "date": "2026-05-04",
    "periodFrom": "2026-04-28",
    "periodTo": "2026-05-04",
    "summary": "今週は肌コンディションが安定していました。睡眠時間も6時間以上を維持できた日が多めです。",
    "insights": [
      "今週7日中5日、睡眠が6時間以上でした",
      "ビタミンB群を毎日摂取できていた一週間でした"
    ],
    "advice": "来週も現在の睡眠リズムを継続できると良さそうです。",
    "suggestions": [
      {
        "careCategory": "保湿ケア",
        "logBasis": "今週7日中5日肌がgoodだったので、来週は保湿の継続にも注目できそうです",
        "label": "参考情報"
      }
    ],
    "generatedAt": "2026-05-04T03:00:00.000Z",
    "model": "claude-haiku-4-5-20251001"
  },
  "tier": "free"
}

未生成の場合 (available: false のときは result_hash を含めない):

{
  "generated_at": "2026-05-04T05:00:00.000Z",
  "available": false,
  "reason": "not_generated",
  "tier": "free"
}

AI クライアントへの注意:

  • suggestions[].careCategory はスキンケアカテゴリのみ。サプリ・成分名・商品名は含まれない。
  • suggestions[].label は常に "参考情報" 固定。
  • このデータを引用する際、AI クライアント側は断定表現に変換しない。

7.3 get_correlations

ログから観察される睡眠と体調の傾向を返す。

検出される傾向は以下の1種:

  • 睡眠(<5h)× 全体コンディション

アイテム(コスメ・サプリ)の使用と肌・体調を結ぶ傾向は返さない。

検出には最低 3 日以上の記録と、絶対差 25 % 以上が必要。

パラメータ:

名前 型 必須 デフォルト 説明
days integer (1–14) No 7 観察期間
min_confidence enum No "low" "low" / "medium" / "high" 以上を返す

返り値:

{
  "generated_at": "2026-05-04T05:00:00.000Z",
  "result_hash": "a1b2c3d4e5f60708",
  "observation_period": { "from": "2026-04-28", "to": "2026-05-04" },
  "days_recorded": 6,
  "correlations": [
    {
      "title": "睡眠が短い日にコンディションが低め",
      "body": "5時間未満の日は67%が不調(3日中2日)、それ以外は20%(5日中1日)でした。",
      "confidence": "medium"
    }
  ],
  "disclaimer": "観察的傾向であり因果関係を示すものではありません。記録日数が少ない場合は精度が下がります。"
}

7.4 list_items

ユーザーの登録アイテム(コスメ・サプリ)の一覧を返す。AI クライアントが「あなたのスタックは何?」のような質問に即答できるようにする。get_recent_logs の補助的役割。

パラメータ:

名前 型 必須 デフォルト 説明
type enum No 全種別 "cosmetic" または "supplement"
include_archived boolean No false isActive: false のアイテムも含める

返り値:

{
  "generated_at": "2026-05-04T05:00:00.000Z",
  "items": [
    {
      "itemId": "item_abc123",
      "name": "ビタミンC 1000mg",
      "type": "supplement",
      "category": null,
      "brand": "Now Foods",
      "isActive": true,
      "pinned": true,
      "defaultDose": 1,
      "doseUnit": "粒",
      "notes": "朝食後に摂取",
      "startDate": "2026-02-01",
      "reminder_times": ["08:00"],
      "low_stock_notify": false
    }
  ]
}
  • reminder_times: 通知時刻("HH:MM"・時刻順、未設定は [])。set_reminder が置き換えのため、呼ぶ前に現在値を確認する用
  • low_stock_notify: 「なくなりそう」通知がオンか(未設定は false)。set_reminder の low_stock_notify を切り替える前に確認する用

意図的に除外するフィールド:生の reminderTimes({hour, minute})、janCode、PK/SK/createdAt/updatedAt。

7.5 add_item(write)

サプリ・コスメを新規登録する write ツール。log_today の前段として、AI との会話だけで「登録 → 記録」を完結させる。 在庫(使用中アイテム)の記録専用であり、商品の推奨には使わない。必須 scope は write:nocci。

パラメータ(snake_case。未知キーは拒否):

名前 型 必須 デフォルト 説明
name string (1〜100) Yes — アイテム名。前後空白は除去して保存
type enum Yes — "supplement" または "cosmetic"
dose_unit enum No — 錠 / 粒 / 包 / ml / g / 滴 / 本 / 回。supplement のみ
default_dose number (0 < x ≤ 99999) No — 1 回あたりの既定量。supplement のみ
pinned boolean No false 習慣サプリとしてピン留め。supplement のみ
notes string (≤ 500) No — メモ
barcode string (^\d{8,13}$) No — janCode として保存するのみ(商品検索はしない)
  • cosmetic に pinned: true / dose_unit / default_dose を指定すると validation_failed(pinned: false は可)
  • dose 系はユーザーが明示した値のみ設定する(AI が推測・計算しない)

冪等性:アクティブ(isActive !== false)なアイテムのうち、名前を trim → NFKC → 小文字化した値が一致するものがあれば、 新規作成せず既存アイテムを created: false で返す(他の引数は適用せず、監査エントリも記録しない)。 アーカイブ済みの同名は一致対象外。同義語(鉄 / 鉄分 / Iron)の判定は行わないため、AI クライアントは必要に応じて list_items で確認する。

上限:アクティブ・アーカイブ済み含め 50 件(アプリの POST /items と同じ)。超過時は validation_failed。

返り値:

{
  "generated_at": "2026-09-22T05:00:00.000Z",
  "created": true,
  "item": {
    "itemId": "4f0c…",
    "name": "ビタミンC",
    "type": "supplement",
    "category": null,
    "brand": null,
    "isActive": true,
    "pinned": false,
    "defaultDose": null,
    "doseUnit": null,
    "notes": null,
    "startDate": "2026-09-22"
  },
  "first_ingredient_card": { "name": "ビタミンC", "category": "…", "description": "…" },
  "next_step_hint": "アイテムを登録しました。…"
}
  • item は list_items と同じ整形
  • first_ingredient_card は「この作成がユーザーの 1 件目」かつ supplement かつ成分辞書に一致したときのみ付与(アプリの初回登録と同じ条件)
  • 新規作成時は監査エントリ(tool: "add_item", before: null)を記録。設定の「AIによる書き込み履歴」から 7 日以内に取り消せる (取り消し = アイテム削除。作成後にアプリ等で変更されていた場合は取り消し不可)。 そのアイテムを使った記録(log_today 等)は削除されず残る

7.5a set_reminder(write)

登録済みアイテムの通知時刻(reminderTimes)を置き換え、あわせて「なくなりそう」通知(lowStockNotify)を on/off する。本節は low_stock_notify の追加(2026-09-27)にあわせて新設した。時刻の検証・置き換えの詳細は mcp/tools/set_reminder.ts のコメントを正とする。

パラメータ:

名前 型 必須 説明
item_id string Yes 対象アイテム(list_items で取得)
times string[] Yes 変更後の通知時刻の全リスト(置き換え)。JST・15 分刻み・最大 4 件。[] で全解除。通知だけ変えるときは list_items の reminder_times をそのまま渡す
low_stock_notify boolean No 「なくなりそう」通知の on/off。省略時は変更しない

low_stock_notify の規則:

  • true にできるのは推定の根拠(内容量 / 期間 / 買い足し記録)があるアイテムだけ。無ければ VALIDATION_FAILED
  • 現在値と同じなら、その項目は変更扱いにしない(時刻も同じなら changed: false で書き込み・監査なし)
  • Free は 1 アイテムまで(last-set wins)。true にしたとき他の通知オンのアイテムを外し、その名前を low_stock_notify_replaced で返す。Premium は外さない
  • 時刻と通知の変更は 1 回の putItem・1 件の監査にまとめる。lowStockNotifiedFor(既送キー)は触らない
  • 監査の undo は対象アイテムの before スナップショットを戻すだけ。Free の 1 アイテム制限で外れた他アイテムの通知は undo しても戻らない(API の PUT /items と同じ挙動)

返り値(抜粋):changed / push_enabled / previous_reminder_times / reminder_times / added_times / removed_times / low_stock_notify(変更後)/ previous_low_stock_notify / low_stock_notify_replaced(Free で外れたアイテム名。無ければ [])/ next_step_hint

通知が送られる条件(残日数・買い足し周期)は docs/inventory-design.md §10e を参照。

7.5b get_replenishment_forecast(read)

アイテムごとの残量めやす・買い足し周期・次の買い足しめやすを構造化して返す。nocci は数字と根拠だけを出し、買うか・いつ買うかの判断は AI とユーザー側に返す。推定は GET /items と同じ withInventoryEstimates(docs/inventory-design.md §4b / §9 / §10)。LLM は使わないので全プランで使える。

パラメータ:

名前 型 必須 デフォルト 説明
item_id string No 全件 1 件だけ返す。存在しなければ ITEM_NOT_FOUND。指定したときはアーカイブ済みでも返す
include_archived boolean No false アーカイブ済みも含める(残量の推定は付かず、basis: null。買い足しの記録だけが入る)

返り値:

{
  "generated_at": "2026-09-27T05:00:00.000Z",
  "today": "2026-09-27",
  "timezone": "Asia/Tokyo",
  "items": [
    {
      "item_id": "low",
      "name": "ビタミンC",
      "type": "supplement",
      "is_active": true,
      "basis": "amount",
      "remaining": 10,
      "estimated_days_left": 5,
      "estimated_run_out_date": "2026-10-02",
      "anchor_date": "2026-09-01",
      "is_cold_start": false,
      "restock_count": 0,
      "last_restock_at": null,
      "restock_cycle_days": null,
      "next_restock_estimate": null,
      "status": "low_stock",
      "jan_code": "4901234567894",
      "low_stock_notify": true,
      "last_logged_at": "2026-09-26",
      "logs_since_anchor": 25,
      "hint": null
    }
  ],
  "note": "すべて記録から計算しためやすです。nocci は良し悪しや購入の判断をしません。"
}
  • basis: "amount"(量ベース)/ "duration"(期間ベース)/ null(内容量も期間も無い・アーカイブ済み)
  • remaining: 量ベースのみ。負値は要補正
  • estimated_days_left: 負値は要補正(期間ベースのめやす超過)
  • estimated_run_out_date: today + estimated_days_left(0 以上のときだけ)
  • restock_count / last_restock_at / restock_cycle_days: 買い足しの記録から(restocks が無ければ 0 / null / null)
  • next_restock_estimate: last_restock_at + restock_cycle_days(両方あるときだけ)
  • last_logged_at: そのアイテムの最終使用ログ日。プランの履歴範囲内(Free 90 日 / Premium 180 日)のログから探し、範囲内に無ければ null
  • logs_since_anchor: anchor_date より後(残量推定と同じ exclusive)の使用ログ日数。last_logged_at と同じ履歴範囲で数える。anchor_date が null なら null
  • hint: ユーザーに伝える 1 文。ok / low_stock / restock_due は null(下の表)
  • jan_code: 商品の同一性のために返す(将来の補充導線で同じ商品を指すための識別子。list_items では意図的に除外しているが、JAN は商品コードであり個人情報ではない)

status の定義(forecastStatus・上から順に判定):

status 条件
needs_correction estimated_days_left < 0(めやすがずれている。アプリで残量の補正を促す)
low_stock 0 <= estimated_days_left <= 14
restock_due 前回の買い足し + 周期 が今日から min(14, 周期/2) 日以内(過ぎていても可)。restockDueDate
no_rate 量ベースで remaining(0 以上)は出せるが、消費ペースが出せず estimated_days_left が null(直近の使用ログが無いなど)。remaining は anchor_date 時点の値で、実際はそれより減っている可能性がある
no_basis 推定の根拠(basis)も買い足しの記録も無い
ok 上のどれにも当たらない

hint:

status hint
no_basis 現在の残量をアプリで入力すると、残りのめやすを計算できます
no_rate(logs_since_anchor が 0 / null) {M/D}以降の使用記録がないため、残量は{M/D}時点のめやすです。記録を続けると残り日数を計算できます
no_rate(logs_since_anchor > 0) 記録がまだ少ないため、残量は{M/D}時点のめやすです。記録を続けると残り日数を計算できます
needs_correction 残量のめやすがずれている可能性があります。アプリで現在の残量を直してください
その他 null

{M/D} は anchor_date の月/日(例: 9/21)。

並び:low_stock → restock_due → needs_correction → no_rate → ok → no_basis。同じ status の中は estimated_days_left の小さい順、無ければ後ろで name 順。

禁止事項:購入 URL・商品や店の提案・価格は返さない。「そろそろ買いましょう」のような促しや、めやすを効果・体の変化と結びつける文言は返さない。読み取り専用(書き込み・監査なし)。

7.6 AI クライアント向け補足: generated_at と result_hash の使い方

すべてのツールのレスポンス最上位に generated_at (ISO8601) が含まれます。これはサーバーが レスポンスを組み立てた時刻で、レイテンシ計測やログ用途を想定しています。

加えて get_correlations と get_latest_weekly_report(available: true のとき)は result_hash を返します。これは結果本体の SHA-256 ハッシュ先頭 16 文字(64bit)で、 generated_at の時刻揺れの影響を受けません。サーバー側に格納されているデータが 変わらない限り、何度呼んでも同じ値が返ります。

推奨される使い方:

同じ会話内で同じツールが繰り返し呼ばれた場合、AI クライアントは前回のレスポンスと result_hash を比較することで、結果が変わっていないかを O(1) で判定できます。 同一の場合、再呼び出しせず前回の結果を再利用することで、ユーザー体験の冗長性と レイテンシを改善できます。

result_hash は generated_at の時刻揺れの影響を受けないため、サーバー側で同じデータが 格納されている限り同じ値を返します。

list_items と get_recent_logs には result_hash を付けていません。前者は 個人情報的な内容を含み AI クライアント側のキャッシュ滞留を抑えたいため、後者は 日付計算の都合上「同じ呼び出しでも翌日には別結果」になりやすいためです。

8. エラーハンドリング

MCP 標準のエラーコードに加え、以下を定義:

コード 意味
INSUFFICIENT_DATA 分析に必要なログ件数(最低 3 日)に達していない
RATE_LIMITED 5分ウィンドウあたりの上限を超過
INVALID_TOKEN JWT または API キーが無効・失効
REPORT_NOT_GENERATED AI レポートがまだ生成されていない

8.1 エラーの返し方(tools/call)

MCP 仕様に合わせ、ツールの実行エラーとプロトコル層のエラーで返し方を分ける。

  • ツールの実行エラー → success レスポンスの result に isError: true を付けて返す(HTTP 200)。 対象: item_not_found / invalid_enum_value / validation_failed(引数の ZodError を含む)/ rate_limited(search_products の検索上限)/ not_configured / internal_error
    {
      "jsonrpc": "2.0", "id": 1,
      "result": {
        "isError": true,
        "content": [{ "type": "text", "text": "{\"error\":\"validation_failed\",\"message\":\"...\",\"suggestion\":\"...\"}" }],
        "structuredContent": { "error": "validation_failed", "message": "...", "suggestion": "..." }
      }
    }
    
    content[0].text(JSON 文字列)と structuredContent は同じ { error, message, suggestion }。 Claude のクライアントは JSON-RPC の error.data をモデルに渡さないため、suggestion を届けるにはこの形が必要。
  • プロトコル層のエラー → 従来どおり JSON-RPC error。
    • tools/call の params 不正: -32602
    • 未知のツール: -32601
    • scope_missing: -32001(error.data に { error, message, suggestion }。HTTP 403)
    • executor が投げた auth_required: -32001(error.data に同じ形)

9. 薬機法・コンテンツ安全性に関する制約

nocci は美容/ウェルネスアプリとして、薬機法および景品表示法を遵守した表現ルールを内部で定めています。MCP 経由でデータを取得する AI クライアントも、以下の制約を理解した上で扱う必要があります:

  • レポート・相関の本文にサプリメント・成分名の推奨は含まれない
  • スキンケアの suggestions はカテゴリ名のみ(例:「保湿ケア」「日焼け止め」)
  • 断定表現(「〜の原因です」「使わないでください」等)は使わない

10. ライセンス

  • 本仕様ドキュメント:CC0 / Public Domain
  • サーバー実装コード:クローズド
  • 本番 MCP エンドポイント利用:nocci 利用規約に準拠

11. 変更履歴

日付 バージョン 変更内容
2026-09-27 0.6.2 get_replenishment_forecast に status no_rate と last_logged_at / logs_since_anchor / hint を追加(§7.5b)。last_logged_at / logs_since_anchor はプランの履歴範囲(Free 90 日)に揃え、no_rate の hint はアンカー後の使用ログの有無で 2 通りにする。
2026-09-27 0.6.1 §7.5a に undo の注記、§7.5b に jan_code の説明を追記。
2026-09-27 0.6 read ツール get_replenishment_forecast(残量・買い足し周期のめやす)を追加(§7.5b)。
2026-09-27 0.5.2 set_reminder に low_stock_notify(「なくなりそう」通知の on/off)を追加し §7.5a を新設。list_items の返り値に low_stock_notify を追加(§7.4。あわせて既存の reminder_times も記載)。
2026-09-26 0.5.1 ツールの実行エラーを JSON-RPC error ではなく isError: true の結果で返すよう変更(§8.1)。
2026-09-22 0.5 write ツール add_item を追加(§7.5)。旧 §7.5 は §7.6 に繰り下げ。
2026-09-02 0.4.2 tools/call 計測ログに ua / st を追加。§12 に CloudWatch Logs Insights の集計クエリを追記。
2026-05-04 0.4.1 Claude Desktop 接続には mcp-remote ブリッジが必要であることを明記。§6 に接続例を追記。
2026-05-04 0.4 全ツールに generated_at、get_correlations と get_latest_weekly_report に result_hash を追加。AI クライアントによる結果キャッシュ判定を可能に。
2026-05-04 0.3 4ツール構成で確定

付録: 実装メモ

  • get_recent_logs の tier は getProfile(actorId).entitlements.premium から導出
  • get_latest_weekly_report は既存 getLatestAiReport(actorId) をそのまま使う
  • get_correlations は listLogs + listItems → generateWeeklyReport → report.insights をマップ
  • list_items は既存 listItems(actorId) をそのまま使い、isActive でフィルタ + 不要フィールド除去
  • 認証は既存 verifyToken → toActorId の流れに乗せる
  • JST 日付計算は const jstNow = new Date(Date.now() + 9 * 60 * 60 * 1000)

12. 計測(CloudWatch Logs Insights)

MCP サーバー (Lambda BeautyMvpStack-Mcp*) は tools/call 1 回につき 1 行の JSON ログを標準出力に書く。 ロググループは Mcp Lambda の既定のもの(/aws/lambda/BeautyMvpStack-Mcp<hash>、Lambda コンソールまたは aws lambda list-functions で BeautyMvpStack-Mcp を前方一致検索して特定する)。

ログ行のフィールド

{"evt":"mcp_tool_call","tool":"get_recent_logs","actor":"USER#abc","ms":123,"ok":true,"empty":false,"ua":"claude-desktop/1.2.3","st":"ok"}
フィールド 型 意味
evt string 固定値 "mcp_tool_call"。フィルタキー
tool string 呼び出されたツール名
actor string 実行主体 (GUEST#… / USER#…)
ms number ツール実行時間 (ミリ秒)
ok boolean 成功なら true、例外で失敗なら false
empty boolean | null 主要配列 (logs / items / correlations) が空なら true。主要配列を持たないツールと失敗時は null
ua string | null リクエストの User-Agent 先頭 80 文字。ヘッダ欠落時は null
st string | null 結果オブジェクトの文字列 status (例: get_recent_logs の ok / no_logs_yet / freshly_connected)。status を持たないツール (log_today 等) と失敗時は null

evt 〜 empty の名前・型・順序は保存済みクエリとの互換性のため変更しない。フィールドを増やす場合は末尾に追加する。

クエリ 1: tool 別 呼び出し回数・ユニークユーザー・エラー率

# 対象期間はコンソール / CLI の実行時に指定する
fields @timestamp, tool, actor, ok
| filter evt = "mcp_tool_call"
| stats count() as calls, count_distinct(actor) as unique_users, avg(ok = 0) as error_rate by tool
| sort calls desc

クエリ 2: tool 別 empty 率(status の内訳つき)

# 対象期間はコンソール / CLI の実行時に指定する
fields tool, empty, st
| filter evt = "mcp_tool_call" and ok = 1
| stats count() as calls, sum(empty) as empty_calls by tool, st
| sort tool, calls desc

クエリ 3: クライアント別 利用状況(ua 別)

# 対象期間はコンソール / CLI の実行時に指定する
fields ua, tool
| filter evt = "mcp_tool_call"
| stats count() as calls, count_distinct(actor) as unique_users by ua
| sort calls desc

本仕様ドキュメントはCC0 / Public Domainで公開されています。自由に参照・引用・実装可能です。

Last updated: 2026-09-22