mcpField
S
sanctions-screening-mcp-server

sanctions-screening-mcp-server

远程服务
github.com/cyanheads法律与政务31 周前更新
代码仓库

关于 sanctions-screening-mcp-server

sanctions-screening-mcp-server 将名称和标识符与 OFAC、EU、UK、UN 制裁名单进行筛查,并通过 GLEIF 查询企业。它使用本地离线镜像提供潜在匹配结果,作为筛查辅助而非合规结论。

主要功能

  1. 01跨制裁名单名称筛查
  2. 02标识符精确查询
  3. 03通过 GLEIF 查询法人实体
  4. 04法人记录与所有权追踪
  5. 05查看数据源及镜像状态

适用场景

  1. 01筛查潜在交易对手名称
  2. 02核查钱包、护照或 SWIFT/BIC 标识符
  3. 03根据企业名称查找 LEI
  4. 04审查企业所有权链

MCP 相关

它向 MCP 客户端提供 7 个筛查与实体工具、3 个资源和 1 个交易对手审查提示词。结果只表示潜在匹配,仍需人工复核。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://sanctions-screening.caseyjhand.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npm@cyanheads/sanctions-screening-mcp-server0.5.1

工具

7
参数类型必填说明
namestring是要筛查的名称(个人、组织、船舶或飞机),可使用任何文字体系。必须至少包含一个字母或数字,且最多包含 64 个词和 1024 个字符。
limitinteger否每页返回的潜在匹配项数量上限。
offsetinteger否要返回的第一个潜在匹配项的从零开始的索引。hasMore 为 true 时,使用返回的 nextOffset 再次调用以遍历所有匹配项;超出末尾的 offset 会返回空页,而不是错误。
sourcesarray否限定为指定的来源名单。省略时筛查所有已加载的名单。
minScorenumber否近似匹配的分数下限(0–1),统一应用于所有模糊候选项,无论匹配方式为何(Jaro-Winkler、词元或语音);只有匹配分数也达到此下限的查询词元,才会计入 queryTokenCoverage。此值适用于所有模糊匹配:模糊模式,以及严格模式下对严格搜索未找到结果的名单执行的匹配,因此提高此值也可能从严格筛查中移除近似匹配。完全匹配和强匹配不受影响。默认使用服务端配置的下限。
matchModeenum否strict(默认):先匹配规范化后的完全一致项,再匹配包含所有词的项,然后对严格搜索未找到结果的每个选定名单执行模糊匹配——如果严格搜索在所有名单中均无结果,则完整执行;否则只添加涵盖姓名中除法律形式、冠词和其他虚词,以及司法辖区代码 uk、usa、uae、rf 之外每个词的候选项。fuzzy:对所有选定名单执行评分式 Jaro-Winkler + 语音匹配。strict | fuzzy
entityTypeenum否限定为一种实体类别;或使用 "any"(默认)筛查所有类别。any | person | organization | vessel | aircraft

详细介绍

@cyanheads/sanctions-screening-mcp-server

对照整合后的 OFAC、EU、UK 和 UN 制裁名单筛查名称,并通过本地 SQLite + FTS5 镜像进行离线模糊匹配,以解析 GLEIF 中的法律实体。此工具仅辅助筛查,不作合规判定。

7 个工具 • 3 个资源 • 1 个提示词

版本 许可证 MCP SDK TypeScript Bun

在 Claude Desktop 中安装 在 Cursor 中安装 在 VS Code 中安装

框架


概述

针对整合后的 OFAC、EU、UK 和 UN 制裁名单以及 GLEIF LEI 注册库进行制裁筛查和法律实体解析,并与本地镜像进行离线匹配。筛查名称是否可能命中观察名单,将公司解析为其 LEI,并追踪其所有权链。

重要

此工具仅辅助筛查,不作合规判定。 每个结果都是带有透明评分和来源溯源信息的潜在匹配,而非判定。命中项是需要对照官方来源核实的候选项;结果为空绝不代表已获准。制裁合规需要人工审查和合格的判定。本服务为这一流程提供支持,但不会代替该流程。

