scb-mcp
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., "@scb-mcp how many workplaces are there in Uppsala län?"
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.
scb-mcp
An MCP server over Statistics Sweden's business register. Point an assistant at it and it can search, count and read Swedish workplaces and legal entities without knowing anything about cursors, path versions or API keys.
No dependencies. The protocol is implemented against the specification rather than
wrapped, which is the point: the handshake, the framing and the error codes are all in
src/, in about three hundred lines you can read.
Use it
// Claude Desktop, claude_desktop_config.json
{
"mcpServers": {
"scb": {
"command": "npx",
"args": ["-y", "scb-mcp"],
"env": { "SCB_API_KEY": "the key you were given" }
}
}
}The key goes in the environment, never on the command line and never in a path. It
travels in the X-API-Key header that the register's contract asks for, and it is not
written to the log.
Related MCP server: SCB MCP Server
The tools
tool | what it does |
| Workplaces, filtered on one of kommun, län, näringsgren or size class |
| The same filters, but only the number |
| One workplace by its CFAR number |
| The same, over legal entities |
| |
| One legal entity by organisation number |
Every search takes limit and follows the register's cursor until it has that many.
full: true asks for every available variable instead of the usual selection.
See it work
node --experimental-strip-types examples/handshake.tsA stubbed register, the real protocol:
-> {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05"}}
<- {"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":false}},"serverInfo":{"name":"scb-mcp","version":"0.1.0"}}
-> {"jsonrpc":"2.0","method":"notifications/initialized"}
(notification, nothing to answer)
-> {"jsonrpc":"2.0","id":2,"method":"tools/list"}
<- 6 tools: search_workplaces, count_workplaces, get_workplace, search_legal_entities, count_legal_entities, get_legal_entity
-> {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"count_workplaces","arguments":{"...
<- ok: { "count": 1403 }
-> {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"search_workplaces","arguments":{...
<- ok: { "count": 2, "hasMore": true, "items": [ { "cfarNr": "10000001", "namn": "Nordvik Bygg AB", "kommun": "0486",
-> {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"get_workplace","arguments":{"cfa...
<- tool error: no such resource in the register: {"message":"unknown path"}Three decisions
A tool that fails is a result, not a protocol error. The last line above is a 404
from the register, and it comes back inside tools/call with isError: true. A model
reads that and tries a different identifier. A JSON-RPC error would take the whole
turn down for something the model could have handled.
Paging is not the model's problem. The register hands out pages with limit and
cursorId and says hasMore when there is more. The search tools follow that until
they have what was asked for and report whether anything was left, so a model never
has to hold a cursor across turns.
The register filters on one thing at a time. That is the API's restriction, not
this server's, and giving two filters comes back as
the register filters on one thing at a time; kommun and lan were both given rather
than one of them being dropped quietly.
Development
npm run check # types
npm test # 56 tests, no network, no key
npm run buildfetch is injected into the client, which is why every test runs offline. The
register's own contract is at apiafr.scb.se; the paths here follow it, including the
/v1 segment and the /count and /full variants.
MIT licensed.
Available Tools
6 toolscount_legal_entitiesA
Count legal entities in the register, with the same filters as the search. Cheaper than listing them.
Inputs: lan, kommun, naringsgren, anstalldaklass.
count_workplacesA
Count workplaces in the register, with the same filters as the search. Cheaper than listing them.
Inputs: lan, kommun, naringsgren, anstalldaklass.
get_legal_entityA
Read one entry from the register by its peOrgNr.
Inputs: peOrgNr (required), full.
get_workplaceB
Read one entry from the register by its cfarNr.
Inputs: cfarNr (required), full.
search_legal_entitiesA
Search legal entities in Statistics Sweden's business register. Filter on one of kommun, lan, naringsgren, anstalldaklass, or leave the filters out to read from the top of the register.
Inputs: lan, full, limit, kommun, +2 more.
search_workplacesA
Search workplaces in Statistics Sweden's business register. Filter on one of kommun, lan, naringsgren, anstalldaklass, or leave the filters out to read from the top of the register.
Inputs: lan, full, limit, kommun, +2 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
The set factorizes cleanly into two resources (workplaces, legal entities) × three operations (get, search, count), and each tool name states both explicitly. The descriptions reinforce this, including a clear note that count is a cheaper alternative to search and that get uses a distinct identifier (cfarNr vs peOrgNr). No two tools can be reasonably confused.
Every tool follows the same snake_case verb_noun pattern (get_/search_/count_ plus the resource), with parallel naming across the two entity types. The pattern is fully predictable, so an agent can infer tool names for a resource without reading descriptions.
Six tools is tightly scoped: exactly the three read operations needed for each of the two register resources, with no redundant or filler tools. The count/search pairing is justified by an explicit cost tradeoff rather than duplication.
For a read-only statistical register, the surface covers the core lifecycle: filtered search, cheap counting, and single-record retrieval by key. The notable gap is discoverability of filter vocabularies (valid kommun/lan/naringsgren/anstalldaklass codes) and pagination semantics, which agents must currently guess at.
Related MCP Connectors
Swedish company data: segment companies by industry, place and size, and look up any company.
Swedish company data (Bolagsverket, SCB) for AI agents, verified, with history and annual reports
Swedish B2B intelligence for AI agents: insolvency risk, procurement, BRF health and more.
Swedish public data as read-only tools: registries, statistics, domains, transport, energy.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceEnables searching and retrieving detailed information about Swedish companies, including financial data and annual reports from Bolagsverket (Swedish Companies Registration Office), with intelligent caching for fast responses.-
- AlicenseNot gradedqualityDmaintenanceEnables LLMs to search, access, and retrieve official Swedish statistics from Statistics Sweden (SCB), providing access to 1,200+ tables covering demographics, economy, environment, labor market, and education with 75+ years of historical data.9MIT
- AlicenseBqualityDmaintenanceEnables interaction with the Norwegian Business Registry (Brønnøysundregistrene) API to search and retrieve detailed information about Norwegian companies, subunits, roles, organization forms, municipalities, and NACE industry codes.1811 npm1MIT
- AlicenseAqualityDmaintenanceQuery Swedish public data from AI tools. Includes company data, SCB statistics, weather, transport, public agencies, and more through the Apiverket API.253 npm2MIT