Skip to main content

kio-orzeczenia-mcp

MCP server (Model Context Protocol) for the case law of the Krajowa Izba Odwolawcza (KIO) (National Appeals Chamber) at the Urzad Zamowien Publicznych (Public Procurement Office) - the public database orzeczenia.uzp.gov.pl.

It lets Claude / Cursor / VS Code MCP agents consume KIO rulings with verifiable citations (signature + URL + date).

Status: POC v0.1.0 | License: Apache-2.0 | Maintainer: MateMatic

Preliminary warning. The v0.1.0 connector is a proof-of-concept release. It fetches data from the public UZP case law database via HTML (no official REST API). Full legal disclaimer - see the "Legal disclaimer" section below. A dedicated smoke test and notification to UZP are required before production deployment.


What KIO is

The Krajowa Izba Odwolawcza (National Appeals Chamber) is an administrative (quasi-judicial) body operating at the Urzad Zamowien Publicznych (Public Procurement Office) - KIO members are independent when adjudicating (art. 471 PZP) - which hears appeals against contracting authorities' decisions in public procurement proceedings (the Act of 11 September 2019 - Public Procurement Law). KIO rulings are made publicly available by UZP under the Act on access to public information.

KIO rulings are not a source of law within the meaning of art. 87 of the Constitution of the Republic of Poland - they are reference material widely used in the practice of law firms dealing with public procurement.

Quickstart

# Clone and enter the directory
git clone https://github.com/matematicsolutions/kio-orzeczenia-mcp.git
cd kio-orzeczenia-mcp

# Virtualenv
python -m venv .venv
.\.venv\Scripts\Activate.ps1

# Install
pip install -e ".[dev]"

# Offline test (signature parser)
pytest tests/test_signature.py -v

# Smoke test (online - hits UZP, rate-limited 1 req/s)
pytest tests/test_smoke.py -v -m smoke

# Run the server (stdio)
python -m kio_orzeczenia_mcp.server

Wiring into Claude Code

Add to ~/.claude.json (or .mcp.json in the project):

{
  "mcpServers": {
    "kio-orzeczenia": {
      "command": "python",
      "args": ["-m", "kio_orzeczenia_mcp.server"],
      "env": {
        "KIO_MCP_RATE_LIMIT": "1.0",
        "KIO_MCP_CACHE_DIR": "~/.matematic/cache/kio"
      }
    }
  }
}

Restart Claude Code. After startup, 5 tools should be visible.

Windows 11 with Smart App Control

Smart App Control blocks unsigned executables, which covers uvx.exe, pip.exe and the kio-orzeczenia-mcp.exe launcher that pip writes at install time. The python.exe and py.exe from the python.org installer are signed by the Python Software Foundation, so running the module through the interpreter works:

python -m pip install kio-orzeczenia-mcp
python -m kio_orzeczenia_mcp

pip.exe is blocked for the same reason, so install with python -m pip, not pip install. If python is not on PATH, use the Windows launcher: py -3 -m kio_orzeczenia_mcp.

{ "mcpServers": { "kio-orzeczenia-mcp": { "command": "python", "args": ["-m", "kio_orzeczenia_mcp"] } } }

Do not turn Smart App Control off to work around this - it cannot be re-enabled without reinstalling Windows.

5 MCP tools

1. kio_search(query: SearchQuery) -> SearchResult

Search over KIO case law. All fields optional.

// Arguments:
{
  "phrase": "razaco niska cena",
  "signature": null,
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "pzp_article": "226",
  "subject_index": null,
  "inflection": true,
  "page": 1,
  "size": 20
}

Returns {total, page, items: [OrzeczenieSummary]}.

2. kio_get_orzeczenie(signature_or_id: str | int) -> Orzeczenie

Fetches the full text of a single ruling.

// Arguments:
"KIO 2924/21"   // string -> first search by signature to resolve internal_id (+1 req)
15903           // int -> directly GET /Home/Details/15903 + /Home/ContentHtml/15903

Returns the full Orzeczenie with content_text, sentence, reasoning (if the parser can extract them), pzp_articles, subject_index, doc_type, outcome, chamber_composition, parties.

issue_date may be null - UZP has no issue date for some older records. We do not substitute a placeholder date.

3. kio_recent(days: int = 30, limit: int = 20) -> list[OrzeczenieSummary]

The most recent rulings from the last N days, sorted by date descending.

// Arguments:
{ "days": 30, "limit": 20 }

4. kio_by_pzp_article(article: str, limit: int = 20) -> list[OrzeczenieSummary]

Rulings citing a specific PZP article. Uses the UZP server-side Art filter, which matches the provisions dictionary and is format-sensitive ("art. 226 ust. 1 pkt 5" hits, plain "226" does not). On an empty result the tool falls back to a full-text phrase search.

// Arguments:
{ "article": "art. 226 ust. 1 pkt 5", "limit": 20 }
{ "article": "224 ust. 1", "limit": 50 }   // "art. " prefix added automatically

5. kio_get_pdf_url(signature_or_id: str | int) -> dict

Returns the URL to the PDF (rendered by UZP from .docx via Qt 4.8.7). Does not fetch bytes - we link to it.

