返回 AICAP-180
B6 · Day 56真 MCP server (2026-07-28 spec)

迁移 AML 工具集上网

B6 从 Day 51 的规范精读、Day 52 的官方 TS SDK 起步、Day 53 的 Zod schema、Day 54-55 的 tools/list/tools/call 网络语义一路铺到今天——前 5 天我们都在「用一个玩具工具(assessTypology)练管线」,今天第一次把真业务能力(仓库里已存在的 AML 三件套)按 MCP 契约拆成 3 个工具暴露上网。这是 B6 从「

阶段: B6 · 真 MCP server (2026-07-28 spec)(Day 51-60) 标签: #mcp #aml-copilot #tool-contract #hitl

今日导引(由浅入深)

B6 从 Day 51 的规范精读、Day 52 的官方 TS SDK 起步、Day 53 的 Zod schema、Day 54-55 的 tools/list/tools/call 网络语义一路铺到今天——前 5 天我们都在「用一个玩具工具(assessTypology)练管线」,今天第一次把真业务能力(仓库里已存在的 AML 三件套)按 MCP 契约拆成 3 个工具暴露上网。这是 B6 从「协议练习」转向「把作品②变成可被任意 MCP 客户端调用的服务」的转折点。承接 Day 53「以 Zod 为单一真相源」,今天把单工具扩成工具;明天(Day 57)让 DeepSeek-V3 当客户端真去调它们。今日「最小可判定产出」:3 个 AML 工具在 MCP Inspector 里逐个 tools/call 调通(git commit 为证)。

1. 机理精读

MCP 工具契约的本质是「把内部函数声明成可被外部 LLM 发现 + 调用的能力」。 仓库里 src/aml/ 下已经有一套确定性的 AML 流水线:

  • typology.ts——类型学规则引擎(structuring / layering / mule_network 阈值判定)。
  • sarDraft.ts——SAR 草稿模板生成(规则模板,非 LLM)。
  • sarNarrative.ts——LLM prompt 构造 + 规则模板基线。
  • auditTrail.ts——哈希链审计 trail。

这些是函数,不是工具——它们没有对外暴露的 name / description / inputSchema,外部 LLM 无从发现,也无从调用。今天的工作就是给它们套上 MCP 契约外壳,让任意 MCP 客户端(明天就是 DeepSeek-V3)能「看见」并「调用」它们。

契约设计的第一性原理是「输入最小化、输出结构化便于 HITL」。 按 Day 56 seed 的拆法,把 AML 能力拆成 3 个 MCP 工具:

  • assessCase(证据 → 类型学比对):输入一个案件标识 / 案件对象,输出命中的类型学规则、聚合得分、证据交易 id。委托给 typology.ts 的规则引擎。
  • draftSar(SAR 草稿):输入案件 + 评估结果,输出按 5W1H 结构化的 SAR 段落。委托给 sarDraft.tsdraftSar()
  • listTypologies(枚举):无输入或最小输入,返回已建模的类型学清单(structuring / layering / mule_network)。

为什么是「输入最小化」? MCP 工具的入参由 LLM 在运行时填充。入参越复杂、越自由:

  1. LLM 填错的概率越高(多一个必填字段就多一处幻觉机会)。
  2. 攻击面越大(Day 57 会讲 description 是攻击面,Day 58 会讲入参是攻击面)。
  3. 敏感 PII 越容易随调用日志外泄。

所以 assessCase 的理想入参就是一个 caseId,让 server 端去取真实案件数据,而不是让 LLM 把整个交易数组塞进入参。

为什么是「输出结构化便于 HITL」? AML 是强合规域,最终 SAR 上报必须有人复核(Human-in-the-Loop)。工具输出若是一坨自由文本,调查员无法逐条核对证据;若是结构化的「命中规则 + 证据交易 id 列表 + 得分」,UI 就能把每条引用高亮、可点击跳转到原始交易。这正是 sarDraft.tsdraftSar() 返回 citedTxIds 字段、把段落拆成 SarSection[] 的原因——结构化是为复核服务的,不是为美观。

工具粒度的权衡:为什么是 3 个工具而不是 1 个「万能 AML 工具」或 10 个细粒度工具?

  • 1 个万能工具:LLM 难以区分「现在该做评估还是该出草稿」,且入参会膨胀。
  • 太多细粒度工具:tools/list 菜单变长,LLM 选择负担加重,选错率上升。
  • 3 个工具对齐 AML 调查的三个自然阶段(枚举类型学 → 评估案件 → 出草稿),粒度与业务语义一一对应,是可解释的拆法。

