Skip to content

mappy_mcp_audit_logs (Audit log MCP)

MụcNội dung
Trạng thái🟡 Đang thiết kế
Case liên quan#13 MCP Server (Thiết lập mới)
Tài liệu chaMCP Server (Tổng thể)
Design liên quanAuth & Tenancy / Cơ chế an toàn write

ER diagram

Tổng quan

Bảng audit log ghi lại toàn bộ thao tác phát sinh qua MCP Server. Read・Write・từ chối・dry_run・lỗi・rate limit・OAuth event đều được ghi không sót, làm dữ liệu nền tảng cho phát hiện lạm dụng・phân tích sự cố・đáp ứng compliance.

Phương châm thiết kế

  1. Ghi toàn bộ: tool call dù thành công/thất bại đều ghi
  2. Theo dõi thao tác thay mặt: tách biệt user_id (người thực thi) và target_user_id (đối tượng)
  3. Tính tìm kiếm: index tổ hợp trên client_id / user_id / tool_name / created_at
  4. Thời gian giữ: chuẩn 1 năm (write 3 năm, tùy yêu cầu)
  5. Cân nhắc PII: không ghi token・password, comment body lưu vào store riêng
  6. Tần suất ghi: ghi async dự kiến vì tần suất cao (có thể tận dụng Jobs queue hiện có)

Định nghĩa bảng

mappy_mcp_audit_logs

NoTên cột (logical)Tên cột (physical)KiểuNULLKeyMô tả
1IDidbigint unsignedNOPKAuto increment
2Request IDrequest_idvarchar(64)NOUKID duy nhất kiểu ULID. Có cả trong response, user đối chiếu được
3Loại eventevent_typevarchar(64)NOIDXtool_call / oauth_authorize / oauth_token / oauth_revoke / oauth_register / rate_limit / dry_run / confirm_token_issued / confirm_token_consumed / forbidden / error
4Client IDclient_idvarchar(64)YESIDX, FKmappy_mcp_oauth_clients.client_id
5User auth IDuser_idbigint unsignedYESIDX, FKmappy_users.id (hoặc NULL khi là admin)
6Loại user authuser_kindvarchar(16)YES-mappy / admin
7Admin IDadmin_idbigint unsignedYESFKadmins.id (khi user_kind=admin)
8User đối tượng IDtarget_user_idbigint unsignedYESIDX, FKmappy_users.id (khi thao tác thay mặt, thường giống user_id)
9Tên tooltool_namevarchar(128)YESIDXlocation.list v.v. OAuth event = NULL
10Scope yêu cầuscope_requiredvarchar(255)YES-Scope cần để chạy tool (cách bằng dấu phẩy)
11Scope được cấpscope_grantedtextYES-Scope gắn vào access token (cách bằng dấu phẩy)
12Hash inputinput_hashchar(64)YES-SHA-256(input JSON đã chuẩn hóa)
13Tóm tắt inputinput_summaryjsonYES-Chỉ trích các tham số chính (loại trừ PII / dữ liệu lớn)
14Statusstatusvarchar(32)NOIDXsuccess / failed / forbidden / rate_limited / invalid / queued / partial
15Error codeerror_codevarchar(64)YES-FORBIDDEN_LOCATION v.v.
16Error messageerror_messagetextYES-Message chi tiết
17Số lượng responseresult_countintYES-Số dòng trả về của list tool
18Batch IDbatch_idvarchar(64)YESIDX, FKTrường hợp xử lý bất đồng bộ: mappy_mcp_batches.batch_id
19Idempotency keyidempotency_keyvarchar(64)YESIDXClient cung cấp
20Confirm tokenconfirm_tokenvarchar(64)YES-Token đã phát・tiêu thụ khi áp dụng hàng loạt
21dry_runis_dry_runtinyint(1)NO-0: thực thi / 1: dry_run
22Thời gian thực thi (ms)elapsed_msint unsignedYES-Mili-giây thực thi tool
23Request IPrequest_ipvarchar(45)YES-IPv4/IPv6
24User-Agentuser_agentvarchar(255)YES-UA của client
25Session IDmcp_session_idvarchar(64)YESIDXSession Streamable HTTP
26Created atcreated_attimestamp(3)NOIDXĐộ chính xác mili-giây (để sắp xếp trong cùng giây)

Index

TênCộtMục đích
idx_audit_user_created(user_id, created_at)Tìm theo thời gian theo user
idx_audit_target_created(target_user_id, created_at)Audit thao tác thay mặt
idx_audit_client_created(client_id, created_at)Phân tích sử dụng theo client
idx_audit_tool_created(tool_name, created_at)Phân tích sử dụng theo tool
idx_audit_status_created(status, created_at)Tổng hợp thất bại・từ chối
idx_audit_batch(batch_id)Tổng hợp theo batch
idx_audit_idempotency(idempotency_key)Phát hiện duplicate
idx_audit_session(mcp_session_id, created_at)Trace theo session

Partitioning

  • Partition tháng theo created_at (phân tán tải ghi・dễ archive log cũ)
  • Vận hành dự kiến: archive partition đã quá 1 năm sang DB khác / S3

mappy_mcp_batches

Bảng quản lý trạng thái xử lý bất đồng bộ (write tool). Là nguồn tham chiếu của tool batch.status.