工具
工具描述
sanctions_screen_name一次性对照所有已加载的观察名单,筛查个人、公司、船舶或航空器名称
sanctions_screen_identifier对照所有已加载的观察名单,精确查找 IMO 编号、SWIFT/BIC 代码、钱包地址、护照号码或国民身份证号码
sanctions_get_designation根据来源名单和条目 ID 或已发布的参考编号,获取单条指定记录的完整信息
sanctions_resolve_entity将公司名称(可选指定司法管辖区)解析为按相关度排序的 GLEIF LEI 候选项
sanctions_get_entity获取 LEI 对应的 GLEIF Level 1 记录,并交叉引用其名称、LEI 和注册编号进行制裁筛查
sanctions_trace_ownership追踪某个 LEI 的母公司和子公司,可选对图中的每个实体进行交叉引用
sanctions_list_sources列出已加载的数据源及其记录数、许可证和镜像新鲜度
资源
资源描述
sanctions://designation/{source}/{entryId}按来源和条目 ID 或已发布的参考编号查询一项制裁指定
sanctions://entity/{lei}按 LEI 查询一个 GLEIF Level 1 实体
sanctions://sources已加载的来源及其数量,以及各镜像的就绪状态和截至时间戳

对于不提供资源的客户端,所有资源数据也可通过工具访问。

提示词
提示词描述
sanctions_vet_counterparty执行交易对手尽职调查:筛查、解析、追踪所有权并汇总

功能参考

sanctions_screen_name 工具
  • name 可使用任何文字系统(最多 64 个单词和 1,024 个字符),并可选用 sources、entityType 和 minScore 筛选条件;matchMode 为 strict(默认)或 fuzzy。如果严格模式在所选列表中均未找到结果,则会对每个所选列表执行模糊匹配:如果所有列表均未找到结果,则执行完整的模糊匹配;否则,在严格匹配结果之后,仅添加涵盖名称中除法律形式、冠词和其他功能词,以及司法管辖区代码 uk、usa、uae 和 rf 之外所有词语的候选项。fuzzySources 列出模糊匹配所搜索的列表;每页最多返回 100 个结果(limit,默认值为 25),并通过 offset 分页
  • 结果包含 source、sourceEntryId、列表中已发布的 referenceNumber(如有)、带有 matchedNameType 的 matchedName,以及 matchType(exact / strong / approximate);近似匹配结果还会包含原始 Jaro-Winkler score(0–1)和 queryTokenCoverage
  • 近似筛查会双向比较原生形式和确定性的俄文字母转写,并始终保留已发布名称及其别名类型。派生出的相等关系仍属于近似匹配,既不是官方别名,也不构成身份认定。每个列表各自独立的 2,000 个名称模糊匹配池会优先处理原生形式的候选项;转写形式和删除前四个码点的签名会补充剩余容量,因此拼写错误的召回率有限
  • sources 列出结果所属的所有所选列表。OFAC 会在两个文件中使用同一个条目 ID,将某一方列入 SDN List 和一个非 SDN 列表;如果同时选择两个 OFAC 列表,该方只计为一个结果,并会列出两个列表,即使筛查仅匹配到一条记录。其他字段(包括指定日期)取自 source 记录;但如果仅 Consolidated 记录匹配或匹配度更高,则使用 Consolidated 记录
  • totalAvailable、hasMore 和 nextOffset 用于分页,分页会涵盖所有计入的匹配结果;totalAvailableBasis 标记计数为 exact(严格匹配覆盖所有所选列表)或 lower_bound(执行了模糊匹配);当某个列表的模糊匹配候选池达到容量上限时,notice 会提示使用更具区分度的词

sanctions_screen_identifier 工具
  • value(你掌握的标识符),以及可选的 type(默认为 any,可选值为 imo、swift_bic、digital_currency_address、passport、national_id)和 sources
  • 规范化后进行精确匹配,绝不模糊匹配,也不评分:忽略空格、字母大小写以及 - . /;IMO 编号无论是否带有 IMO 前缀都能匹配;SWIFT/BIC 仅比较前 8 个字符,因此分支 BIC11 可匹配其机构的 BIC8;钱包地址仅对十六进制(0x…)、bech32(bc1…、ltc1…、bnb1…)和 cashaddr 编码忽略大小写,base58 地址则进行精确比较
  • type 按各列表发布的标签匹配:imo 对应 OFAC 的 Vessel Registration Identification、英国的 IMO Number 和欧盟的 IMO (vessel identification);swift_bic 对应 SWIFT/BIC 和 SWIFT BIC;digital_currency_address 对应 OFAC 的 Digital Currency Address - <code>;passport 和 national_id 涵盖各列表中的护照和国家身份证标签。any 还会匹配所有未分类的标签(MMSI、呼号、尾号、税务和注册编号、电子邮件、网站)
  • 每个指定对象仅返回一条命中,按列表顺序、再按条目 ID 排序;每条包含匹配的 matchedIdentifiers(按原样发布)及其 sources。OFAC 对象若同时出现在两份 OFAC 列表中,只算一条命中,并列出两个列表;不分页。列表仅在自由文本备注中打印的标识符,或与其他编号捆绑在同一字段中的标识符,不会匹配

