legal-mcp-croatia
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., "@legal-mcp-croatiaSearch for bankruptcy notices for Podravka d.d. from last month"
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.
legal-mcp-croatia
An MCP server that lets an AI assistant read Croatian public legal registers:
e-Oglasna ploča sudova — the court noticeboard
Sudski registar — the company register, including a change monitor
It is read-only, it stores nothing, and it logs nothing. There is no database, no account, and no service in the middle: the server runs on your machine, talks to public government APIs, and returns the answer. Nothing about what you searched for leaves the process.
That is deliberate. Which companies or people a law firm looks up is the firm's client list, and it is not ours to hold.
Install
git clone https://github.com/AvoccadoTech/legal-mcp-croatia.git
cd legal-mcp-croatia
pip install -e .Requires Python 3.11 or newer.
Related MCP server: Law7 MCP
Run
The server speaks MCP over stdio. Register it with any MCP-capable client:
{
"mcpServers": {
"croatia-legal": {
"command": "python",
"args": ["-m", "croatia_legal_mcp"],
"env": {
"SUDREG_CLIENT_ID": "...",
"SUDREG_CLIENT_SECRET": "..."
}
}
}
}e-Oglasna needs no credentials. Sudski registar does — see below. Without them the e-Oglasna tools work normally and the Sudreg tools return an error saying where to register.
Optional: set EOGLASNA_DOWNLOAD_ROOT to choose where downloaded PDFs go. It defaults to ./eoglasna-downloads, and the server refuses to write outside it.
e-Oglasna ploča sudova
The electronic noticeboard where Croatian courts publish notices they are legally required to make public — enforcement (ovrha), corporate and personal bankruptcy, land-registry proceedings, substitute service, and other court publications. Notices from FINA and from notaries appear on the same board.
Each notice carries the issuing court, the case number, publication and expiry dates, the parties named, and the scanned decision as PDF.
The API is genuinely open: no registration, no API key, no rate-limit documentation. The underlying data is published under the Croatian Otvorena dozvola (Open Licence).
It is a noticeboard, not a case-law database. There is no legislation and no judgments here — for those, see Narodne novine and the Supreme Court's case-law portal.
Tools
Tool | What it does |
| Search by company name, personal name, case number or OIB, optionally within a publication date range |
| One notice in full — every party, every attached document |
| Save one attached PDF locally and return its path |
| Every court and body publishing to the board, with codes |
eoglasna_search_notices takes a source:
| Endpoint | Use it for |
|
| Everything from courts, with court, case number and case type |
|
| Also FINA and notary notices, but without those three fields |
|
| Corporate insolvency only — has a client's counterparty gone under? |
|
| Consumer insolvency only |
The bankruptcy views are separate endpoints rather than a filter, because caseType is another parameter the API accepts and ignores.
In company_bankruptcies every debtor is a company — the view is filtered on LEGAL_PERSON_BANKRUPTCY — which makes it the least risky view to put on a screen in front of an audience. It is not a guarantee that no individual appears: the other participants are not filtered, and the bankrupt company's zakonski zastupnik shows up as a named natural person with an OIB. Check the page before you project it.
One thing worth knowing before you build your own
The published OpenAPI document describes the search filter as an object, and the API accepts a JSON-encoded filter= parameter and then ignores it. You get HTTP 200, a well-formed page of results, and the entire ~900,000-notice corpus sorted newest-first — for every search term, including nonsense ones.
It looks like it is working. It is not. Spring binds the filter from flat query parameters:
GET /api/v1/court-notice?text=HEP&datePublishedFrom=2026-01-01&page=0A monitoring tool built on the documented form would report a match for every term it was ever given. There is a regression test in tests/test_smoke.py guarding this.
Personal data
Notices name natural persons and include their OIB and, in the full record, their home address. This is a public register and republication is lawful, but it is still personal data under GDPR.
Two consequences the server enforces or flags:
Addresses appear only when you request one specific notice, never in bulk search output.
Every notice carries an expiry date. That is the date it comes off the board — the state has decided it should stop being public. If you keep a copy past that date, you are republishing something that was deliberately withdrawn. Build a retention rule.
The expiry date is not a procedural deadline and must never be presented as one. It says when the notice disappears, not when anyone has to do anything.
Sudski registar
Croatia's company register, kept by the commercial courts: every company, branch and institution entered in the court register, with its registered name, legal form, seat, share capital, registry court, and whether a bankruptcy or liquidation is running.
Sole traders (obrt) are not here — they are in the Obrtni registar. Associations are in the Registar udruga. Both are separate registers with separate services.
Credentials
Free, but not open. Register at sudreg-data.gov.hr, confirm the email, and you are issued a Client ID and Client Secret. Set them in the environment of the server:
export SUDREG_CLIENT_ID=...
export SUDREG_CLIENT_SECRET=...Both values end in two literal dots. They are part of the credential and are easily lost when copying. If the server reports rejected credentials, check the ends of the strings first.
Authentication is OAuth2 client credentials; the token lasts six hours and is cached in the process.
The credentials are issued to a registered user. Before serving several firms through one set, read the terms — a shared key across clients is a question for the register, not an implementation detail.
Tools
Tool | What it does |
| One company by OIB or MBS — name, legal form, seat, capital, status, proceedings, accounts filed |
| Find companies by registered name, returning MBS and OIB |
| The monitor. Which of the companies you watch have changed since you last looked |
| Which daily snapshots the open-data service is serving, and how fresh they are |
The monitor, and why it holds no watchlist
Every subject in the register carries scn_zadnje_izmjene — an Oracle system change number, monotonically increasing, returned on every read. That one field is enough to make monitoring a pure function:
you pass the identifiers and the SCNs you last saw, we say which ones moved, you store the new SCNs.
So there is no watchlist here, no seen-ledger, and no state of any kind. Which companies a firm watches is its client list; keeping it on the firm's side is not a limitation of this design, it is the design.
A run starts from the firm's own file, wherever the firm keeps it:
[
{ "identifier": "75399377119", "identifier_type": "oib", "last_seen_scn": 6641203, "label": "Counterparty A" },
{ "identifier": "080000604", "identifier_type": "mbs", "last_seen_scn": 6640911, "label": "Client B" }
]Pass those to sudreg_check_watchlist. The report leads with what moved, says what each changed subject looks like now — struck off, in bankruptcy, in liquidation — and ends with a table of SCNs to write back. Omit last_seen_scn on the first run and the report gives you the baseline instead.
Two honest limits, both stated in the output of the tool itself:
The register says that a subject changed, not which field. Compare
sudreg_get_subjectagainst your own record to see what moved.Open data is copied from the live register at 19:00 on working days. Something filed this morning may not appear until tomorrow, and on a Monday the freshest snapshot is Friday — three days old. Every watchlist report prints the snapshot age on the first line rather than burying it, and pins every lookup in the run to that one snapshot so the whole report describes a single state.
One word of caution about register status. It means entered in the register, not trading and not solvent: a company keeps status 1 for years while in bankruptcy. The output says "registered" rather than "active" for exactly that reason, and prints any running proceeding in bold next to it.
What is not in this register
No officers, no board members, no beneficial owners. Personal data was withdrawn from the open service, so nothing here answers "who can sign for this company". That comes from a court extract (izvadak), or for ownership from the Registar stvarnih vlasnika. The tool descriptions say so, because an assistant that guesses at representation from a company record is worse than no tool at all.
No financial figures. The register records that annual accounts were filed and when — useful on its own — but the numbers are in the Fina RGFI.
One thing worth knowing before you build your own
This is a replication API, not a lookup API. Of its 39 methods, exactly one — /detalji_subjekta — takes an identifier. Everything else (/tvrtke, /sjedista, /temeljni_kapitali, /promjene) is a full table dump with offset and limit and no way to filter by company. It is built for someone mirroring the register nightly.
/promjene looks like the obvious basis for a monitor and is the wrong one for this job: it is the change list for the whole register, meant to be diffed against the copy you already hold. For a firm watching a few dozen counterparties, one /detalji_subjekta call each is smaller, exact, and needs no stored copy.
/subjekti accepts tvrtka_naziv and is the only server-side text filter the public API offers — and it carries identifiers but not the name, which lives in a separate table. So a name search resolves each candidate with a second call.
tvrtka_naziv is a SQL LIKE pattern with no implicit wildcards. Verified live on 2026-08-31:
tvrtka_naziv=KOESTLIN → 0 rows
tvrtka_naziv=%KOESTLIN% → the company
tvrtka_naziv=%koestlin% → the company (matching is case-insensitive)This is the same class of trap as the e-Oglasna filter, failing the other way. e-Oglasna returns everything and looks like it worked; here you get an empty result that reads as a fact about the world — "no such company" about a company that exists, which is the worse of the two answers to hand a lawyer. The server wraps a bare term in %…% and passes through anything containing %, and there is a live test pinning all three cases.
Two smaller things that produce wrong output rather than no output:
naznaka_imenais not a suffix. It is the distinguishing designation and it repeats part of the name — for MBS 010000162 the pair is("KOESTLIN dioničko društvo,tvornica keksa i vafla", "KOESTLIN"). Concatenating them invents a company name that no register ever issued. The full name isimealone.postupakis always present, and code 1 reads "Bez postupka" — no proceeding. Rendering it verbatim puts a bankruptcy-shaped alarm on every healthy company. The live code list is 1 Bez postupka, 2 Stečaj, 3 Likvidacija, 4–7 the predstečaj stages.
Not a substitute for a lawyer
These are search tools over public registers. They do not check whether a notice was validly served, whether a deadline runs, whether a filing was correct, or what any of it means. A qualified lawyer decides that.
Tests
pip install -e ".[dev]"
pytest -m "not live" # offline: query building, identifiers, change detection
pytest -m live # hits the real APIs; Sudreg tests skip without credentialsRoadmap
e-Savjetovanja — draft legislation out for public consultation. Open licence, no key. Warns that a statute is being amended before it is.
Narodne novine (official gazette) — ELI metadata is open and keyless; full text is HTML/PDF and the reuse licence is unclear.
Sister servers for other jurisdictions will follow the same shape: one repository per jurisdiction, tools named for the register they query.
Licence
Apache-2.0. Built by Avoccado Tech.
The code is free and always will be. If you would rather someone else kept it working when the state moves an endpoint — as the company register did this year, breaking every tutorial written about it — that is what we do for a living.
This server cannot be deployed
Maintenance
Related MCP Connectors
Search U.S. case law, fetch opinions, and ask matter-aware legal questions over your documents.
Slovak court decisions as MCP tools. 12,000+ decisions, GDPR-compliant, pseudonymized, SLA-backed.
Simplified lookup of a person's or company's lawsuits from the CPF or CNPJ. Platform-hosted, no cred
Resolve, search and verify legal citations against the official sources, with provenance.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides AI agents with access to Moroccan Court of Cassation decisions through search tools and PDF retrieval. Enables both real-time queries against the official portal and local searches across indexed decisions.-
- FlicenseNot gradedqualityBmaintenanceProvides AI assistants with up-to-date legal documents from official sources, enabling accurate legal information retrieval and analysis.18-
- FlicenseAqualityDmaintenanceEnables querying and retrieving Italian civil court rulings, decrees, and orders from the Ministry of Justice's database via natural language, using CIE authentication.11-
- AlicenseAqualityDmaintenanceConnects LLMs to the EcourtsIndia Partner API for searching Indian court cases, retrieving orders, reading cause lists, and accessing AI summaries.9MIT