实战后台 MCP 03:审计日志和高风险二次确认

先理解:审计和二次确认是写操作上线前提

后台系统的写操作可能影响真实业务,例如修改订单状态、触发补偿、导出敏感数据。MCP Server 一旦开放这类能力,就必须记录谁在什么时候请求了什么,以及高风险动作是否经过确认。

本篇实现审计日志和二次确认。高风险 Tool 不直接执行,只生成确认请求。

审计日志记录什么

至少记录调用时间、用户角色、工具名、参数摘要、结果状态、风险级别。不要记录完整敏感数据,避免审计日志本身变成泄露源。

二次确认不是形式主义

二次确认让 AI 从“直接执行者”变成“操作建议者”。人类确认后再执行,能显著降低误操作风险。

本篇解决生产风险:谁让 AI 做了什么、参数是什么、结果是什么,都必须可追溯。

审计模块

src/audit.ts

ts
import { mkdirSync, appendFileSync } from "node:fs"

export function audit(event: {
  userId: string
  tool: string
  args: unknown
  result: "success" | "blocked" | "error"
  reason?: string
}) {
  mkdirSync("logs", { recursive: true })
  appendFileSync("logs/audit.jsonl", JSON.stringify({
    ...event,
    ts: new Date().toISOString(),
  }) + "\n")
}

接入普通 Tool

在 handler 中包一层:

ts
const ctx = currentContext()
try {
  requireRole(ctx, ["readonly", "operator", "admin"])
  const order = await getOrder(orderId)
  audit({ userId: ctx.userId, tool: "get_order", args: { orderId }, result: "success" })
  return { content: [{ type: "text", text: JSON.stringify(order, null, 2) }] }
} catch (err) {
  audit({ userId: ctx.userId, tool: "get_order", args: { orderId }, result: "error", reason: String(err) })
  throw err
}

高风险动作只生成确认请求

退款不要做成直接执行 Tool,而是准备确认请求:

ts
server.tool(
  "prepare_refund_request",
  "准备退款申请,不直接执行退款。返回人工确认所需信息",
  { orderId: z.string(), amount: z.number(), reason: z.string() },
  async ({ orderId, amount, reason }) => {
    const ctx = currentContext()
    requireRole(ctx, ["operator", "admin"])
    audit({
      userId: ctx.userId,
      tool: "prepare_refund_request",
      args: { orderId, amount, reason },
      result: "blocked",
      reason: "requires_manual_confirmation",
    })
    return {
      content: [{
        type: "text",
        text: JSON.stringify({
          status: "requires_manual_confirmation",
          orderId,
          amount,
          reason,
        }, null, 2),
      }],
    }
  },
)

验收

调用任意 Tool 后检查:

bash
tail -n 5 logs/audit.jsonl

每条日志应包含:

  • userId
  • tool
  • args
  • result
  • ts

高风险动作必须返回 requires_manual_confirmation,不能直接修改后台状态。

实战后台 MCP 04:本地调试、部署和灰度给运营团队
实战后台 MCP 02:增加 Resources 和权限控制