NoTên cột (logical)Tên cột (physical)KiểuNULLKeyMô tả
1IDidbigint unsignedNOPKAuto increment
2Batch IDbatch_idvarchar(64)NOUKULID. Trả về client
3Client IDclient_idvarchar(64)NOIDX, FKClient phát hành
4User IDuser_idbigint unsignedNOIDX, FKUser phát hành
5User đối tượng IDtarget_user_idbigint unsignedNO-Cho thao tác thay mặt
6Tên tooltool_namevarchar(128)NO-post.create v.v.
7Statusstatusvarchar(32)NOIDXqueued / processing / done / partial / failed / cancelled
8JSON inputinput_jsonjsonNO-Input gốc (đã cân nhắc PII)
9Số lượng đối tượngtarget_countint unsignedNO-Số location_ids v.v.
10Số thành côngsuccess_countint unsignedNO-Mặc định 0
11Số thất bạifailure_countint unsignedNO-Mặc định 0
12Chi tiết thất bạifailuresjsonYES-error_code/message theo location
13Thời điểm queuequeued_attimestampNO-Lúc dispatch
14Thời điểm bắt đầustarted_attimestampYES-Lúc Worker pull
15Thời điểm hoàn thànhcompleted_attimestampYES-Lúc chốt status cuối
16Job ID hiện cójob_idbigint unsignedYES-jobs.id (Laravel Jobs queue)
17Idempotency keyidempotency_keyvarchar(64)YESIDXClient cung cấp
18Progress (%)progresstinyint unsignedNO-0〜100
19Created atcreated_attimestampNO-Thời điểm tạo record
20Updated atupdated_attimestampNO-Thời điểm update cuối

Index

TênCột
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 (tùy chọn・bổ trợ Redis)

Lịch sử hit rate limit. Counter và trạng thái ngắn hạn ở Redis, ghi persistent ở bảng này.

NoCộtKiểuMô tả
1idbigint unsigned PKAuto increment
2scopevarchar(64)user_per_min / client_per_hour v.v.
3client_idvarchar(64)Client tương ứng
4user_idbigint unsignedUser tương ứng
5tool_namevarchar(128)Tool tương ứng
6limit_valueintGiá trị giới hạn
7observed_countintCount quan sát
8retry_after_secondsintretry-after trả cho client
9created_attimestampThời điểm phát sinh

Redis vs DB

  • Counter・trạng thái gần đây ở Redis (nhanh, INCR + EXPIRE)
  • DB dùng cho persist và phân tích lịch sử hit (ghi async)

Phương châm ghi tóm tắt input

input_summary không bao gồm PII, chỉ ghi các điểm chính.

Spec tóm tắt theo từng tool

toolBao gồm trong input_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

Quy tắc loại trừ PII

MụcCách xử lý
Body post (summary)Không ghi (chỉ ghi 50 ký tự đầu vào input_summary)
Body trả lời review (reply)Không ghi (chỉ ghi số ký tự)
Bản thân media (media_urls)Chỉ ghi domain của URL
Keyword có thể chứa thông tin cá nhânKhông ghi
Access token / refresh_token / codeTuyệt đối không ghi

Không bao gồm token trong audit log

Chỉ ghi jti của JWT, cấm ghi token body. Đối phó rủi ro rò rỉ.

Ví dụ query tổng hợp cho report

① Tình hình sử dụng theo client (30 ngày gần nhất)

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;

② Ranking sử dụng theo tool

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;

③ Phát hiện thao tác thay mặt

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;

④ Tổng hợp thất bại write

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;

⑤ Tỷ lệ hit rate limit

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;

Đối tượng alert (CloudWatch Alarms v.v.)

Điều kiệnMức thông báo
5 phút có ≥ 10 forbidden của cùng user_idWARNING
5 phút có ≥ 50 rate_limited của cùng client_idWARNING
1 giờ có ≥ 100 thao tác thay mặt của adminCRITICAL
≥ 10 xung đột cùng idempotency_keyWARNING
Tỷ lệ phát OAuth token thất bại > 10%CRITICAL
Trung bình elapsed_ms > 3000ms (trung bình 30 phút)WARNING

Giữ・archive data

Loại dataThời gian giữNơi archive
audit_logs (read)1 nămS3 Glacier
audit_logs (write)3 nămS3 Glacier
batches3 tháng (done/failed)Xóa
batches (cancelled/partial)1 nămS3
rate_limit_logs90 ngàyXóa

Vận hành dạng archive partition tháng nguyên si, xóa bằng DROP PARTITION.

Ước lượng dung lượng

Giá trị giả định

MụcGiá trị
Số client active Phase 1100
Số tool call / client / ngày100
Size 1 recordKhoảng 1 KB (bao gồm input_summary)

→ 10,000 record/ngày = khoảng 10 MB → 300,000 record/tháng = khoảng 300 MB → 3,650,000 record/năm = khoảng 3.6 GB

Phase 2/3 write tăng thì dự kiến gấp đôi. Vận hành partition tháng là đủ.

DDL (tham khảo)

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 Server audit log'
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 quản lý batch bất đồng bộ';

Điểm chưa chốt (quyết định tại review design)

#MụcPhương án
1Đơn vị partitionTháng / Tuần (tùy tải ghi)
2Thời gian giữChuẩn 1 năm / kéo dài tùy yêu cầu pháp lý
3Nơi archiveS3 Glacier / Cho phép search bằng Athena
4Size tối đa input_summary1 KB / 4 KB
5Có tổng hợp realtime khôngCó cần dashboard Redash v.v. không
6Trách nhiệm filter PIIMCP Server / Laravel API

Tài liệu liên quan