sanctions_get_designation 工具
  • source(ofac_sdn、ofac_consolidated、eu、uk、un)和 entryId:可使用筛查命中的 sourceEntryId,也可使用列表发布的参考编号(UN QDe.004、欧盟 EU.27.28、英国 OFSI Group ID 14196)。匹配时会先去除首尾空格并忽略大小写,优先匹配条目 ID;如果多个指定对象共用一个参考编号,则返回 reference_ambiguous,并列出两者
  • 如果列表发布了 referenceNumber,则会与 sourceEntryId 一并返回;OFAC 不发布参考编号,其条目 ID 即为其发布的编号
  • 返回所有已发布的别名、标识符、地址、出生日期和出生地、国籍、描述性特征、计划、法律依据和指定日期;源数据未提供的字段会缺失,绝不会补填
  • 标识符涵盖身份证件,以及列表发布的 SWIFT/BIC 代码、数字货币地址、船舶呼号、飞机尾号和序列号、电话号码、电子邮件地址和网站;每个标识符均按列表自身的标签分类,值则按原样返回
  • 出生日期采用 ISO 8601 格式,精度与源数据一致(1952-10-07、1946-08、1938,或 1955/1957 之类的区间);源数据标记为约数时,使用 circa: true;designationDate 按 YYYY-MM-DD 格式返回源数据中的指定日期
  • OFAC 对象的日期取自其文件所发布的列表条目:ofac_sdn 取 SDN List,ofac_consolidated 取非 SDN 列表,均优先采用最早日期。同一对象出现在两个文件中时,各文件中的日期可能不同
  • legalBasis 为列表引用的原文法律文书:OFAC 的法律依据参考(Executive Order 14024 (Russia))、欧盟法规标题(2024/1488 (OJ L27052024))或英国政权法规(The Russia (Sanctions) (EU Exit) Regulations 2019);多个条目以 ; 连接。UN 列表不发布此项
  • features 包含列表发布的、用于描述而非识别该对象的信息;每项均按列表自身的标签分类,并按发布顺序排列:OFAC 的船旗、类型、所有者和吨位,飞机型号、运营方和制造日期,职称、性别和制裁备注(Secondary sanctions risk:、See Section 11 of Executive Order 14024.),以及英国列表中的船舶详情(CurrentBelievedFlagOfShip、TypeOfShip、YearBuilt,……)。日期采用 ISO 8601 格式,精度与发布内容一致;OFAC 标记为约数时,使用 circa: true。欧盟和 UN 列表不提供此类信息,任何筛查工具都不会匹配特征值

sanctions_resolve_entity 工具
  • 任意文字体系的 name(长度限制与 sanctions_screen_name 相同),以及可选的 jurisdiction、status 和 minScore;matchMode 为 strict(默认值),仅在严格匹配无结果时才回退到模糊匹配,或为 fuzzy;每页最多 50 个候选项(limit,默认值为 10),可使用 offset 分页
  • jurisdiction 可以是国家代码,匹配该国家及其下属的所有次级行政区(US 匹配 US-DE 和 US-CA),也可以是 ISO 3166-2 次级行政区代码(US-DE),此时精确匹配;不区分大小写
  • status:issued(默认值)匹配 ISSUED,lapsed 精确匹配 LAPSED,any 则不应用筛选——只有使用 any 才能查到 RETIRED、DUPLICATE、ANNULLED、PENDING_TRANSFER、PENDING_ARCHIVAL 或 MERGED 记录,每个候选项的 status 都会标明其状态
  • 搜索 GLEIF 发布的所有名称:法定名称、曾用法定名称、营业名称、其他语言的法定名称,以及其他文字体系法定名称的 ASCII 转写
  • 候选项包含 lei、legalName、matchedName 及其 matchedNameType(LEGAL_NAME、PREVIOUS_LEGAL_NAME、TRADING_OR_OPERATING_NAME、……;如果名称存储时没有类型,则为 UNKNOWN),以及 matchType;近似匹配还包含 score 和 queryTokenCoverage;每个 LEI 仅返回一个候选项,并使用相同的 totalAvailable / totalAvailableBasis / hasMore / nextOffset 字段进行分页

