@cyanheads/sanctions-screening-mcp-server
OfficialScreens names against the United Nations sanctions list, returning potential matches with scores and source provenance.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@cyanheads/sanctions-screening-mcp-serverScreen Acme Corporation against sanctions lists"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://sanctions-screening.caseyjhand.com/mcp
This is a screening aid, not legal or compliance certification. Every tool returns potential matches with a transparent score and source provenance — never a verdict. A hit means "review this candidate against the official source"; an empty result never means "cleared." Real sanctions compliance is a legal process — it requires human review and a qualified compliance determination. This server feeds that process; it does not perform it, and its output is not a compliance record.
Overview
sanctions-screening-mcp-server turns the world's open sanctions data plus the global legal-entity registry into one screening-and-resolution workflow, answered offline and fuzzy-matched. It screens a name against the consolidated US (OFAC), EU, UK, and UN sanctions lists at once, and resolves legal entities against the GLEIF Legal Entity Identifier (LEI) database with corporate-ownership tracing.
All sources are bulk-downloadable, keyless, and clear for redistribution. The server mirrors them to a local SQLite + FTS5 index and serves matches from that mirror — no live API key, no per-request rate limit on the hot path. The agent sees screening verbs (screen_name, resolve_entity, trace_ownership); which list answered a query surfaces only as provenance on each hit.
The matching model is transparent by design: strict token matching first (exact-normalized, then all-tokens-present via FTS5), with a scored Jaro-Winkler + phonetic fuzzy fallback. Approximate hits carry the raw Jaro-Winkler similarity (0–1) — a real measurement, never a fabricated "confidence percentage."
Related MCP server: sanctionwise
Tools
Six tools organized around two workflows — screen a name against the watchlists, and resolve a legal entity to its global identifier and ownership graph:
Tool | Description |
| Screen a name (person, company, vessel, aircraft) against all loaded watchlists at once — OFAC SDN + Consolidated, EU, UK, UN — alias- and fuzzy-aware. Returns scored potential matches with source list, program, designation date, and the matched alias. |
| Fetch the full record for one sanctions designation by source list + entry ID: all aliases, identifiers, addresses, dates/places of birth, nationalities, program, legal basis, and designation date. |
| Resolve a company / organization name (+ optional jurisdiction) to ranked candidate GLEIF LEIs. Turns a free-text counterparty name into a stable global identifier. |
| Fetch the full GLEIF Level 1 record for one LEI — legal name, trading names, addresses, registration status, jurisdiction — plus a sanctions cross-reference screened on the legal name. |
| Trace the GLEIF Level 2 corporate-ownership graph for an LEI (parents and/or children, BFS to a bounded depth), optionally screening every node for beneficial-ownership screening. |
| List the loaded watchlists and GLEIF datasets with record counts, source URLs, licenses, and the mirror's readiness and as-of timestamps. |
sanctions_screen_name
The 80% entry point — "is this entity on a watchlist?"
Fans out across all four sanctions lists (OFAC SDN + Consolidated, EU, UK, UN) in one call; the source surfaces only as provenance per hit
Alias-aware: matches against every published primary name, a.k.a., and f.k.a., not just the canonical name
Strict mode (default): exact-normalized equality, then all-tokens-present via FTS5 — handles word-order swaps and missing interior words with no fuzzy library
Fuzzy mode (opt-in, or automatic when strict finds nothing): adds Jaro-Winkler similarity and Double-Metaphone phonetic matching for transliteration-class misses
Hits labeled
exact/strong/approximate; approximate hits carry the raw Jaro-Winkler score (0–1)Filter by entity type, source list subset, similarity floor (
min_score), and result limitOn an empty result, returns guidance on how to broaden — and states explicitly that no match is not a clearance
sanctions_get_designation
The drill-in after sanctions_screen_name surfaces a candidate.
Full normalized record by
source+entry_id(thesourceEntryIdfrom a screen hit)All published aliases, structured identifiers (passport / national ID / tax / registration), addresses, dates and places of birth, nationalities, sanctioning program, legal basis, and designation date
Preserves source sparsity — missing fields mean the source omitted them; the record is never padded with fabricated data
sanctions_resolve_entity
The bridge from a free-text counterparty name to a stable LEI that the entity tools key off.
Resolves a company / organization name to ranked GLEIF LEI candidates
Optional ISO 3166-1 alpha-2 jurisdiction filter and registration-status filter (
issueddefault,lapsed, orany)Same strict-then-fuzzy matching model as name screening; approximate hits carry the raw Jaro-Winkler score
Matches against legal names and published other/trading names
sanctions_get_entity
Who is this legal entity — plus a watchlist cross-reference in the same call.
Full GLEIF Level 1 record: legal name, other/trading names, legal and headquarters addresses, registration status, jurisdiction, registration authority and ID, last-update date
Cross-references the entity's legal name against all loaded watchlists (strict match only — auto-fuzzy on a generic legal name would flood the result with single-common-token false positives)
LEI input is regex-validated (20 chars: 18 alphanumerics + 2 check digits)
sanctions_trace_ownership
Beneficial-ownership screening — the cross-source workflow that single-list tools can't do.
Traverses the GLEIF Level 2 ownership graph breadth-first to a bounded depth (1–5)
direction: walkparents(who owns it),children(what it owns), orbothReturns nodes (with role and depth) and directed ownership edges with relationship type
screenNodes: truescreens every entity in the graph against all watchlists — "is anyone in this ownership chain sanctioned?"Per-node screen is strict-only and reports
screenedNodeCount/flaggedNodeCountso a caller can see coverage at a glance
Resources and prompts
Type | Name | Description |
Resource |
| One sanctions designation by source + entry ID (URI mirror of |
Resource |
| One GLEIF Level 1 entity by LEI (URI mirror of |
Resource |
| Loaded lists + GLEIF datasets with counts and refresh timestamps (URI mirror of |
Prompt |
| Sequences the tools into a full counterparty due-diligence pass: resolve → trace ownership → screen the entity and every beneficial owner → summarize with provenance and the decision-support caveat. |
All resource data is also reachable via the tools, which are the primary path for tool-only MCP clients. The resources are a convenience for resource-capable clients only.
Source lists
The server aggregates five upstream sources behind the screening surface. All are bulk, keyless, and clear for redistribution.
Source | Role | License |
OFAC SDN + Consolidated (US Treasury) | Primary US sanctions/watchlist — individuals, entities, vessels, aircraft, with a.k.a. aliases | US Government public domain |
EU Consolidated Financial Sanctions List | EU-designated persons and entities | Freely redistributable |
UK Sanctions List (UKSL, FCDO) | UK sanctions targets — persons, entities, ships | Open Government Licence v3.0 |
UN Security Council Consolidated List | UN-designated individuals and entities across all regimes | Freely redistributable |
GLEIF LEI (Level 1 + Level 2) | Who-is-who (entity reference) and who-owns-whom (corporate ownership) | CC0 1.0 Universal |
The UK source is the UK Sanctions List (UKSL), the single authoritative UK source since the OFSI Consolidated List closed on 28 January 2026.
First run: populate the mirror
The mirror is not bundled — the sanctions lists and the GLEIF golden copy are downloaded and normalized on first run. Run the init lifecycle script out-of-band before screening:
bun run mirror:initThis harvests all four sanctions lists in full, rebuilds the per-alias name index, then streams the GLEIF golden copy (Level 1 entities + Level 2 ownership relationships). It is resumable and intended to run once, off the request path.
Script | Purpose |
| Full initial load of all sources (sanctions lists + GLEIF golden copy). |
| Re-harvest the sanctions lists and apply GLEIF deltas. The sanctions half (lists + name index) also runs on a cron under HTTP transport; GLEIF deltas are manual. |
| Report mirror readiness and per-source record counts. |
| Load a small synthetic fixture for local smoke tests (no downloads). |
Set SANCTIONS_INIT_SKIP_GLEIF=1 on mirror:init to load only the (small) sanctions lists and skip GLEIF.
GLEIF memory note: the GLEIF Level 1 ingest is the heavy leg — the full golden copy is roughly 3.3M LEI records (~892 MB compressed, several GB decompressed).
mirror:initstreams and ingests it in bounded batches, so peak resident memory stays modest rather than scaling to the whole decompressed document. The four sanctions lists and the GLEIF deltas / Level 2 ownership data are light by comparison. Size disk for the mirror accordingly, or skip GLEIF withSANCTIONS_INIT_SKIP_GLEIF=1if you only need watchlist screening.
Features
Built on @cyanheads/mcp-ts-core:
Declarative tool, resource, and prompt definitions — single file per primitive, framework handles registration and validation
Unified error handling — handlers throw, framework catches, classifies, and formats
Typed error contracts with recovery hints (
mirror_not_ready,designation_not_found,lei_not_found)Pluggable auth:
none,jwt,oauth(defaults tonone— all data is public)Structured logging with optional OpenTelemetry tracing
STDIO and Streamable HTTP transports
Sanctions-specific:
Multi-source, workflow-organized surface — one screen fans out across OFAC, EU, UK, and UN internally; sources surface only as provenance
Local SQLite + FTS5 mirror via the framework
MirrorService— offline, no live API key, no per-request rate limitNormalized common schema across the four sanctions lists, with a denormalized per-alias name index (one row per name and per alias) so a query matches any of an entity's names in one FTS scan
Strict-then-fuzzy matching: exact-normalized → all-tokens-present (FTS5) → Jaro-Winkler + Double-Metaphone, capped to bound work on short queries
GLEIF Level 1 + Level 2 ingest for entity resolution and beneficial-ownership tracing
Agent-friendly output:
Real signal, not synthetic confidence — approximate hits carry the raw Jaro-Winkler similarity (0–1); strict hits carry a
match_type(exact/strong), never a fabricated percentageProvenance on every hit — source list, sanctioning program, designation date, the exact name/alias that matched, and its type (
primary/aka/fka/low-quality-aka)Decision-support caveat carried in every screening tool's output — a hit is a candidate to verify, an empty result is not a clearance
Freshness surfaced via
sanctions_list_sources— each source's record count and the mirror's as-of timestamp, so an agent can judge staleness
Getting started
Public Hosted Instance
A public instance is available at https://sanctions-screening.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP, with this client config:
{
"mcpServers": {
"sanctions-screening-mcp-server": {
"type": "streamable-http",
"url": "https://sanctions-screening.caseyjhand.com/mcp"
}
}
}Self-hosted / local
Add the following to your MCP client configuration file. The server is offline-first — populate the mirror with bun run mirror:init before screening (see Source lists).
{
"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"
}
}
}
}Or with npx (no Bun required):
{
"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"
}
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.3 or higher (or Node.js v24+).
Disk for the local mirror (the populated SQLite files; GLEIF Level 1 dominates). No API key for any source.
Installation
Clone the repository:
git clone https://github.com/cyanheads/sanctions-screening-mcp-server.gitNavigate into the directory:
cd sanctions-screening-mcp-serverInstall dependencies:
bun installConfigure environment:
cp .env.example .env
# edit .env if you need to override defaults (all optional)Populate the mirror:
bun run mirror:initConfiguration
All sources are keyless — there is no required API key. Every variable below is optional with a sensible default.
Variable | Description | Default |
| Filesystem path for the SQLite mirror; a persistent volume on a hosted deployment. |
|
| Cron for the scheduled refresh of the sanctions lists + name index (HTTP transport only). GLEIF deltas are refreshed manually via |
|
| Default Jaro-Winkler similarity floor for fuzzy matches when |
|
| Hard cap on fuzzy candidates scored per query, to bound work on short queries. |
|
| Override for the OFAC SDN advanced-XML file. | official SLS URL |
| Override for the OFAC Consolidated advanced-XML file. | official SLS URL |
| Override for the EU consolidated XML file (includes the static public token path component). | official EU URL |
| Override for the UK Sanctions List (UKSL) XML file. | official FCDO URL |
| Override for the UN Security Council consolidated XML file. | official UN URL |
| Override for the GLEIF golden-copy / delta download API. |
|
| Transport: |
|
| Port for the HTTP server. |
|
| Log level (RFC 5424). |
|
Source URLs default to the verified official endpoints; overrides exist for testing and for pinning a mirror in restricted environments. The EU "token" is a static public path component, not a credential.
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security, changelog sync bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t sanctions-screening-mcp-server .
docker run --rm -p 3010:3010 -v sanctions-data:/usr/src/app/data sanctions-screening-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/sanctions-screening-mcp-server. The image runs under Bun, so the mirror uses bun:sqlite (no native build). Mount a volume at the mirror path (/usr/src/app/data by default) so the populated mirror survives container restarts, and run bun run mirror:init inside the container (docker exec) to populate it. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions ( |
| Prompt definitions ( |
| The screening service — local mirror, normalized schema, source ingesters (OFAC/EU/UK/UN/GLEIF), and the strict/fuzzy matching engine. |
| Mirror lifecycle CLI — init, refresh, verify, seed. |
| Unit and integration tests mirroring |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools and resources via the barrels in
src/mcp-server/*/definitions/index.tsWrap external sources: validate raw → normalize to the common schema → return the output schema; never fabricate fields a source omits, and never synthesize a confidence score
Attribution
This server redistributes open data from the following sources, cited here per their terms:
OFAC SDN and Consolidated lists — US Department of the Treasury, Office of Foreign Assets Control (US Government public domain).
EU Consolidated Financial Sanctions List — European Commission / EEAS (freely redistributable).
UK Sanctions List — UK Foreign, Commonwealth & Development Office, licensed under the Open Government Licence v3.0 (attribution required).
UN Security Council Consolidated List — United Nations Security Council (freely redistributable).
GLEIF LEI data — Global Legal Entity Identifier Foundation, CC0 1.0 Universal.
Contributing
Issues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceTrust Intelligence API - entity screening, sanctions, risk scoring, IBAN validation, and compliance checks via MCPLast updatedMIT
- AlicenseAqualityAmaintenanceScreens names against the official UK FCDO Sanctions List to identify possible matches with designation details, and retrieves full sanctions entries by unique ID.Last updated265Apache 2.0
- Alicense-qualityCmaintenanceScreens individuals and entities against the OIG LEIE exclusion list, returning candidate matches that require human verification.Last updatedMIT
- Alicense-qualityCmaintenanceEnables querying global sanctions and politically exposed persons (PEP) data via OpenSanctions, with free access and no authentication required.Last updated7MIT
Related MCP Connectors
Screen names against the US Consolidated Screening List: OFAC SDN, BIS Entity List +10 more lists
Sanctions screening for KYC/AML — EU FSF + OFAC SDN checks for Czech companies & individuals.
Pay-per-call compliance via x402: wallet sanctions, OFAC name, UK + US company verification.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/cyanheads/sanctions-screening-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server