Skip to content

mappy_mcp_audit_logs(MCP 監査ログ)

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

ER 図

概要

MCP サーバー経由で発生したすべての操作を記録する監査ログテーブル。読取・書込・拒否・dry_run・エラー・レート制限・OAuth イベントを漏れなく記録し、不正利用検知・障害解析・コンプライアンス対応の基礎データとする。

設計方針

  1. 全件記録: tool 呼び出しは成功/失敗を問わず全件
  2. 代理操作の追跡: user_id(実行者)と target_user_id(対象)を分離
  3. 検索性: client_id / user_id / tool_name / created_at に複合インデックス
  4. 保持期間: 標準 1 年(書込系は 3 年、要件確認次第)
  5. PII 配慮: トークン・パスワードは記録しない、コメント本文等は別ストアへ
  6. 書込頻度: 高頻度想定のため非同期書込(既存 Jobs キューを利用可)

テーブル定義

mappy_mcp_audit_logs

Noカラム名(論理)カラム名(物理)データ型NULLキー説明
1IDidbigint unsignedNOPK自動採番
2リクエスト IDrequest_idvarchar(64)NOUKULID 等の一意 ID。レスポンスにも含めユーザーが照合可能
3イベント種別event_typevarchar(64)NOIDXtool_call / oauth_authorize / oauth_token / oauth_revoke / oauth_register / rate_limit / dry_run / confirm_token_issued / confirm_token_consumed / forbidden / error
4クライアント IDclient_idvarchar(64)YESIDX, FKmappy_mcp_oauth_clients.client_id
5認証ユーザー IDuser_idbigint unsignedYESIDX, FKmappy_users.id(または admin の場合 NULL)
6認証ユーザー種別user_kindvarchar(16)YES-mappy / admin
7Admin IDadmin_idbigint unsignedYESFKadmins.id(user_kind=admin の場合)
8対象ユーザー IDtarget_user_idbigint unsignedYESIDX, FKmappy_users.id(代理操作時、通常は user_id と同じ)
9ツール名tool_namevarchar(128)YESIDXlocation.list 等。OAuth イベントは NULL
10要求スコープscope_requiredvarchar(255)YES-tool 実行に必要だった scope(カンマ区切り)
11与えられたスコープscope_grantedtextYES-アクセストークンに付与された scope(カンマ区切り)
12入力ハッシュinput_hashchar(64)YES-SHA-256(入力 JSON 正規化済み)
13入力サマリーinput_summaryjsonYES-主要パラメータのみ抜粋(PII / 大容量は除外)
14ステータスstatusvarchar(32)NOIDXsuccess / failed / forbidden / rate_limited / invalid / queued / partial
15エラーコードerror_codevarchar(64)YES-FORBIDDEN_LOCATION 等
16エラーメッセージerror_messagetextYES-詳細メッセージ
17レスポンス件数result_countintYES-リスト系 tool の返却件数
18バッチ IDbatch_idvarchar(64)YESIDX, FK非同期処理の場合 mappy_mcp_batches.batch_id
19冪等性キーidempotency_keyvarchar(64)YESIDXクライアント提供
20確認トークンconfirm_tokenvarchar(64)YES-一括反映時に発行・消費されたトークン
21dry_runis_dry_runtinyint(1)NO-0: 本実行 / 1: dry_run
22経過時間 (ms)elapsed_msint unsignedYES-tool 実行ミリ秒
23リクエスト IPrequest_ipvarchar(45)YES-IPv4/IPv6
24User-Agentuser_agentvarchar(255)YES-クライアントの UA
25セッション IDmcp_session_idvarchar(64)YESIDXStreamable HTTP セッション
26作成日時created_attimestamp(3)NOIDXミリ秒精度(同一秒の順序判定用)

インデックス

名前カラム用途
idx_audit_user_created(user_id, created_at)ユーザー別の時系列検索
idx_audit_target_created(target_user_id, created_at)代理操作監査
idx_audit_client_created(client_id, created_at)クライアント別の利用分析
idx_audit_tool_created(tool_name, created_at)ツール別の利用分析
idx_audit_status_created(status, created_at)失敗・拒否の集計
idx_audit_batch(batch_id)バッチ単位の集約
idx_audit_idempotency(idempotency_key)重複検知
idx_audit_session(mcp_session_id, created_at)セッション単位のトレース