sanctions_get_entity 工具
  • 一个 20 个字符的 lei;返回法定名称、otherNames、法定地址和总部地址、status、jurisdiction、注册机构以及 lastUpdate
  • alternateNames 会列出所有其他名称和转写名称,并附上各自在 GLEIF 中的类型;镜像在类型尚未保留时存储的名称会显示为 UNKNOWN
  • sanctionsHits 将该实体与每个观察名单交叉核对:对法定名称及每个 alternateNames 条目进行严格筛查(精确匹配,然后要求包含所有词元,不进行模糊匹配);对 LEI 和 registrationAuthorityEntityId 进行精确查找,将其作为非证件类标识符处理(绝不作为护照、国家身份证件、IMO 编号、SWIFT/BIC 代码或钱包处理)。注册号只与该实体 jurisdiction 所属国家发布的标识符匹配;如果实体未发布管辖区信息,或用不可用占位符(N/A、n.a.)代替注册号,则跳过该注册号
  • 每个指定对象返回一条命中记录;同时出现在两个 OFAC 名单上的 OFAC 当事方算作一条命中记录,其 sources 会列出两个来源。先列出名称和标识符精确匹配,再列出强名称匹配;合并后最多返回 25 条。matchedOn 会列出产生该命中的所有输入(legal_name、带有 GLEIF 类型的 other_name、lei、registration_number);标识符匹配会添加 matchedIdentifiers,其中的标识符按名单发布的形式列出;如果没有名称产生命中记录,则不包含 matchedName 或 matchType。任何命中记录都不含 score:只有近似(模糊)匹配才有该字段,而此处的所有筛查都是严格匹配
  • screeningStatus(screened / not_ready)表示是否已执行交叉核对;sanctionsScreen 会统计所有输入对应的不同指定对象数(totalAvailable)、标记结果列表是否达到上限(hasMore),并在 screenedInputs 中列出除始终筛查的法定名称和 LEI 外已筛查的输入

sanctions_trace_ownership 工具
  • 根节点 lei、direction(parents / children / both,默认值为 both)和 depth 1–5(默认值为 3);screenNodes: true 会像 sanctions_get_entity 一样交叉引用每个节点(严格匹配其名称,并将其 LEI 和国家匹配的注册号作为标识符),每个节点最多合并 10 个命中项;没有 Level 1 记录的节点没有可供筛查的名称,仅通过其 LEI 查找。both 表示从根节点分别向上遍历父级和向下遍历子级,各自遍历至 depth;不会到达同级节点或共同父级
  • nodes(包含 role 和 depth)以及 edges(包含 relationshipType,每条边连接两个返回的节点);role 表示到达该节点时所处的方向。depth 计算除 IS_ULTIMATELY_CONSOLIDATED_BY 之外的每种关系类型;该关系是通往集团顶层的捷径:若某节点仅通过这条边在 depth 范围内到达,则该节点是未遍历的叶节点,标记为 reachedVia: "ultimate",其深度为一跳。如果图被 truncated(存在超过深度限制的关系,或标记的叶节点的链接未显示;只有当 ultimate-parent 边指向图中未返回的实体时才计入),或 missingEntityLeis 列出了没有 Level 1 记录的节点,则 complete 为 false。它仅涵盖已加载的关系,而且大多数实体不会发布父级关系
  • 遍历读取了其父级关系的每个节点都包含 parentStatus.direct / .ultimate:值为 relationship、exception(GLEIF 报告例外,包含所有原因,例如 NATURAL_PERSONS)、none 或 unknown。unknown 表示未加载例外数据,reportingExceptionsLoaded: false 会说明这一点
  • screeningStatus(screened / not_requested / not_ready)、screenedNodeCount 和 flaggedNodeCount;每个已筛查节点都包含自身的 sanctionsScreen(hasMore、screenedInputs)以及带有 matchedOn 和 matchedIdentifiers 的命中项,格式与 sanctions_get_entity 相同