与相邻概念的边界:今天只做「把内部函数封装成工具并调通」,不做让 LLM 自动选工具(那是 Day 57)、不做零信任输入校验的对抗测试(那是 Day 58)、不做进程内 vs 网络的对拍回归(那是 Day 59)。背景类型学知识引 IBM AMLworld(2024-04)合成 AML 数据集与类型学分类。

2. 推导 / 手算 / 代码走读

Day 56 的 handler 委托给仓库已有真实模块。逐条走读关键符号(均来自 Read 验证):

  • src/aml/sarDraft.ts 导出 draftSar(c: AmlCase, assessment: TypologyAssessment): SarDraft(第 61 行)。它是规则模板生成(非 LLM)——文件头部第 2-4 行明确标注「W1 原型为【规则模板生成(非 LLM)】,按 FinCEN SAR 叙述 5W1H 结构拼装中文段落」。draftSardraftSardraftSar 工具的真实底层实现。
  • draftSar 内部先 dedupe(assessment.hits.flatMap((h) => h.evidenceTxIds)) 抽出引用交易 id(第 64 行),再按 dayOffset 排序证据交易(第 66-68 行),输出 6 个固定 SarSection:引言/主体身份(Who)/可疑活动(What·When·Where)/可疑原因(Why)/作案手法(How)/总结建议。返回对象带 generatedBy: 'rule-template'(第 167 行)——这是诚信标签,下游 UI 据此显示「非 LLM 输出」。
  • src/aml/sarNarrative.ts 导出 buildSarPrompt(第 121 行)与 ruleTemplateSar(第 247 行)。文件头第 18-20 行写明「本仓库当前【未接入任何 LLM】。凡 LLM 化部分一律是 prompt+rubric+接口,无 key 时 graceful 降级到 ruleTemplateSar」。所以 draftSar 工具的诚实状态是「规则模板」,不能对外宣称「LLM 生成的 SAR」。
  • src/aml/typology.ts(第 1-49 行)是 assessCase 的底层:定义了 CTR_THRESHOLD_CENTS = 1_000_000($10,000)、ASSESS_THRESHOLD = 0.5SCORE_PRIMARY = 0.6 / SCORE_SECONDARY = 0.4 等阈值常量,规则 id 如 STRUCT-01/LAYER-01/MULE-01。assessCase 工具就是把这套确定性规则引擎的判定结果结构化返回。
  • src/aml/auditTrail.ts 导出 AuditTrail 类(第 123 行)与 fnv1a 哈希(第 24 行)。SOTA 检查里强调的「保留 auditTrail.ts 审计轨迹」就指这里:append-only + 哈希链,任意历史事件被改则其后所有 hash 校验失败(第 10-11 行注释)。
  • 封装层用 src/agent/mcp/toolRegistry.tsregister(spec, handler)(第 151 行)把这 3 个工具注册进 McpToolRegistry,每个 handler 内部委托给上述真实模块。register 会校验 name 合法(第 152 行 /^[a-zA-Z][\w.-]*$/)、拒绝重名(第 155 行)、强制 inputSchema.type === 'object'(第 158 行)。

一个 tools/call 往返的报文形状(基于 handle() 第 199-218 行的真实行为):

请求侧 —— assessCase 一次合法调用:

{ "jsonrpc": "2.0", "id": 7,
  "method": "tools/call",
  "params": { "name": "assessCase", "arguments": { "caseId": "C-1024" } } }

响应侧 —— handle()call() 的返回包进 result.content(第 209 行 { ...base, result: { content: result } }):

{ "jsonrpc": "2.0", "id": 7,
  "result": { "content": {
    "topTypology": "structuring",
    "scores": { "structuring": 0.6, "layering": 0, "mule_network": 0 },
    "hits": [ { "ruleId": "STRUCT-01", "evidenceTxIds": ["T0003","T0005","T0009"] } ],
    "threshold": 0.5
  } } }

注意:content 里全是结构化字段——evidenceTxIds 让 UI 能逐笔高亮、scores/threshold 让调查员判断「为何过阈」。这就是「输出结构化便于 HITL」在报文层的落地。draftSarresult.content 同理会带 sections: SarSection[] + citedTxIds + generatedBy: 'rule-template'

