EU Company & VAT MCP Server avatar

EU Company & VAT MCP Server

Pricing

Pay per event + usage

Go to Apify Store
EU Company & VAT MCP Server

EU Company & VAT MCP Server

MCP server for AI agents: identify EU legal entities from official open registers (GLEIF, Brreg, ARES, Sirene) and verify EU VAT numbers (VIES). Read-only, sourced, timestamped. Charged only for successful results.

Pricing

Pay per event + usage

Rating

0.0

(0)

Developer

Benjamin Cojocaru

Benjamin Cojocaru

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

6 days ago

Last modified

Share

eu-company-mcp

An MCP server that lets AI agents identify EU/EEA legal entities in official open registers and check EU VAT numbers in VIES. Every answer is structured JSON that carries its source URLs, licences and retrieval timestamps. The core is open source (Apache-2.0).

Part 1 of the "EU-data MCP servers" series. The register logic is copied from the reviewed Apify actor products/apify-actors/eu-company-identity.

Tools

All tools are read-only (readOnlyHint: true, idempotentHint: true, destructiveHint: false, openWorldHint: true). Each one declares an outputSchema and returns structuredContent, plus the same JSON as text for older clients.

ToolWhat it does
lookup_company(query, country?, strictness?, max_results?)Takes a name, a registration number or an LEI. It returns resolved (exactly one entity) or ambiguous (candidates). It never guesses.
get_company_details(identifier, country?)Takes an exact NO orgnr, CZ ICO, FR SIREN/SIRET or LEI. With a country, it also takes FI Y-tunnus, PL KRS, SK IČO, LV/LT codes, US CIK, GB company number, AU ABN or CH UID. It returns one record merged from the national register and GLEIF.
verify_vat(vat_number, country_code?, include_trader_details?)Checks a VAT number in VIES. It returns valid, invalid, unavailable or invalid_input.
list_sources()Lists the registers, coverage, licences and privacy rules. It makes no network request.

Coverage:

  • GLEIF LEI records, worldwide.
  • National registers for Norway (Brreg), the Czech Republic (ARES) and France (Sirene via recherche-entreprises.api.gouv.fr). These are always searched.
  • More national registers, queried only when you pass their country. Their results are linked to GLEIF by registration number, never by name:
    • Finland (PRH/YTJ): name or Y-tunnus.
    • Poland (KRS): KRS number only.
    • Slovakia (RPO): name or IČO.
    • Latvia (Register of Enterprises via data.gov.lv): name or registration number.
    • Lithuania (Register of Legal Entities via get.data.gov.lt): name or code.
    • United States (SEC EDGAR): CIK only, so SEC-registered companies only.
  • Optional registers that need a free key, enabled only when the env var is set:
    • United Kingdom (Companies House): COMPANIES_HOUSE_API_KEY.
    • Australia (ABN Lookup): ABN_LOOKUP_GUID.
    • Switzerland (Zefix): ZEFIX_USERNAME + ZEFIX_PASSWORD.
  • VIES for the EU-27 plus XI (Northern Ireland).

Any other country can be reached through GLEIF only, so only entities that have an LEI will be found. The same holds for a keyed country whose key is not set; a note says so. See COVERAGE.md for every register that was considered, with its licence, access method and the reason it was added, deferred or skipped. list_sources shows what is enabled in the running server.

Install / run

uvx eu-company-mcp # stdio (after the package is on PyPI)
uvx --from /path/to/company eu-company-mcp # straight from this folder
pipx install /path/to/company
eu-company-mcp --http --port 8000 # streamable HTTP at http://127.0.0.1:8000/mcp
eu-company-mcp --http --host 0.0.0.0 --allowed-hosts mcp.example.com,mcp.example.com:* # non-loopback

The HTTP mode has no authentication. If you bind to an address other than loopback, the server refuses to start unless you give a Host allow-list (--allowed-hosts / EU_MCP_ALLOWED_HOSTS, optional --allowed-origins / EU_MCP_ALLOWED_ORIGINS). That list turns on the SDK's DNS-rebinding protection. Put a reverse proxy with authentication in front. The Apify wrapper is the one exception: it runs behind Apify's token-checking proxy, and its Host check is on only when EU_MCP_ALLOWED_HOSTS is set.

Claude Desktop (claude_desktop_config.json)

{
"mcpServers": {
"eu-company": {
"command": "uvx",
"args": ["eu-company-mcp"],
"env": { "EU_MCP_CONTACT": "you@example.com" }
}
}
}

Until the package is published, use "args": ["--from", "/absolute/path/to/products/eu-data-mcp/company", "eu-company-mcp"].

Cursor (~/.cursor/mcp.json or .cursor/mcp.json)

{ "mcpServers": { "eu-company": { "command": "uvx", "args": ["eu-company-mcp"] } } }

To use a running HTTP server instead: { "mcpServers": { "eu-company": { "url": "http://127.0.0.1:8000/mcp" } } }