パーティショニング

  • created_at による 月次パーティション(書込負荷分散・古いログのアーカイブ容易化)
  • 1 年経過パーティションを別 DB / S3 にアーカイブする運用を想定

mappy_mcp_batches

非同期処理(書込系 tool)の状態管理テーブル。batch.status tool の参照元。

Noカラム名(論理)カラム名(物理)データ型NULLキー説明
1IDidbigint unsignedNOPK自動採番
2バッチ IDbatch_idvarchar(64)NOUKULID。クライアントに返却
3クライアント IDclient_idvarchar(64)NOIDX, FK発行元クライアント
4ユーザー IDuser_idbigint unsignedNOIDX, FK発行ユーザー
5対象ユーザー IDtarget_user_idbigint unsignedNO-代理対応
6ツール名tool_namevarchar(128)NO-post.create 等
7ステータスstatusvarchar(32)NOIDXqueued / processing / done / partial / failed / cancelled
8入力 JSONinput_jsonjsonNO-元入力(PII配慮済み)
9対象件数target_countint unsignedNO-location_ids 等の件数
10成功件数success_countint unsignedNO-デフォルト 0
11失敗件数failure_countint unsignedNO-デフォルト 0
12失敗詳細failuresjsonYES-per-location の error_code/message
13キューイング日時queued_attimestampNO-dispatch 時刻
14開始日時started_attimestampYES-Worker pull 時刻
15完了日時completed_attimestampYES-最終ステータス確定時刻
16既存 Job IDjob_idbigint unsignedYES-jobs.id(Laravel Jobs キュー)
17冪等性キーidempotency_keyvarchar(64)YESIDXクライアント提供
18進捗 (%)progresstinyint unsignedNO-0〜100
19作成日時created_attimestampNO-レコード作成日時
20更新日時updated_attimestampNO-最終更新日時

インデックス

名前カラム
idx_batches_user_status(user_id, status)
idx_batches_client_created(client_id, created_at)
idx_batches_idempotency(user_id, idempotency_key)

mappy_mcp_rate_limit_logs(任意・Redis 補助)

レート制限ヒットの履歴。短期はカウンタ含め Redis、永続的記録は本テーブル。

Noカラムデータ型説明
1idbigint unsigned PK自動採番
2scopevarchar(64)user_per_min / client_per_hour 等
3client_idvarchar(64)該当クライアント
4user_idbigint unsigned該当ユーザー
5tool_namevarchar(128)該当ツール
6limit_valueint制限値
7observed_countint観測カウント
8retry_after_secondsintクライアントに返した retry-after
9created_attimestamp発生日時

Redis vs DB

  • カウンタ・直近の状態は Redis(高速、INCR + EXPIRE)
  • ヒット履歴の永続化と分析用に DB(非同期書込)

入力サマリーの記録方針

input_summary には PII を含めない方針で要点のみ記録する。

tool ごとのサマリー仕様

toolinput_summary に含めるもの
location.listuser_id, group_id, limit, has_filter
location.getlocation_id, include_raw
review.listuser_id, location_id, since, until, has_filter
ranking.listuser_id, location_id, since, until, aggregate, keyword (truncated 50 chars)
insight.summaryuser_id, location_id/group_id, since, until, metrics
post.createlocation_ids, target_count, has_event, has_cta, has_media, dry_run
review.replyreview_id, reply_length
media.uploadlocation_ids, target_count, media_count, total_bytes
report.createtemplate, period, group_id, location_id, include_ai_advice

PII 除外ルール

項目扱い
投稿本文 (summary)記録しない(先頭 50 文字のみ input_summary に)
口コミ返信本文 (reply)記録しない(文字数のみ)
メディア本体 (media_urls)URL のドメインのみ記録
個人情報を含む可能性のあるキーワード記録しない
アクセストークン / refresh_token / code絶対に記録しない

