StatsMapped: Irish statistics (CSO, county & council data)
StatsMapped MCP server exposes Irish and UK public statistics as MCP tools for AI agents.
Query data: list all datasets, or get latest figures/summaries/history for a specific area or dataset using
query_data.List geographies: get area IDs and names by boundary level using
list_areas.Compare: rank areas by a stat, list registered comparison pairs, get pair details, or check whether two stats are comparable using
compare.Explain metrics: get definition, methodology, and standing caveats for a stat using
explain_metric.Supports both Ireland and the United Kingdom via a
countryargument, and requires no API key.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@StatsMapped: Irish statistics (CSO, county & council data)Rank Irish counties by median house price"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
statsmapped-mcp
An MCP server exposing StatsMapped's public API as tools for AI agents (Claude Desktop, Cursor, and any other MCP client).
StatsMapped tracks public data for Ireland (by county) and the UK (by local authority) — housing,
crime, health, the economy and social welfare — from official publishers (CSO, PSRA, Central Bank
of Ireland, DHLGH, NTPF, the Office of Government Procurement, EU Publications Office for Ireland;
ONS/HM Land Registry/Nomis/DfE/DfT for the UK), each figure carrying its own caveats. This
package lets an agent query that data directly as tool calls instead of crawling and parsing
web pages. Every tool below takes a country argument ("ireland" or "united-kingdom",
default "ireland") — the two countries track genuinely different datasets and geography levels,
so call query_data/list_areas for the country you actually want rather than assume
Ireland's defaults apply.
This is a thin client. It calls StatsMapped's already-public, unauthenticated HTTPS API
(documented at statsmapped.com/openapi.json); no API key
is needed for anything below. Runs on your own machine over stdio by default (the recommended way
to use it today) -- see Why stdio for a hosted
streamable-http mode this package also supports, and the real tradeoff that comes with it.
Install
Published on PyPI as statsmapped-mcp (confirmed live: https://pypi.org/project/statsmapped-mcp/):
pip install statsmapped-mcpRelated MCP server: ELS MCP server
Configure
Add to your MCP client's config (for Claude Desktop, claude_desktop_config.json; Cursor uses an
equivalent mcp.json):
{
"mcpServers": {
"statsmapped": {
"command": "statsmapped-mcp"
}
}
}Tools
4 tools (consolidated from an original 9 -- query_data and compare are each one tool with a
few modes, chosen by which arguments you give, rather than several near-identical single-purpose
ones). Every tool takes a country argument ("ireland" or "united-kingdom", default
"ireland") — Ireland and the UK track different datasets and geography levels, so call
query_data/list_areas for the country you want rather than assume Ireland's defaults apply.
query_data(area_id=None, dataset=None, history_months=0, country="ireland")— three modes:neither
area_idnordataset: every stat StatsMapped tracks for one country, with its key, label, and which geography levels it's published at. Start here.area_idgiven,datasetomitted: every dataset available for one area (e.g."county:kerry"for Ireland,"uk:lad:e09000033"for the UK), with its latest figure and year-on-year change. Caveats are projected to label + severity only, not full text — the point is deciding which datasets matter before paying for the full detail on any one of them.both
area_idanddatasetgiven: full detail on one dataset in one area — a written summary, full caveat text, and (optionally, viahistory_months) recent history.
list_areas(level="county", country="ireland")— every geography at one boundary level.leveldefaults to Ireland's 26 counties; the UK's own primary level is"lad"(local authority districts), not"county"— other levels exist per country too (Ireland'slocal_authority/garda_divisionamong them).compare(stat_key=None, level=None, pair_key=None, stat_key_a=None, stat_key_b=None, country="ireland")— four modes, exactly one set of arguments at a time (mixing them raises an error):stat_keyalone: every area at one level, ranked by its latest figure for that stat, highest first.pair_keyalone: full detail for one registered comparison pair — each axis's label/unit/publisher, the correlation stats (r, rho, a leave-one-out sensitivity range), and caveats.pair_keycomes from the no-argument mode below.both
stat_key_aandstat_key_b: does StatsMapped have a registered, hand-vetted comparison between these two stats? Registry-backed only — never computes a fresh correlation for an arbitrary pair.comparableis a string, not a bool:"yes"(a registered, hand-vetted pair;pair_keynames it),"no"(the two stats share no geography level at all), or"unknown"(not registered, but not ruled out: treat as "ask a human", not "probably yes")."unknown"is the normal result for most pairs. Compare the value explicitly (result["comparable"] == "yes"); a truthiness test is true for all three.reasons(a list) always explains the answer.none of the above: every registered cross-dataset comparison pair for one country (e.g. "median sale price vs new dwelling completions per 1,000 residents"). A small, hand-curated set, not an arbitrary-pair engine.
explain_metric(stat_key, country="ireland")— definition, methodology and standing caveats for one stat, never a current figure. Use this when the question is about what a metric means or how it's measured, not about one area's value.
Why stdio, not a hosted server, by default
StatsMapped runs on a single free-tier instance. A remote MCP endpoint hosted there would let an agent's own multi-area query pattern (calling the same tool once per area, in a loop) reproduce exactly the load pattern that has already caused timeouts on that instance under a large geography fan-out. Running over stdio means every call goes through your own network connection to the same public HTTPS API this package's tools call directly, with no shared bottleneck -- each user's own machine makes the HTTP calls, so N users' traffic is naturally spread across N source IPs, not funnelled through one.
server.py also supports a real hosted streamable-http mode (MCP_TRANSPORT=streamable-http)
for a deployment that accepts that tradeoff -- StatsMapped's public API is itself rate-limited
per source IP (600 requests/hour), but a hosted MCP endpoint proxies every remote user's calls
through ONE shared egress IP, so all remote users of a hosted endpoint would share that one
bucket rather than each getting their own. A StatsMapped-hosted endpoint is live at
https://mcp.statsmapped.com/mcp (Streamable HTTP) -- confirmed responding correctly, no
separate install needed for a client that speaks Streamable HTTP directly. The bare host
(https://mcp.statsmapped.com, no path) redirects to the same endpoint as a courtesy.
Development
cd mcp-server
pip install -e .
python tests/test_client.pyThe test suite runs against the real live API (https://statsmapped.com by default, or
STATSMAPPED_MCP_BASE_URL if set) — read-only GETs only, nothing here writes any data or needs
a key.
Licence
MIT for this package. The underlying data keeps each publisher's own licence — see
statsmapped.com/ireland/sources for Ireland's own
publisher/licence detail before reusing any figure outside of querying it through an agent (a UK
equivalent page doesn't exist yet — check each UK tool response's own caveats/sources fields
in the meantime).
Available Tools
5 toolscompareAInspect
Use when the question is how areas rank or compare on a stat, or whether two stats can be compared
fairly. For one area's own figures use query_data.
Four modes, depending on which arguments are given -- consolidates what
were four separate tools (rank_areas, list_comparisons, get_comparison,
check_comparability) behind one, since they are all really "how does this
stat compare" at different scopes. Exactly one mode's arguments should be
given; mixing arguments from different modes (e.g. both stat_key and
pair_key, or only one of stat_key_a/stat_key_b) raises an error
rather than silently guessing which mode was meant.
stat_keyalone (nopair_key, nostat_key_a/stat_key_b): ranks every area at one geography level by its latest figure for that stat, for one country -- e.g. "which counties have the highest median sale price" (country="ireland").stat_keycomes fromquery_data's dataset-listing mode, for the SAME country.levelomitted uses this ranking's own default level; pass one of that dataset's owncompatible_levelsfor a different one -- a level this ranking doesn't have registered returns an empty list rather than an error. Where the underlying stat has no honest per-area denominator (crime, homelessness, live_register and similar -- StatsMapped's own RANKING_NO_DENOMINATOR_STATS), each row'srate_per_1000is the real figure to rank/compare by, notlatest_value, which is a raw count dominated by area population size. Always carry forward every entry incaveatswhen using a row in an answer.pair_keyalone: full detail for one registered comparison pair -- each axis's label, unit and publisher, the correlation stats (r, rho, and a leave-one-out sensitivity range naming the single most influential area), and caveats.pair_keycomes from mode 4's own response, for the SAME country.Both
stat_key_aandstat_key_bgiven: does StatsMapped have a registered, hand-vetted comparison between these two stats? Registry- backed only -- never computes a fresh correlation for an arbitrary pair. Both stat_keys come fromquery_data's dataset-listing mode, for the SAME country.verdictis one of"SUPPORT"(a real, hand-vetted registered pair with no open caveats -- may be treated as a confirmed relationship),"QUALIFY"(hand-vetted, but the evidence carries real caveats -- e.g. no robustness check for outliers, or an unverified geography-level join; readuncertaintyandreasonsbefore presenting it as confirmed),"REJECT"(a real structural impossibility or a human-vetted "no" -- the two stats share no geography level at all, or a reviewer rejected this exact pairing), or"INSUFFICIENT"(not registered, not ruled out either -- StatsMapped genuinely hasn't vetted this pair; never treat this as "probably comparable").uncertaintynames 4 separate dimensions (data_quality, comparability, statistical_strength, causal_strength) --causal_strengthis always"not_established", since no comparison here implies causation regardless of verdict.comparable(DEPRECATED, kept only for callers that haven't migrated) collapsesverdictto the old 3-way yes/no/unknown --"yes"for bothSUPPORTandQUALIFY(both mean "hand-vetted", the oldcomparablemeaning this field has always carried; the caveats aQUALIFYpair carries live inuncertainty/reasons, not in demotingcomparable),"no"forREJECT,"unknown"forINSUFFICIENT. Preferverdictdirectly when you need to distinguish a fully-confirmedSUPPORTfrom a caveatedQUALIFY. Readreasonsbefore presenting any answer other than"SUPPORT"as unqualified.None of the above given: lists every registered cross-dataset comparison pair for one country -- e.g. "median sale price vs new dwelling completions per 1,000 residents". A small, hand-curated set, not an arbitrary-pair engine: pass one of the returned
pair_keyvalues to mode 2 for the real correlation and axis detail.levelis only meaningful together withstat_key(mode 1); giving it withoutstat_keyraises rather than silently dropping it and falling through to mode 4's unrelated pair listing.
| Name | Required | Description | Default |
|---|---|---|---|
| level | No | ||
| country | No | ireland | |
| pair_key | No | ||
| stat_key | No | ||
| stat_key_a | No | ||
| stat_key_b | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations, so the description carries the full load and does: unregistered `level` returns an empty list rather than an error, mixed arguments raise, mode 3 never computes a fresh correlation and is registry-backed only, `causal_strength` is always 'not_established', `comparable` is deprecated with a precise mapping, and `caveats` must be carried forward. These are exactly the behavioral traits annotations would otherwise supply.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but front-loaded with the when-to-use routing before the mode enumeration, and organized as a numbered list an agent can scan. Some passages, notably the deprecated `comparable` mapping, are verbose, though they still carry migration-relevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values needn't be documented, yet the description still explains the verdict/uncertainty semantics an agent must interpret correctly. For a six-parameter, four-mode tool with no annotations, nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate and it does: each of the six args is tied to a mode (stat_key, pair_key, stat_key_a/stat_key_b, level only with stat_key, country implied as 'SAME country' with an example). The only gap is that `country`'s accepted format/default is only shown by example, not defined.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('how areas rank or compare on a stat', 'whether two stats can be compared fairly') and explicitly distinguishes itself from the sibling `query_data` for single-area figures. The four modes are enumerated so an agent knows the full scope of the tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('question is how areas rank or compare') and when-not ('For one area's own figures use query_data'). It also gives the exact arg-combination rule that selects each mode, warns that mixing arguments raises rather than silently guessing, and notes `level` without `stat_key` raises instead of falling through to mode 4.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_metricAInspect
Use when the question is what a metric means or how it is measured; for a figure use query_data.
Definition, methodology and standing caveats for ONE stat ('ireland' or
'united-kingdom') -- never a current figure. Call this when the question is
about what a metric MEANS or how it's measured ("how is the claimant count
defined", "is this a mean or a median"), not about a specific area's value --
query_data/compare already answer that. stat_key comes
from query_data(country=...) for the SAME country.
| Name | Required | Description | Default |
|---|---|---|---|
| country | No | ireland | |
| stat_key | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the behavioral burden. It discloses the output nature (definition/methodology/caveats), the important constraint that it never returns a current figure, supported country values, and the stat_key dependency; it does not spell out read-only/no-side-effect or error behavior, but the core behavior is clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The structure is front-loaded: usage rule, output scope, exclusions, then parameter provenance. However, the 'when to use' rule is repeated in the opening and again in the fourth sentence, so some trimming is possible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter explanation tool with an output schema, the description supplies the critical routing, scope, and stat_key provenance. No major invocation detail is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains that stat_key comes from query_data(country=...) for the same country and lists the supported country values, covering both parameters, though it does not mention the default country or stat_key format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states that the tool returns definition, methodology, and standing caveats for one metric, and explicitly says it never returns a current figure. It distinguishes itself from query_data and compare by routing numeric questions to those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to use this when the question is about what a metric means or how it is measured, not for a figure, and names query_data/compare as the alternatives. It also states where stat_key comes from, giving the agent a clear invocation path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_sceneAInspect
The data to DRAW one scene, nothing rendered: use it when asked for a chart, still or short clip of a figure you can cite. Today one scene exists, "ireland-builds" (Ireland's homes
granted permission, with a commencement notice and completed, by quarter from 2018Q1). The licence DIFFERS BY STAGE (see licence.stages): a stage whose licence is unconfirmed or
ShareAlike is withheld (its cells are absences, not zeros) and the licence line names its holder. You get rows, a table twin, alt text, notes, absences (a missing figure is a typed
absence, never a zero), the licence block, scene_hash, a receipt and the canonical URL. YOU draw it, and the last frame must match the table. Print the scene_hash and the licence
line in the first, middle and last frame, quote only numbers that are in rows, do not loop, and keep the "stages are not a cohort" note. purpose is "analytical" (default) or
"promotional": a promotional use of a source whose licence forbids advertising is refused (licence_refused). vintage (ISO date) omitted = the current data; an earlier vintage is
not stored and returns unknown_vintage. Example: get_scene(scene_id="ireland-builds").
| Name | Required | Description | Default |
|---|---|---|---|
| country | No | ireland | |
| purpose | No | analytical | |
| vintage | No | ||
| scene_id | No | ireland-builds |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With zero annotations the description carries the full burden and does so richly: it discloses that licence differs by stage, that withheld stages produce absences not zeros, that a licence holder is named, that the caller must print scene_hash and the licence line in first/middle/last frames, and that earlier vintages return unknown_vintage. Named error states (licence_refused, unknown_vintage) and anti-loop guidance are exactly the beyond-schema context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening is well front-loaded, but the body is a dense run-on paragraph that mixes parameter semantics, licence rules, and multi-frame rendering instructions. Every element is relevant, yet the lack of structure makes it hard to scan for the arguments an agent must actually pass.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param tool with an output schema, the description is thorough: it explains absences vs zeros, licence staging, error outcomes, and citation requirements. It even describes return contents (rows, table twin, alt text, receipt, canonical URL) that the output schema likely already covers, and only the 'country' parameter is left unexplained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate and it largely does: scene_id (only 'ireland-builds' exists, example given), purpose ('analytical' default or 'promotional' with refusal behavior), and vintage (ISO date, omitted = current, earlier = unknown_vintage). The 'country' parameter (default 'ireland') is never mentioned, which is the one gap preventing a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'The data to DRAW one scene, nothing rendered', and clarifies scope with 'use it when asked for a chart, still or short clip of a figure you can cite.' It implicitly separates itself from data-query siblings (query_data, compare) by being a rendering-input tool, but never names an alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear trigger conditions ('when asked for a chart, still or short clip of a figure you can cite') and states that nothing is rendered by the tool itself. It also covers purpose-based refusal (promotional + advertising-forbidden licence → licence_refused). No explicit sibling routing or when-not-to-use exclusion, keeping it below a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_areasAInspect
Use when you need the ids and names of the areas (counties, local authorities, districts) to pass to
query_data.
List every geography at one boundary level, for one country ('ireland'
or 'united-kingdom'). level defaults to "county" (Ireland's 26 counties);
the UK's own primary level is "lad" (local authority districts), not
"county". Other levels exist per country (e.g. Ireland's "local_authority",
"garda_division") -- see a dataset's own compatible_levels from
query_data for which levels a given stat is actually published at.
Returns each area's id (used by query_data's area-scoped modes,
always paired with the SAME country), name and level. Slim by default;
include_parents=True adds each area's parents (the regions it sits in)
and Irish-language name.
| Name | Required | Description | Default |
|---|---|---|---|
| level | No | county | |
| country | No | ireland | |
| include_parents | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden and does well: it discloses output fields (`id`, `name`, `level`), that results are slim by default, what `include_parents=True` adds, and the pairing constraint that an `id` must always be used with the SAME `country` in `query_data`. It stops short of mentioning ordering, pagination, or whether the list is exhaustive per level, but the behavioral picture is largely complete for a read-only lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the use case, then defaults, then caveats, then return shape — a sensible order with no filler sentences. It runs slightly long and repeats the `id`-is-for-`query_data` point twice, which is the only wasted effort.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-optional-parameter lookup with no annotations, the description covers defaults, country/level coupling, the extended-output option, and the cross-tool key contract. An output schema exists, so the brief return-value sketch is sufficient and nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and it does: it gives `level`'s default ('county', 26 Irish counties), the country-specific twist that the UK's primary level is 'lad' rather than 'county', the allowed `country` values ('ireland' or 'united-kingdom'), and the exact effect of `include_parents`. That is meaning the schema cannot supply.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('list every geography at one boundary level, for one country') and immediately names its consumer, `query_data`. An agent can distinguish it from `query_data` without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Opens with an explicit when-to-use ('Use when you need the ids and names of the areas ... to pass to `query_data`') and clarifies the division of labour by pointing to `compatible_levels` on `query_data` for per-dataset level availability. The when-not is implicit but strong: this tool lists geographies, `query_data` fetches statistics.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_dataAInspect
Use when you need to find which datasets exist, which exist for one area, or the figures and history
for one area and dataset (or a council planning view). For what a metric means use explain_metric;
for how areas rank use compare.
Three modes, depending on which of area_id/dataset are given (plus a planning mode, council, described last) --
consolidates what were three separate tools (list_datasets,
list_area_datasets, get_dataset_for_area) behind one, since they are all
really "how do I get data" at different levels of specificity:
Neither
area_idnordataset: lists every dataset (stat) StatsMapped tracks for one country ('ireland' or 'united-kingdom'), with its key, human label, and which geography levels it can be shown at. Ireland and the UK track genuinely different datasets -- call this first for the right country before assuming a stat_key exists there, to find the rightstat_keyforcompare's ranking mode.area_idgiven,datasetomitted: lists every dataset available for that one area (e.g. "county:kerry" for Ireland, "uk:lad:e09000033" for the UK), with its latest figure, year-on-year change, and caveat labels only (not full caveat text -- use mode 3 for the full detail on any one dataset that matters). Passstat_key(from mode 1) to list only that stat's series for the area: a full listing is tens of KB, one stat is a few hundred bytes.area_idcomes fromlist_areas;countrymust match whichever country that call used, or this simply 404s ("unknown geography").Both
area_idanddatasetgiven: full detail for one dataset in one area -- the latest figure, a written summary, full caveat text, and (ifhistory_monthsis set) recent history.datasetis aseries_keyfrom mode 2's own response.history_monthsmeans actual months of history (0 = everything) -- e.g. 24 returns 2 years of an annual series, not 24 years.countrymust matcharea_id's own country. A stat key from mode 1 is also accepted asdatasetwhen the area has exactly one series for it (the reply saysresolved_from_stat_key); with several, the error names the series keys to use.councilalone (an Irish council slug, e.g. "cork-city-council"; country "ireland" only; no other argument): that council's planning applications by year received -- count, grant and refusal share of decided applications, median days to a decision -- with source, licence, the last data date, a receipt, plain notes, and typedabsencesinstead of zeros. A council the national planning feed has stopped carrying (for example Cork City, last record 2025-11-04) saysstatus: "stopped_reporting": a low recent figure is a feed gap, not fewer applications. Example: query_data(council="cork-city-council").datasetandhistory_monthsare only meaningful together witharea_id(and, forhistory_months,datasettoo, since it only applies to mode 3); giving either without its real precondition raises rather than silently dropping the argument and dispatching to the wrong mode.
| Name | Required | Description | Default |
|---|---|---|---|
| area_id | No | ||
| council | No | ||
| country | No | ireland | |
| dataset | No | ||
| stat_key | No | ||
| history_months | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so well: it explains mode dispatch, error behavior for mismatched country/area, 404s for unknown geography, raises for invalid argument combinations, response sizes, caveat handling, `resolved_from_stat_key`, and `stopped_reporting` status. It also clarifies that `history_months` means actual months rather than periods of the series.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but the length is largely justified by four distinct modes and several argument interactions. It is front-loaded with a usage statement and structured into numbered modes, though some passages could be tightened without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given six parameters with zero schema coverage, no annotations, and an output schema, the description provides all the missing invocation context an agent needs. It covers mode selection, parameter dependencies, error cases, output characteristics, and special status handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: every parameter is explained in context, including `area_id`, `country`, `dataset`, `stat_key`, `history_months`, and `council`. It adds semantics the schema lacks, such as country matching, `series_key` sourcing, `stat_key` acceptance, and `history_months=0` meaning all history.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific multi-mode purpose: finding datasets, area-specific datasets, figures/history for an area and dataset, and Irish council planning data. It explicitly consolidates three former tools and distinguishes the sibling tools `explain_metric` and `compare` by their roles.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states when to use the tool and names alternatives for adjacent questions: `explain_metric` for metric meaning and `compare` for rankings. The four modes are keyed to which arguments are supplied, with preconditions such as `area_id` coming from `list_areas` and `dataset` coming from mode 2.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.3.4- Added
get_scene - Changed
list_areas1 field changed- added
Input schema / properties / include_parentsAdded value: +{ + "default": false, + "title": "Include Parents", + "type": "boolean" +}
- Changed
query_data2 fields changed- added
Input schema / properties / councilAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Council" +} - added
Input schema / properties / stat_keyAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Stat Key" +}
9 tool updates
v0.3.0- Removed
check_comparability - Added
compare - Removed
get_comparison - Removed
get_dataset_for_area - Removed
list_area_datasets - Removed
list_comparisons - Removed
list_datasets - Added
query_data - Removed
rank_areas
9 tool updates
v0.1.0- First observed
check_comparability - First observed
explain_metric - First observed
get_comparison - First observed
get_dataset_for_area - First observed
list_area_datasets - First observed
list_areas - First observed
list_comparisons - First observed
list_datasets - First observed
rank_areas
TDQS
Scored across 5 tools
Each tool has a stated, non-overlapping role and the descriptions explicitly cross-route ("for what a metric means use explain_metric; for how areas rank use compare"), so an agent can pick the right entry point. The main friction is that query_data and compare each multiplex four modes selected by which arguments are present, so within a single tool name the boundaries are argument-driven rather than name-driven.
Four of five names follow a clear verb_noun snake_case pattern (query_data, list_areas, explain_metric, get_scene). The bare verb `compare` deviates slightly, but the overall convention is readable and predictable.
Five tools is a well-scoped surface for a read-only statistics server, and the consolidation of nine former tools into query_data/compare is deliberate. The trade-off is that individual tools carry heavy multi-mode dispatch, making each call signature much larger than the count suggests.
The lifecycle is covered end to end: discover datasets, resolve area ids, fetch figures with history, rank/compare with vetting verdicts, explain methodology, and pull scene/visualisation data with licensing. Remaining gaps (bulk export, cross-country listing in one call) are minor and workable.
Maintenance
Related MCP Connectors
Read-only Irish public data for AI assistants: stats, weather, transport, law, property and maps.
Query UK Parliament, elections, crime stats, ONS census data, and national archives
Official statistics for AI agents: Eurostat, World Bank, OECD, IMF and WHO data for 150+ countries.
UK property research tools - crime stats, schools, demographics, valuations for AI.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to perform due diligence on Irish properties by querying public datasets for planning applications, sold prices, flood risk, radon risk, and zoning.174 npm8MIT

ELS MCP serverofficial
FlicenseNot gradedqualityBmaintenanceEnables LLM agents to query the Explore Local Statistics API for local area data like employment rates and demographics.-- AlicenseNot gradedqualityBmaintenanceEnables AI agents to search, inspect, and retrieve Irish Central Statistics Office PxStat datasets through MCP tools. Supports catalog search, metadata discovery, full-table reads, and filtered JSON-stat queries.253 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to search, preview, and query Ireland's public-sector open data catalogue, including CSV, Excel, JSON, GeoJSON, and JSON-stat resources. It supports filtering, grouping, counting, summing, and sorting datasets conversationally without manual downloads or cleanup.MIT