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. 設計原則
- Read-only first:v1.0 では参照のみ。書き込みは将来検討。
- User-scoped:認証トークンに紐づく
actorId(GUEST#{uuid}またはUSER#{cognitoSub})のデータのみ返す。 - Privacy-first:他人のデータには絶対にアクセスできない。
- Stateless:サーバー側で AI クライアントの会話状態を保持しない。
- Narrative over score:レポートは数値スコアではなく文章として返す(nocci の差別化②)。
- 薬機法準拠:医療的アドバイスや断定表現を含めない(後述)。
- 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 日)のログから探し、範囲内に無ければ nulllogs_since_anchor:anchor_dateより後(残量推定と同じ exclusive)の使用ログ日数。last_logged_atと同じ履歴範囲で数える。anchor_dateが null なら nullhint: ユーザーに伝える 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に同じ形)
- tools/call の params 不正:
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