search_cubes_by_title
Find StatCan tables by title keywords. Returns productId, title, dates and frequency; each includes key_template, the dimension order of the SDMX key.
offsetmax_resultssearch_termrequiredio.github.Aryan-JhaveriPublished by GitHub account Aryan-Jhaveriv0.19.0Updated Nov 7, 2026
Access Statistics Canada data via the Web Data Services API
Connects an assistant to Statistics Canada data: find tables, inspect dimensions, fetch filtered observations, and compute summaries server-side.
Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.
Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.
Read https://sourceweft.com/mcp/io.github.Aryan-Jhaveri%2Fmcp-statcan/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.Add this to your client's mcpServers config.
{
"mcpServers": {
"statistics-canada": {
"type": "http",
"url": "https://mcp-statcan.com/mcp"
}
}
}[Statistics Canada MCP Server]
[Python 3.10+] [License: MIT] [MCP] [GitHub] [SafeSkill 93/100]
MCP server and CLI for Statistics Canada's Web Data Service (WDS) and SDMX REST API. Gives any MCP client — Claude, Cursor, VS Code Copilot, Gemini — structured access to Canadian statistical data. Includes a standalone statcan CLI for direct downloads without an LLM.
Hosted on Render — no install required for most users. See Quick Start.
⚠️ LLMs may fabricate data. Always verify important figures against official Statistics Canada sources.
[Terminal recording: statcan search, statcan metadata and statcan download for the Consumer Price Index table]The statcan CLI searching, inspecting and downloading a table. See statcan CLI.
Pick the option that fits you. You don't need to install anything for Option 1.
Connect directly to the public server on Render. No uv, no terminal, no local setup.
Claude Desktop / Claude.ai
mcp-statcanhttps://mcp-statcan.com/mcpClaude Code
The hosted server provides all WDS + SDMX tools. Database tools (SQLite) require local setup (Option 3) — they are intentionally excluded from the shared server.
Run a local server with the same tools as the hosted version.
Step 1 — Install uv:
Step 2 — Start the server:
Step 3 — Connect your client to http://localhost:8000/mcp.
Everything from Option 2, plus database tools for storing and querying data with SQL. Runs via stdio.
Step 1 — Install uv (same as above).
Step 2 — Configure your client with the stdio snippets in Setup by Client below.
uvx downloads and runs the server automatically on first use.
statcan CLI (no LLM needed)Download StatCan data directly from the terminal. See statcan CLI.
Claude Desktop — Settings → Connectors → Add Custom Connector
mcp-statcanhttps://mcp-statcan.com/mcpClaude Code
Cursor — .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
VS Code (GitHub Copilot) — .vscode/mcp.json:
Start
uvx statcan-mcp-server --transport httpfirst, then configure your client.
Most clients need mcp-proxy to bridge stdio ↔ HTTP. Claude Code connects natively.
Claude Desktop — Settings → Developer → Edit Config:
Claude Code
Cursor / VS Code / Gemini — same mcp-proxy wrapper, pointing to http://localhost:8000/mcp.
Claude Desktop — Settings → Developer → Edit Config:
Pass
--db-pathwith an absolute path. Claude Desktop overrides the subprocessHOMEenv var, which can break default path resolution.
Claude Code
Cursor / VS Code / Gemini — use uvx statcan-mcp-server as the stdio command.
Claude.ai (web) has no bash, and its code sandbox can't reach StatCan, so all data comes through the connector's MCP tools.
The pattern:
Use sql for rankings, growth and averages; use format="csv" only when the rows need to go into a file.
After a server update, disconnect and reconnect the connector in claude.ai to refresh the tool list.
Claude Code (bash sandbox) uses the statcan CLI instead:
The server ships five prompts accessible as slash commands in supported clients. Each has two sets of instructions: Claude Code (the statcan CLI in bash) and Claude.ai web (the MCP tools, with sql and format="csv" to keep rows out of context).
The tool calls in the prompts follow the active toolset.
Usage in Claude Code:
A standalone CLI for downloading StatCan data without an LLM. Outputs pipe-friendly CSV/JSON to stdout; progress and errors go to stderr.
Exploring a table (search, then metadata, then download): see the recording at the top of this page.
Agent mode (--json envelopes, typed exit codes, statcan describe):
Recordings are generated from the scripts in assets/tapes/ with VHS: vhs assets/tapes/cli-agent.tape.
Install:
Commands:
Common usage:
Output formats: csv (default for download/vector), table (default for search/metadata/codeset), json, ndjson
For agents and scripts: put --json before the subcommand (or set STATCAN_OUTPUT=json) to get one JSON envelope on stdout, JSON errors with a hint on stderr, and stable exit codes (0 ok, 2 usage, 3 not found, 4 rejected, 5 retryable, 6 empty). With --output, the envelope summarizes the file (rows, columns, period range, series count) so it never has to be read back. Details: machine-readable mode.
Pipe patterns:
For the complete CLI reference see src/cli/README.md.
Five tools, in the default core toolset:
CSV output: get_sdmx_data(format="csv") returns one row per series and one column per period, with fields shared by every series written once as # name: value lines. It always returns the rows (ignores full, max 500 observations) and works with sql. It is about 3x smaller than full=true JSON (table 15100032, key 7...: 7,892 to 2,637 characters; 18100004, key .2, last 12: 13,247 to 3,630).
Key syntax (passed to get_sdmx_data):
"1.2.1" — Geography=1, Gender=2, Age=1".2.1" — all geographies (wildcard), Gender=2, Age=1"1+2.2.1" — Geography 1 or 2, Gender=2, Age=1Note: Wildcard (
.) returns every member of the dimension, including totals and parent aggregates. For sums or rankings use theleaf_keyfromget_sdmx_structure(productId, dimension=N), and passsqlto compute over large result sets.
The server publishes one of two toolsets, chosen at startup. core is the default; legacy is the previous 17-tool set (hosted).
Smaller tool lists leave more of the context window for data. Sizes of the tools/list response, including outputSchema (o200k tokens):
Legacy tool to core replacement:
These tools are not available on the hosted Render server — SQLite is per-process and not shared across users.
Observation store. Both fetch tools upsert into two shared tables, so data accumulates instead of being copied into a new table per call:
new, revised or unchanged.table_name is a view over the series and periods that call fetched, with the same columns as before (dimension labels, period, value, VECTOR_ID, UOM, ...).Claude.ai web (hosted server):
Claude Code (bash sandbox):
Thanks to everyone who has contributed code, fixes and bug reports:
get_changed_series_list to use StatCan's undated endpoint (#130)Want to help? See CONTRIBUTING.md.
Source: README.md at commit 74458fb
Find StatCan tables by title keywords. Returns productId, title, dates and frequency; each includes key_template, the dimension order of the SDMX key.
offsetmax_resultssearch_termrequiredA table's dimensions in key order with their codes (id, name, parent). Use search to find the codes for labels like 'Ontario' instead of guessing.
searchdimensionproductIdrequiredObservations for productId + key, or one vectorId. Over 100 observations you get a per-series summary. Pass sql to compute over every row (growth, averages, ranking) server-side. Cite _sdmx_url.
keysqlfullformatvectorIdendPeriodproductIdstartPeriodlastNObservationsSeries metadata for productId + coordinates, or vectorIds: vectorId, key, title, frequency, unit of measure and scalar (decoded), decimals.
productIdvectorIdscoordinatesWhat StatCan released: tables updated on a date (default today), or today's new data points for one series (vectorId, or productId + coordinate).
datelimitoffsetvectorIdproductIdcoordinate100% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
claude mcp add statcan --transport http https://mcp-statcan.com/mcp --scope global# macOS / Linuxcurl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"uvx statcan-mcp-server --transport http# Listening at http://localhost:8000uvx statcan-mcp-server # installs the packagestatcan search "labour force"statcan metadata 14-10-0287-01 # run first to find dimension IDsstatcan download 14-10-0287-01 --key "1.1.1" --last 12 --output lfs.csv # run `statcan metadata <pid>` first to find real dimension IDsstatcan describe # machine-readable command reference for agentsclaude mcp add statcan --transport http https://mcp-statcan.com/mcp --scope global{ "mcpServers": { "statcan": { "url": "https://mcp-statcan.com/mcp" } }}{ "servers": { "statcan": { "type": "http", "url": "https://mcp-statcan.com/mcp" } }}{ "mcpServers": { "statcan": { "command": "uvx", "args": ["mcp-proxy", "--transport", "streamablehttp", "http://localhost:8000/mcp"] } }}claude mcp add statcan --transport http http://localhost:8000/mcp --scope global{ "mcpServers": { "statcan": { "command": "uvx", "args": ["statcan-mcp-server", "--db-path", "/Users/<you>/.statcan-mcp/statcan_data.db"] } }}claude mcp add statcan --scope global -- uvx statcan-mcp-server1. Discovery (small payloads): search_cubes_by_title("labour force") → productId + key_template get_sdmx_structure(productId=..., search="Ontario;Employment") → codes by label
2. Answers: get_sdmx_data(..., sql="SELECT ...") → only the result comes back3. Files: get_sdmx_data(..., format="csv") → copy the CSV verbatim into a filestatcan search "labour force"statcan metadata 14-10-0287-01 # run first to find dimension IDsstatcan download 14-10-0287-01 --key "1.1.1" --last 12 --output ./lfs.csv # run `statcan metadata <pid>` first to find real dimension IDsawk -F',' 'NR>1 && $1=="Canada"' ./lfs.csv | sort -t',' -rn -k5 | head -10/statcan-data-lookup topic="consumer price index" analysis_goal="trend last 5 years"/statcan-download product_id=18100004 last_n=24pip install statcan-mcp-server # or: uvx statcan-mcp-server (no install)statcan search <term> Search tables by keywordstatcan metadata <product-id> Show table structure (dimensions + members)statcan download <product-id> Download observations via SDMXstatcan vector <vector-id>... Download one or more vector seriesstatcan codeset Show StatCan code definitions (UOM, frequency, etc.)statcan describe Commands, options, exit codes and JSON envelopes as JSON# Find a tablestatcan search "consumer price index"statcan search "labour force" --max-results 10 --format json
# Inspect structure before downloadingstatcan metadata 18-10-0004-01statcan metadata 18100004 --full # show all dimension members
# Download data (run `statcan metadata <pid>` first to find real dimension IDs)statcan download 18-10-0004-01 --key "1.1.1" --last 12 --output cpi.csvstatcan download 18-10-0004-01 --key "1.1.1" --start 2020-01 --end 2024-12statcan download 18-10-0004-01 --key "1.1.1" --last 5 --dry-run # preview SDMX URL
# Download by vector IDstatcan vector v41690973 --last 24 --output series.csvstatcan vector v41690973 v41690974 --last 12 --output multi.csv
# Decode numeric codesstatcan codeset --type uomstatcan codeset --type frequency --format json# Top 10 by value (run `statcan metadata <pid>` first to find real dimension IDs)statcan download 14-10-0287-01 --key "1.1.1" --last 1 --format csv \ | awk -F',' 'NR>1' | sort -t',' -k5 -rn | head -10
# Extract unique geographies (run `statcan metadata <pid>` first to find real dimension IDs)statcan download 14-10-0287-01 --key "1.1.1" --last 1 --format csv \ | awk -F',' 'NR>1 {print $1}' | sort -u
# Chain search → download (run `statcan metadata <pid>` first to find real dimension IDs)PID=$(statcan search "CPI" --format json | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['Product ID'])")statcan download $PID --key "1.1.1" --last 12 --output cpi.csvget_sdmx_data(productId=18100004, key=".2", lastNObservations=12, format="csv")STATCAN_TOOLSET=legacy uvx statcan-mcp-server # or: uvx statcan-mcp-server --toolset legacy-- Seasonal component: CPI not seasonally adjusted (18100004) minus seasonally adjusted (18100006)SELECT nsa.period, ROUND(nsa.value - sa.value, 2) AS seasonalFROM _statcan_observations nsa JOIN _statcan_observations sa USING (ref_date)WHERE nsa.series_id = '18100004:2.2' AND sa.series_id = '18100006:1.1'ORDER BY ref_date DESC;1. search_cubes_by_title("unemployment rate") → productId e.g. 14100287
2. get_sdmx_structure(productId=14100287) → dimension positions + sample codes
3. get_sdmx_structure(productId=14100287, search="Ontario;Employment") → ids of the codes you want, by label
4. get_sdmx_data(productId=14100287, key=".2.1", lastNObservations=24, sql="SELECT ... FROM data") → server-side SQL: only the result comes back (omit sql for the observations)statcan search "unemployment rate"statcan metadata 14100287statcan download 14-10-0287-01 --key "1.1.1" --last 24 --output ./lfs.csv # run `statcan metadata <pid>` first to find real dimension IDsawk -F',' 'NR>1 && $1=="Canada"' ./lfs.csv | sort -t',' -rn -k5 | head -10src/├── api/│ ├── core/│ │ └── tools.py # core toolset (default): the five merged tools│ ├── cube/ # legacy toolset: search/list cubes, metadata, series, change detection│ ├── vector/│ │ └── vector_tools.py # legacy toolset: vector series, bulk range fetch│ ├── sdmx/│ │ └── sdmx_tools.py # legacy toolset: SDMX structure/data/query_sdmx; shared fetch helpers│ ├── composite_tools.py # fetch_sdmx_to_database, fetch_vectors_to_database, store_cube_metadata (stdio only)│ └── metadata_tools.py # get_code_sets (legacy toolset)├── cli/│ ├── main.py # statcan CLI entry point (Typer app)│ ├── output.py # write_output, format helpers│ └── commands/│ ├── search.py # statcan search│ ├── metadata.py # statcan metadata│ ├── download.py # statcan download│ ├── vector.py # statcan vector│ └── codeset.py # statcan codeset├── db/ # SQLite: observation store (store.py), per-request SQL for get_sdmx_data(sql=) (ephemeral.py), schema, queries├── models/ # Pydantic input models├── util/│ ├── registry.py # ToolRegistry — @decorator → MCP Tool schema│ ├── truncation.py # Response truncation + pagination guidance│ ├── sdmx_xml.py # SDMX-ML (structure-specific XML) → labelled tabular rows│ └── cache.py # 1-hour TTL cache for cube list├── config.py # BASE_URL, SDMX_BASE_URL, RENDER_BASE_URL, TRANSPORT, PORT├── toolset.py # resolve_toolset(): STATCAN_TOOLSET / --toolset└── server.py # create_server(), MCP Prompts, resources, HTTP transport, CLI