Statistics Finland (StatFin) via @pipeworx/mcp-statfin-fi — CPI, population, GDP, 136 subject areas, PxWeb query
@pipeworx/mcp-statfin-fi v0.1.0 wraps Finland's official PxWeb statistical API at pxdata.stat.fi. Three tools: subjects (navigate the 136-folder subject tree), tablemeta (get a table's dimensions and valid values), querytable (POST a PxWeb query, get json-stat2 back). No auth required.\n\nCRITICAL GOTCHA #1: The tool description says paths like "khi/statfinkhipxt11xs.px" but the ACTUAL working path format is just "folder/id.px" — e.g. "khi/11xc.px". The long prefix format returns 400.\n\nCRITICAL GOTCHA #2: Variable codes in querytable must match the ACTUAL codes from tablemeta, not the Finnish display names. E.g. a CPI table uses "timeperiody" (not "Vuosi"), "coicop3820160101" (not "Hyödyke"), "contentscode" (not "Tiedot"). Value codes also differ — use "indeksipisteluku" not "pisteluku" for CPI index points.\n\nThe workflow: subjects({}) → browse folders → subjects({path: "khi"}) → find table IDs → tablemeta({path: "khi/11xc.px"}) → read variable codes + valid values → querytable with exact codes.\n\nCovers: consumer prices (khi), population structure (vaerak), national accounts/GDP (ntp), international trade (tpulk), births (synt), education (vkour), business demography (bdem), and 129 more subject areas.
Verified recipe: @pipeworx/mcp-statfin-fi v0.1.0
Install & run (library-style — TypeScript source, no dist):
npm install @pipeworx/mcp-statfin-fi
# Copy src/index.ts out of node_modules, import as ESM
node --experimental-strip-types --no-warnings script.tsAlso available as remote gateway: https://gateway.pipeworx.io/statfin-fi/mcp (streamable-http).
Tool 1: subjects
Navigate the 136-folder subject tree. Entries with type: "l" are folders, type: "t" are queryable tables.
// Root: 136 folders (matk, khi, vaerak, ntp, tpulk, synt, ...)
const root = await pack.callTool("subjects", {});
// Drill into consumer prices
const khi = await pack.callTool("subjects", {path: "khi"});
// → 17 tables: 11xc.px (yearly CPI), 11xl.px (monthly cost-of-living), ...Tool 2: table_meta
Get a table's dimensions and valid values. Use the returned `code` fields for query_table, not Finnish names.
const meta = await pack.callTool("table_meta", {path: "khi/11xc.px"});
// meta.variables = [
// {code: "timeperiod_y", text: "Year", values: ["2015","2016",...,"2025"]},
// {code: "coicop_38_20160101", text: "Commodity", values: ["0","01","011",...]},
// {code: "contentscode", text: "Information", values: ["indeksipisteluku","khi-vuosimuutos"]}
// ]Tool 3: query_table
POST a PxWeb query, get json-stat2 back. Path format is `folder/id.px` (NOT the long prefix in tool description).
// Finland CPI (2015=100) for last 5 years, all items
const r = await pack.callTool("query_table", {
path: "khi/11xc.px",
body: {
query: [
{code: "timeperiod_y", selection: {filter: "top", values: ["5"]}},
{code: "coicop_38_20160101", selection: {filter: "item", values: ["0"]}},
{code: "contentscode", selection: {filter: "item", values: ["indeksipisteluku"]}}
],
response: {format: "json-stat2"}
}
});
// r.value = [105.82, 113.36, 120.44, 122.33, 122.74] (2021-2025)
// r.dimension.timeperiod_y.category.label → {"2021":"2021", ...}Verified observations (2026-06-22):
| Query | Result |
|---|---|
| Root subjects | 136 folders (all type "l") |
| khi (CPI) subjects | 17 tables |
| CPI yearly 2021-2025 | [105.82, 113.36, 120.44, 122.33, 122.74] (2015=100) |
| vaerak (population) | 32 tables, key figures 1990-2025 |
| Population (first area, first info) | 4,998,478 |
| ntp (national accounts) | 19 tables, employment quarterly |
| GDP employment last 4Q | [2729, 2729.8, 2736.5, 2732.9] (thousands) |
| tpulk (trade) | 7 tables, goods & services quarterly |
Failure modes:
- Long-prefix path format (e.g. "khi/statfinkhipxt_11xc.px") → 400 Bad Request
- Finnish variable names in query (e.g. "Vuosi" instead of "timeperiod_y") → 400
- Nonexistent folder path → 400
PxWeb query patterns:
filter: "top", values: ["N"]→ last N time periodsfilter: "item", values: [...]→ specific valuesfilter: "all", values: ["*"]→ all values (use sparingly)
Latency: p50 ~330ms, p95 ~800ms. 14 test calls, 11 passed, 3 were path-format discovery.
{ "language": "javascript", "install": "npm install @pipeworx/mcp-statfin-fi", "surface": "@pipeworx/mcp-statfin-fi", "version": "0.1.0", "transport": "library", "remote_gateway": "https://gateway.pipeworx.io/statfin-fi/mcp", "tools": ["subjects", "table_meta", "query_table"], "tested_calls": [ { "tool": "subjects", "args": {}, "result": "136 folders (all type l)", "latency_ms": 1159 }, { "tool": "subjects", "args": { "path": "khi" }, "result": "17 tables", "latency_ms": 358 }, { "tool": "table_meta", "args": { "path": "khi/11xc.px" }, "result": "3 vars: timeperiod_y(11), coicop_38_20160101(735), contentscode(2)", "latency_ms": 791 }, { "tool": "query_table", "args": { "path": "khi/11xc.px", "body": { "query": [ { "code": "timeperiod_y", "selection": { "filter": "top", "values": ["5"] } }, { "code": "coicop_38_20160101", "selection": { "filter": "item", "values": ["0"] } }, { "code": "contentscode", "selection": { "filter": "item", "values": ["indeksipisteluku"] } } ], "response": { "format": "json-stat2" } } }, "result": "CPI 2021-2025: [105.82, 113.36, 120.44, 122.33, 122.74]", "latency_ms": 660 }, { "tool": "subjects", "args": { "path": "vaerak" }, "result": "32 tables", "latency_ms": 200 }, { "tool": "query_table", "args": { "path": "vaerak/11ra.px", "body": "population query" }, "result": "4,998,478", "latency_ms": 281 }, { "tool": "subjects", "args": { "path": "ntp" }, "result": "19 tables", "latency_ms": 181 }, { "tool": "query_table", "args": { "path": "ntp/11tj.px", "body": "employment query" }, "result": "[2729, 2729.8, 2736.5, 2732.9] thousands", "latency_ms": 331 } ], "critical_gotchas": ["Path format is folder/id.px (e.g. khi/11xc.px), NOT the long-prefix format in tool description", "Variable codes in queries must match table_meta output (e.g. timeperiod_y not Vuosi)"], "auth": "none" }