3. 今日实战

  1. 在 Day 52 起的 server 进程里,用 server.tool()(官方 SDK)或 McpToolRegistry.register()(进程内对照基线)注册 3 个工具:assessCase / draftSar / listTypologies
  2. 为每个工具写清 description(明天就是 LLM 的选工具依据)与 inputSchema(最小必填):
    • assessCasedescription 说明「对给定案件运行类型学规则引擎,返回命中规则与证据交易」;inputSchema 仅含 caseId: string(必填)。
    • draftSardescription 说明「基于评估结果生成 SAR 草稿(规则模板,非 LLM),输出需人工复核」;入参 caseId + 可选评估结果。
    • listTypologiesdescription 说明「枚举已建模的洗钱类型学」;无入参。
  3. 每个 handler 内部委托真实模块:assessCasetypology.ts 的规则引擎;draftSarsrc/aml/sarDraft.tsdraftSar(c, assessment)listTypologies → 枚举 structuring/layering/mule_network
  4. 入参设计遵循「最小化」:assessCase 入参用 caseId(让 server 取数据)而非整包交易数组。
  5. npx @modelcontextprotocol/inspector 连 server,逐个 tools/call 三个工具,确认各自返回结构化 result.content
  6. 确认 draftSar 输出透传 generatedBy: 'rule-template' 标签到 result.content,UI 据此显示「非 LLM 输出 / 需人工复核」。
  7. git commit:标题写明「3 个 AML 工具 Inspector 调通」,并在 commit body 诚实标注「上网封装为待建 / 底层 src/aml/* 为真实已有」。

4. 今日实测 / 产出

  • 状态:待建——git commit:3 个 AML 工具全部 Inspector 调通。
  • 底层 src/aml/sarDraft.tssarNarrative.tsauditTrail.ts 均为仓库已有真实文件(本日已 Read 核实存在)。
  • 上网封装为待建
  • 纯结构化逻辑,无需 key

(按诚信纪律:上述「待建」状态逐字保留,不升级为「已完成」。)

5. 常见误区 / 陷阱

  • 把整包交易数据塞进入参:违反「输入最小化」,既放大 LLM 填错概率,也把敏感 PII 暴露在工具调用日志里。正解是传 caseId,server 端取数。
  • 让工具直接生成最终 SAR 并上报:SOTA 检查明确 AVOID——必须保留 HITL 与 auditTrail.ts 审计轨迹,合规上不可全自动。draftSar 返回的是「草稿」,不是「报告」。
  • 伪造 generatedBydraftSar 返回 'rule-template',绝不能在工具输出里谎称「LLM 生成」。诚信标签必须透传到 UI。
  • 重名注册静默覆盖McpToolRegistry.register 第 155 行对重名直接抛错,这是好设计;若用别的注册方式要确认它不会静默覆盖同名工具。

6. 学习资源(每条带 YYYY-MM)

  • MCP 规范(2026-07-28,写作时未最终定稿,硬复查点 07-28)—— tools 章节定义 tools/list/tools/call 契约。
  • MCP TypeScript SDK server 文档(2026-03)—— McpServer + server.tool() 注册接口。
  • FIS × Anthropic「Financial Crimes AI Agent」(2026-05-04 宣布,GA 2026 H2)—— 证据汇集 → 类型学比对 → SAR 叙述的产品主线。
  • IBM AMLworld 合成 AML 数据集(2024-04)—— 类型学(structuring/layering/mule)分类背景。
  • FinCEN SAR 叙述指引(2003-11;2025-10-09 新增 4 条 FAQ 强调「质量优于数量」)—— 5W1H 叙述结构出处(见 sarNarrative.ts 头注)。

SOTA检查 (2026-06 更新)

  • 当前主流方案:复刻 FIS+Anthropic 2026-05 AML Copilot 模式(证据汇集 → 类型学比对 → SAR 草稿 → HITL → 审计轨迹)仍是当前主线,2026-06 无更优替代。
  • 是否仍 SOTA:是。金融机构 GenAI 合规叙事在 2026 H1 集中落地(FIS GA 排在 2026 H2),把 AML 调查从数天压到分钟级。
  • 过时黑名单 / AVOID:禁止在工具里直接生成最终 SAR 上报——必须保留 HITL 与 auditTrail.ts 审计轨迹,合规上不可全自动。禁止把 generatedBy='rule-template' 标签去掉伪装成 LLM 输出。
  • 下次复查点:07-28 MCP 规范定稿后重验工具契约字段(content 结构);08-02 EU AI Act Article 50 透明义务生效后,确认 AI 生成内容标注义务对 draftSar 输出的要求。

衔接

  • 昨天:Day 55 — tools/call 网络往返 + content 封装(学会单工具的成功/失败报文形状)。
  • 今天:把仓库真业务 AML 三件套按 MCP 契约拆成 3 个工具暴露上网,输入最小化、输出结构化便于 HITL。
  • 明天:Day 57 — DeepSeek-V3 经 OpenRouter 作 MCP 客户端,让模型自己从 tools/list 选工具并调用。