Skip to main content
Glama

vat-whitelist-mcp

A Model Context Protocol server that gives AI assistants clean, typed access to the Polish VAT White List (Wykaz podatników VAT). Look up taxpayers by NIP, REGON, or bank account and verify whether an account is associated with an active taxpayer on a specified date.

The official VAT White List API returns taxpayer details, VAT status, bank accounts, and confirmation identifiers. vat-whitelist-mcp exposes its REST search and check methods as five simple tools.

Built and maintained by Smart Mobile House — secure AI implementation for enterprise.

Tools

Tool

Description

search_by_nip(nip, date)

Look up a taxpayer by 10-digit NIP (tax id).

search_by_regon(regon, date)

Look up a taxpayer by 9- or 14-digit REGON.

search_by_bank_account(bank_account, date)

Find taxpayers associated with an account.

search_bulk(identifiers, id_type, date)

Look up 1–30 identifiers of one type in a single API request.

check_bank_account(identifier, id_type, bank_account, date)

Check an account's association with an active taxpayer by NIP or REGON.

Every tool requires an explicit YYYY-MM-DD date. NIP, REGON, and Polish bank account checksums are validated locally. Bank accounts accept a 26-digit NRB or its PL IBAN form, with common grouping separators.

Search responses contain count, results, date, and a source block naming the register, environment, and UTC retrieved_at time. The API's requestId and requestDateTime are retained, along with the original taxpayer fields.

Bulk id_type is nip, regon, or bank_account; check id_type is nip or regon. Bulk results contain one entry per identifier, with either subjects or an upstream error; count counts entries. requested contains normalized inputs, and unmatched lists successful entries with no subjects. Failed entries are never treated as missing taxpayers. Checks preserve accountAssigned as TAK or NIE; API failures raise errors rather than returning NIE.

Related MCP server: nip-checker-mcp

Quick start

No install needed — run it straight from the repo with uv:

uvx --from git+https://github.com/SmartMobileHouse/vat-whitelist-mcp vat-whitelist-mcp

By default it uses the sandbox, with no API key or account required. Set VAT_ENV=prod for live data. For example, ask your assistant to look up a NIP using today's explicit date.

After the first PyPI release, the package can also run as uvx vat-whitelist-mcp.

Use it in Claude Desktop / Claude Code

Add to your MCP config (e.g. claude_desktop_config.json or .mcp.json):

{
  "mcpServers": {
    "vat-whitelist": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/SmartMobileHouse/vat-whitelist-mcp", "vat-whitelist-mcp"],
      "env": {
        "VAT_ENV": "prod"
      }
    }
  }
}

During development, point it at a local checkout instead:

{
  "mcpServers": {
    "vat-whitelist": {
      "command": "uvx",
      "args": ["--from", "/absolute/path/to/vat-whitelist-mcp", "vat-whitelist-mcp"],
      "env": { "VAT_ENV": "test" }
    }
  }
}

Configuration

Variable

Default

Description

VAT_ENV

test

test for the sandbox or prod for live data.

VAT_TIMEOUT

30

Positive finite HTTP timeout in seconds.

Set these in the shell or MCP configuration. .env.example is a reference; .env files are not loaded automatically.

The API base URLs are https://wykazpodatnikowvat-test.mf.gov.pl/api/ for the sandbox and https://wykazpodatnikowvat.mf.gov.pl/api/ for production.

Development

git clone https://github.com/SmartMobileHouse/vat-whitelist-mcp
cd vat-whitelist-mcp
uv sync --locked        # create the venv and install dependencies
uv run pytest           # offline validation, mocked HTTP, MCP discovery and stdio tests
                        # (network tests are skipped by default)