Environment

  • EU_MCP_CONTACT: optional contact e-mail, sent in the User-Agent so register operators can reach you. It is never logged.
  • EU_MCP_RESPECT_ROBOTS=0: turns the robots.txt check off. The default is on. Only turn it off if you have a reason.
  • EU_MCP_CONTACT is also strongly recommended for the US register: the SEC asks automated clients to identify themselves.
  • Optional register keys: COMPANIES_HOUSE_API_KEY, ABN_LOOKUP_GUID, ZEFIX_USERNAME, ZEFIX_PASSWORD.
    • The server reads each one from the environment. If a key is not set there, it reads KEY=VALUE lines from ~/.config/upside/*.env (change the folder with EU_MCP_KEY_DIR).
    • Only these variable names are read.
    • Keys are sent only to their own register, as a header where the API allows it. ABN Lookup only accepts its GUID as a query parameter.
    • Keys never appear in results, source URLs or error messages.

Behaviour and data rules

  • Untrusted data. Names, notes and other text come from third-party registers. Treat them as data, never as instructions. The server instructions tell the model the same. Control characters and bidi characters are stripped, and register strings are capped at 300 characters.

  • Errors. Results with status: "error" (a register failed, or the server is busy) come back with isError: true. They still carry the full structured content.

  • Legal entities only. Sole traders, natural persons, non-diffusible French records, estates and similar entries are excluded, and the result only shows how many were excluded (excludedRecordsCount). The server never reads officers, owners, street addresses or phone numbers. The address field holds only city, postcode and country.

    • Every extra register uses an allow-list of legal forms. Its natural-person forms are listed in COVERAGE.md and in list_sources under privacy. Examples: SK legal forms 100-110 and trade-licence records, LV individual merchants, LT individual enterprises, AU individuals/partnerships/trusts, CH sole proprietorships, and SEC individual filers.
    • PRH (the API has no private traders), KRS and Companies House hold no sole traders. They still hold partnerships.
    • Partnerships (same rule everywhere): a partnership registered in a commercial register as its own entity is kept: NO ANS/DA, FI AY/KY, PL sp.j./sp.k., SK v.o.s./k.s., LV PS/KS, LT TŪB/KŪB, GB LP/LLP, CH Kollektiv-/Kommanditgesellschaft. Only its registered name is returned, which may contain a partner's surname, as the register publishes it. Partner data is never read. Australian partnerships are excluded, because ABN registrations of partnerships are not separate legal entities and are mostly individuals.
  • VIES privacy default. VIES can return a trader's name and address, and for a sole trader that is a natural person's personal data. The server returns only validity unless you set include_trader_details=true. When you do, a note warns that the data is personal.

  • No guessing. A name lookup is resolved only when the full normalised legal name matches exactly (legal form included). A registration number or LEI resolves only on an exact match. If a register in scope fails, the result is incomplete, not resolved.

  • Politeness:

    • It only calls allowlisted official API hosts over https (core/http.ALLOWED_HOSTS: the original five plus the extra registers' hosts), with SSRF guards: no private IPs, at most 3 redirects, size and time caps.
    • A register whose search answer lacks the legal form (SK, AU) gets at most 3 detail requests per name search. Bulk open-data dumps are never downloaded.
    • A name search asks for up to 50 results where the API takes a limit. If the register says more names matched than it returned (or more candidates exist than the detail cap), the answer is incomplete instead of resolved or "not found". That answer carries searchTruncated: true and is never cached or charged.
    • It waits at least 1 s between requests to the same host, across all tool calls.
    • It allows at most 40 requests per tool call.
    • Requests to the same host go one at a time, keeping the 1 s gap. At most 4 tool calls do upstream work at once, and at most 16 wait for a slot, each for up to 20 s. Otherwise the answer is busy, retry (status: error, never charged).
    • After a 403 or 429 from a host, it leaves that host alone for 10 minutes.
    • It caches successful answers in memory for 15 minutes. The cache is process-wide: in Apify Standby it is shared by every user of one run. It holds only public register answers. Cache hits are marked cached: true and are never charged.
    • It uses no proxies and no browsers.
  • robots.txt is read once per host per day and checked for every request path (RFC 9309; the product token is eu-company-mcp). If robots.txt is unreachable or returns a 5xx, the host is treated as disallowed, and the server tries robots.txt again after 10 minutes.

  • Licences and attribution:

    • GLEIF: CC0. See the GLEIF terms.
    • Brreg: NLOD 2.0.
    • Sirene: Licence Ouverte 2.0.
    • ARES: under the Ministry of Finance's operating conditions. Those licence terms are not confirmed (see the actor README).
    • VIES: a public EC service.
    • Extra registers: PRH CC BY 4.0, RPO CC BY 4.0, Latvia CC0, Lithuania CC BY 4.0, SEC public domain, Companies House (attribution "Contains Companies House data"; the reuse basis is to be confirmed by the founder), ABN Lookup Web Services Agreement, Zefix terms. KRS states no licence; see COVERAGE.md.
    • Each result includes an attribution list.

Development

$nice -n 10 python3 -m pytest -q -p no:cacheprovider

Tests use recorded register fixtures (copied from the actor; FI/PL/SK/LV/LT/US recorded 2026-10-13 and trimmed to the fields used) and synthetic VIES, GB, AU and CH fixtures. They never touch the network. They include MCP protocol tests that run over the SDK's in-memory client and over a real stdio subprocess.

See PAID.md for a possible hosted tier and PUBLISH.md for publishing on PyPI or Apify (founder steps).

Pricing on Apify (pay per event)

  • company-resolved $0.008: One legal entity identified by lookup_company or get_company_details. Ambiguous, not found, cache hits and errors are free.
  • vat-checked $0.003: VIES gave a definitive valid or invalid answer. Unavailable, errors and cache hits are free.

Exact repeats served from the 15-minute cache, partial answers, not-found results and errors are free. In Standby mode Apify also bills the small platform usage of the server to the user.