sanctions_list_sources 工具
  • 无输入;每个制裁名单各有一行,另有 gleif 一行;每行都包含 recordCount、url(已配置的源 URL)和 license;gleif 行中的 recordCount 是 Level 1 实体数量,其 relationshipCount 是 Level 2 所有权关系数量
  • sanctionsReady / sanctionsAsOf 和 leiReady / leiAsOf 报告各镜像是否已同步以及同步时间;sanctionsAsOf 是所有制裁名单都已刷新的最近一次同步时间。此工具不受就绪状态限制,因此会报告空镜像,而不是失败
  • reportingExceptionsLoaded;报告例外加载后,gleif 行还会包含 reportingExceptionCount
  • alternateNamesIndexed:说明是否已为 GLEIF 的商号、曾用名、其他语言名称和转写名称建立索引;在 mirror:init 建立索引之前,sanctions_resolve_entity 仅搜索法定名称

sanctions://designation/{source}/{entryId} 资源
  • source 是五种名单代码之一,entryId 是该名单自己的 ID 或其公布的参考编号;解析方式与 sanctions_get_designation 相同,如果经过百分号编码,则解码一次;返回 sanctions_get_designation 负载,类型为 application/json
  • 缓存一小时,作用域为 private

sanctions://entity/{lei} 资源
  • 单个 lei 的 sanctions_get_entity Level 1 负载,不包含制裁交叉引用;该交叉引用仅由工具提供
  • 缓存一小时,作用域为 private

sanctions://sources 资源
  • sanctions_list_sources 负载,保持不变
  • ttlMs: 0:永不缓存,因为就绪状态和截至时间戳就是该负载的内容

sanctions_vet_counterparty 提示词
  • 参数:必填 name;可选 jurisdiction(国家代码,包括其下属行政区,或 ISO 3166-2 行政区代码)
  • 返回一条用户消息,用于筛查名称(以及调用方持有的任何标识符,使用 sanctions_screen_identifier),将其解析为 LEI,以 screenNodes: true 追踪所有权,获取每个命中项的指定记录,并要求提供摘要:将每个匹配项都视为待核实的候选对象,并根据 matchedOn 说明实体的哪个名称或标识符产生了匹配。将 GLEIF 母公司称为会计合并母公司,而非受益所有人;对于报告例外情况,报告其原因,不要将其解读为“没有母公司”

功能

基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none / jwt / oauth)、可替换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1),以及结构化日志和可选的 OpenTelemetry 跟踪。

制裁筛查专属功能:

  • 单次筛查覆盖 OFAC SDN、OFAC Consolidated、EU、UK(UKSL)和 UN;匹配列表会作为每个命中项的来源信息显示
  • 离线且无需密钥,无每请求速率限制:通过框架的 MirrorService 将全部五个来源规范化为本地 SQLite + FTS5 镜像
  • 按别名建立名称索引,因此一次查询即可通过单次 FTS 扫描匹配实体的任意名称;另设标识符索引,可通过 IMO 编号、SWIFT/BIC、钱包地址或证件号码进行精确查找
  • 先严格匹配,再模糊匹配:先精确规范化匹配,再检查所有词元是否存在(FTS5),最后对每个列表的 2,000 个候选项池使用 Jaro-Winkler + Double-Metaphone;因此,添加一个列表不会挤掉其他列表的候选项,且每个符合条件的候选项都可通过分页获取
  • GLEIF Level 1(谁是谁)和 Level 2(谁拥有谁),用于实体解析和所有权追踪

便于 Agent 使用的输出:

  • 提供带来源信息的真实信号:近似命中项包含原始 Jaro-Winkler score 和字面值 queryTokenCoverage 计数,不会混合计算置信度;每个命中项都会注明其列表、计划、指定日期和匹配名称,并将名称类型标记为 primary / aka / fka / low-quality-aka
  • 在 sanctions_screen_name、sanctions_screen_identifier、sanctions_get_designation、sanctions_get_entity 和 sanctions_trace_ownership 的输出中提供决策支持用的 caveat
  • 明示未覆盖内容:totalAvailableBasis、screeningStatus、complete / truncated / missingEntityLeis 以及每个节点的 parentStatus 会说明响应未覆盖的内容
  • 错误类型明确:除来源列表外,所有工具和资源在镜像加载完成前都会以可重试的 mirror_not_ready 失败;未知 ID 会以 designation_not_found 或 lei_not_found 失败;镜像中不存在、且 ISO 17442 校验位不通过的 LEI(表示字符输入有误)会以 invalid_lei_checksum 失败;两个指定项共用的参考编号会以 reference_ambiguous 失败;不含字母或数字的名称会以 name_not_searchable 失败,超出长度限制的名称会以 name_too_long 失败;移除空格和分隔符后不剩任何内容的标识符会以 identifier_not_searchable 失败