uv run vat-whitelist-mcp # run the server over stdio
uv build                # build source and wheel distributions
uvx twine check dist/*  # validate package metadata

# Live tests against the official sandbox (opt-in; no production requests):
VAT_RUN_NETWORK=1 uv run pytest -m network

The client is a small REST layer over httpx (see src/vat_whitelist_mcp/client.py), with no authentication session or automatic retries. Python 3.10 or newer is required.

Releases

GitHub Actions runs the offline tests, validates versions, builds the wheel and source distribution, and checks metadata on pull requests and pushes to main. Pushing a version tag such as v0.1.0 publishes the tested artifacts to PyPI using Trusted Publishing, then publishes the matching MCP Registry metadata. The workflow can also be dispatched manually from main.

Before the first release, add a pending Trusted Publisher in the maintainer's PyPI account with these values:

Field

Value

PyPI project name

vat-whitelist-mcp

GitHub owner

SmartMobileHouse

Repository

vat-whitelist-mcp

Workflow filename

publish.yml

Environment

pypi

The GitHub pypi environment must exist. No PyPI API token is needed. See PyPI's setup guide. Keep versions in pyproject.toml, src/vat_whitelist_mcp/__init__.py, and server.json aligned before tagging. A failed MCP Registry job can be retried independently after PyPI succeeds.

Notes & limitations

  • Sandbox data is synthetic. Use VAT_ENV=prod for live taxpayer information.

  • Dates must be no later than today in Poland and fall within the current year or the five preceding calendar years, no earlier than 1 September 2019. The API may impose additional historical-data restrictions.

  • The published limits are 100 search requests per day, up to 30 identifiers per request, and 5,000 check verifications per day. Quotas apply to the requesting IP; exhausting a quota can block access until midnight. See the official API documentation for current terms and limits.

  • WL2 status queries and flat-file verification are outside this tool set.

  • This project is independent and is not affiliated with or endorsed by the Ministry of Finance or the National Revenue Administration.

License

MIT © Smart Mobile House

Available Tools

5 tools
check_bank_accountB

Check account association with an active taxpayer on YYYY-MM-DD.

id_type: nip or regon. accountAssigned is the API's TAK/NIE answer; API
failures raise errors and must never be interpreted as a negative match.
NameRequiredDescriptionDefault
dateYes
id_typeYes
identifierYes
bank_accountYes

TDQS

B3.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, this description does real work: it discloses that the result field is 'accountAssigned' reflecting the API's TAK/NIE answer, and warns that API failures raise errors and must never be read as a negative match — an important interpretation trap. It still omits auth requirements and whether the check is read-only or side-effect free.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the purpose and followed by the two highest-risk clarifications. The unsubstituted 'YYYY-MM-DD' placeholder is slightly confusing, but overall it is tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, and the description only explains one return signal (accountAssigned); it doesn't describe the overall response shape or how a false/absent result is represented. Combined with zero parameter documentation, an agent can guess the call but not confidently interpret all outcomes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the full burden. It only documents id_type values ('nip or regon') and gives a date format hint via the literal 'YYYY-MM-DD'; identifier and bank_account are completely unexplained (format, TAK vs NIE, normalization of the account number).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: check whether a bank account is associated with an active taxpayer. The 'check' verb distinguishes it from the sibling search_* tools, which look records up rather than answer an association question. It does not explicitly name search_by_bank_account as the alternative, so differentiation is implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by the verb 'check' and the phrase 'active taxpayer'. With siblings search_by_nip / search_by_regon / search_by_bank_account that overlap substantially, the description never says when to prefer this tool over them or what preconditions (an active taxpayer existing) mean in practice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_bulkA

Look up 1–30 identifiers in one request on YYYY-MM-DD.

id_type: nip, regon, or bank_account. Results retain each identifier's
subjects or API error. Only successful empty entries appear in unmatched.
count is the number of returned entries, not the number of taxpayers.
NameRequiredDescriptionDefault
dateYes
id_typeYes
identifiersYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does add real behavioral context: per-identifier results retain subjects or an API error, only successful empty entries land in 'unmatched', and count is entries not taxpayers. This pre-empts the most likely misreading of the response. It says nothing about auth or rate/latency behavior for a 30-item batch, which is the remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Compact and front-loaded — the core action and limit land in the first sentence, with response semantics in a tight trailing block. Minor deduction for the unrendered 'YYYY-MM-DD' template token, which reads as a leftover placeholder rather than deliberate wording.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-required-parameter read tool with no annotations and no output schema, the description covers the essentials the structured fields omit: identifier count limit, id_type values, and return-shape semantics. It is missing only what 'date' means and any statement about partial-failure handling beyond 'API error' being retained per entry.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate and largely does: it enumerates id_type values (nip, regon, bank_account) that are absent from the schema's free-form string, and states the 1–30 bound on the identifiers array. The date parameter is only gestured at via 'on YYYY-MM-DD', which clarifies format but not what the date selects (snapshot vs. registration date).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and scope: 'Look up 1–30 identifiers in one request,' which distinguishes it from the single-identifier siblings (search_by_nip, search_by_regon, search_by_bank_account) by breadth. It never names a sibling explicitly, so the differentiation is inferable rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The '1–30 identifiers in one request' framing implies bulk use and the id_type enumeration implies mixed-identifier use, but there is no explicit 'use search_by_nip instead when you have one identifier' or exclusion guidance. The agent must infer the boundary from the siblings' names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_by_bank_accountB

Find taxpayers for a Polish bank account on YYYY-MM-DD; accepts NRB or PL IBAN.

NameRequiredDescriptionDefault
dateYes
bank_accountYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the full behavioral burden. It does disclose two useful traits: the lookup is scoped to Polish accounts and accepts NRB or PL IBAN formats, plus 'Find' implies a read-only lookup. However, it says nothing about result limits, no-match behavior, or what a returned taxpayer record contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler, and the identifier constraint is placed immediately after the purpose. It is arguably too terse given the 0% schema coverage, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter lookup with no annotations and no output schema, the description covers purpose and input formats but omits result shape, date semantics, and behavior on no match. It is minimally viable rather than complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate for both parameters. It does add meaning for bank_account (NRB or PL IBAN accepted) and gives a date format (YYYY-MM-DD), which is genuinely helpful. But it doesn't explain what the date means — as-of date, registration date, or something else — leaving a real semantic gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: "Find taxpayers for a Polish bank account". The identifier type (bank account) inherently separates it from search_by_nip and search_by_regon, but it never explicitly distinguishes itself from check_bank_account, which is the closest sibling and the main source of confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use, when-not-to-use, or alternative routing is given. It never says whether this should be preferred over check_bank_account or search_bulk, leaving the agent to infer selection purely from the tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_by_nipC

Look up taxpayer details by NIP on an explicit YYYY-MM-DD date.

NameRequiredDescriptionDefault
nipYes
dateYes

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden, but it only says 'look up' (implying a read) and never states whether the result is a point-in-time snapshot as of the given date, what happens when no taxpayer matches, or any auth/rate-limit considerations. That leaves the most consequential behavior — the meaning of the date — undisclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler, and the format constraint is placed where it will be read. It is arguably under-specified rather than padded, which is a completeness issue rather than a structural one.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-required-parameter lookup with no annotations and no output schema, the description should explain what 'taxpayer details' contains, whether the date is an as-of filter, and how misses are signalled. None of that is present, so an agent cannot predict the response shape or failure mode.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% for two required parameters, so the schema supplies no meaning. The description adds real value for 'date' by constraining it to explicit YYYY-MM-DD format, but it never explains what that date selects (as-of status? registration date?), and 'nip' is left entirely undefined beyond the acronym.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ('Look up') and resource ('taxpayer details') and identifies the key as NIP, which implicitly separates it from search_by_regon and search_by_bank_account. It does not name those siblings, so an agent must infer the differentiation from the differing identifier.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to use this tool versus search_by_regon, search_bulk, or check_bank_account, and no conditions or exclusions. The only implied guidance is that the caller must already hold a NIP and a date.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_by_regonC

Look up taxpayer details by 9- or 14-digit REGON on YYYY-MM-DD.

NameRequiredDescriptionDefault
dateYes
regonYes

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the full behavioral burden. 'Look up taxpayer details' suggests a read-only operation, but it says nothing about permissions, rate limits, failure behavior, or what taxpayer details are returned.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence with no wasted words. It states the operation, identifier, and date format efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero annotation coverage, no output schema, and no parameter descriptions in the schema, the description is too sparse. It does not describe return values beyond 'taxpayer details', error cases, or the precise meaning of the date parameter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It usefully specifies that REGON is 9- or 14-digit and gives the date format as YYYY-MM-DD, but it does not explain what the date means (e.g., as-of date, snapshot date, or search date).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: 'Look up taxpayer details' by REGON. It clearly distinguishes the lookup scope from sibling tools like search_by_nip and search_by_bank_account because the identifier type is stated, though it does not explicitly name those alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It implies the tool is used when a 9- or 14-digit REGON and date are available, but provides no explicit when-to-use, when-not-to-use, or alternative-tool guidance against search_by_nip, search_by_bank_account, or search_bulk.

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. 5 tool updatesv0.1.0
    • First observedcheck_bank_account
    • First observedsearch_bulk
    • First observedsearch_by_bank_account
    • First observedsearch_by_nip
    • First observedsearch_by_regon

TDQS

A3.5/5.0

Scored across 5 tools

Disambiguation4/5

The single-identifier lookup tools are clearly separated by NIP, REGON, and bank account, and search_bulk is explicitly bulk. check_bank_account and search_by_bank_account both concern bank-account relationships and could be momentarily confused, but their descriptions distinguish search from association checking.

Naming Consistency4/5

All tool names use snake_case and clear action/resource wording. There is a minor deviation between search_by_* tools, search_bulk, and check_bank_account, but the pattern remains readable and predictable.

Tool Count5/5

Five tools is well scoped for a focused VAT whitelist lookup server. Each tool covers a distinct lookup mode and none feels redundant or excessive.

Completeness4/5

The tool set covers core lookup workflows: NIP, REGON, bank account, bulk lookup, and bank-account association checking. Minor gaps exist, such as no dedicated explicit VAT-status check by NIP/REGON beyond search results, but the main domain surface is covered.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Look up Polish companies from any AI assistant: registry data (KRS, REGON, CEIDG), VAT white list checks before payments, and financial statements of 4.4M businesses. Read-only tools backed by official public registers.
    4
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables real-time verification of Polish NIP (Tax Identification Numbers) using the official Ministry of Finance API. Also supports checking if a bank account belongs to a specific NIP.
    2
    4 npm
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    MCP server that provides AI agents with Polish business data tools: identifier validation (NIP, PESEL, REGON, KRS, IBAN), VAT whitelist checks, EU VIES lookups, and NBP exchange rates.
    5
    7 npm
    MIT