io. github. cyanheads/ eurostat-mcp-server
by cyanheads · remote · local (npm) · no sign-in to list tools · v0.10.0 · published by GitHub user cyanheads
Search and query the Eurostat catalogue — EU economy, demography, trade, and NUTS regional data.
8 tools: 3 change things and 5 only read.
Scanned Oct 21, 2026
- Deletes or cancels0Claude Code: deny
- Can't be undone0Claude Code: ask
- Changes things3Claude Code: ask: see these tools
- Only reads5Claude Code: allow: see these tools
2 checks matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.
claude mcp add --transport http eurostat https://eurostat.caseyjhand.com/mcpFindings
Matches of fixed checks, with the text they matched.
The server marks "eurostat_browse_themes" read-only (readOnlyHint: true), and its own name, description or input give the class "write".
What this check looks forMatched text
annotations: {"readOnlyHint":true,"idempotentHint":true,"openWorldHint":true}; The name "eurostat_browse_themes" says "browse": a word for reading.
The server marks "eurostat_dataframe_query" read-only (readOnlyHint: true), and its own name, description or input give the class "write".
What this check looks forMatched text
annotations: {"readOnlyHint":true,"idempotentHint":true,"openWorldHint":false}; The name "eurostat_dataframe_query" says "query": a word for reading.
Tools
Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.
8 tools
Changes things 3Claude Code: ask
eurostat_browse_themesNavigate the Eurostat theme tree.1 finding
Why it is in this group
- The name "eurostat_browse_themes" says "browse": a word for reading.
- The description's first verb is "navigate": a word for a change.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
Findings
- Warn
The server marks "eurostat_browse_themes" read-only (readOnlyHint: true), and its own name, description or input give the class "write".
What this check looks forMatched text
annotations: {"readOnlyHint":true,"idempotentHint":true,"openWorldHint":true}; The name "eurostat_browse_themes" says "browse": a word for reading.
Description, as the server wrote it Navigate the Eurostat theme tree. Without theme_code returns the top-level theme folders (Economy, Population, Transport, etc.) — the practical starting points. With a theme_code returns its immediate children: subtheme folders and datasets in that branch. Use this for structured discovery when you know the domain but not the dataset code, or to drill down from a broad topic to a specific dataset. Pair with eurostat_search_datasets for keyword-based discovery. The tree is the dissemination table of contents plus the Comext host's DS-* collections: detailed trade under ext_go_detail (inside ext_go, "International trade in goods") and PRODCOM under prom (inside icts, "Industry, trade and services"). A collection on neither, such as the legacy PRODCOM DS-056120, is not disseminated and appears nowhere in the tree.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: true
eurostat_dataframe_queryRun a read-only SQL SELECT against tables staged on a Eurostat dataframe canvas — the way to reach observations past the 5,000-row inline cap of eurostat_query_dataset and past the…1 finding
Why it is in this group
- The name "eurostat_dataframe_query" says "query": a word for reading.
- The description's first verb is "run": a word for a change.
- The input takes a statement or command to run (input.sql), which can change anything it can reach.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
Findings
- Warn
The server marks "eurostat_dataframe_query" read-only (readOnlyHint: true), and its own name, description or input give the class "write".
What this check looks forMatched text
annotations: {"readOnlyHint":true,"idempotentHint":true,"openWorldHint":false}; The name "eurostat_dataframe_query" says "query": a word for reading.
Description, as the server wrote it Run a read-only SQL SELECT against tables staged on a Eurostat dataframe canvas — the way to reach observations past the 5,000-row inline cap of eurostat_query_dataset and past the inline preview of a eurostat_download_dataset bulk download, and to aggregate, group, or join across staged tables without re-fetching from Eurostat. Call eurostat_dataframe_describe first for the table and column names, which differ between the tools that stage them. Only a single SELECT statement runs: statement chaining, non-SELECT verbs, and functions that read files or external data are rejected. Columns are flat — every dimension is a code column named after the dimension, the measure is obs_value, the observation flag is obs_flag / obs_flag_label and the confidentiality marker is conf_status / conf_status_label; a "_label" companion per dimension exists only on tables eurostat_query_dataset staged. Both observation stagers write the same five measure columns with the same codes, so join their tables on dimension codes and time and compare obs_flag or conf_status across them directly; a DS-* table also carries obs_value_text, a value published as text (e.g. a PRODCOM unit "KG"). A value list eurostat_get_dimension_values staged has two columns, code and label: join it to the code column of a download (e.g. JOIN df_x g ON d.geo = g.code) to label that table.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: false
eurostat_download_datasetDownload a Eurostat dataset in bulk through the SDMX 2.1 TSV endpoint and stage every observation as a SQL table on the dataframe canvas — the route to a whole dataset, where euros…No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
Description, as the server wrote it Download a Eurostat dataset in bulk through the SDMX 2.1 TSV endpoint and stage every observation as a SQL table on the dataframe canvas — the route to a whole dataset, where eurostat_query_dataset is the route to a slice of one. The TSV wire format is roughly half the bytes of the JSON-stat body eurostat_query_dataset reads, so it reaches datasets that would otherwise time out, and it is expanded here into one row per observation. Filters take the same dimension-code map eurostat_query_dataset uses and are applied server-side by Eurostat; call eurostat_get_dataset_info first for the dimension codes and eurostat_get_dimension_values for their values. Narrow with since_period/until_period rather than asking for the most recent N periods — the TSV layout keeps a column for every period whichever is requested, so a period range is what actually shrinks the response. Transfers are bounded by a byte budget enforced while streaming: when it is spent the download stops and budgetExceeded is set, leaving a prefix of the dataset rather than an error. Only preview_limit rows come back inline. When a table is staged, call eurostat_dataframe_describe first to confirm its columns, then eurostat_dataframe_query; without a canvas, rows past the preview are not retained.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: true
Only reads 5Claude Code: allow
eurostat_dataframe_describeList the tables staged on a Eurostat dataframe canvas, with their row counts and column names and types.No findings
Why it is in this group
- The name "eurostat_dataframe_describe" says "describe": a word for reading.
Description, as the server wrote it List the tables staged on a Eurostat dataframe canvas, with their row counts and column names and types. Call this before eurostat_dataframe_query to learn the table and column names to write SQL against. The canvas_id comes from a eurostat_query_dataset or eurostat_download_dataset response that reported a staged table. Three tools stage tables, and they write different columns, so read the columns reported here rather than assuming. The two observation stagers keep every column flat: eurostat_query_dataset gives each dimension a code column named after the dimension (e.g. "geo") plus a label companion (e.g. "geo_label"); eurostat_download_dataset gives code columns only — the bulk endpoint carries no labels — plus a "time" column. Both write the same five measure columns — obs_value, obs_flag, obs_flag_label, conf_status, conf_status_label — carrying the same codes for the same observation, so their tables join on dimension codes and time and compare like with like. A table staged from a DS-* dataset (Comext detailed trade, PRODCOM) adds obs_value_text, holding a value Eurostat published as text, such as a PRODCOM quantity unit. eurostat_get_dimension_values, given a canvas_id, stages one dimension's value list as two columns, code and label, which labels a download's code column through a join (e.g. d.geo = g.code).
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: false
eurostat_get_dataset_infoFetch metadata for a Eurostat dataset: dimensions with valid values, time range, observation count, and last-update date.No findings
Why it is in this group
- The name "eurostat_get_dataset_info" says "get": a word for reading.
Description, as the server wrote it Fetch metadata for a Eurostat dataset: dimensions with valid values, time range, observation count, and last-update date. Call this before eurostat_query_dataset or eurostat_download_dataset to discover what dimension codes are valid (unit, na_item, geo, etc.); eurostat_download_dataset builds its positional filter key from this dimension list, so a filter naming a dimension absent here is rejected outright. Returns up to 10 sample values per dimension for orientation; use eurostat_get_dimension_values to list the full set for large dimensions. A DS-* code (detailed trade and PRODCOM, in any case) is read from the Comext dissemination host, which reports no period coverage or observation count, so timeRange and obsCount come back unreported; the first call on a large Comext collection downloads its full structure (23 MB for DS-045409) and takes longer, and repeat calls within the hour reuse it.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: true
eurostat_get_dimension_valuesList the valid values for a specific dimension in a Eurostat dataset (e.g., all unit codes for nama_10_gdp, all geo codes for a regional dataset).No findings
Why it is in this group
- The name "eurostat_get_dimension_values" says "get": a word for reading.
Description, as the server wrote it List the valid values for a specific dimension in a Eurostat dataset (e.g., all unit codes for nama_10_gdp, all geo codes for a regional dataset). Use this when eurostat_get_dataset_info returns more values than the 10-item sample, or to confirm exact codes before querying. For the "geo" dimension, use geo_level to filter by NUTS hierarchy (country, nuts1, nuts2, nuts3). An invalid code matches nothing: eurostat_query_dataset names it in unmatchedValues, or in its no_results error when the query matched nothing at all, and Eurostat rejects it as a fault on eurostat_download_dataset; use this tool to verify codes first. To find one code in a long list, such as the 37,069 CN8 product codes of DS-045409, pass filter: words its code or label contains. A long list comes back a page at a time, each response held to 64,000 bytes; a page with more after it carries nextCursor — pass it back as cursor for the next page. Pass canvas_id to also stage the whole list, whatever its length, as a two-column code/label table on that dataframe canvas: search it with SQL, or join it to a eurostat_download_dataset table, whose columns carry dimension codes only.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: true
eurostat_query_datasetFetch statistical data from a Eurostat dataset with dimension filters.No findings
Why it is in this group
- The name "eurostat_query_dataset" says "query": a word for reading.
Description, as the server wrote it Fetch statistical data from a Eurostat dataset with dimension filters. Returns a deterministic inline prefix of decoded observations with dimension codes and labels, numeric values, an OBS_FLAG status (e.g., "p" = provisional, "e" = estimated) and a separate CONF_STATUS confidentiality marker (e.g., "C" = confidential, which is usually why a value is null). preview_limit controls only that prefix; filters and period controls reduce the matched result itself. Call eurostat_get_dataset_info first to discover valid dimension codes and values. Apply filters to keep the result set manageable — large unfiltered queries may trigger an async response error. Use filters.geo for specific country/region codes, or geo_level for NUTS hierarchy filtering (mutually exclusive). Use last_n_periods for the N most recent periods without knowing the end date. Matches above 5,000 observations are staged whole when this deployment runs a dataframe canvas: call eurostat_dataframe_describe first, then eurostat_dataframe_query. Matches at or below 5,000 are never staged. When the target is a whole dataset rather than a slice, eurostat_download_dataset reads the SDMX bulk endpoint instead and is the cheaper route.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: true
eurostat_search_datasetsSearch the Eurostat catalogue by keyword.No findings
Why it is in this group
- The name "eurostat_search_datasets" says "search": a word for reading.
Description, as the server wrote it Search the Eurostat catalogue by keyword. Returns matching datasets with codes, descriptions, period coverage, and theme breadcrumbs. Use this to discover dataset codes before calling eurostat_get_dataset_info, then eurostat_query_dataset for a slice of a dataset or eurostat_download_dataset for the whole of one. Results are limited to datasets and predefined tables — folders are excluded. The catalogue joins two sources: the dissemination table of contents, and the Comext host's dataflow list, which adds the DS-* collections — detailed trade by CN8, HS, SITC, BEC and CPA, and PRODCOM — filed under "International trade in goods - detailed data (Comext)" and "Statistics on the production of manufactured goods (PRODCOM)". Comext entries report a last-update date but no period coverage or observation count. A collection on neither list, such as the legacy PRODCOM DS-056120, is not disseminated and cannot be reached through this server.
Annotations the server declares
- readOnlyHint: true
- idempotentHint: true
- openWorldHint: true
This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.
Install
Pinned to version 0.10.0. Values in angle brackets are yours to fill in.
claude mcp add --transport http eurostat https://eurostat.caseyjhand.com/mcpRun in a terminal.
Claude Code permissions
Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.
{
"permissions": {
"allow": [
"mcp__eurostat__eurostat_search_datasets",
"mcp__eurostat__eurostat_get_dataset_info",
"mcp__eurostat__eurostat_get_dimension_values",
"mcp__eurostat__eurostat_query_dataset",
"mcp__eurostat__eurostat_dataframe_describe"
],
"ask": [
"mcp__eurostat__eurostat_browse_themes",
"mcp__eurostat__eurostat_download_dataset",
"mcp__eurostat__eurostat_dataframe_query"
],
"deny": []
}
}Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as eurostat. Review it before you use it.
