MCP server
The Model Context Protocol (MCP) is an open standard that lets AI assistants and agents (Claude, Cursor, VS Code Copilot, the OpenAI and Anthropic APIs) call external tools. The maticna.si remote MCP server exposes the FURS register as 11 read-only tools: search, lookup, bulk lookup, VAT and tax-number validation, changes and change history, watched tax numbers, financial statements from AJPES annual reports, reference codes and usage. The assistant calls them when a question needs them (“Is SI80267432 VAT registered?”).
| URL | https://mcp.maticna.si/mcp |
| Transport | Streamable HTTP (POST only, JSON responses, no sessions) |
| Auth | Authorization: Bearer mk_… (API key) |
| Billing | Same as REST: the same units, quota and rate limits |
MCP uses the same API keys as REST. Create one in the dashboard and keep it in an environment variable; never write a literal key into a config file that may end up in git.
export MATICNA_API_KEY="mk_…"- Recommended: a dedicated key per assistant with a monthly unit cap. A looping agent then spends at most what you allow, and you can revoke the key without touching your backend.
- Secret
mk_…keys are accepted (oldermk_live_…keys too). There are no test keys and no sandbox: MCP always returns real data and is billed in units. Formermk_test_…keys get401 test_keys_removed. - Publishable
mk_pub_keys get 401. X-API-Keyworks instead ofAuthorization.- A key in the URL (
?api_key=…) returns400and the key is revoked automatically, as on REST. - There is no OAuth sign-in yet, so ChatGPT and the claude.ai connector directory cannot connect yet (see limitations).
Install
Section titled “Install”claude mcp add --transport http maticna https://mcp.maticna.si/mcp \ --header "Authorization: Bearer ${MATICNA_API_KEY}"Your shell expands the variable, so the key is stored in your local Claude Code config. For a shared project use
.mcp.json instead: Claude Code expands ${MATICNA_API_KEY} at startup, so the file is safe to commit.
{ "mcpServers": { "maticna": { "type": "http", "url": "https://mcp.maticna.si/mcp", "headers": { "Authorization": "Bearer ${MATICNA_API_KEY}" } } }}In ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project):
{ "mcpServers": { "maticna": { "url": "https://mcp.maticna.si/mcp", "headers": { "Authorization": "Bearer ${env:MATICNA_API_KEY}" } } }}In .vscode/mcp.json. VS Code prompts for the key once and stores it securely:
{ "inputs": [ { "type": "promptString", "id": "maticna-api-key", "description": "maticna.si secret API key (mk_…)", "password": true } ], "servers": { "maticna": { "type": "http", "url": "https://mcp.maticna.si/mcp", "headers": { "Authorization": "Bearer ${input:maticna-api-key}" } } }}The Messages API MCP connector (beta) sends
authorization_token as a Bearer token, so pass the bare key:
curl https://api.anthropic.com/v1/messages \-H "content-type: application/json" \-H "x-api-key: $ANTHROPIC_API_KEY" \-H "anthropic-version: 2023-06-01" \-H "anthropic-beta: mcp-client-2025-11-20" \-d '{ "model": "claude-opus-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Is SI80267432 VAT registered?"}], "mcp_servers": [{ "type": "url", "url": "https://mcp.maticna.si/mcp", "name": "maticna", "authorization_token": "'"$MATICNA_API_KEY"'" }], "tools": [{"type": "mcp_toolset", "mcp_server_name": "maticna"}]}'The Responses API mcp tool. The key goes in authorization (no Bearer prefix); OpenAI does not store it, so send it
with every request:
curl https://api.openai.com/v1/responses \-H "Content-Type: application/json" \-H "Authorization: Bearer $OPENAI_API_KEY" \-d '{ "model": "gpt-6-astra", "input": "Is SI80267432 VAT registered?", "tools": [{ "type": "mcp", "server_label": "maticna", "server_url": "https://mcp.maticna.si/mcp", "authorization": "'"$MATICNA_API_KEY"'", "require_approval": "never" }]}'Other clients that support remote Streamable HTTP servers with custom headers (LangChain langchain-mcp-adapters, the
OpenAI Agents SDK) work with the same URL and Authorization: Bearer … header.
claude.ai and ChatGPT
Section titled “claude.ai and ChatGPT”- claude.ai, Claude Desktop: custom connectors accept static request headers only in a limited beta, for organisation owners, and the key is shared by the whole organisation. Without it, use Claude Code or wait for OAuth.
- ChatGPT accepts OAuth only, so maticna.si does not work there yet.
Tools and cost
Section titled “Tools and cost”Every tool is read-only and billed exactly like the matching REST call.
| Tool | Purpose | Units | Billed as |
|---|---|---|---|
search_entities | Find companies and s.p. by name, or filter by city, postcode, activity, VAT status or legal form. Up to 20 per page, cursor. | 1 | GET /v1/entities |
get_entity | Full record by tax number, VAT ID (SI…) or registration number (7 or 10 digits). | 1 | GET /v1/entities/{tax}, /by-vat, /by-registration-number |
lookup_entities | Up to 50 mixed identifiers in one call. Starter plan and up. | 1 per distinct ID | POST /v1/entities/lookup |
validate_vat_id | Whether SIxxxxxxxx is a valid, registered Slovenian VAT ID as of the data date. | 1 | GET /v1/vat/validate/{vat} |
validate_tax_number | mod-11 checksum and presence in the FURS lists. | 1 | GET /v1/tax-number/validate/{n} |
list_reference_codes | Reference codes: SKD activities, legal forms, tax offices, postal codes. | 0 | GET /v1/reference/{kind} |
get_usage | Plan, units used and remaining, reset time, the key's usage and monthly cap. | 0 | GET /v1/usage |
list_changes | Changes in the FURS lists since a date or cursor (new entities, deactivations, VAT …), filter by type. Up to 50 per page. Growth plan and up. | 1 | GET /v1/changes |
get_entity_history | Change history of one tax number (all registrations), cursor. Growth plan and up. | 1 | GET /v1/entities/{tax}/history |
list_monitors | The organisation’s watched tax numbers and watch slots used. | 0 | GET /v1/monitors |
get_financials | Financial statements from AJPES annual reports (revenue, net profit, employees, assets, equity …) by tax number or matična, with source and CC BY 4.0 licence. Never for s.p. | 1 | GET /v1/entities/{tax}/financials |
get_entityon a well-formed identifier that is not in the register returnsfound: falseand costs 1 unit, like a REST 404: “does not exist” is an answer.lookup_entitiesneeds the Starter plan or higher (likePOST /v1/entities/lookup); on Hobby it returnsplan_upgrade_requiredand costs no units. It reserves units up front, one per distinct well-formed ID (found or not).list_changesandget_entity_historyneed the Growth plan or higher and thechangeskey scope, as on REST. Start withsince= a date, then continue withsince=next_cursor. Suppressed records appear only as redacted events (redacted: true). The history of an unknown, well-formed tax number returns anot_founderror and costs 1 unit, like a REST 404.list_monitorsis free and needs themonitorsscope; add watched tax numbers in the dashboard or over REST (Starter plan and up).get_financialsreturns the same object asGET /v1/entities/{tax}/financials, with the same plan access (Starter and up; on Hobbyplan_upgrade_required, no units) and 1 unit per call. It also accepts a matična. For a sole proprietor (s.p.) it returnscoverage.status: not_coveredand no figures. Keepsource.attribution(“Vir: AJPES …”, CC BY 4.0) with figures you pass on.- There is no autocomplete over MCP; use
search_entities. - Every register result (search, get, lookup, validate) carries
data_as_ofandsource: "Vir: FURS";list_reference_codescarriesdata_as_of. Every result’s_meta["si.maticna/usage"]reports units charged and remaining. - Sole-proprietor (s.p.) records are personal data. The same daily caps, depth caps and terms apply as on REST.
Usage and limits
Section titled “Usage and limits”MCP and REST share one counter: a tool call is recorded under the same key and organisation as a REST call. The
plan’s monthly quota, the daily cap, a key’s monthly cap, the per-organisation burst budget, overage and the 80 % / 100 %
alerts all count both. Protocol messages (initialize, tools/list) are free and do not use the burst budget;
get_usage and list_reference_codes keep working at 100 % quota. A client retry after a lost response is billed
again, like a REST retry without Idempotency-Key.
Errors
Section titled “Errors”Key problems are HTTP errors: 401 for a missing, invalid, revoked, expired or mk_pub_ key, 400 for a key in
the URL (the key is revoked), 403 for an IP outside the allow-list. Everything else (quota, rate limits, scope,
payment, validation, cursor_expired, the natural-person cap) is a tool result with isError: true, a code that
links to Errors, and retry_after_seconds where it applies. Errors cost 0 units. The model reads the
text in content; programs read the same fields from _meta["si.maticna/error"] (error results carry no
structuredContent). JSON-RPC batches are not supported (HTTP 400): send one request per POST.
Trying it out
Section titled “Trying it out”MCP has no sandbox: every tool call runs on real data and uses units like REST. For development, create a dedicated key
with a low monthly unit cap, so an agent cannot spend more than you allow. You can try single REST requests for free
in the API tester in the dashboard. Try the MCP server with the
MCP Inspector (npx @modelcontextprotocol/inspector).
Source: FURS · unofficial source, not an official extract · Terms · Privacy · maticna.si