// Returns:
{
  "pdf_url": "https://orzeczenia.uzp.gov.pl/Home/PdfContent/15903?Kind=KIO",
  "signature": "KIO 2924/21",
  "internal_id": 15903,
  "human_readable_citation": "Wyrok KIO z 2021-10-28, sygn. KIO 2924/21"
}

3 usage examples (natural language)

Example 1: "KIO rulings on abnormally low price from the past year"

The agent calls kio_search:

{
  "phrase": "razaco niska cena",
  "date_from": "2025-05-20",
  "date_to": "2026-05-20",
  "inflection": true,
  "size": 50
}

Result: a list of OrzeczenieSummary with human_readable_citation ready to insert into a court filing.

Example 2: "KIO rulings citing art. 226 sec. 1 point 5 PZP"

The agent calls kio_by_pzp_article:

{ "article": "226 ust. 1 pkt 5", "limit": 30 }

Example 3: "Ruling KIO 2924/21 - who were the parties and was the appeal upheld"

The agent calls kio_get_orzeczenie:

"KIO 2924/21"

Result: the full Orzeczenie with parties, sentence, reasoning.


Limitations (POC)

  1. Mapping signature -> internal_id requires a search - if you query by signature, we make +1 req
  2. Server-side PZP article filter is dictionary-based - Art matches entries of the UZP provisions dictionary, so the format matters ("art. 226 ust. 1 pkt 5", not "226"); on a miss we fall back to a phrase search, which is broader and needs verification
  3. PDF not fetched - only a link to the UZP page (product decision)
  4. The sentence/reasoning parser is shallow - in the POC we return content_text as plain text. Splitting into sections -> v1.0
  5. Rate limit 1 req/s - large lists may be slow. A 7-day cache for rulings (immutable) mitigates this.
  6. UZP serves a fixed 10 results per page - size > 10 is stitched client-side from consecutive pages, i.e. +1 request per extra page
  7. Scraping, not an API - UZP rebuilt the search engine in July 2026 and every endpoint moved (see DISCOVERY.md). Run pytest -m smoke after any UZP-side change; tests/test_parser_regression.py guards the parser offline.

Cache

  • Rulings (immutable): 7 days
  • Search result lists: 6 hours
  • PZP dictionary (once implemented): 30 days

Cache location: ~/.matematic/cache/kio/ (configurable via KIO_MCP_CACHE_DIR).

Audit log

Location: ~/.matematic/audit/kio-orzeczenia-mcp.jsonl

JSONL format (one entry per tool call). See CONSTITUTION.md Art. 3.

What is NOT logged: the full text of a ruling (content_text, reasoning). We log only signatures and metadata.

Legal disclaimer

The data comes from the public UZP case law database (orzeczenia.uzp.gov.pl), made available under the Act of 6 September 2001 on access to public information and the Act of 11 September 2019 - Public Procurement Law.

The connector:

  • does not modify the source data,
  • does not de-anonymize the parties to a proceeding beyond what UZP publishes,
  • does not circumvent any technical protections,
  • identifies itself with the User-Agent header matematic-kio-mcp/{version} (+https://matematic.co).

Pre-release blocker. Before publishing the repository on GitHub, a notification to UZP (kontakt@uzp.gov.pl) about launching the connector is planned - User-Agent, query limit, nature of access. Status: TODO.

In case of objections from UZP or other parties - contact: kontakt@matematic.co.

License

Apache-2.0. See LICENSE.

Project constitution

See CONSTITUTION.md - 4 governance principles (public data, rate limit, audit log, citations).

Other open connectors for Polish law

Open-source connectors by MateMatic that complement the scope of this repository:

  • mcp-saos - SAOS (Supreme Court, Supreme Administrative Court, common courts)
  • mcp-eu-sparql - EU law via Cellar SPARQL
  • mcp-isap - Journal of Laws, Monitor Polski, ministerial gazettes (Sejm ELI API)

External catalog of legal sources: worldwidelaw/legal-sources (bulk harvest scripts, MIT).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kio_orzeczenia_mcp-0.3.0.tar.gz (163.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kio_orzeczenia_mcp-0.3.0-py3-none-any.whl (33.8 kB view details)

Uploaded Python 3

File details

Details for the file kio_orzeczenia_mcp-0.3.0.tar.gz.

File metadata

  • Download URL: kio_orzeczenia_mcp-0.3.0.tar.gz
  • Upload date:
  • Size: 163.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for kio_orzeczenia_mcp-0.3.0.tar.gz
Algorithm Hash digest
SHA256 eff8c5cfc73a0ac66639ae215ce3f01a7bbd2207650d9a677a76fbdbe73320a6
MD5 fe1ee4b9d65909e79e634035a12a0871
BLAKE2b-256 161538686738a21756c8b87b854ec75de0e55cd03d096e2f4d886a3a194b79f7

See more details on using hashes here.

File details

Details for the file kio_orzeczenia_mcp-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for kio_orzeczenia_mcp-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 500684fc31a8ba07b23e21422882b6ea94ea12df58c5ca96d581e9b48f3eb604
MD5 b4094e5c6958f3361e998ebd9168646a
BLAKE2b-256 e36244fd47437114341894a13c5723e1f9b9f09dc08d76baac5bb1e2ce9fb103

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page