mcp-ssb
# mcp-ssb
MCP-server for **Statistisk sentralbyrå** — 3 898 statistikktabeller indeksert lokalt,
tallene hentet live. Ingen autentisering.
Dette er de faktiske norske tallene: prisvekst, boligpriser, lønn, befolkning,
arbeidsledighet. Til forskjell fra [mcp-datanorge](https://github.com/synjan/mcp-datanorge),
som bare forteller hvilke datasett som finnes.
## Hvorfor lokal indeks
SSBs eget fritekstsøk er ubrukelig. Målt 2. september 2026 mot
`data.ssb.no/api/pxwebapi/v2-beta/tables?query=`:
| Søk | SSBs søk | Denne serveren |
| --- | --- | --- |
| `konsumpris` | 1 treff — feil tabell | 16 treff, Konsumprisindeks øverst |
| `boligprisindeks` | 0 treff | 2 treff, Prisindeks for brukte boliger |
| `arbeidsledighet` | — | 11 treff |
| `befolkning` | 318 treff, FoU-personale øverst | 18 treff, befolkningstabeller |
Søket er delstreng uten stemming eller rangering. Men hele katalogen kommer i **ett
kall** — 3 898 tabeller, 6 MB — så den indekseres lokalt med FTS5 i stedet.
## Søket er bygget for norsk
Tre ting skiller det fra et vanlig fulltekstsøk:
- **Dagligtale oversettes til SSBs termer.** «Boligprisindeks» finnes ikke i noen
tabelltittel; SSB kaller den «Prisindeks for brukte boliger». Broen er en kuratert
liste i `src/synonyms.js`, ikke en ordbok — hver oppføring er verifisert mot katalogen.
- **Søket trapper opp.** Eksakte ord → prefiks → stammet prefiks → delvise treff. Norsk
er et sammensetningsspråk, så «konsumpris» finnes ikke som eget ord i
«Konsumprisindeks», og «arbeidsledighet» ikke i «Arbeidsledige». Feltet `strategi`
sier hvilket trinn som slo til.
- **`variableNames` er indeksert.** En tabell er ofte lettest å finne på dimensjonene
den har enn på tittelen.
## Verktøy
| Verktøy | Hva det gjør |
| --- | --- |
| `search` | Finn tabellen. Lokalt, millisekunder. |
| `table` | Dimensjonene i en tabell med gyldige koder. Bruk før `data`. |
| `data` | Tall med eksplisitt utvalg per dimensjon. |
| `latest` | Siste N perioder uten dimensjonsarbeid — «hva er tallet nå». |
| `status` / `sync` | Indeksens alder; oppfrisking. |
## Kommandolinje
```bash
ssb sok boligpriser # oversettes til «brukte boliger prisindeks»
ssb tabell 03013 # dimensjoner og koder
ssb siste 03013 --perioder 3 # 138.7 · 138.9 · 139.1
ssb data 03013 --velg ContentsCode=Tolvmanedersendring --velg Konsumgrp=TOTAL --perioder 4
ssb status
```
`--json` gir rå JSON. `ssb hjelp` viser alt.
## Installasjon
```bash
npm install
npm run sync # bygger indeksen, ~2 s
claude mcp add --scope user ssb -- node ~/Work/mcp-ssb/src/index.js
ln -sf ~/Work/mcp-ssb/src/cli.js ~/.local/bin/ssb
```
Indeksen havner i `~/.local/share/mcp-ssb/ssb.db`. Overstyr med `SSB_DB` eller
`XDG_DATA_HOME`.
## API-ene
To generasjoner brukes med vilje:
- **v2-beta** (`/api/pxwebapi/v2-beta/tables?pageSize=5000`) — hele katalogen i ett kall
- **v0** (`/api/v0/no/table/{id}`) — metadata med GET, tall med POST og json-stat2
json-stat2 er tett: én flat verdiliste pluss dimensjoner med indeks, der siste dimensjon
varierer raskest. Flatingen til rader ligger i `flattenJsonStat()` og har egne
enhetstester på et innbakt eksempel — ingen nettverk.
Dimensjoner merket `elimination` kan utelates, og da summerer SSB over dem. Det er slik
`latest` får totaltall uten å måtte velge en verdi i hver dimensjon.
## Utvikling
```bash
npm test # 14 tester; de mot indeksen hopper over hvis den mangler
npm start # kjør serveren på stdio
```
## Lisens
MIT for koden. Tallene er SSBs, gjenbrukbare etter deres vilkår.
TDQS
Scored across 6 tools
The six tools map to distinct stages in the workflow: discovery (search), schema lookup (table), explicit queries (data), quick latest values (latest), and catalog maintenance/status (status/sync). Even though data and latest both return numbers, latest is clearly framed as a convenience shortcut, so an agent should not confuse them.
All names are lowercase single words, so the style is uniform and there is no case or convention mixing. The semantic pattern is less regular, however: some are verbs (search, sync), some are nouns (table, data, status), and latest is an adjective, and none follow a verb_noun shape.
Six tools is appropriate for a read-only statistics API: discovery, metadata, query, convenience access, and catalog health/maintenance are each represented without redundancy. The count feels well-scoped for the server's purpose.
The core workflow is complete: search finds a table, table exposes dimensions and codes, data fetches specific selections, and latest covers a common shortcut; status and sync handle catalog freshness. The only minor gap is a lack of any browse/list-all-tables capability, but search is clearly designed to cover discovery.