入门

公共托管实例

可使用公共实例 https://sanctions-screening.caseyjhand.com/mcp,无需安装。通过 Streamable HTTP 将任意 MCP 客户端指向该实例:

{
  "mcpServers": {
    "sanctions-screening-mcp-server": {
      "type": "streamable-http",
      "url": "https://sanctions-screening.caseyjhand.com/mcp"
    }
  }
}
自托管 / 本地部署

将以下内容添加到 MCP 客户端配置文件中。镜像不包含在软件包中,npm 软件包也无法构建镜像:从克隆的仓库中运行 bun run mirror:init(参见安装),或在 Docker 镜像内运行,然后将 SANCTIONS_MIRROR_PATH 指向生成的镜像(参见镜像生命周期)。

{
  "mcpServers": {
    "sanctions-screening-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/sanctions-screening-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

也可以使用 npx(无需 Bun):

{
  "mcpServers": {
    "sanctions-screening-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/sanctions-screening-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

对于 Streamable HTTP,设置传输方式并启动服务:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
先决条件
  • Bun v1.4.0 或更高版本(或 Node.js v24+)。
  • 本地镜像所需的磁盘空间;GLEIF Level 1 占用空间最大。所有数据源均无需 API 密钥。
安装
  1. 克隆代码库:
git clone https://github.com/cyanheads/sanctions-screening-mcp-server.git
  1. 进入目录:
cd sanctions-screening-mcp-server
  1. 安装依赖项:
bun install
  1. 配置环境:
cp .env.example .env
# edit .env if you need to override defaults (all optional)
  1. 填充镜像:
bun run mirror:init

配置

所有数据源均无需密钥,因此此处无需配置任何内容。

变量描述默认值
SANCTIONS_MIRROR_PATHSQLite 镜像的文件系统路径;托管时请使用持久卷。./data/sanctions.db
SANCTIONS_REFRESH_CRON定时刷新的 Cron 表达式(仅限 HTTP 传输)。受监督的子进程会刷新制裁名单及其索引,然后在一个新的 4 小时界限内应用 GLEIF 增量。需要运行 mirror:init 的缺口会记录日志;该计划任务不会加载黄金副本。0 4 * * *
SANCTIONS_REFRESH_SKIP_GLEIF设为 1 可跳过定时刷新和 mirror:refresh 中的 GLEIF 阶段。未设置
SANCTIONS_FUZZY_MIN_SCORE未提供 minScore 时,模糊匹配使用的 Jaro-Winkler 分数下限。0.85
OFAC_SDN_URLOFAC SDN 高级 XML URL。OFAC 官方 URL
OFAC_CONSOLIDATED_URLOFAC Consolidated 高级 XML URL。OFAC 官方 URL
EU_FSF_URLEU 合并 XML URL。其 token 查询值是静态公开路径组成部分,并非凭据。EU 官方 URL
UK_SANCTIONS_URLUK Sanctions List(UKSL)XML URL。FCDO 官方 URL
UN_SC_URLUN 安全理事会合并 XML URL。UN 官方 URL
GLEIF_GOLDEN_COPY_BASE_URLGLEIF 黄金副本和增量下载 API。https://goldencopy.gleif.org
MCP_TRANSPORT_TYPE传输方式:stdio 或 http。stdio
MCP_HTTP_PORTHTTP 服务端口。3010
MCP_SESSION_MODEHTTP 会话模式:stateless、stateful 或 auto。createApp() 声明为 stateless;设置此变量会覆盖该值。stateless
MCP_LOG_LEVEL日志级别(debug、info、warning、error 等)。info
LOG_TOOL_FAILURE_PAYLOADS记录每次失败的工具调用参数和结果;按键名进行脱敏,并限制在 LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES(默认 16384)以内。自由格式值中的机密不会被脱敏。false

完整的可选覆盖项列表,请参见 .env.example。

运行服务

本地开发
  • 构建并运行:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • 运行检查和测试:

    bun run devcheck   # Lint, format, typecheck, security, changelog sync
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    
镜像生命周期

镜像在带外加载,绝不会在请求路径上加载。

在 HTTP 部署中,定时刷新会使用服务运行时及其运行时参数,在单独的进程中运行。SQLite WAL 可在子进程写入时确保已提交的索引仍可读取,因此健康检查和筛查请求可在重建期间继续处理。超时或关机请求会触发取消;系统会给清理操作最多 5 秒,然后终止并等待仍未退出的子进程。每种终止结果都会释放运行槽位,以便下一个定时任务启动。被终止的运行可能会留下已提交的采集页面;下一次成功刷新会在完成前重建这些页面的派生索引。服务进程无需重启即可读取更新后的新鲜度和报告例外计数。

脚本用途
bun run mirror:init完整加载:全部五个制裁名单、名称和标识符索引,然后是 GLEIF 黄金副本(Level 1 及其名称索引、Level 2 和报告例外),将每个文件的 ContentDate 记录为 GLEIF 检查点,最后加载 GLEIF 精确名称索引;当严格解析达到上限时,该索引会优先匹配精确名称。可安全地重复运行;中断后重新运行会从头开始。设置 SANCTIONS_INIT_SKIP_GLEIF=1 可仅加载制裁名单。
bun run mirror:refresh重新采集制裁名单,移除名单完整文档不再发布的指定对象(每次运行最多移除名单中一半的对象)。随后从检查点将 GLEIF 更新至最新:对每个数据集,使用能够回溯至上次应用文件的最小增量窗口(从 IntraDay 到 LastMonth),包括删除项。对于没有记录加载时间的报告例外,加载其黄金副本;如果 GLEIF 精确名称索引缺失,脚本(而非 cron)会构建该索引。在 HTTP 环境下,SANCTIONS_REFRESH_CRON 会触发相同的刷新(仅处理增量),最长运行 4 小时,与此脚本相同。设置 SANCTIONS_REFRESH_SKIP_GLEIF=1 可跳过 GLEIF。
bun run mirror:verify报告镜像就绪状态、各来源记录数、GLEIF Level 1 / Level 2 / 报告例外的记录数、是否已为 GLEIF 替代名称建立索引、是否已构建精确名称索引,以及 GLEIF 检查点。
bun run mirror:seed加载小型合成测试数据,以便在本地进行冒烟测试,不下载任何内容。

如果某个名单下载失败或内容被截断,系统会保留其已存储的行且不删除任何内容;其他名单仍会刷新,并重新构建名称和标识符索引。之后仍会刷新 GLEIF,运行结束时会以非零状态退出,并列出每个失败的名单(ofac_sdn、eu 等)。只有在所有名单都成功刷新的运行中,sanctionsAsOf 才会更新;首次运行 mirror:init 时,如果有名单失败,镜像将不会就绪。

GLEIF 要么整体更新,要么完全不更新。只有在所有数据集的覆盖范围增量均已应用后,leiAsOf 和检查点才会推进。因此,中断的刷新会让两者保持原样,下次运行会从同一位置重新应用。以下两种情况不会对 GLEIF 应用任何内容、保持 leiAsOf 不变,并以非零状态退出,同时指出 mirror:init:检查点早于一个月窗口,以及镜像没有检查点。所有由 0.3.0 或更早版本写入的镜像都没有检查点,因此升级后请运行一次 mirror:init。在此之前,追踪会将未发布的母实体读为 unknown,而 sanctions_resolve_entity 只搜索法定名称,并提示替代名称尚未建立索引;随后模糊匹配会在较长名称的前三个特征词处停止,并提示已达到候选项上限。0.3.0 会存储其他名称,但不存储其类型,也完全不存储转写名称,因此名称索引会基于 mirror:init 加载的黄金副本构建,而非基于已存储的行。此后的每次 GLEIF 写入都会保持索引最新。回滚后由较早版本写入 GLEIF 会导致索引落后;在下次运行 mirror:init 之前,解析会退回到仅搜索法定名称,并显示相应提示。 较早版本写入的镜像会在首次打开时原地升级:designation 表会新增 reference_number 列;在显示首个界面前,会根据存储的指定记录重建制裁名称索引(对于 2026-10-03 的列表,大约需要 4 s);在首次查询前,会根据存储的记录构建标识符索引,因此无需重新初始化,sanctions_screen_identifier 就能从已填充的镜像中返回结果。较早版本未读取或读取错误的数据——参考编号、除身份证件外的 OFAC 和 UK 标识符、精确到公布精度的日期、从各自文件中的列表提取的 OFAC 指定日期、legalBasis 和 features——会在下一次制裁数据刷新时补齐;刷新会重写所有已存储的指定记录,因此升级后请运行 mirror:refresh,不要等定时任务执行。在此之前,sanctions_get_designation 对每条已存储记录都返回 features: [],而较早版本存储为标识符的占位值(UK 的 N/A 护照)仍会在 sanctions_screen_identifier 中匹配。GLEIF 数据源同步时,同一次 mirror:refresh 也会构建 GLEIF 精确名称索引;在此之前,严格解析如果达到 2,000 个名称的上限,就会在不使用该索引的情况下运行,并漏掉扫描范围之外的精确名称。如果后续同步未覆盖的同步操作更改了已存储的记录(例如较早版本在回滚后运行的同步),标识符索引也会在打开时重建。首次打开 GLEIF 镜像时会删除 lei_entity 状态索引;任何解析查询都不会读取该索引。完整数据集上大约需要 2 s,可释放约 54 MiB 空间供后续写入复用。只有手动执行 VACUUM 后,文件才会缩小。

mirror:init 和 mirror:refresh 的每个数据源阶段都会按有界批次流式处理,因此峰值内存取决于批次大小,而非源数据大小。制裁 XML 总计约 172 MB。GLEIF Level 1 黄金副本约有 340 万条记录(压缩后约 890 MB),占用磁盘空间最多;其名称索引(约 400 万个名称)还会增加约 0.8 GB。报告例外数据增加约 640 万行(磁盘占用约 525 MiB)。

Docker
docker build -t sanctions-screening-mcp-server .
docker run --rm -p 3010:3010 -v sanctions-data:/usr/src/app/data sanctions-screening-mcp-server

Dockerfile 默认使用 HTTP 传输、无状态会话模式,并将日志写入 /var/log/sanctions-screening-mcp-server。请在 /usr/src/app/data 挂载一个卷,以便镜像在重启后保留,并通过 docker exec 运行 bun run mirror:init 填充该卷。默认会安装 OpenTelemetry 对等依赖;如需省略这些依赖,请使用 --build-arg OTEL_ENABLED=false 构建。

项目结构

目录用途
src/index.tscreateApp() 入口:注册功能界面、初始化筛查服务并安排 HTTP 刷新。
src/config使用 Zod 解析和验证服务器专用环境变量。
src/mcp-server/tools工具定义(*.tool.ts)和共享的筛查注意事项。
src/mcp-server/resources资源定义(*.resource.ts)。
src/mcp-server/prompts提示词定义(*.prompt.ts)。
src/services/screening筛查服务:镜像、规范化架构、OFAC/EU/UK/UN/GLEIF 数据导入器、匹配引擎。
scripts/mirror-*.ts镜像生命周期命令行工具:初始化、刷新、验证、播种。
tests/工具、资源、提示词、服务、集成、模糊测试和冒烟测试。

开发指南

开发指南和架构规则请参阅 CLAUDE.md/AGENTS.md。简要说明如下:

  • 处理程序抛出异常,框架负责捕获——工具逻辑中不要使用 try/catch
  • 使用 ctx.log 记录请求级日志;通过 getScreeningService() 访问镜像,而不是使用 ctx.state
  • 通过 src/mcp-server/*/definitions/index.ts 中的汇总导出文件注册新工具和资源
  • 封装外部数据源:验证原始数据 → 规范化为通用架构 → 返回输出架构;绝不伪造数据源未提供的字段,也不合成置信度分数

归属

本服务再分发以下来源的开放数据,并按其条款注明出处:

来源发布方许可证
OFAC SDN 和综合名单美国财政部外国资产控制办公室美国政府公有领域
欧盟综合金融制裁名单欧盟委员会 / EEAS可自由再分发
英国制裁名单(UKSL)英国外交、联邦和发展事务部开放政府许可 v3.0(须注明出处)
联合国安全理事会综合名单联合国安全理事会可自由再分发
GLEIF LEI 数据(Level 1 + Level 2)全球法人机构识别编码基金会CC0 1.0 通用

自 OFSI 综合名单于 2026 年 1 月 28 日关闭以来,UKSL 一直是英国唯一的权威来源。

参与贡献

欢迎提交问题。提交前请运行检查和测试:

bun run devcheck
bun run test

许可证

Apache-2.0 — 详情请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。