fairquery-sanctions-screener
OfficialA sanctions screening MCP server for checking person and company names against OFAC, EU, UK, and UN watchlists, with free tools for source and cache information.
screen_names — Run a paid Apify Actor (needs
APIFY_TOKEN) to fuzzy-match names/organisations against OFAC SDN, OFAC Consolidated, EU, UK, and UN sanctions lists; supports bulk names, per-query country/dateOfBirth/entityType, minScore, maxMatches, optional list subset, and returns screening or error rows with scores, matches, and list versions.list_sources — Free, local, no token: returns the covered sanctions list IDs, official source names/authorities/URLs, the 0–100 score scale, and the legal disclaimer.
list_cache_status — Free but needs
APIFY_TOKEN: reads your Apify key-value store to report per-list cache status (cached/fresh/stale/missing, fetch and publication dates, entry counts, and whether the next screen_names run reuses or re-downloads each list).Workflow uses — Pre-screen customers, suppliers, vendors, or counterparties; bulk re-screen CRM/ERP exports; choose list subsets; cite sources; and check cache freshness before large or time-critical runs. Not a certified screening service: review potential matches manually.
Click on "Deploy 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., "@fairquery-sanctions-screenerscreen Jane Example Smith against OFAC, EU, UK and UN 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.
Sanctions & Watchlist Screener (OFAC, EU, UK, UN)
Screens people and company names against the OFAC, EU, UK and UN sanctions lists (from the official sources, re-downloaded at least every 6 hours, with each list's publication date in every row) for $3 per 1,000 names. You pay $0.003 per name that gets a screening row, and if no list can be downloaded nothing is charged. Example: re-screening 2,000 suppliers costs 2,000 × $0.003 = $6.00, plus a $0.007 Actor-start fee per run.
Fairquery Apify Actor that screens people and company names against the main public sanctions lists, downloaded from the official sources (re-downloaded whenever the cached copy is older than 6 h, configurable 0–12 h): OFAC SDN and Consolidated (US), EU Consolidated Financial Sanctions, the UK Sanctions List (FCDO / OFSI), and the UN Security Council Consolidated List. Each name gets a potential_match / no_match status, a 0–100 fuzzy score, and the matching entries with aliases, programs, countries and dates of birth.
Not a certified screening service. This is automated fuzzy matching against public lists. It can return false positives and can miss true matches (transliterations, very short names, lists that fail to download). Review every potential match manually against the official source, and get legal advice before acting on results. It does not replace a regulated KYC/AML provider.
When to use this Actor (LLM / tool selection)
Use it when an agent or workflow needs to:
Pre-screen a new customer, supplier, vendor or marketplace seller against sanctions lists (KYB / onboarding)
Re-screen a counterparty list in bulk (thousands of names per run)
Check whether a company or person is on OFAC, EU, UK or UN lists and see the program and listing details
Add a sanctions check step to an export, payments or procurement workflow
Related MCP server: Sanctions Screening MCP Server
Lists and sources
| List | Source |
| OFAC Specially Designated Nationals |
|
| OFAC Consolidated (non-SDN: SSI, NS-MBS, FSE, …) | CONS_PRIM / CONS_ALT / CONS_ADD.CSV |
| EU Consolidated Financial Sanctions List |
|
| UK Sanctions List (incl. OFSI asset-freeze targets) |
|
| UN Security Council Consolidated List |
|
List freshness and cache. Parsed lists are cached in a named key-value store in your Apify account (fairquery-sanctions-list-cache, about 1.6 MB) and reused only while they are younger than listCacheMaxAgeHours (default 6, max 12, measured from the download time). An older copy is never used: the list is downloaded again, and if that download fails the list is reported as unavailable rather than served stale. Set listCacheMaxAgeHours to 0 to download fresh on every run. Every result row carries list_versions with each list's published_at (the date stated by the source: OFAC file time, EU fileGenerationDate, UK Report Date, UN dateGenerated), source_last_modified, fetched_at, from_cache and cache_age_secs. Only your account's storage is used; no screened names are stored. If a source is down, the run continues with the other lists and every row reports it in lists_unavailable; per-list entry counts, download times and errors are in RUN_SUMMARY.
Matching
Names are normalised (diacritics, case, punctuation,
&, legal suffixes such as LLC/GmbH/JSC, honorifics) and compared token by token with Jaro-Winkler, so word order (PUTIN, Vladimir), extra middle names, and spelling variants (Poutine,Usama/Osama,Gaddafi/Qadhafi) still match.Every alias (a.k.a., f.k.a., non-Latin script names) is screened;
matched_ontells you whether the hit was the primary name or an alias.Optional country (ISO-2 or name) adds
country_match;excludeNonMatchingCountrydrops mismatches.Optional dateOfBirth drops individuals whose listed birth years differ by more than
dobYearTolerance; entries without a DOB are kept.
Input
Field | Type | Default | Description |
|
| – (sample names are prefilled in the Console form) | One name per line |
| object[] |
|
|
|
| all five |
|
| int |
| 60–100 |
| int |
| Top matches per name |
|
|
| |
| string | – | Default country for all names |
| bool |
| |
| int |
| |
| int |
| Per list file |
| int |
| Safety cap |
{
"names": ["Banco Nacional de Cuba", "Jane Example Smith"],
"queries": [{ "name": "Ali Khamenei", "id": "cust-42", "country": "IR", "dateOfBirth": "1939" }]
}Output
{
"schema_version": "1.0.0", "type": "screening",
"query": { "name": "Ali Khamenei", "id": "cust-42", "country": "IR", "date_of_birth": "1939", "entity_type": "any" },
"status": "potential_match", "best_score": 92.5, "match_count": 1,
"matches": [{
"score": 92.5, "matched_name": "KHAMENEI, Ali Husseini", "matched_on": "primary",
"list": "OFAC_SDN", "list_name": "OFAC Specially Designated Nationals (SDN) List", "entry_id": "…",
"entity_type": "individual", "primary_name": "KHAMENEI, Ali Husseini", "aliases": ["…"], "programs": ["IRAN-EO13876"],
"countries": ["Iran"], "dates_of_birth": ["19 Apr 1939"], "listed_on": null,
"country_match": true, "dob_match": true, "source_url": "https://sanctionssearch.ofac.treas.gov/Details.aspx?id=…"
}],
"lists_screened": ["OFAC_SDN", "OFAC_CONS", "EU", "UK", "UN"], "lists_unavailable": [],
"min_score": 85, "disclaimer": "Not a certified screening service. …"
}Error rows (type: "error", never charged): INPUT_EMPTY, MAX_NAMES_EXCEEDED, LISTS_UNAVAILABLE (no list could be downloaded).
Pricing
Event | Price | When |
| $0.003 | Each name that gets a screening row ( |
| $0.007 | Once per run (memory is capped at 512 MB, so always one event) |
Error rows (INPUT_EMPTY, MAX_NAMES_EXCEEDED, LISTS_UNAVAILABLE) are never charged. If no list can be downloaded, nothing is charged.
Worked example: a monthly re-screen of 2,000 counterparties in one run: 2,000 × $0.003 = $6.00, plus $0.007 (512 MB counts as one start event). Put all names into one run: the per-name price is the same, but every run pays its own $0.007 start fee, so a single-name run costs $0.003 + $0.007 = $0.01.
To cap spend, set a maximum cost per run in the run options; the Actor stops cleanly at the limit. maxNames caps how many names one run screens. Prices are from the Store pricing tab (October 2026).
Memory / runtime
Default and maximum 512 MB. Each run loads and indexes all five lists (about 33k entries, 100k+ names) before screening: about 1–5 s from a fresh cache, or 10–40 s (up to about 60 s when a government server is slow) when the lists are downloaded again. After that, screening runs at hundreds of names per second. Put all names into one run rather than one run per name.
MCP / Apify tools
Call from agents via Apify MCP with Actor fairquery/sanctions-watchlist-screener:
{ "actor": "fairquery/sanctions-watchlist-screener", "input": { "names": ["Acme Trading LLC"] } }Local stdio MCP server
The mcp/ folder is a stdio MCP server (TypeScript, @modelcontextprotocol/sdk) with three tools, all with annotations and output schemas:
Tool | What it does | Cost |
| Runs this Actor and returns the rows | Needs |
| Lists covered lists, source URLs, score scale, disclaimer | Free, local, no token |
| Per list (OFAC SDN/Consolidated, EU, UK, UN): whether a parsed copy is cached in your Apify account, its age, source publication date, entry count, and whether the next | Free, needs |
cd mcp && npm install && npm run build
node scripts/smoke-test.mjs # initialize + tools/list + free tool, no token
APIFY_TOKEN=... node scripts/smoke-test.mjs --call # real call{ "mcpServers": { "fairquery-sanctions-screener": { "command": "node", "args": ["/path/to/sanctions-watchlist-screener/mcp/dist/index.js"], "env": { "APIFY_TOKEN": "<your Apify token>" } } } }Docker: the root Dockerfile builds the MCP server image (docker build -t fairquery-sanctions-screener-mcp .); it is also the Dockerfile for Glama. The Actor image is .actor/Dockerfile. glama.json lists fairquery as maintainer.
Works well after
Website Contact & Company Enricher or Google Maps Scraper: screen the company names they return before you onboard a supplier, partner or marketplace seller.
Any CRM or ERP export of customers, vendors or payees: map name, country and date of birth into
queriesto cut false positives.
Troubleshooting
Symptom | Cause and fix |
Run ends with only an | No names in |
| An official source was down or slow. The other lists were still screened. Re-run later, or raise |
| No list could be downloaded at all (network or source outage). Retry later. |
Too many potential matches for common names | Add |
A known listed name was not matched | Try a lower |
First minute of the run shows no results | This is expected when the cache is older than the window: the lists are downloaded and indexed first (usually 10–40 s, up to about 60 s). |
FAQ
Is this a certified screening service?
No. It is automated fuzzy matching against public lists. Review every potential match against the official source, and use a regulated KYC/AML provider where the law requires one.
How fresh are the lists?
They come from OFAC, the European Commission, the UK FCDO and the UN. A run reuses a copy cached in your account only if it was downloaded less than listCacheMaxAgeHours ago (default 6 h, max 12 h); otherwise it downloads them again. Each row's list_versions shows the publication date and download time of every list used.
How long does a run take?
Usually 10–40 s (up to about 60 s) to load the lists, then hundreds of names per second.
How much does it cost?
$0.003 per screened name ($3 per 1,000), plus a $0.007 start fee per run. Error rows are free, and nothing is charged if no list loads.
How do I limit spend?
Set a maximum cost per run in the run options and/or lower maxNames.
Can an AI agent call it?
Yes, through Apify MCP with Actor fairquery/sanctions-watchlist-screener, or through the Fairquery MCP server (npx -y @fairquery/agent-trust-mcp, tool sanctions_screen_names).
Fairquery family
Other Fairquery tools on the Apify Store. Each one returns structured rows with machine-readable error codes, and error rows are never charged:
Email Validator for Agents (MX, Disposable, Typo): syntax, MX, disposable, role and typo checks without sending mail; $0.79 per 1,000 emails
Website Contact & Company Enricher: domain in, public business emails, phones, socials and company details out; $3 per 1,000 domains
Website Tech, SEO & llms.txt Check for Agents: tech stack, SEO score, AI-crawler rules and llms.txt per site; $1.50 per 1,000 sites
LLM Data Guard: PII & Secret Redactor: redact PII and secrets before text reaches an LLM; $1.50 per 1,000 documents + $0.20 per 1,000 findings
Dependency Vulnerability Check for Agents: packages and lockfiles against OSV.dev; $0.50 per 1,000 packages + $1.50 per 1,000 vulnerabilities
EDGAR Company Facts & Filings for Agents: SEC filings and XBRL facts by ticker, CIK or name; from $1.50 per 1,000 companies
Company Jobs Feed: Greenhouse, Lever & Ashby: live jobs from employers' own ATS boards with age and repost signals; $0.99 per 1,000 jobs + $0.0005 per board
Competitor Change Tracker: Pricing, Terms, Careers & Changelog: watch competitors' public pricing, terms, careers and changelog pages for real changes with plain-English summaries and webhook alerts; $0.00049 per page checked + $0.0049 per change
AI Exposure Scanner: Public Secrets, Files & AI-Crawler Policy: passive, scored scan of your own domains and public GitHub repos for leaked secrets (masked), exposed files, AI-crawler policy, security headers and SPF/DMARC; $0.039 per domain + $0.0039 per repo + $0.0019 per finding
MCP server
@fairquery/agent-trust-mcp: one MCP server for Claude Desktop, Cursor and VS Code (npx -y @fairquery/agent-trust-mcp). It has 8 free tools that need no token, plus paid tools that call the PII, email, sanctions and OSV Actors with your own Apify token.
All Fairquery Actors: https://apify.com/fairquery
Kits & templates
Optional guides from Fairquery for wiring this Actor into agents and automations (the Actor works fine without them):
AI Agent Data Toolkit Quick-Start (PDF): MCP setup for Claude Desktop and Cursor, API calls, recipes, cost estimates.
n8n + Zapier Workflow Template Pack: 10 importable n8n workflows for the four original Fairquery Actors (SEC EDGAR, website/tech, email, OSV); it does not include workflows for this Actor yet, but the patterns adapt easily.
Agent Prompt Pack for Research & Lead Ops: 69 prompts for company research, lead cleaning, SEO and security reviews.
Agent Starter Kit: 10 copy-paste MCP + n8n recipes ($5): 10 copy-paste MCP + n8n recipes, with ready-made Claude/Cursor configs and 3 starter workflows.
Disclaimer
Not a certified screening service. Results come from automated fuzzy matching against public lists downloaded from the official sources (at run time or from a cache no older than the freshness window) and are provided as is, without warranty. They may be incomplete, out of date or wrong. Always confirm potential matches with the official publication of the relevant authority (OFAC, European Commission, UK FCDO/OFSI, UN Security Council) and take legal advice before making compliance decisions. Data comes from public government sources; Fairquery is not affiliated with any of them.
Links
Apify Store: https://apify.com/fairquery/sanctions-watchlist-screener
GitHub: https://github.com/fairquery/sanctions-watchlist-screener
Contact: info@getfairquery.com
License: MIT
Development
Local development, tests and deployment notes are in DEVELOPMENT.md. The Apify Store README is .actor/README.md.
Available Tools
3 toolslist_cache_statusShow sanctions list cache freshness (free)ARead-onlyIdempotentInspect
WHAT: Show, per list (OFAC_SDN, OFAC_CONS, EU, UK, UN), whether a parsed copy is cached in your Apify account, when it was downloaded from the official source, the source publication date, entry count, and whether the next screen_names run will reuse it or re-download it. WHEN TO USE: before a large or time-critical screen_names batch (to know whether lists load in ~2-5 s or 10-40 s), or to state in a report how current the screened lists were. WHEN NOT TO USE: to screen names (screen_names, paid) or to list covered sources and their URLs (list_sources, free, no token). Does not refresh the cache; the next screen_names run does that. BEHAVIOR: GET requests to the Apify API only (your user, the key-value store "fairquery-sanctions-list-cache", one small record per list); never writes. Typically <1 s; up to ~3 s when the Actor has not yet written per-list meta records and the cached lists themselves (~1.6 MB gzip in total) are read instead. COST: free; needs your APIFY_TOKEN (the cache lives in your account) but starts no Actor run and charges no event. RETURNS: one status object; lists[] in the order above plus fresh / stale / missing summaries and a next_run sentence; Errors: APIFY_TOKEN_MISSING, APIFY_TOKEN_INVALID, APIFY_API_FAILED (retryable). PARAMETERS: maxAgeHours sets the freshness window used for fresh (default 6, the window screen_names runs use; the Actor never accepts more than 12). A list is fresh only if it was downloaded at most maxAgeHours ago and is non-empty; stale lists are never used for screening, they are re-downloaded. store_found=false means no screen_names run has cached anything in this account yet, so all five lists are missing. read_from says whether a small meta record or the cached list itself was read. EXAMPLE: {} -> {"store_found":true,"lists":[{"list":"OFAC_SDN","cached":true,"fresh":false,"fetched_at":"2026-10-17T19:15:36Z","age_hours":21.27,"published_at":"2026-10-15T16:34:34Z","entries":19457,...},...],"stale":["OFAC_SDN","OFAC_CONS","EU","UK","UN"],"next_run":"OFAC_SDN, ... would be re-downloaded ..."}
| Name | Required | Description | Default |
|---|---|---|---|
| maxAgeHours | No | Optional number 0-12, default 6 (the freshness window screen_names uses). 0 reports every cached list as stale. Example: 6 |
Output Schema
| Name | Required | Description |
|---|---|---|
| fresh | Yes | |
| lists | Yes | Per list: list, cached, fresh, fetched_at, age_hours, published_at, source_last_modified, entries, bytes, read_from |
| stale | Yes | |
| missing | Yes | |
| next_run | Yes | What the next screen_names run will do with each list |
| store_id | Yes | |
| store_found | Yes | false = no cache in this Apify account yet |
| cache_max_age_hours | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the read-only/idempotent safety profile; the description adds substantial context beyond them: GET-only calls to the Apify API, the exact key-value store name, 'never writes', typical latency (<1 s, up to ~3 s in a fallback path), the ~1.6 MB gzip read fallback, free-of-charge status, the APIFY_TOKEN requirement, and the specific error codes including which are retryable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Strongly front-loaded with WHAT/WHEN/WHEN NOT/BEHAVIOR/COST/RETURNS/PARAMETERS/EXAMPLE headings, so an agent can scan to the relevant section. It is verbose in places, and the long inline EXAMPLE return dump partly overlaps with the output schema, but nearly every sentence carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, free read tool with a full output schema, this covers everything needed: trigger conditions, cost, token requirement, failure modes, and the meaning of the freshness window. Nothing required to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and already documents the 0-12 range and default of 6, so the baseline is met. The description adds genuine semantics beyond the schema: what 'fresh' means (downloaded within maxAgeHours AND non-empty), that stale lists are re-downloaded rather than screened, that maxAgeHours=0 marks everything stale, and what store_found and read_from indicate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Show), a specific resource (sanctions list cache freshness), and enumerates the exact lists covered (OFAC_SDN, OFAC_CONS, EU, UK, UN). It explicitly distinguishes itself from both siblings, naming screen_names and list_sources as the tools this is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Has explicit WHEN TO USE (before large/time-critical screen_names batches, or to document list currency in a report) and WHEN NOT TO USE (screening names, listing sources), naming the alternative tool for each case. It also clarifies that this tool does not refresh the cache.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sourcesList covered sanctions sources (free)ARead-onlyIdempotentInspect
WHAT: Static list of the official sanctions lists screen_names checks (id, name, issuing authority, download URL), the 0-100 score scale and the legal disclaimer. WHEN TO USE: to choose the lists parameter for screen_names, cite sources in a report, or explain coverage. WHEN NOT TO USE: to screen a name - use screen_names. For how fresh the cached lists are, list_cache_status (free). Does not download lists. COST: free; local, no network, no APIFY_TOKEN. (screen_names is paid per name.) RETURNS: sources[].id is the value for screen_names lists; score_scale explains minScore. PARAMETERS: None; the result is static and cannot be filtered. EXAMPLE: call with {}, then pass the ids you need to screen_names, e.g. {"names":["Acme Trading LLC"],"lists":["OFAC_SDN","UN"]} to screen only the US SDN and UN lists.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| sources | Yes | Covered lists; id is the value for screen_names.lists |
| disclaimer | Yes | Legal disclaimer to show with results |
| score_scale | Yes | How best_score is computed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive, non-open-world), and the description adds context beyond them: free, local, no network, no APIFY_TOKEN, does not download lists, and that the sibling screen_names is paid per name. These cost and execution-locality details materially affect when and how an agent calls it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Labeled sections (WHAT, WHEN TO USE, WHEN NOT TO USE, COST, RETURNS, PARAMETERS, EXAMPLE) front-load the purpose and the routing decision. The longer length is earned by information density, and the concrete example call clarifies the practical handoff to screen_names.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, return values need no full explanation, yet the description still summarizes sources[].id and score_scale for practical use. Cost, locality, usage boundaries, and the screen_names handoff cover everything an agent needs to call this zero-param tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero-parameter tool, so the baseline is 4; the schema is empty and fully self-documenting. The description explicitly states 'PARAMETERS: None; the result is static and cannot be filtered,' which usefully prevents wasted attempts to filter, though there is little parameter meaning left to add.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: a static list of the official sanctions lists that screen_names checks, including id, name, issuing authority, download URL, score scale, and disclaimer. It also names the siblings screen_names and list_cache_status, so an agent can distinguish it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit WHEN TO USE (choosing the lists parameter, citing sources, explaining coverage) and WHEN NOT TO USE (screening a name -> screen_names; cache freshness -> list_cache_status; does not download lists). It routes the agent to the correct alternative for each adjacent need with no inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screen_namesScreen names against sanctions listsARead-onlyIdempotentInspect
WHAT: Fuzzy-match people or organisation names against the OFAC SDN, OFAC Consolidated (non-SDN), EU, UK and UN sanctions lists, from the official sources (cached in your Apify account for at most 6 h, otherwise re-downloaded; each row reports list publication dates). Order-, case- and diacritics-insensitive; optional country and date-of-birth filters per name. WHEN TO USE: KYC/KYB onboarding, vendor or counterparty checks, bulk re-screening of customer lists. Put all names into one call (lists are downloaded once per run). WHEN NOT TO USE: to see which lists/authorities are covered or to cite sources, call list_sources (free); to see how fresh the cached lists are, list_cache_status (free). Not a PEP or adverse-media check (see LIMITS). COST: paid. Runs Apify Actor fairquery/sanctions-watchlist-screener with your APIFY_TOKEN; pay-per-event "name-screened": $0.003 per name that gets a screening row, match or no match, plus a $0.007 start fee per call (one run); nothing is charged per name if no list could be loaded, and error rows are free. 200 names in one call ~ $0.61. Lists load in ~2-5 s from a cache in your Apify account (at most 6 h old) or ~10-40 s when re-downloaded, then hundreds of names/s. RETURNS: one type="screening" row per name (status potential_match | no_match; matches[] best first, each with list, entry id, score, country_match and dob_match) or free type="error" rows (code, message). EXAMPLE: {"queries":[{"name":"Banco Nacional de Cuba","entityType":"entity"}],"minScore":90} -> one screening row, status potential_match with OFAC_SDN matches. PARAMETERS: names and/or queries: at least one is required although the schema marks both optional (neither -> a free INPUT_EMPTY error row); both may be combined and every entry is billed once, so send all names in ONE call (one start fee and one list load per run). Use names for bare strings and queries when you have per-name country / dateOfBirth / entityType or want your own id echoed. Per query, dateOfBirth drops listed individuals whose recorded birth year differs by more than 1 year (entries without a DOB are kept); country only sets country_match (true/false/null) unless excludeNonMatchingCountry=true, which then drops matches whose listed countries exclude it (entries without country data are kept). entityType: a query's own value wins over the top-level one; "entity" means anything that is not an individual (organisations, vessels, aircraft), and list entries of unknown type always pass. lists: omit for all five; a list whose download fails is reported in lists_unavailable rather than failing the run. minScore: a candidate is returned only if its 0-100 name similarity is >= minScore; it does not change the price - 85 default, 90-95 for large batches with fewer false positives, 75-80 for transliterated names. maxMatchesPerName trims matches[] (best first) but match_count still counts all. LIMITS: Not a certified screening service. Automated fuzzy matching against public lists downloaded at run time; results can contain false positives and miss matches. Review every potential match manually and consult official sources and legal counsel before acting.
| Name | Required | Description | Default |
|---|---|---|---|
| lists | No | Optional, default all five. Any subset of "OFAC_SDN" | "OFAC_CONS" | "EU" | "UK" | "UN" (ids from list_sources). Example: ["OFAC_SDN","EU"] | |
| names | No | Optional if queries is given (at least one of the two is required). Plain person or organisation names (non-empty strings, any order/case/diacritics); billed per name like queries. Example: ["Vladimir Putin","Acme Trading LLC"] | |
| queries | No | Optional if names is given. {name, id?, country?, dateOfBirth?, entityType?} objects with per-name filters; billed per entry like names. Example: [{"name":"Ali Khamenei","id":"cust-42","country":"IR","dateOfBirth":"1939","entityType":"individual"}] | |
| minScore | No | Optional integer 60-100, default 85. Minimum 0-100 fuzzy name-similarity score for a match. Use 90+ for fewer false positives, ~80 for more recall. Example: 90 | |
| entityType | No | Optional, one of "any" | "individual" | "entity", default "any". Entity filter for all names; a query's own entityType wins. Example: "entity" | |
| maxMatchesPerName | No | Optional integer 1-100, default 10. Top matches returned per name (best first); match_count still reports the total. Example: 3 | |
| excludeNonMatchingCountry | No | Optional boolean, default false. true removes matches whose listed countries do not include the query country (entries without country data are kept). No effect without queries[].country. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of rows in items |
| items | Yes | Dataset rows: type=screening or type=error |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the readOnly/openWorld/idempotent annotations: it discloses cache lifetime (6 h), load latency (~2-5 s cached, ~10-40 s re-downloaded), throughput, the exact pay-per-event price model ($0.003/name + $0.007 start fee, error rows free), billing for non-matches, and that failed list downloads degrade to lists_unavailable rather than failing the run.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but deliberately so for a complex, paid, cost-incurring tool. Sections are labelled (WHAT / WHEN TO USE / WHEN NOT TO USE / COST / RETURNS / EXAMPLE / PARAMETERS / LIMITS), front-loaded with purpose and cost, and each section carries non-redundant operational facts.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be described, yet the description still summarises the row shapes (type=screening with status/matches[] vs. free type=error rows) and adds an end-to-end example. Cost, latency, limits/liability caveats, and edge cases (INPUT_EMPTY, lists_unavailable) are all covered, so nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (baseline 3), but the description adds meaning the schema cannot: it flags that names and queries are both schema-optional yet at least one is required, explains billing per entry, entityType precedence (query value wins), dateOfBirth ±1-year drop behavior, country semantics with excludeNonMatchingCountry, and minScore tuning guidance (90-95 large batches, 75-80 transliterated).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Fuzzy-match people or organisation names against the OFAC SDN, OFAC Consolidated (non-SDN), EU, UK and UN sanctions lists.' It names the exact sources and matching semantics (order-, case-, diacritics-insensitive), and the WHEN NOT TO USE section explicitly differentiates it from the siblings list_sources and list_cache_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit WHEN TO USE (KYC/KYB onboarding, vendor/counterparty checks, bulk re-screening) and WHEN NOT TO USE with named alternatives (list_sources for coverage/citation, list_cache_status for freshness). It also states the batching condition — put all names into one call — leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v1.1.0- Added
list_cache_status
1 tool update
v1.0.5- Changed
screen_names2 fields changed- changed
Input schema / properties / names / descriptionPrevious value: -"Optional if queries is given (at least one of the two is required). Plain person or organisation names (non-empty strings, any order/case/diacritics); $0.003 each. Example: [\"Vladimir Putin\",\"Acme Trading LLC\"]"New value: +"Optional if queries is given (at least one of the two is required). Plain person or organisation names (non-empty strings, any order/case/diacritics); billed per name like queries. Example: [\"Vladimir Putin\",\"Acme Trading LLC\"]" - changed
Input schema / properties / queries / descriptionPrevious value: -"Optional if names is given. {name, id?, country?, dateOfBirth?, entityType?} objects with per-name filters; $0.003 each. Example: [{\"name\":\"Ali Khamenei\",\"id\":\"cust-42\",\"country\":\"IR\",\"dateOfBirth\":\"1939\",\"entityType\":\"individual\"}]"New value: +"Optional if names is given. {name, id?, country?, dateOfBirth?, entityType?} objects with per-name filters; billed per entry like names. Example: [{\"name\":\"Ali Khamenei\",\"id\":\"cust-42\",\"country\":\"IR\",\"dateOfBirth\":\"1939\",\"entityType\":\"individual\"}]"
2 tool updates
v1.0.2- Changed
list_sources3 fields changed- added
Output schema / properties / disclaimer / descriptionAdded value: +"Legal disclaimer to show with results" - added
Output schema / properties / score_scale / descriptionAdded value: +"How best_score is computed" - added
Output schema / properties / sources / descriptionAdded value: +"Covered lists; id is the value for screen_names.lists"
- Changed
screen_names13 fields changed- added
Input schema / properties / entityType / descriptionAdded value: +"Optional, one of \"any\" | \"individual\" | \"entity\", default \"any\". Entity filter for all names; a query's own entityType wins. Example: \"entity\"" - added
Input schema / properties / excludeNonMatchingCountry / descriptionAdded value: +"Optional boolean, default false. true removes matches whose listed countries do not include the query country (entries without country data are kept). No effect without queries[].country." - changed
Input schema / properties / lists / descriptionPrevious value: -"Default: all five"New value: +"Optional, default all five. Any subset of \"OFAC_SDN\" | \"OFAC_CONS\" | \"EU\" | \"UK\" | \"UN\" (ids from list_sources). Example: [\"OFAC_SDN\",\"EU\"]" - added
Input schema / properties / maxMatchesPerName / descriptionAdded value: +"Optional integer 1-100, default 10. Top matches returned per name (best first); match_count still reports the total. Example: 3" - changed
Input schema / properties / minScore / descriptionPrevious value: -"Default 85"New value: +"Optional integer 60-100, default 85. Minimum 0-100 fuzzy name-similarity score for a match. Use 90+ for fewer false positives, ~80 for more recall. Example: 90" - changed
Input schema / properties / names / descriptionPrevious value: -"Names to screen"New value: +"Optional if queries is given (at least one of the two is required). Plain person or organisation names (non-empty strings, any order/case/diacritics); $0.003 each. Example: [\"Vladimir Putin\",\"Acme Trading LLC\"]" - changed
Input schema / properties / queries / descriptionPrevious value: -"Names with optional country (ISO-2 or name), dateOfBirth (YYYY or YYYY-MM-DD), entityType"New value: +"Optional if names is given. {name, id?, country?, dateOfBirth?, entityType?} objects with per-name filters; $0.003 each. Example: [{\"name\":\"Ali Khamenei\",\"id\":\"cust-42\",\"country\":\"IR\",\"dateOfBirth\":\"1939\",\"entityType\":\"individual\"}]" - added
Input schema / properties / queries / items / properties / country / descriptionAdded value: +"Optional. ISO 3166-1 alpha-2 code (\"IR\") or English country name (\"Iran\"); adds country_match to each match (filters only with excludeNonMatchingCountry=true)" - added
Input schema / properties / queries / items / properties / dateOfBirth / descriptionAdded value: +"Optional. Format YYYY or YYYY-MM-DD, e.g. \"1939\" or \"1939-04-19\"; drops listed individuals whose birth year differs by more than 1 year" - added
Input schema / properties / queries / items / properties / entityType / descriptionAdded value: +"Optional, one of \"individual\" | \"entity\" | \"any\"; default = top-level entityType. \"entity\" = organisations, vessels, aircraft" - added
Input schema / properties / queries / items / properties / id / descriptionAdded value: +"Optional. Your own reference echoed in the output row, e.g. \"cust-42\"" - added
Input schema / properties / queries / items / properties / name / descriptionAdded value: +"Required. Person or organisation name to screen (non-empty), e.g. \"Ali Khamenei\"" - added
Output schema / properties / count / descriptionAdded value: +"Number of rows in items"
2 tool updates
v0.1.0- First observed
list_sources - First observed
screen_names
TDQS
Scored across 3 tools
Each tool has a single distinct purpose: screen_names performs paid screening, list_sources returns static source metadata, list_cache_status reports cache freshness. The descriptions even cross-reference each other with explicit 'WHEN NOT TO USE' pointers, eliminating misselection.
All three names follow a consistent snake_case verb_noun pattern (screen_names, list_sources, list_cache_status). The shared 'list_*' prefix for the two informational tools and 'screen_*' for the action makes the grouping immediately legible.
Three tools is slim, but the domain is a single screening operation plus two genuinely useful free helpers (source coverage, cache freshness). Each earns its place with no filler, though the surface is minimal for a paid service.
The core screening lifecycle is covered: run the screen, discover supported lists and their IDs, and check cache freshness before batch runs. Minor gaps remain (no way to force-refresh the cache, no async job/status retrieval for very large batches, no PEP/adverse-media coverage), but these are disclosed and workaroundable.
Maintenance
Related MCP Connectors
Screen names and addresses on US, UN, EU, UK and other sanctions and export-control lists. Free.
Screen a name or entity against OFAC SDN, the EU Consolidated list and the UK list.
Screen people & companies against 12 US sanctions & exclusion lists (OFAC, LEIE, SAM, Medicaid).
Checks names against OFAC, UK, EU, UN and more sanctions lists; returns scored possible matches.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceScreens names against the US Consolidated Screening List including OFAC SDN and BIS Entity List, keyless.207 npmMIT
- FlicenseNot gradedqualityDmaintenanceScreens names and companies against OFAC, EU, UK, and UN sanctions lists with fuzzy-match scores, supporting bulk lookups for AML/KYC checks. Data is sourced directly from official government lists and cached for fast repeat checks.-
- AlicenseNot gradedqualityBmaintenanceScreen names against consolidated OFAC, EU, UK, and UN sanctions lists and resolve legal entities via GLEIF, with offline fuzzy matching.456 npm3Apache 2.0

CompliAPIofficial
AlicenseNot gradedqualityCmaintenanceReal-time OFAC and global sanctions screening for AI agents: screen crypto addresses, emails, websites, government IDs, and countries against OFAC SDN and 10+ sanctions/crime/risk lists, plus PEP screening, VPN detection, and IP geolocation. Hosted remote streamable-HTTP server at https://api.compliapi.com/mcp (anonymous tools/list; free API key or x402 pay-per-call).MIT