Skip to main content
Glama

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

search_workplaces

Workplaces, filtered on one of kommun, län, näringsgren or size class

count_workplaces

The same filters, but only the number

get_workplace

One workplace by its CFAR number

search_legal_entities

The same, over legal entities

count_legal_entities

get_legal_entity

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

A 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 build

fetch 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 tools
count_workplacesA

Count workplaces in the register, with the same filters as the search. Cheaper than listing them.

ParametersJSON Schema
NameRequiredDescriptionDefault
lanNoCounty code, two digits, for example 04 for Södermanland.
kommunNoMunicipality code, four digits, for example 0486 for Strängnäs.
naringsgrenNoIndustry code (SNI), for example 41200 for building construction.
anstalldaklassNoSize class code for the number of employees.

TDQS

A3.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry behavioral disclosure. It adds useful efficiency context ("cheaper than listing them") but does not state read-only behavior, permissions, rate limits, or return format for the count.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is a single, front-loaded sentence with no wasted material. It immediately conveys the operation and the key efficiency tradeoff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple count tool with four optional, fully documented filters and no output schema, the description is mostly complete. It could say more about the returned count or filter behavior, but the core operation is adequately covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all four filter parameters. The description adds only the general point that these are the same filters as search, without adding syntax or meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: "Count workplaces in the register." It also distinguishes the tool from listing-oriented siblings by saying it uses "the same filters as the search" and is "cheaper than listing them," though it does not explicitly name the sibling search tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context: use this when you need a count with search-equivalent filters, and prefer it over listing results because it is cheaper. It does not explicitly state when not to use it or name the alternative tool, but the intended choice is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_workplaceB

Read one entry from the register by its cfarNr.

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNoReturn every available variable.
cfarNrYesThe workplace identifier used by the register.

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description's only behavioral signal is 'Read', which conveys non-mutating intent. It says nothing about what happens if the cfarNr does not exist, whether an error or empty result is returned, or any access constraints, leaving the full disclosure burden largely unmet.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler. It is efficient, though the terseness leaves little room for the context an agent would need to handle edge cases.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Without annotations or an output schema, the description should carry more weight. For a simple keyed lookup it is minimally adequate, but it omits not-found behavior and the effect of the 'full' parameter, both of which an agent needs to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented in the schema. The description restates cfarNr's role but does not mention the optional 'full' flag that controls return verbosity, adding no meaning beyond the structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Read one entry from the register by its cfarNr.' This clearly distinguishes a single-record fetch from list-style siblings like search_workplaces and count_workplaces, though it never names them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'by its cfarNr' implies you must already have an identifier, which implicitly separates it from search_workplaces. However, there is no explicit when-to-use guidance, no stated fallback when the identifier is unknown, and no named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
lanNoCounty code, two digits, for example 04 for Södermanland.
fullNoReturn every available variable instead of the usual selection.
limitNoHow many workplaces to return. Paging is followed for you.
kommunNoMunicipality code, four digits, for example 0486 for Strängnäs.
naringsgrenNoIndustry code (SNI), for example 41200 for building construction.
anstalldaklassNoSize class code for the number of employees.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses the useful default behavior of reading from the top of the register when no filters are supplied, but it does not explicitly confirm read-only semantics, describe permissions or rate limits, or explain what the returned records contain.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single tight sentence with the core purpose front-loaded and the fallback behavior stated immediately after. Every clause earns its place with no repetition or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with six optional parameters, no annotations, and no output schema, the description covers purpose and basic filtering but leaves gaps around return values and output shape. It is minimally adequate but not fully complete for an agent that needs to understand what comes back.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters thoroughly. The description reinforces that the four named filters are optional and can be omitted, but it omits any mention of the 'full' or 'limit' parameters, so it adds only marginal meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Search workplaces in Statistics Sweden's business register'), making the purpose immediately clear. It does not explicitly distinguish this tool from siblings like search_legal_entities or count_workplaces, so it falls short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives implied usage guidance by naming the four filter fields and noting that filters can be omitted to read from the top of the register. However, it does not say when to use this tool instead of count_workplaces, get_workplace, or other siblings, nor does it state any exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedcount_legal_entities
    • First observedcount_workplaces
    • First observedget_legal_entity
    • First observedget_workplace
    • First observedsearch_legal_entities
    • First observedsearch_workplaces

TDQS

A3.9/5.0

Scored across 6 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables 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.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables 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.
    9
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables 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.
    18
    9 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides access to Norway's official business registry for searching companies, looking up organizational details, and identifying company roles and sub-units. It utilizes data from Brønnøysundregistrene to enable detailed queries by industry, municipality, or organization number.
    8 npm
    MIT