Audit ログにトークンを含めない

JWT の jti のみ記録、トークン本体は記録禁止。漏洩リスク対策。

レポート用集計クエリ例

① クライアント別の利用状況(直近 30 日)

sql
SELECT
  client_id,
  COUNT(*) AS total_calls,
  SUM(status = 'success') AS success_calls,
  SUM(status = 'forbidden') AS forbidden_calls,
  SUM(status = 'rate_limited') AS rate_limited_calls,
  AVG(elapsed_ms) AS avg_elapsed_ms
FROM mappy_mcp_audit_logs
WHERE event_type = 'tool_call'
  AND created_at >= NOW() - INTERVAL 30 DAY
GROUP BY client_id
ORDER BY total_calls DESC;

② ツール別の利用ランキング

sql
SELECT
  tool_name,
  COUNT(*) AS calls,
  COUNT(DISTINCT user_id) AS unique_users,
  AVG(elapsed_ms) AS avg_elapsed_ms,
  MAX(elapsed_ms) AS max_elapsed_ms
FROM mappy_mcp_audit_logs
WHERE event_type = 'tool_call'
  AND created_at >= NOW() - INTERVAL 30 DAY
  AND status = 'success'
GROUP BY tool_name
ORDER BY calls DESC;

③ 代理操作の検出

sql
SELECT
  request_id,
  user_kind,
  admin_id,
  target_user_id,
  tool_name,
  created_at
FROM mappy_mcp_audit_logs
WHERE user_kind = 'admin'
  AND target_user_id IS NOT NULL
  AND created_at >= NOW() - INTERVAL 7 DAY
ORDER BY created_at DESC;

④ 書込失敗の集計

sql
SELECT
  tool_name,
  error_code,
  COUNT(*) AS occurrences,
  MIN(created_at) AS first_seen,
  MAX(created_at) AS last_seen
FROM mappy_mcp_audit_logs
WHERE status IN ('failed', 'partial')
  AND event_type = 'tool_call'
  AND created_at >= NOW() - INTERVAL 7 DAY
GROUP BY tool_name, error_code
ORDER BY occurrences DESC;

⑤ レート制限ヒット率

sql
SELECT
  client_id,
  user_id,
  COUNT(*) AS rate_hits
FROM mappy_mcp_audit_logs
WHERE status = 'rate_limited'
  AND created_at >= NOW() - INTERVAL 24 HOUR
GROUP BY client_id, user_id
HAVING rate_hits >= 10
ORDER BY rate_hits DESC;

アラート対象(CloudWatch Alarms 等)

条件通知レベル
5 分間で同一 user_id の forbidden が 10 回以上WARNING
5 分間で同一 client_id の rate_limited が 50 回以上WARNING
1 時間で admin の代理操作が 100 件以上CRITICAL
同一 idempotency_key の衝突が 10 件以上WARNING
OAuth トークン発行失敗率 > 10%CRITICAL
平均 elapsed_ms > 3000ms (30 分平均)WARNING

データ保持・アーカイブ

データ種別保持期間アーカイブ先
audit_logs(読取系)1 年S3 Glacier
audit_logs(書込系)3 年S3 Glacier
batches3 ヶ月(done/failed)削除
batches(cancelled/partial)1 年S3
rate_limit_logs90 日削除

月次パーティションをそのままアーカイブする運用とし、削除は DROP PARTITION で実施。

容量見積もり

想定値

項目
Phase 1 のアクティブクライアント数100
1 クライアントあたり 1 日のツール呼び出し100
1 レコードのサイズ約 1 KB(input_summary 含む)

→ 1 日 10,000 レコード = 約 10 MB → 1 ヶ月 300,000 レコード = 約 300 MB → 1 年 3,650,000 レコード = 約 3.6 GB

Phase 2/3 で書込系が増えれば倍程度を想定。月次パーティションで運用十分

DDL(参考)

