Finnish Foreign Trade (Tulli) MCP avatar

Finnish Foreign Trade (Tulli) MCP

Pricing

from $1.00 / 1,000 search trade tables

Go to Apify Store
Finnish Foreign Trade (Tulli) MCP

Finnish Foreign Trade (Tulli) MCP

Search Finnish Customs (Tulli) foreign-trade tables, inspect their dimensions, and query clean flattened import/export data by commodity, country and period.

Pricing

from $1.00 / 1,000 search trade tables

Rating

0.0

(0)

Developer

Anton Aouat

Anton Aouat

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

2 days ago

Last modified

Categories

Share

An MCP server that gives an AI agent clean access to Finnish Customs (Tulli) foreign-trade statistics — imports and exports by commodity, country, and period. It decodes Tulli's "Uljas" json-stat trade cubes into flat, labelled rows an agent can read directly.

Data © Finnish Customs, Uljas statistical database, licensed CC BY 4.0.

Tools

ToolWhat it does
search_trade_tablesList trade tables (CN goods, SITC, NACE industry, BEC), filter by keyword. Returns each table's ifile.
get_trade_dimensionsA table's dimensions + classification granularities (CN2…CN8, Year/Quarter/Month, Country/Continents). Pass a classification to also get its value codes.
get_trade_dataQuery flattened import/export rows (json-stat decoded), by commodity × country × period × flow × indicator.

Agents chain them: search table → dimensions (learn codes) → data.

Example

"Finland's monthly total imports over the last year?"

  1. search_trade_tables({ query: "CN" })ifile for ULJAS_CN.
  2. get_trade_dimensions({ ifile, classification: "Flow" }) → Flow codes (1=imports, 2=exports), dimensions.
  3. get_trade_data({ ifile, selections: [ { classification: "Classification of Products CN2", code: "00 - 99" }, { classification: "Time period", anchor: "FIRST", count: 12 }, { classification: "Country", code: "AA" }, { classification: "Flow", code: "1" }, { classification: "Indicators", code: "V1" } ] })
    → 12 monthly import totals in EUR.

Notes on this API (hard-won)

  • The Uljas API responses are BOM-prefixed and the selection grammar needs = * ; sent literally — Node's fetch/undici mangles it (500s), so the client uses the raw https module. All handled internally.
  • Selection grammar: each dimension takes a single code, or a relative range via anchor (FIRST/LAST) + count. For Time period, FIRST = the most recent periods.
  • Current-year detail may be incomplete (product-level nulls); aggregates (00 - 99, all countries AA) are published first. Limit: 50,000 cells/query (guarded client-side).

Local use (stdio)

$npm install && npm run build
{ "mcpServers": { "tulli": { "command": "node", "args": ["/abs/path/servers/tulli-trade/dist/server.js"] } } }

No API key — Tulli/Uljas is open data.

Development

npm run typecheck # tsc --noEmit
npm test # vitest — unit tests vs recorded real fixtures (offline)
npm run smoke # live: boots the server, real MCP handshake + real Uljas calls
npm run build # produces dist/

Windows: run tools directly (node ./node_modules/vitest/vitest.mjs run) or via PowerShell.

Design

  • src/tulli/client.ts — HTTP only (Stats/Dims/Class/Data via the raw https module). Custom minimal URL encoder, BOM strip, throttle + cache, typed TulliApiError.
  • src/tulli/normalize.ts — the moat: flatten json-stat v1 cubes → flat rows; tidy stats/dims.
  • src/tulli/query.ts — build the Data selection grammar + guard the 50k-cell cap.
  • src/tools.ts — the 3 MCP tools + Pay-Per-Event billing hook.
  • src/server.ts (stdio) / src/standby.ts (Apify HTTP) — both call one factory.