Skip to content

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 (older mk_live_… keys too). There are no test keys and no sandbox: MCP always returns real data and is billed in units. Former mk_test_… keys get 401 test_keys_removed.
  • Publishable mk_pub_ keys get 401.
  • X-API-Key works instead of Authorization.
  • A key in the URL (?api_key=…) returns 400 and 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).
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.

.mcp.json
{
"mcpServers": {
"maticna": {
"type": "http",
"url": "https://mcp.maticna.si/mcp",
"headers": {
"Authorization": "Bearer ${MATICNA_API_KEY}"
}
}
}
}

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, 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.

Every tool is read-only and billed exactly like the matching REST call.

ToolPurposeUnitsBilled as
search_entitiesFind companies and s.p. by name, or filter by city, postcode, activity, VAT status or legal form. Up to 20 per page, cursor.1GET /v1/entities
get_entityFull record by tax number, VAT ID (SI…) or registration number (7 or 10 digits).1GET /v1/entities/{tax}, /by-vat, /by-registration-number
lookup_entitiesUp to 50 mixed identifiers in one call. Starter plan and up.1 per distinct IDPOST /v1/entities/lookup
validate_vat_idWhether SIxxxxxxxx is a valid, registered Slovenian VAT ID as of the data date.1GET /v1/vat/validate/{vat}
validate_tax_numbermod-11 checksum and presence in the FURS lists.1GET /v1/tax-number/validate/{n}
list_reference_codesReference codes: SKD activities, legal forms, tax offices, postal codes.0GET /v1/reference/{kind}
get_usagePlan, units used and remaining, reset time, the key's usage and monthly cap.0GET /v1/usage
list_changesChanges 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.1GET /v1/changes
get_entity_historyChange history of one tax number (all registrations), cursor. Growth plan and up.1GET /v1/entities/{tax}/history
list_monitorsThe organisation’s watched tax numbers and watch slots used.0GET /v1/monitors
get_financialsFinancial 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.1GET /v1/entities/{tax}/financials
  • get_entity on a well-formed identifier that is not in the register returns found: false and costs 1 unit, like a REST 404: “does not exist” is an answer.
  • lookup_entities needs the Starter plan or higher (like POST /v1/entities/lookup); on Hobby it returns plan_upgrade_required and costs no units. It reserves units up front, one per distinct well-formed ID (found or not).
  • list_changes and get_entity_history need the Growth plan or higher and the changes key scope, as on REST. Start with since = a date, then continue with since = next_cursor. Suppressed records appear only as redacted events (redacted: true). The history of an unknown, well-formed tax number returns a not_found error and costs 1 unit, like a REST 404.
  • list_monitors is free and needs the monitors scope; add watched tax numbers in the dashboard or over REST (Starter plan and up).
  • get_financials returns the same object as GET /v1/entities/{tax}/financials, with the same plan access (Starter and up; on Hobby plan_upgrade_required, no units) and 1 unit per call. It also accepts a matična. For a sole proprietor (s.p.) it returns coverage.status: not_covered and no figures. Keep source.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_of and source: "Vir: FURS"; list_reference_codes carries data_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.

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.

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.

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