sql
CREATE TABLE mappy_mcp_audit_logs (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  request_id VARCHAR(64) NOT NULL,
  event_type VARCHAR(64) NOT NULL,
  client_id VARCHAR(64) DEFAULT NULL,
  user_id BIGINT UNSIGNED DEFAULT NULL,
  user_kind VARCHAR(16) DEFAULT NULL,
  admin_id BIGINT UNSIGNED DEFAULT NULL,
  target_user_id BIGINT UNSIGNED DEFAULT NULL,
  tool_name VARCHAR(128) DEFAULT NULL,
  scope_required VARCHAR(255) DEFAULT NULL,
  scope_granted TEXT DEFAULT NULL,
  input_hash CHAR(64) DEFAULT NULL,
  input_summary JSON DEFAULT NULL,
  status VARCHAR(32) NOT NULL,
  error_code VARCHAR(64) DEFAULT NULL,
  error_message TEXT DEFAULT NULL,
  result_count INT DEFAULT NULL,
  batch_id VARCHAR(64) DEFAULT NULL,
  idempotency_key VARCHAR(64) DEFAULT NULL,
  confirm_token VARCHAR(64) DEFAULT NULL,
  is_dry_run TINYINT(1) NOT NULL DEFAULT 0,
  elapsed_ms INT UNSIGNED DEFAULT NULL,
  request_ip VARCHAR(45) DEFAULT NULL,
  user_agent VARCHAR(255) DEFAULT NULL,
  mcp_session_id VARCHAR(64) DEFAULT NULL,
  created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  PRIMARY KEY (id, created_at),
  UNIQUE KEY uk_request_id (request_id),
  KEY idx_audit_user_created (user_id, created_at),
  KEY idx_audit_target_created (target_user_id, created_at),
  KEY idx_audit_client_created (client_id, created_at),
  KEY idx_audit_tool_created (tool_name, created_at),
  KEY idx_audit_status_created (status, created_at),
  KEY idx_audit_batch (batch_id),
  KEY idx_audit_idempotency (idempotency_key),
  KEY idx_audit_session (mcp_session_id, created_at)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COMMENT='MCP サーバー監査ログ'
PARTITION BY RANGE (UNIX_TIMESTAMP(created_at)) (
  PARTITION p202606 VALUES LESS THAN (UNIX_TIMESTAMP('2026-07-01')),
  PARTITION p202607 VALUES LESS THAN (UNIX_TIMESTAMP('2026-08-01')),
  PARTITION pmax VALUES LESS THAN MAXVALUE
);

CREATE TABLE mappy_mcp_batches (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  batch_id VARCHAR(64) NOT NULL,
  client_id VARCHAR(64) NOT NULL,
  user_id BIGINT UNSIGNED NOT NULL,
  target_user_id BIGINT UNSIGNED NOT NULL,
  tool_name VARCHAR(128) NOT NULL,
  status VARCHAR(32) NOT NULL DEFAULT 'queued',
  input_json JSON NOT NULL,
  target_count INT UNSIGNED NOT NULL,
  success_count INT UNSIGNED NOT NULL DEFAULT 0,
  failure_count INT UNSIGNED NOT NULL DEFAULT 0,
  failures JSON DEFAULT NULL,
  queued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  started_at TIMESTAMP NULL DEFAULT NULL,
  completed_at TIMESTAMP NULL DEFAULT NULL,
  job_id BIGINT UNSIGNED DEFAULT NULL,
  idempotency_key VARCHAR(64) DEFAULT NULL,
  progress TINYINT UNSIGNED NOT NULL DEFAULT 0,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  UNIQUE KEY uk_batch_id (batch_id),
  KEY idx_batches_user_status (user_id, status),
  KEY idx_batches_client_created (client_id, created_at),
  KEY idx_batches_idempotency (user_id, idempotency_key)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COMMENT='MCP 非同期バッチ管理';

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

#項目候補
1パーティション単位月次 / 週次(書込負荷次第)
2保持期間標準 1 年案 / 規制要件次第で延長
3アーカイブ先S3 Glacier / Athena 検索可能化
4input_summary の最大サイズ1 KB / 4 KB
5リアルタイム集計の有無Redash 等のダッシュボード化要否
6PII フィルタリングの責務MCP Server / Laravel API

関連ドキュメント