server.json
2 fields changed
- env_vars
-
MCP_LOG_LEVEL, SANCTIONS_MIRROR_PATH, SANCTIONS_FUZZY_MIN_SCOREMCP_LOG_LEVEL, SANCTIONS_MIRROR_PATH, SANCTIONS_FUZZY_MIN_SCORE, SANCTIONS_NORMALIZE_INPUTS - version
-
0.6.00.6.1
io.github.cyanheads/sanctions-screening-mcp-server
9 changes recorded. MCP Harbor re-reads this listing from the official registry every six hours and asks the live server what it exposes, and keeps what changed between one look and the next.
https://raw.githubusercontent.com/cyanheads/sanctions-screening-mcp-server/HEAD/AGENTS.md
− **Version:** 0.5.1− **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`− **MCP SDK:** `@modelcontextprotocol/server` ^2.3.1 (via the framework)− Entity screening and resolution over the world's open sanctions data plus the global legal-entity registry, served offline. It screens a name — or looks up an identifier such as an IMO number, SWIFT/BIC code, wallet address, or document number exactly — against the consolidated OFAC (SDN + Consolidated), EU, UK (UKSL), and UN sanctions lists at once, and resolves legal entities against the GLEIF LEI database with corporate-ownership tracing.− **The data path is a local mirror, not a live API.** All five sources are bulk, keyless, and clear for redistribution. They are normalized into two local SQLite + FTS5 mirrors via the framework `MirrorService` — a sanctions `designation` mirror with a per-alias `name` index (Double-Metaphone phonetic keys) and a per-identifier `designation_identifier` index, and a GLEIF `lei_entity` mirror with a per-name `lei_name` index (legal, other, and transliterated names, typed) and a `lei_relationship` o− Skills are modular instructions in `framework-skills/` at the project root. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry. The directory is deliberately not `skills/`: Claude Code and Codex auto-load a plugin's root `skills/`, so a server that ships `.claude-plugin/` or `.codex-plugin/` would hand these development skills to every agent that installs it. Keep `skills/` free for skills meant f− **Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.− | `api-mirror` | MirrorService — persistent self-refreshing local mirror of a bulk upstream dataset (embedded SQLite + FTS5). The data path this server is built on. |+ **Version:** 0.6.0+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`+ **MCP SDK:** `@modelcontextprotocol/server` ^2.4.0 (via the framework)+ Entity screening and resolution over eleven sanctions and export-control lists plus the GLEIF legal-entity registry, served offline. The lists are OFAC SDN/Consolidated, EU, UK, UN, BIS Entity/Denied Persons/Unverified/Military End User, and State ITAR Debarred/Nonproliferation Sanctions. Name and exact-identifier screening share this corpus; GLEIF supplies accounting-consolidation relationship tracing.+ **The data path is a local mirror, not a live API.** All eleven watchlists and GLEIF use keyless bulk downloads. The six BIS/State lists share one CSL download per sync; skip CSL Treasury copies, preserve provider id verbatim, and retain missing type as unknown. They are normalized into two local SQLite + FTS5 mirrors via the framework `MirrorService` — a sanctions `designation` mirror with a per-alias `name` index (Double-Metaphone phonetic keys) and a per-identifier `designation_identifier` in+ - Source membership derives from `SOURCE_CODES`; keep default screens, cross-references, source listings, and schemas aligned automatically. OFAC grouping remains limited to its two direct feeds. CSL restrictions, notices, end dates, and provenance URLs remain labeled features, never inferred legal status.+ - Ownership traces page nodes, then edges, then boundaries (50 default, 100 maximum records; soft 64-KiB target with intact oversized records). Drain a segment before same-side boundary re-rooting; deduplicate branch roots and edges. Topology fingerprints invalidate changed graphs; entity and screening values remain current rather than frozen. Completeness covers loaded accounting-consolidation data only.+ - `sanctionsAsOf` is the last successful local all-list sync, not upstream publication freshness. Existing mirrors need `mirror:refresh` to load newly supported sources; configured source rows can have zero stored records before that refresh.+ csl-ingest.ts # Shared trade.gov download and per-list spools for six BIS/State lists+ Two skill trees live at the project root, written for different readers:+ | Tree | For | Written by |+ |:-----|:----|:-----------|+ | `framework-skills/` | The agent developing this server — framework skills (`metadata.audience: external`) plus any development-time skills of the server's own | `init` and the `maintenance` sync (framework skills); you (your own) |+ | `skills/` | The agents that install the server and call its tools — tool chains, identifier sources, gates | You, deliberately, with the `add-skill` skill. Absent by default; usually none is needed |+ Development skills are modular instructions. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry. Their directory is deliberately not `skills/`: Claude Code and Codex auto-load a plugin's root `skills/`, so a server that ships `.claude-plugin/` or `.codex-plugin/` would hand them to every agent that installs it.+ A published skill in root `skills/` reaches plugin installs and the `.mcpb` bundle as-is, ships in the npm package and the Docker image, and reaches MCP clients when the server opts in with `createApp({ skills: 'skills' })`. `lint:packaging` validates the tree.+ `skills/sanctions-screening-guide/SKILL.md` is the published consumer guide: identity confirmation, ownership continuation, capped cross-reference recovery, and screening uncertainty.+ **Agent skill directory:** Copy `framework-skills/` into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.+ | `add-skill` | Author a skill the server publishes in root `skills/` for the agents that use it — when one earns its place, structure, validation, delivery |+ | `api-mirror` | MirrorService: persistent self-refreshing local mirror (embedded SQLite + FTS5) of a bulk upstream dataset — Tier 3 opt-in |
https://raw.githubusercontent.com/cyanheads/sanctions-screening-mcp-server/HEAD/AGENTS.md
− **Version:** 0.5.0− **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.11`− **MCP SDK:** `@modelcontextprotocol/server` ^2.2.0 (via the framework)− **Zod:** ^4.6.5− setup() { initScreeningService(); scheduleRefresh(); },− async teardown() { await getScreeningService().close(); },− `teardown(core)` is the `setup()` counterpart — release a watcher, socket, or non-`unref()`'d timer there. Here it closes both mirrors, which releases their prepared statements along with the SQLite files instead of leaving them pinned until garbage collection. It runs after the transport stops and before the logger closes, on every shutdown path, and a signal-triggered shutdown then exits the process explicitly (0, or 1 if a step never settles within the framework's 10 s ceiling). The scheduled− throw new McpError(JsonRpcErrorCode.DatabaseError, 'Connection failed', { pool: 'primary' });− **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the changelog entry plus a gates section); `release-pr-review` reviews and fixes on that branch (each fix an ordinary commit on top of the stack, pushed plainly — nothing already pushed is ever rewritten, so `main` keeps the record of w+ **Version:** 0.5.1+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`+ **MCP SDK:** `@modelcontextprotocol/server` ^2.3.1 (via the framework)+ **Zod:** ^4.6.7+ async setup() { initScreeningService(); await scheduleSanctionsRefresh(); },+ async teardown() {+ await stopSanctionsRefresh();+ await getScreeningService().close();+ },+ `teardown(core)` is the `setup()` counterpart — release a watcher, socket, or non-`unref()`'d timer there. Here it first stops refresh cron ticks, cancels and awaits the child (five-second grace, then SIGKILL), then closes both serving mirrors and their prepared statements. It runs after the transport stops and before the logger closes, on every shutdown path, and a signal-triggered shutdown then exits the process explicitly (0, or 1 if a step never settles within the framework's 10 s ceiling). + throw new McpError(JsonRpcErrorCode.InitializationFailed, 'Connection failed', { pool: 'primary' });+ scheduled-refresh-process.ts # Supervised compiled child, pipe drain, cancellation and teardown+ scheduled-refresh-job.ts # Deltas-only scheduled entry, compiled into dist+ **Every release goes through a gated release PR** — `git-wrapup`'s "Release PR mode", mode `gated`. Three separate runs, never one: `git-wrapup` lands the commit stack on `release/<version>`, pushes it, and opens the PR (title = the release commit subject, body = the release digest: theme line, `## Changes`, `## Gates`, changelog link last); `release-pr-review` reviews and fixes on that branch (each fix an ordinary commit on top of the stack, pushed plainly — nothing already pushed is ever rewri
https://raw.githubusercontent.com/cyanheads/sanctions-screening-mcp-server/HEAD/AGENTS.md
− **Version:** 0.4.0− **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.7`− **MCP SDK:** `@modelcontextprotocol/server` ^2.0.0 (via the framework)− **Match signal is the raw Jaro-Winkler value (0–1) — never a fabricated confidence percentage.** Strict matching (exact-normalized → all-tokens-present via FTS5) is the default and the ~90% path; fuzzy (Jaro-Winkler + phonetic) is opt-in or auto-on-empty. Surface only real signal: `matchType` (`exact`/`strong`/`approximate`), the matched name and its type, the raw score for approximate hits, and `queryTokenCoverage` — a literal count of the query tokens a candidate explains. Coverage ranks candi− Real example: `sanctions_screen_name` (trimmed). Note the typed error contract (`ctx.fail` + `ctx.recoveryFor`), the load-bearing caveat in the output, and the `enrichment` block for non-result metadata (normalized query, mode used, empty-result notice).− matchModeUsed: z.string().describe('The match mode actually applied (strict may auto-upgrade to fuzzy on empty).'),− throw ctx.fail('mirror_not_ready', 'The local sanctions mirror is not yet populated.', { ...ctx.recoveryFor('mirror_not_ready') });− if (!entity) throw ctx.fail('lei_not_found', `No GLEIF entity with LEI "${params.lei}".`, { ...ctx.recoveryFor('lei_not_found') });− // optional with a default — the mirror path, fuzzy-match tuning, the refresh− fuzzyMaxResults: z.coerce.number().int().min(1).default(50).describe('Hard cap on fuzzy candidates scored per query.'),− fuzzyMaxResults: 'SANCTIONS_FUZZY_MAX_RESULTS',− | `ctx.fail` / `ctx.recoveryFor` | Typed error contract — `ctx.fail(reason, msg, …)` against the tool's `errors[]` union; `ctx.recoveryFor(reason)` pulls the declared recovery metadata. Used by every read tool to throw `mirror_not_ready` / `*_not_found`. |− | `ctx.requestInput` / `ctx.inputs` | Suspend and ask the caller for more input — `return ctx.requestInput(...)`, then read `ctx.inputs.accepted(key, schema)` on re-entry. Unused here; every read is answered from the mirror. |− | `ctx.requestId` | Unique request ID. |− **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable?, severity?, thrownBy? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reaso− if (!item) throw ctx.fail('no_match', `No item ${input.id}`, ctx.recoveryFor('no_match'));− schema.ts # Normalized designation/name/identifier/lei_entity/lei_name/lei_relationship schema + MirrorService defs + the v2 migration− text-matching.ts # Fold/tokenize, Jaro-Winkler, Double-Metaphone+ **Version:** 0.5.0+ **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.11`+ **MCP SDK:** `@modelcontextprotocol/server` ^2.2.0 (via the framework)+ **Match signal is the raw Jaro-Winkler value (0–1) — never a fabricated confidence percentage.** Strict matching (exact-normalized → all-tokens-present via FTS5) is the default and the ~90% path; fuzzy (Jaro-Winkler + phonetic) is opt-in, or runs on its own over each selected list a strict screen found nothing on (all of them when strict found nothing anywhere). Surface only real signal: `matchType` (`exact`/`strong`/`approximate`), the matched name and its type, the raw score for approximate hi+ Real example: `sanctions_screen_name` (trimmed). Note the typed error contract (`errors[]` + `ctx.fail`), the load-bearing caveat in the output, and the `enrichment` block for non-result metadata (normalized query, mode used, empty-result notice).+ matchModeUsed: z.string().describe('fuzzy when every selected list was fuzzy-searched; strict otherwise, including a strict screen whose strict-empty lists were completed.'),+ throw ctx.fail('mirror_not_ready', 'The local sanctions mirror is not yet populated.');+ if (!entity) throw ctx.fail('lei_not_found', `No GLEIF entity with LEI "${params.lei}".`);+ // optional with a default — the mirror path, the fuzzy score floor, the refresh+ | `ctx.fail` | Typed error contract — `ctx.fail(reason, msg, …)` against the definition's `errors[]` union; the framework puts the declared `recovery` on the wire. Used by every read tool to throw `mirror_not_ready` / `*_not_found`. |+ | `ctx.requestInput` / `ctx.inputs` | Suspend and ask the caller for more input — `return ctx.requestInput(...)`, then read `ctx.inputs.accepted(key, schema)` on re-entry; `ctx.inputs` holds only responses the client's declared capabilities cover. Unused here; every read is answered from the mirror. |+ | `ctx.clientCapabilities` | What the client declared for this request, `undefined` when no view exists. Decides whether to ask for optional context; never a reason to skip a consent prompt. Unused here. |+ | `ctx.requestId` | Request ID — the one every log record of the call carries and its error envelope returns as `data.requestId`. |+ **Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable?, severity?, thrownBy? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. The framework puts it on the+ if (!item) throw ctx.fail('no_match', `No item ${input.id}`);+ schema.ts # Normalized designation/name/identifier/lei_entity/lei_name/lei_relationship schema + MirrorService defs + each spec's v2 migration+ text-matching.ts # Fold/tokenize, Jaro-Winkler, Double-Metaphone, the fuzzy-admission stoplist (FUZZY_STOPLIST)+ candidate-pool.ts # Fuzzy blocking pool — whole blocks, smallest first, under one budget, then pair lookups+ cross-reference.ts # get_entity / trace_ownership cross-reference — strict name screens + LEI and registration-number lookups, merged per designation+ country-codes.ts # Published country names → ISO 3166-1 alpha-2 (the registration-number country gate)+ lei-checksum.ts # ISO 17442 check digits — invalid_lei_checksum on a mirror miss
We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect