Skip to main content
Glama
emilpinski

mcp-polish-data

by emilpinski
README.md
# mcp-polish-data

[![CI](https://github.com/emilpinski/mcp-polish-data/actions/workflows/ci.yml/badge.svg)](https://github.com/emilpinski/mcp-polish-data/actions/workflows/ci.yml)

![Status](https://img.shields.io/badge/Status-Live-green)

> MCP Server with Polish public data — KRS, CEIDG, GUS BDL for Claude, Cursor, and Windsurf.

![Landing page](screenshot.png)

## What is it

A Model Context Protocol (MCP) server that gives AI assistants direct access to Polish government registries and GUS statistics without leaving the chat. Install once, and Claude or Cursor automatically knows how to look up companies in KRS, verify sole traders in CEIDG, and retrieve regional statistics from GUS BDL.

MIT licensed, no API key required.

## Features

- **KRS** — look up a company by NIP (via VAT Whitelist — KRS API doesn't support name search), retrieve full extract by 9 or 10-digit KRS number
- **CEIDG** — search sole trader businesses by name, NIP, REGON, or owner surname
- **GUS BDL** — population by voivodeship, unemployment rate, average gross salary, statistical variable discovery
- **VAT Whitelist (Biala Lista MF)** — verify taxpayer VAT status (active/exempt/deregistered), registered bank accounts, SHA-256 response hash for audit trail
- **NIP / REGON / PESEL validation** — checksum verification with no API calls; PESEL also extracts date of birth and gender (flagged PII-sensitive)
- **SQLite caching** — transparent response cache with per-tool TTL (KRS/CEIDG: 7 days, GUS: 30 days, VAT: 1 day); validation tools are never cached
- **Retry with exponential backoff** — handles 429 (respects Retry-After header) and 5xx errors with up to 3 attempts and jitter
- **Graceful degradation** — when CEIDG requires a JWT token, the server provides a helpful message instead of crashing
- **Zero configuration** — single pip install, no API keys required for basic functions
- **Python 3.11+** — async/await, httpx, FastMCP 2.0

## Stack

| Layer | Technology |
|-------|-----------|
| Protocol | Model Context Protocol (MCP) |
| Framework | FastMCP 2.0 |
| HTTP | httpx (async) |
| Python | 3.11+ |
| Build | Hatchling |
| Tests | pytest, pytest-asyncio |
| License | MIT |

## Getting Started

```bash
pip install mcp-polish-data
```

### Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "polish-data": {
      "command": "mcp-polish-data"
    }
  }
}
```

Restart Claude Desktop — tools will appear automatically.

### Cursor / Windsurf

```bash
git clone https://github.com/emilpinski/mcp-polish-data
cd mcp-polish-data
pip install -e ".[dev]"
pytest tests/ -v -m "not integration"
```

## Available Tools

| Tool | Description |
|------|-------------|
| `krs_search_company(nip)` | Search company by NIP (via VAT Whitelist — KRS API doesn't support name search) |
| `krs_get_company_details(krs_number)` | Full extract for a 9 or 10-digit KRS number |
| `ceidg_search_business(name, nip, regon, surname)` | Search sole traders in CEIDG |
| `gus_get_population(unit_name, year)` | Population by voivodeship |
| `gus_get_unemployment_rate(year)` | Unemployment rate by voivodeship |
| `gus_get_average_salary(year)` | Average gross salary by voivodeship |
| `gus_search_variable(query)` | Discover statistical variables in GUS BDL |
| `vat_whitelist_check(nip, check_date)` | Check VAT taxpayer status in MF Biala Lista — returns VAT status, registered bank accounts, response hash for audit |
| `validate_nip_number(nip)` | Validate NIP checksum — pure local computation, no API calls |
| `validate_regon_number(regon)` | Validate REGON checksum (9 or 14 digits) — pure local computation, no API calls |
| `validate_pesel_number(pesel)` | Validate PESEL checksum and extract date of birth and gender (PII-sensitive, GDPR applies) |
| `batch_company_lookup(nips)` | Look up up to 50 companies by NIP simultaneously — returns name, VAT status, KRS number, REGON per NIP. Results cached 7 days. |
| `cache_stats_info()` | Show SQLite cache statistics: total entries, per-tool breakdown, hits in last 24h |

## Environment Variables

| Variable | Description | Required |
|----------|-------------|----------|
| `CEIDG_TOKEN` | JWT token for advanced CEIDG endpoints | optional |

## Example Prompts

- *"Look up NIP 5270103391 and tell me the company name and address"*
- *"Compare the unemployment rate in 2023 across all voivodeships"*
- *"What is the average salary in Pomerania vs Masovia?"*
- *"Find all CEIDG sole traders with surname Kowalski in Kraków"*

## Status

Live — [mcp-polish-data.vercel.app](https://mcp-polish-data.vercel.app) | [PyPI: mcp-polish-data](https://pypi.org/project/mcp-polish-data/)

---
Built by [Emil Piński](https://emilpinski.pl)

## Screenshots

![Landing page and documentation](docs/screenshots/claude-desktop-integration.jpeg)
![API endpoints overview](docs/screenshots/krs-lookup-example.jpeg)

TDQS

A4/5.0

Scored across 7 tools

Disambiguation4/5

Tools are mostly distinct: CEIDG vs KRS for different entity types, GUS tools for different statistics. However, ceidg_search_business and krs_search_company could be confused when searching for a company that might be in both, but descriptions clarify which to use.

Naming Consistency5/5

All tools follow a consistent 'datasource_action_entity' pattern (e.g., ceidg_search_business, gus_get_average_salary, krs_search_company). No mixing of conventions.

Tool Count5/5

7 tools is appropriate for a Polish business data server covering CEIDG, KRS, and GUS statistical data. Each tool serves a distinct purpose without being too few or too many.

Completeness4/5

Covers key business lookup (CEIDG, KRS) and major GUS indicators (salary, population, unemployment) with a generic search. Missing some Polish databases (e.g., REGON) but core workflows are well-supported.

Maintenance

ActivityInactive
ResponsivenessNo issues