ares-mcp
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., "@ares-mcpCheck IČO 04084063 — who is it, are they VAT registered, and what do they do?"
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.
ares-mcp
An MCP server that gives an LLM agent grounded access to ARES, the Czech public business register: look a company up by its registration number (IČO), search the register by name, check VAT registration, and validate an IČO offline.
Why it exists. Ask a model about a Czech company and it will happily invent an address and a VAT number. That is fine in a chat and unacceptable in a back-office workflow — onboarding a client, checking a counterparty, filling a contract header. This server replaces the guess with a citable record from the state register: every answer carries a
source_urla human can open.
Tools
Tool | What it does | Network |
| Full company profile: name, seat, legal form, incorporation date, VAT ID, CZ-NACE activities, registers | ARES |
| Full-text search by business name, capped at 50 hits | ARES |
| Whether the subject is an active VAT payer, plus its VAT ID | ARES |
| Modulo-11 checksum validation and normalisation | none — pure logic |
Every tool returns a flat, documented JSON object. Failures come back as
{"error": "...", "message": "..."} instead of an exception, so the agent can
recover rather than abort the turn.
Related MCP server: cz-agents-mcp
Quick start
git clone https://github.com/Tomi5037/ares-mcp.git
cd ares-mcp
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytestRun the server directly — it speaks MCP over stdio, so it waits for a client:
ares-mcp # stdio (default)
ares-mcp --transport streamable-http # run it as an HTTP service insteadBuilt on the official MCP Python SDK 2.x.
All four tools are annotated read_only_hint, so a client can auto-approve them
without prompting on every call.
Use it from Claude Code
claude mcp add ares -- /absolute/path/to/.venv/bin/ares-mcpUse it from Claude Desktop
claude_desktop_config.json:
{
"mcpServers": {
"ares": {
"command": "/absolute/path/to/.venv/bin/ares-mcp"
}
}
}Then ask, in plain language:
"Check IČO 04084063 — who is it, are they VAT registered, and what do they do?"
{
"ico": "04084063",
"name": "CETIN a.s.",
"legal_form": "Joint-stock company (a.s.)",
"address": { "city": "Praha", "region": "Hlavní město Praha", "postal_code": "19000" },
"established_on": "2015-06-01",
"vat_number": "CZ04084063",
"vat_registered": true,
"is_active": true,
"activities": [{ "code": "6110", "section": "J", "section_label": "Information and communication" }],
"source_url": "https://ares.gov.cz/ekonomicke-subjekty?ico=04084063"
}How it works
LLM client (Claude Code / Desktop)
│ MCP over stdio
▼
server.py 4 tools, input validation, error contract
▼
client.py httpx async, timeouts, retry + backoff, TTL cache
▼
models.py raw ARES JSON -> flat pydantic schema
▼
ARES REST API v3 (public, no API key)Three decisions worth calling out:
Validate before you call. An IČO is checked locally with its modulo-11 checksum. A hallucinated or mistyped number never becomes an HTTP request, and the agent gets a specific error instead of a generic 404.
Normalise the payload. ARES answers with deeply nested Czech keys and the same record repeated once per source register.
models.pyflattens that into one documented schema — fewer tokens for the model, and one place to change when the upstream API moves.Cache and retry. A TTL cache keeps a repeated lookup off the state API, and transient 5xx/timeout responses are retried with exponential backoff. A public service you do not own is a dependency you should be polite to.
Configuration
All optional — ARES is a public API and needs no key.
Variable | Default | Meaning |
|
| API root |
|
| Per-request timeout |
|
| Attempts before giving up |
|
| Cache lifetime |
Tests
pytest --cov=ares_mcp # 45 tests, no network access
ruff check . && mypy src # lint and strict typingHTTP is mocked with httpx.MockTransport against payloads recorded from the
live API, so the suite is deterministic and runs offline in CI. Covered:
checksum edge cases, cache hits, retry on 503 and on timeout, 404 mapping,
missing upstream fields, and the exact JSON contract of every tool.
Limitations
ARES exposes public register data only; personal data of natural persons is returned by the upstream API in a limited form and this server does not enrich or store it.
The insolvency register (ISIR) is reported only as a presence flag, not with case detail.
Data is as fresh as ARES itself (
data_updated_onis passed through).
Roadmap
Streamable HTTP transport in addition to stdio
check_insolvencybacked by ISIRBulk lookup for a list of IČO with concurrency limits
Optional Redis cache for multi-process deployments
License
MIT — see LICENSE.
Data comes from ARES, operated by the Czech Ministry of Finance. This project is not affiliated with the Ministry.
Available Tools
4 toolscheck_vat_registrationARead-onlyIdempotent
Check whether a company is an active VAT payer and return its VAT ID.
Args: ico: The company's IČO.
Returns:
A vat_registered flag, the VAT ID and a link to the ARES record.
| Name | Required | Description | Default |
|---|---|---|---|
| ico | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, covering the safety profile. The description adds useful behavioral context beyond that: it returns a vat_registered flag, the VAT ID, and a link to the ARES record, making the tool's behavior and output nature clear.
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?
The description is compact and well-structured: it front-loads the primary purpose, then clearly separates Args and Returns. Every sentence contributes useful information with no repetition or filler.
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 the low complexity of the tool (one required parameter, a straightforward output schema, and safe annotations), the description is complete. It explains the input, the output fields, and the tool's core behavior without leaving significant gaps.
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?
The schema only defines 'ico' as a string with no description, so schema coverage is 0%. The description compensates by explaining that ico is the company's IČO, which gives essential semantic meaning. It could provide more format or validation details, but for a single identifier parameter this is a solid clarification.
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?
The description clearly states the tool's purpose: checking whether a company is an active VAT payer and returning its VAT ID. This distinguishes it from siblings like validate_ico_number (which likely validates IČO format) and lookup_company (which probably retrieves broader company data).
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?
The description implies when to use this tool: when you need VAT registration status or a VAT ID for an IČO. However, it does not explicitly mention alternatives or state conditions under which another sibling tool would be more appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_companyARead-onlyIdempotent
Look up a Czech company profile by its registration number (IČO).
Args: ico: The company's IČO; spaces and missing leading zeros are fine.
Returns: Name, registered seat, legal form, incorporation date, VAT ID, CZ-NACE activities and the registers the subject is listed in.
| Name | Required | Description | Default |
|---|---|---|---|
| ico | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds useful behavioral context beyond annotations: the input-tolerant behavior ('spaces and missing leading zeros are fine') and the exact set of returned fields. No contradiction with annotations.
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?
The description is compact, well-structured with Args and Returns sections, and leads with the core purpose. Each sentence adds value, and there is no redundant or filler content.
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, read-only lookup tool with a declared output schema, the description is complete. It covers the purpose, the input format tolerance, and the expected return contents. Nothing essential for invoking the tool 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?
The schema provides only a string parameter named 'ico' with no description, so schema coverage is 0%. The description compensates fully by explaining that the parameter is the company's IČO and that spaces and missing leading zeros are acceptable. This gives agents the information needed to normalize user input correctly.
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?
The description states a specific verb ('Look up'), a specific resource ('Czech company profile'), and a precise input ('registration number (IČO)'). This clearly differentiates it from sibling tools like validate_ico_number, search_companies, and check_vat_registration, which address different needs.
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?
The description clearly implies when to use the tool: when you have a Czech IČO and want a company profile. It does not explicitly exclude alternatives or mention siblings, but the context is unambiguous enough for an agent to choose this tool over the listed siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_companiesARead-onlyIdempotent
Find Czech companies by a full or partial business name.
Args: name: The name to search for, e.g. "Renomia". limit: How many results to return (1-50).
Returns: The total number of matches and a list of hits with IČO, name and address.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly and non-destructive behavior, and the description adds useful return details: total matches plus hits with IČO, name, and address. It does not hide side effects or contradict the annotations.
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?
The first sentence states the core purpose, followed by a compact Args/Returns layout. Every line earns its place without repetition or fluff.
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 two-parameter, read-only search tool with an output schema, the description covers the input semantics, limit behavior, and result shape. Nothing essential is missing for correct invocation.
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?
Input schema has 0% description coverage, but the description compensates fully by defining 'name' with an example and explaining 'limit' with a range (1-50). This is exactly the semantics an agent needs beyond the bare property names.
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?
The description opens with a specific verb ('Find'), a specific resource ('Czech companies'), and the matching mode ('full or partial business name'). It is clearly distinct from siblings such as validate_ico_number or lookup_company, which do exact identifier-based lookups rather than name search.
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?
The description clearly implies use when the caller has a company name to search, but it does not explicitly state when to prefer this tool over lookup_company or when to use the validation siblings. There are no when-not conditions or alternative routing instructions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_ico_numberARead-only
Validate an IČO offline via its modulo-11 checksum, without calling ARES.
Useful for a quick sanity check on form input or on a number read out of a scanned document, where 0/8 and 1/7 are routinely confused.
Args: ico: A string that is supposed to be an IČO.
Returns:
valid plus the normalised eight-digit form when the number is valid.
| Name | Required | Description | Default |
|---|---|---|---|
| ico | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint=true annotation, the description discloses that validation is offline, based on modulo-11 checksum, and that it returns the normalized eight-digit form when valid. It also hints at the type of input errors it addresses (digit confusion in scanned documents), adding meaningful behavioral context.
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?
The description is compact, front-loaded with the most important purpose statement, and organized with clear Args/Returns sections. Every sentence adds value: purpose, use cases, parameter definition, and return behavior. No filler or repetition.
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 the tool's low complexity (one parameter, output schema present, no nested objects), the description fully covers purpose, usage, behavior, and parameter semantics. The return value is summarized even though an output schema exists, and the offline/online distinction is highlighted.
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?
With 0% schema description coverage, the description compensates by defining 'ico' as 'A string that is supposed to be an IČO.' This adds semantic meaning beyond the bare string type, although it does not specify length or formatting constraints explicitly—those are mildly implied by the mention of a normalized eight-digit return.
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?
The description states a specific verb ('validate'), a precise resource ('IČO'), and the validation method ('modulo-11 checksum') while explicitly noting it does not call ARES. This distinguishes it from sibling tools like lookup_company and check_vat_registration without ambiguity.
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?
It provides clear usage context: 'a quick sanity check on form input or on a number read out of a scanned document, where 0/8 and 1/7 are routinely confused.' It does not explicitly name alternatives or state when not to use them, but the offline/no-ARES framing implies a lighter-weight verification than the sibling lookup tools.
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.
4 tool updates
v0.2.0- First observed
check_vat_registration - First observed
lookup_company - First observed
search_companies - First observed
validate_ico_number
TDQS
Scored across 4 tools
The tools are mostly distinct: validate_ico_number handles offline checksum validation, search_companies finds by name, and lookup_company returns a full profile. There is minor overlap between lookup_company and check_vat_registration since both accept an IČO and lookup_company already returns a VAT ID, but the descriptions make the focused VAT-status purpose clear.
All tool names follow the same imperative verb_object pattern in snake_case: validate_, lookup_, search_, check_. This makes the tool set highly predictable and easy for an agent to reason about.
Four tools is a well-scoped size for an ARES-focused MCP server. Each tool covers a distinct, useful operation without redundancy or unnecessary bloat.
The domain is Czech company registry lookups, and the set covers offline validation, name search, full company profile retrieval, and VAT registration status. There are no important dead ends for common workflows involving finding and validating Czech companies.
Maintenance
Related MCP Connectors
Czech & Slovak business registry — company lookup by IČO, name, legal form, VAT. Official ARES.
Czech VAT-payer reliability (ADIS / nespolehlivý plátce DPH) + registered bank accounts by DIČ.
Validate EU, UK, AU VAT numbers for AI agents. EU ViDA e-invoicing compliance.
CompanyLens is a remote MCP server giving AI agents instant access to official company registry data across 19 jurisdictions in Europe, the Americas, and Asia-Pacific. Eighteen read-only tools let you search companies and people, look up officers and beneficial owners, map corporate networks through shared directors, screen names against the UK disqualified directors register, find every company at a registered address, and pull filing history — all from a single connector. Visit our website: https://companylens.io
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides access to the Czech ARES business registry API, enabling search and retrieval of official information about Czech companies, validation of IČO numbers, and filtering by various criteria like legal form, industry codes, and location.2MIT
- AlicenseAqualityCmaintenanceMCP servers for Czech government & business data: ARES (Business Register) + ČNB (FX rates). Native AI access to company lookups, VAT status, bank accounts, currency conversion.96MIT

companieswiseofficial
AlicenseAqualityCmaintenanceProvides verified UK company lookup and number validation for AI agents using official Companies House data. Enables lookup of registered details by number, validation of company number format, and search by company name.335 npmApache 2.0- AlicenseAqualityBmaintenanceMCP server for the Czech business registry ARES, enabling company validation, lookup, and due diligence checks directly from AI clients.1428 npmMIT