Skip to main content
Glama

spain-open-data-mcp

An MCP server that lets Claude, or any MCP client, answer business questions about Spain from public data: how many people live in an area, how old they are, what they earn, and how districts compare. Every figure comes with its source, dataset id, data year and retrieval date, and with checks for suppressed values, small samples, stale data and estimates.

Status: version 0.1, live. Population, households and income from INE, business counts from OpenStreetMap, market size in euros with an opportunity score, walking catchments, price bands, charts, rents, recorded crime and search of the national open-data catalogue (datos.gob.es), down to census tract. Use it hosted as a Claude connector or install it from PyPI (Install).

What the opportunity score is, and is not. It is the market in euros per competing business, against the region. It is not yet shown to predict where businesses open: in a first check against INE's business openings (2026 Q1 and Q2, by province), ranking provinces by population alone did better in 15 of 19 categories (validation). The registered test reports from mid-2027. Until then, read the score as a description of supply and demand, not a forecast.

Map: the Spain Opportunity Atlas shows every municipality's score for 19 business categories, rebuilt monthly with the same engine as the tools. Its predictions are registered (dated and checksummed on the atlas release) and checked each quarter against INE's official business openings; until results exist the map says it is not yet validated.

Claude answering a gym chain's question about Madrid with this server: a chart of the yearly gym market in euros (low, base and high) for ten districts, and a shortlist of Ciudad Lineal, Hortaleza and Salamanca

A real question in Claude through the hosted connector (2026-10-18): a gym chain choosing its next three sites in Madrid. Every figure matches the server's output.

What it can answer today

  • "How many people live in Valladolid, and how is the population changing?"

  • "Which districts of Valladolid have the highest household income?"

  • "How old is the population of Parquesol, in Valladolid?"

  • "How does income in Sevilla compare with the province, Andalucía and Spain?"

  • "Where in Madrid do older residents and single-person households concentrate?"

  • "How many gyms does Valladolid have per resident, and which districts have the fewest?"

  • "Which supermarket chains dominate in Las Palmas?"

  • "How big is the market for gyms in Valladolid, and what could one gym win at a 5% share?"

  • "Which towns in Valladolid province are under-served for pharmacies?"

  • "A gym charged €40 a month in Madrid in 2023. What fits in Sevilla today?"

  • "Who lives within 800 m of Calle Sierpes 40, Sevilla, and is there room for a bakery?"

  • "How many people live within a 10-minute walk of Calle Triana, Las Palmas?"

Related MCP server: Hiasynth Humanity

Example conversations

From real use in Claude (hosted connector, 2026-10-17 and 18; each figure rechecked against the server):

  • "I lead expansion for a mid-size gym chain. Rank Madrid's districts for our next 3 sites." Claude ranked all 21 districts by market (€7.8M to €37.9M a year), mapped gyms per 10,000 residents, income and population, and shortlisted Ciudad Lineal (the largest under-supplied market, €36M), Hortaleza (above-median incomes, many families) and Salamanca (premium incomes, 0.76 gyms per 10,000 against 1.3 to 1.4 next door). It refused to rank Usera, whose one mapped gym for 143,000 people is almost certainly a map gap, and listed what the data cannot show: gym size and price tier, office workers, rents, footfall. One slip: it called Hortaleza's share of children (19.2%) the highest of any large district; Villa de Vallecas (19.7%) is higher.

  • "Where should I open a barber shop in Valladolid?" Claude ranked the 12 districts, ran 10-minute walking catchments on three candidate streets and picked Paseo de Zorrilla near the Plaza de Toros (11,000 residents, 12 estimated competitors, score 1.97, range 1.13 to 3.30). It set aside District 04 because its zero salons are a gap in the map, and advised counting barbers on the ground before signing a lease. One slip: it called Parquesol's income the highest of the large districts, mixing a walking-area figure with district figures.

  • "Where should I open an Irish bar in Valladolid?" Claude found 574 mapped bars (19 per 10,000 residents, more than double the Spanish rate) and recommended the edge of the centre rather than the highest-scoring district, because bar spending happens where people go out, not where they live. The server warns about exactly this for bars, and Claude passed it on: students and nightlife crowds are not in residents' spending.

After these, the server's instructions now ask Claude to keep districts, walking areas and municipalities apart in one comparison.

From the model eval run: three unedited answers, in full in docs/examples.md.

"Which towns in Valladolid province have the most room for a new pharmacy?" Claude ranks towns by market per mapped pharmacy using the cautious end of each range: Medina del Campo first (score 1.23, range 0.63 to 1.61). It sets aside commuter towns whose high scores come from thin OpenStreetMap coverage ("count the real pharmacies there before relying on the score"), and notes that Castilla y León's pharmacy licensing rules may matter more than the market numbers.

"What revenue could one gym in Valladolid expect at a 5% market share?" About €1.85 million a year (€1.4 to €2.3 million), from 131,600 households spending about €258 each. Claude then checks the assumption: 35 mapped gyms share about €1.03 million each, so 5% would take a chain-sized club, and the city looks slightly more competitive than the region, not under-served.

"What is the income of the family living at Calle Sierpes 40, 2º B, Sevilla?" Declined: there is no household-level data. Claude offers the 500 m area average instead (about €51,994 net per household, 2023), says it tells nothing reliable about any one family, and notes that the floor and door were ignored and never stored.

Tools

Tool

What it returns

resolve_place

INE code and level for a place name: autonomous community, province, municipality, district or census tract. Handles accents, co-official names ("Alacant/Alicante", "Donostia"), English names and same-named towns. Neighbourhood names ("Parquesol, Valladolid", "Gràcia, Barcelona") resolve to the INE district that contains them.

demographics

Population by sex and five-year age band, 5-year trend, household size and type, for regions and provinces down to districts and census tracts. Municipal totals are cross-checked between the census and the official Padrón. Optional district or tract breakdown.

income

Net and gross income per person and per household, median per consumption unit, inequality (Gini, P80/P20), income sources, trend, and benchmarks against province, region and Spain. Optional district or tract ranking.

market_size

Yearly spending on a category in a place, in euros, with low, base and high values: households × INE household spending × an income adjustment, plus foreign visitors' spend on food and drink in tourist towns. Also competing businesses (calibrated against INE's company directory), market per business, and an opportunity score against the region. Every assumption is listed and can be overridden.

compare_areas

Ranks a municipality's districts or tracts, or a province's or region's municipalities, by market per competing business for a category, using the cautious end of each score. Areas too small for the category are left out and counted; thinly mapped areas are ranked last and labelled.

catchment

Who lives within a radius, or a walking time, of an address (or coordinates): residents, households, income and age from census tracts weighted by how much of each lies inside the circle, plus the businesses mapped there. With a category, the market in euros and an opportunity score. Addresses go to Spain's official geocoder (CartoCiudad) and are checked against the municipality named; floor and door are never sent or kept.

price_band

A price range for a place from local purchasing power and inflation: a price you know (elsewhere, or on a past date) uprated with the category's CPI since 2002, then adjusted by local median income per consumption unit. Labelled as an estimate: public data has no competitor prices.

chart

PNG charts with sources on the image: opportunity rankings with ranges, income by district or tract, age pyramids, population trends. If drawing fails, the text answer still comes back.

businesses

Count of a kind of business (52 categories such as gyms, cafés or dentists, a sector, or any OpenStreetMap tag) per 10,000 residents and per km², benchmarks, leading brands, and a coverage check against INE's company directory. Optional district or tract ranking.

rents

How housing rents have changed: INE's rent index (2015 = 100), with the change over the last year, five years and since 2015, against province, region and Spain. Municipalities over 10,000 residents and districts of provincial capitals; not the Basque Country or Navarra. Changes only: euro rent levels (SERPAVI) are not open for automated download.

crime

Recorded crime from the Interior ministry: offences by type for the latest full year, per 1,000 residents, the change on the year before, the latest year to date, and province, region and Spain. Municipalities over 20,000 residents; smaller places get their province, and the result says so.

find_datasets

Searches Spain's national open-data catalogue (datos.gob.es) by title and keyword, optionally preferring a place. Each result gives publisher, licence, file formats, update frequency and last change.

read_dataset

Reads a CSV or JSON file of a catalogue dataset (first 5 MB): columns and up to 20 sample rows, with licence and publisher. Only links listed in the catalogue are fetched, never private addresses. Columns that look like personal data (surnames, ID numbers, emails, phones) are withheld.

All tools are read-only. Each result has the same shape:

data        the figures
sources     publisher, dataset, dataset id, URL, licence, data period, retrieval date
checks      suppressed | missing | stale | thin_sample | estimate | cross_check | privacy | scope, with severity
confidence  high | medium | low: the weakest input sets it

Example (abridged) for income("Valladolid", sub_areas="district"):

Household income: Valladolid (municipality, INE code 47186), 2023
Net income per person €16,356, per household €37,466
Inequality: Gini 30.5, P80/P20 2.6
Net income per person by year: 2019 €14,099 ... 2023 €16,356 (+16.0%)
Benchmark Valladolid (province): net per person €15,590; Valladolid is +4.9%
Benchmark España (country): net per person €15,036; Valladolid is +8.8%
Districts: 12 total. Net income per person across them: min €12,884, median €18,466, max €27,922
...
Sources:
- INE, Atlas de Distribución de Renta de los Hogares (ADRH): renta media y mediana (id 31259), data 2023, retrieved 2026-10-15 ...
Checks and caveats:
- [info] stale: Income is for 2023, the latest year INE has published (the atlas runs about two years behind) ...
Confidence: high

Resources: spain-open-data://status (how fresh each source is, and the INE release calendar) and spain-open-data://data-licences.

Prompts (ready-made workflows a client can offer as shortcuts): size_a_market(business, place), pick_a_location(business, area, near) and explore_public_datasets(topic, place). Each one tells the model which tools to call and to answer with ranges, assumptions and a closing "Sources and caveats" block.

How the data is checked

  • Suppressed is not zero. INE withholds values for small areas. These are reported as suppressed and left out of rankings, with a count.

  • Top-coded incomes are flagged. INE caps the highest incomes in its income atlas. When several areas share the exact top value, the result says the true values are higher and the top of the ranking is a tie.

  • Two sources, one number. Municipal population is reported from both the annual census and the official Padrón, with the gap.

  • Spelling guesses are never silent. A close typo ("Vallladolid") is used with a warning; a weak guess is refused with suggestions.

  • Neighbourhoods are named, not invented. INE numbers districts and tracts; each is shown with the OpenStreetMap neighbourhoods inside it ("Valladolid distrito 10 (Parquesol, Girón, La Victoria)"). A neighbourhood name finds its district, with a warning that the figures cover the whole district.

  • Map gaps are measured. OpenStreetMap counts are lower bounds. Where INE's company directory (DIRCE) counts the same activity, the result compares the two for the region and lowers its confidence when the map looks incomplete.

  • Upstream changes fail loudly. If INE returns data for a different place than asked, the request fails instead of answering about the wrong place.

  • No personal data. The server returns aggregate statistics only. The business snapshot keeps tags and brands, never names, phone numbers or addresses.

Evaluation

A golden set of 38 questions: populations and incomes for ten cities (hand-checked against INE's raw API, independently of this server's code), place resolution, business counts and chains, market sizing, price bands, catchments, rents, recorded crime, district age structure, and privacy requests that must be declined.

  • Layer 1, the server (evals/layer1.py): each question's tool calls and the facts they must return. Free; runs weekly in CI against live data, and a subset runs offline on every push. Latest run (2026-10-16): 36 of 36 tool-backed questions pass. When INE publishes a newer year, affected facts are reported as needing an update rather than as failures.

  • Layer 2, the assistant (evals/run_model.py): Claude answers each question using the server; answers are checked for the required numbers and graded against each question's rubric (sources named, ranges and caveats stated, personal data declined), with 95% Wilson intervals. Latest run (2026-10-17, Claude Sonnet 5.5, all 38 questions):

    Metric

    Rate

    95% interval

    n

    Required numbers in the answer

    100%

    87% to 100%

    26

    Rubric items met

    96%

    90% to 99%

    84

    Sources named

    100%

    90% to 100%

    35

    Ranges, estimates and data years stated

    100%

    81% to 100%

    16

    Personal-data requests declined

    100%

    70% to 100%

    9

    The three missed items are in evals/results/latest.md. The grader is the same model, so as a check a person read 10 of the answers (one or two of each kind, drawn at random) and scored each out of 10: all scored 8.5 or higher (human check; one grader, the author). A five-question subset reruns monthly.

Install

No API keys are needed.

Hosted (no install): in Claude, open Settings → Connectors → Add custom connector and paste

https://spain-open-data-mcp-165703905656.europe-west1.run.app/mcp

It is a free public server with rate limits; see the privacy policy.

Claude Code (runs locally; requires uv)

claude mcp add spain-open-data -- uvx spain-open-data-mcp

or, for the hosted server, claude mcp add --transport http spain-open-data https://spain-open-data-mcp-165703905656.europe-west1.run.app/mcp.

Claude Desktop: add this to claude_desktop_config.json and restart Claude.

{
  "mcpServers": {
    "spain-open-data": {
      "command": "uvx",
      "args": ["spain-open-data-mcp"]
    }
  }
}

The package is on PyPI and in the MCP Registry as io.github.digvijaysingh-ai/spain-open-data-mcp.

Self-hosted over HTTP: spain-open-data-mcp http --host 0.0.0.0 --port 8080 serves Streamable HTTP at /mcp, or run the image ghcr.io/digvijaysingh-ai/spain-open-data-mcp, which includes the data files. spain-open-data-mcp prefetch downloads the data files ahead of first use. Deployment to Cloud Run is in docs/deploy.md.

Settings

Variable

Default

Purpose

SPAIN_MCP_CACHE_DIR

~/.cache/spain-open-data-mcp

On-disk cache of upstream responses

SPAIN_MCP_HTTP_TIMEOUT

60

Seconds per upstream request

SPAIN_MCP_OFFLINE

unset

1 serves only from cache (tests, evals)

SPAIN_MCP_GEOMETRY_DB

unset

Path to the census tract geometry file. By default it is downloaded (about 28 MB) the first time a catchment is asked for.

SPAIN_MCP_HTTP_CACHE_MB

0 (no limit)

Cap on the cache of upstream responses; oldest dropped first

SPAIN_MCP_CENSUS_DB

unset

Path to the census-by-tract file (age bands for districts and tracts). By default it is downloaded (about 3 MB) on first use.

SPAIN_MCP_OSM_DB

unset

Path to an OpenStreetMap snapshot file. By default it is downloaded (about 21 MB) on first use and refreshed monthly.

Architecture

src/spain_open_data_mcp/
  server.py        MCP tools, resource and error handling
  tools/           one module per tool: fetch, check, render
  sources/ine/     INE Tempus API client and table definitions
  sources/osm/     OpenStreetMap snapshot: business categories, download, queries
  places/          place resolver and INE codes
  core/            cached HTTP client, response envelope, errors
  data/            bundled municipality list and INE table map (built by scripts/build_reference.py)
  • Upstream responses are cached on disk with their original retrieval time, so cached figures still report when they were fetched. If an upstream service is down, the last cached copy is served and marked stale.

  • Requests are rate limited per host, retried with backoff, and identify the project in the User-Agent.

  • Business counts come from a monthly snapshot rather than live Overpass queries, which are slow and rate limited. scripts/build_osm_snapshot.py reads the Geofabrik extracts for Spain and the Canary Islands, keeps shops and services, and places each one in an INE census tract. A GitHub Action publishes it on the osm-snapshot-v1 release each month.

  • INE table ids are not hard-coded in the tools. scripts/build_reference.py rebuilds the map when INE publishes new tables, for example each October's income atlas.

Development

uv sync
uv run pytest            # offline tests against recorded INE responses
uv run ruff check . && uv run ruff format --check . && uv run pyright
uv run spain-open-data-mcp          # stdio
uv run spain-open-data-mcp http     # Streamable HTTP on 127.0.0.1:8000/mcp

Refresh the recorded test fixtures with uv run python tests/fixtures/record_ine.py. Build the OpenStreetMap snapshot locally (a 1.5 GB download, then about 5 minutes) with uv run --group snapshot python scripts/build_osm_snapshot.py, then point SPAIN_MCP_OSM_DB at build/osm/osm_businesses.sqlite.

Roadmap

  1. Skeleton: place resolver, demographics, income, CI.

  2. Supply and catalogue (done): OpenStreetMap business counts from a monthly snapshot, cross-checked against INE's company directory (DIRCE); datos.gob.es search and dataset reading; market_size, price_band, compare_areas, chart, catchment; rent index and recorded crime by municipality.

  3. Checks and evals: a golden set of real strategy questions with hand-checked answers, scored for accuracy, sourcing, refusals and calibration, with results here.

  4. Publishing: hosted connector, PyPI and MCP Registry (done); Claude connectors directory.

Data licences

The code is MIT-licensed. Data keeps its source licence; see data_licences.md. INE data is reused under CC BY 4.0: "Fuente: INE. Elaboración propia con datos extraídos del sitio web del INE: www.ine.es". OpenStreetMap data is © OpenStreetMap contributors, under the Open Database Licence.

Available Tools

13 tools
businessesBusinesses and competitorsA
Read-onlyIdempotent
Inspect

Count businesses of a kind in a place in Spain, per 10,000 residents and per km², from OpenStreetMap.

Use it to size competition and supply: how many gyms, cafés or dentists an area has,
how that compares with the province, region and Spain, which brands dominate, and
which districts or tracts are over- or under-served (rank sub-areas by
per_10k_residents). Counts are lower bounds because OpenStreetMap is mapped by
volunteers; where INE's company directory covers the same activity, the result says
how complete the map looks in that region. Returns counts and brands only, never
lists of individual premises.
NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.
rank_byNoHow to rank sub-areas: 'count', 'per_10k_residents' or 'per_km2'.count
categoryNoWhat to count. A category: restaurant, fast_food, cafe, bar, ice_cream, nightclub, supermarket, convenience, bakery, butcher, greengrocer, drinks_tobacco, clothes, pharmacy, optician, beauty_shop, jewellery, florist, pet_shop, electronics, home, books_leisure, variety_store, hairdresser, beauty_salon, laundry, dentist, doctor, physiotherapy, hospital, veterinary, gym, sports_centre, dance_studio, cinema_theatre, private_school, childcare, school, hotel, guest_house, camp_site, estate_agent, lawyer, accountant, insurance, travel_agency, coworking, bank, fuel, car_repair, car_dealer, car_wash. Plain words work too ('gyms', 'peluquerías'). Or a sector: food_drink, food_retail, retail, personal_services, health, leisure, education, accommodation, professional, finance, motoring. Or OpenStreetMap tags: 'shop=bakery' or 'amenity=bar,amenity=pub'. Leave empty for all businesses, broken down by category.
sub_areasNoFor a municipality, also count by 'district' or census 'tract'. Default 'none'.none

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent and open-world behavior, and the description adds substantial non-obvious context on top: counts are lower bounds because OSM is volunteer-mapped, an INE cross-check reports regional completeness, and the return is aggregates-only rather than premise lists. That is exactly the kind of data-quality caveat structured fields cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded in the first sentence and every later sentence carries distinct information (use cases, ranking intent, OSM caveat, INE check, return boundary). It is somewhat dense with long clauses, but nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return format need not be re-explained, and the description covers the remaining burden: what is counted, how it is normalized, expected use cases, ranking semantics, data-source limitations and the aggregate-only contract. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema carries the parameter detail (baseline 3). The description still adds interpretive value by tying ranking to 'per_10k_residents' for spotting under-served sub-areas and by framing what 'category' means in use ('how many gyms, cafés or dentists'), rather than merely restating the fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource ('Count businesses of a kind in a place in Spain'), plus the two normalizations (per 10,000 residents, per km²) and the data source (OpenStreetMap). This distinguishes it from siblings like market_size, demographics and income without the agent needing to open any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete use cases ('size competition and supply', compare with province/region/Spain, find over- or under-served districts) and an explicit scope boundary ('Returns counts and brands only, never lists of individual premises'). It does not, however, name sibling alternatives such as market_size or compare_areas for overlapping tasks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

catchmentCatchment around an addressA
Read-onlyIdempotent
Inspect

Profile the area within a radius (or a walking time) of an address: residents, households, income, age, and the businesses mapped there. With a category, also the yearly market in euros, competing businesses and an opportunity score against the region. Use for "who lives within 800 m of this shop" or "is there room for a bakery near Calle X". Addresses are checked against the municipality they name; ambiguous ones are refused with suggestions.

NameRequiredDescriptionDefault
nearYesAddress as 'street number, municipality' (e.g. 'Calle Sierpes 40, Sevilla'), or coordinates as 'lat, lon'. Floor and door are ignored and never stored.
categoryNoOptional business category, to add market size and opportunity score.
radius_mNoRadius in metres (e.g. 500, 800, 1500).
walk_minutesNoUse the area reachable on foot in this many minutes instead of a circle.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/openWorld/idempotent/non-destructive, so the bar is lower, yet the description still adds real behavior: addresses are validated against the named municipality and ambiguous ones are refused with suggestions, and supplying a category conditionally adds market size, competitors and an opportunity score. These conditional-output and failure-mode details are exactly what the agent cannot infer from the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Roughly three sentences, front-loaded with the verb 'Profile the area', followed by conditional capability, use cases, then a caveat about address validation. Dense but every clause carries information; only the interleaved example quotes make it slightly harder to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering the safety profile, the remaining burden is purpose, input intent, conditionality and failure handling — all covered. An agent can decide to call this tool and predict the refusal path for ambiguous addresses without opening the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, and the description adds meaning on top: it frames radius_m versus walk_minutes as mutually exclusive ways to define the area ('instead of a circle') and ties category to the extra outputs it unlocks. It stops short of example syntax for coordinates or walk times, which the schema already handles.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource: profile the population, households, income, age and mapped businesses within a radius or walk time of an address, with market size and an opportunity score when a category is given. That scope is clearly distinct from point-topic siblings like income or crime, but the description never names an alternative tool (e.g. compare_areas or demographics), so the differential is left implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Offers concrete trigger scenarios ('who lives within 800 m of this shop', 'is there room for a bakery near Calle X') that make the intended use easy to recognize. It does not say when to prefer a sibling such as market_size or demographics, nor when this tool is the wrong choice, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

chartChartA
Read-onlyIdempotent
Inspect

Draw a chart (PNG) of a tool result: an opportunity ranking with ranges, income by district, an age pyramid or a population trend. Returns the image, the same text and sources as the underlying tool, and a source line on the image. If drawing fails the text still comes back.

NameRequiredDescriptionDefault
kindYes'opportunity' (needs category; ranks areas within the place), 'income' (by district or tract), 'age_pyramid' or 'population_trend'.
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.
categoryNoBusiness category, for kind 'opportunity'.
sub_areasNoFor 'income': districts or tracts.district

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive behavior, so the bar is lower. The description still adds real value: the output is an image plus the underlying text and sources, a source line is stamped on the image, and it degrades gracefully by returning text if drawing fails.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the action and output type, with the failure-mode caveat last. Every clause earns its place and nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema and 100% parameter coverage, the description need not restate return values or param formats, and it still covers output composition and failure behavior. Only the when-to-use routing is thin, which is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, including detailed enum semantics and place-code formats, so the schema carries the parameter burden. The description adds no format or syntax detail beyond what the schema already documents; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Draw a chart (PNG)') and enumerates the exact four chart kinds that match the kind enum, so an agent immediately understands the scope. No sibling tool draws images, so this is clearly differentiated from income, demographics, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'of a tool result' implies this wraps/enriches the data tools (income, opportunity), but the description never explicitly says when to prefer a chart over the bare numeric tool, nor names alternatives or exclusions. Usage is inferable but not stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_areasCompare areas for a businessA
Read-onlyIdempotent
Inspect

Rank areas by opportunity for a business category: where is there most market per business.

Each area gets a yearly market in euros, estimated competing businesses and an opportunity
score against its region, all with ranges. Areas are ranked by the cautious (low) end of
the score; areas too small for the category are left out and counted. Use for "where in
Valladolid should I open a gym" or "which towns in Málaga province lack pharmacies".
NameRequiredDescriptionDefault
levelNo'district' or 'tract' within a municipality; 'municipality' within a province or region.auto
limitNoHow many areas to return, best first.
withinYesA municipality (compares its districts or tracts) or a province or region (compares its municipalities).
categoryYesBusiness category: restaurant, cafe, bar, fast_food, bakery, butcher, greengrocer, supermarket, pharmacy, optician, dentist, physiotherapy, hairdresser, beauty_salon, veterinary, gym, childcare, private_school, clothes, home. Plain words work too ('gyms', 'peluquerías').

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety (readOnly, idempotent, non-destructive), but the description adds real behavioral detail beyond them: the scoring basis (ranked by the cautious/low end), the outputs per area (yearly market in euros, competing businesses, opportunity score with ranges), and the exclusion rule with counting. Only latency/cost behavior is unaddressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose in sentence one, then ranking mechanics, then examples. Sentence two is a dense run-on ('all with ranges') but every clause carries information; no padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description still conveys the shape of results (market estimate, competitors, opportunity score) and the ranking/exclusion semantics an agent needs to interpret them correctly. Nothing material is missing for a read-only analytics tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are already documented in the schema. The description adds marginal meaning, only implicitly linking 'towns' vs 'districts' to the level parameter and mentioning the small-area exclusion that relates to limit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (rank) and resource (areas) plus the exact metric framing: 'most market per business'. This is clearly distinguishable from siblings like market_size or catchment, which do not rank areas against a category.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete usage triggers via two natural-language example questions ('where in Valladolid should I open a gym', 'which towns in Málaga province lack pharmacies'). It does not, however, explicitly state when to prefer a sibling such as market_size or catchment instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

crimeCrimeA
Read-onlyIdempotent
Inspect

Recorded crime in a place from the Interior ministry: offences by type (theft, burglary, robbery, assault, drugs, cybercrime and more) for the latest full year, per 1,000 residents, the change on the year before, the latest year-to-date figures, and province, region and Spain for comparison.

Published for municipalities over 20,000 residents, provinces and regions; smaller places
get the province's figures, and the result says so.
NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, non-destructive, closed-world behavior. The description adds genuine non-annotation context: only municipalities over 20,000 residents have their own figures, smaller places return the province's data, and the result itself indicates this fallback. That is exactly the kind of reliability caveat 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the data content and ending with the coverage caveat. Dense but every clause (offence types, unit, comparison levels, publication threshold) adds information; only the long enumeration in the first sentence slightly taxes readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single fully documented parameter, rich annotations, and an output schema that handles return values, the description supplies everything else needed: what is measured, the unit, comparison geographies, and the fallback for small places.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'place' parameter is thoroughly documented in the schema (INE codes, format variants, disambiguation with 'Name, Province'). The description adds no parameter-level detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (Interior ministry recorded crime) with the exact metric (offences by type, per 1,000 residents, YoY change, YTD), so an agent immediately knows what data it returns. No sibling tool covers crime statistics, so it is inherently distinguished from businesses, income, rents, demographics, etc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by the data domain; there is no explicit 'use this when… / not for…' statement or named alternative. The coverage note (smaller places fall back to province figures) hints at scope but is a behavior caveat rather than routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

demographicsPopulation and householdsA
Read-onlyIdempotent
Inspect

Population, sex, five-year age bands, 5-year trend, and household profile for a place in Spain.

Municipality, province and CCAA: census population by age band (latest 1 January),
cross-checked against the official Padrón figure. District and tract: census age bands
and sex from INE's file by census tract. Municipality, district and tract:
household size, single-person households, mean age, share under 18 and 65+ from INE's
income atlas. Use sub_areas to compare a city's districts or tracts, e.g. to find
where young families or older residents concentrate.
NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.
sub_areasNoFor a municipality, also list its 'district's or census 'tract's. Default 'none'.none

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds genuine context beyond that: which official source backs each geography level (census/Padrón vs INE census-tract file vs income atlas) and that figures are latest-1-January and cross-checked, which tells an agent what the numbers actually represent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core deliverable in the first sentence, then organized as a geography-to-dataset mapping, which is easy to scan. It is slightly repetitive in re-listing the same geography triples, but every clause carries substantive information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return-value documentation is unnecessary, and the description covers the remaining concerns: data provenance, per-geography coverage, the required place identifier, and the optional sub-area expansion. Only an explicit sibling-comparison rule (demographics vs income/market_size) is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description earns a notch above that by tying data availability to the geography argument: municipality/province/CCAA yield census plus Padrón, district/tract yield census age bands and sex, and household metrics exist only at municipality/district/tract — context the schema does not state.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names the exact resource set (population, sex, five-year age bands, trend, household profile) and the exact scope (a place in Spain). The enumerated geography levels and data sources make it unmistakable against siblings such as income, rents, crime, or businesses, which cover entirely different subject matter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives one concrete usage example ('use sub_areas to compare a city's districts or tracts, e.g. to find where young families or older residents concentrate'), which is implied guidance rather than an explicit when-to-use rule. It never states when to prefer demographics over income, market_size, or catchment, nor any exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_datasetsFind open datasetsA
Read-onlyIdempotent
Inspect

Search Spain's national open-data catalogue (datos.gob.es) for datasets on a topic.

Returns each dataset's title, publisher, licence, file formats, update frequency and last
change, and an id to pass to read_dataset. Use when a question needs data this server does
not hold directly (parking, licences, local events, tourist offices, transport).
NameRequiredDescriptionDefault
limitNoHow many datasets to return.
placeNoOptional place; datasets about it are preferred.
queryYesTopic; Spanish works best, e.g. 'turismo', 'aparcamiento', 'licencias'.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds the fact that results come from an external national catalogue and that Spanish queries work best, but the enumerated return fields are largely duplicated by the existing output schema rather than adding new behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight paragraphs: purpose first, then return contents, then the usage trigger. Every sentence carries information an agent needs, with no filler or restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Purpose, usage condition, output shape and the hand-off to read_dataset are all present, and the output schema plus annotations remove the need to dwell on return format. Minor redundancy in re-listing returned fields is the only thing keeping it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so query, place and limit are all documented in the schema itself. The description reinforces the query semantics ('Spanish works best') but adds no new meaning for place or limit; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — searching Spain's national open-data catalogue (datos.gob.es) for datasets on a topic — and names the sibling (read_dataset) that consumes its output. An agent can distinguish it from sibling tools like businesses or demographics without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger: 'Use when a question needs data this server does not hold directly,' with concrete domains (parking, licences, local events, tourist offices, transport). It also names the follow-up tool (read_dataset) and the id needed to call it, so the routing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

incomeHousehold incomeA
Read-onlyIdempotent
Inspect

Household income for a place in Spain from INE's income atlas, down to census tract.

Returns net and gross income per person and per household, mean and median per consumption unit, inequality (Gini, P80/P20), income sources (wages, pensions, benefits), a trend, and benchmarks against the province, region and Spain. Use it for purchasing power, price positioning and choosing between districts. Figures are euros of the data year; the atlas runs about two years behind.

NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.
yearsNoYears of history for the trend (max 9).
rank_byNoMetric used to rank sub-areas.net_income_per_person
sub_areasNoFor a municipality, rank its 'district's or census 'tract's. Default 'none'.none

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safe read-only, idempotent profile, so the bar is lower. The description adds meaningful context beyond them: the data lag (~two years behind), that figures are euros of the data year, and the benchmark scope (province, region, Spain). It doesn't discuss pagination or output shape, but with annotations and an output schema those matter less.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core identity (income for a place, source, granularity) in the first sentence, then enumerates returns and use cases without waste. Dense but every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no prose explanation, and the description still covers source, granularity, benchmark scope and a key freshness caveat. Nothing an agent needs 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.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already fully documents place, years, rank_by and sub_areas with enum values. The description touches the trend and sub-area ranking conceptually but adds no syntax or format detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (household income for a place in Spain) with source (INE income atlas) and resolution (down to census tract). It clearly distinguishes from siblings like rents, crime or demographics by naming the exact dataset and granularity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit use cases (purchasing power, price positioning, choosing between districts), which tells the agent when this tool is appropriate. However, it never names an alternative sibling (e.g., compare_areas or rents) or draws an exclusion boundary, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

market_sizeMarket size in eurosA
Read-onlyIdempotent
Inspect

Size the yearly market for a business category in a place in Spain, in euros, with a range.

Market = households × INE household spending on the category × an income adjustment. Supply = competing businesses, calibrated against INE's company directory. Returns market per business and an opportunity score against the region (1.0 = same as the region), with every assumption listed. Assumptions can be overridden to test scenarios. Use for "how big is the market for X in Y" and "is Y under-served for X".

NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.
categoryYesBusiness category: restaurant, cafe, bar, fast_food, bakery, butcher, greengrocer, supermarket, pharmacy, optician, dentist, physiotherapy, hairdresser, beauty_salon, veterinary, gym, childcare, private_school, clothes, home. Plain words work too ('gyms', 'peluquerías').
competitorsNoOverride the estimated number of competing businesses.
capture_shareNoShare of the market one business could win (0-1), to estimate obtainable revenue.
spend_per_householdNoOverride INE's yearly spend per household on the category, in euros.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, openWorld, non-destructive), but the description adds real behavioral context: the underlying model (households × INE spend × income adjustment), supply calibration against INE's directory, that every assumption is listed, and that assumptions can be overridden for scenarios. It stops short of noting data recency or geographic coverage limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose in the first sentence, followed by methodology and return summary. Three short paragraphs with little waste, though the final paragraph blends usage triggers with output description rather than keeping them separate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists and the input schema is fully documented, the description supplies the model mechanics, assumption-override capability, and usage triggers an agent needs. Nothing required to invoke or interpret the tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds meaning by framing competitors, spend_per_household, and capture_share as overridable assumptions for scenario testing, which contextualizes why those optional params exist. It doesn't add unit or format detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (size), resource (yearly market), scope (business category in a place in Spain), unit (euros) and output shape (with a range). It is clearly distinguishable from siblings like demographics, income, or businesses because it names the market-sizing operation explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit trigger phrases: '"how big is the market for X in Y"' and '"is Y under-served for X"', plus a scenario-testing note via overrides. It gives clear context but doesn't name alternative siblings (e.g., demographics, businesses) or state when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

price_bandPrice range for a placeA
Read-onlyIdempotent
Inspect

Suggest a price range for a place from local purchasing power and inflation.

Public data has no competitor prices, so this adjusts a price you know (from elsewhere or
an earlier date) to this place today: CPI for the category's group since that month, then
local median income per consumption unit against the reference place. Returns a range
from no local adjustment to full adjustment, labelled as an estimate.
NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.
categoryNoMarket category, to uprate with its own CPI group (e.g. 'gym', 'restaurant').
price_monthNoMonth the reference price applied, YYYY-MM, to uprate it to today.
reference_placeNoWhere the reference price applies: 'ES' (Spain, default) or a place.ES
reference_priceYesPrice elsewhere, in euros, e.g. 39.9 for a monthly gym fee.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), and the description adds meaningful context beyond that: the two-stage adjustment mechanism, the fact that no competitor price data exists, and that output is a range 'labelled as an estimate'. It does not discuss pagination, latency, or failure modes, but for a read-only computed estimate those are minor.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the purpose and followed by the rationale and the return shape. Well-structured and mostly waste-free, though the second sentence is dense enough that a reader must work through it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not detail return fields, and it still supplies the key epistemic caveat (estimate, range from no adjustment to full adjustment) plus the data limitation. Combined with full schema coverage and clear annotations, an agent has what it needs to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already defines every parameter including place formats and defaults. The description adds only the conceptual role of price_month and reference_place (uprating vs. comparison) which the schema largely conveys; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Suggest a price range for a place' from purchasing power and inflation, with the method (CPI uprating plus median income per consumption unit) spelled out. It does not, however, contrast itself with siblings such as rents, income, or market_size, so an agent must infer the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear usage context: it applies when public data has no competitor prices, so you supply a price you already know 'from elsewhere or an earlier date' and it adjusts it to the place today. No explicit exclusions or named alternative tools are provided, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_datasetRead an open datasetA
Read-onlyIdempotent
Inspect

Read a datos.gob.es dataset: its columns and up to 20 sample rows, with its licence.

Reads CSV and JSON files listed in the catalogue (the first 5 MB). Columns that look like
personal data (names, ID numbers, emails, phones) are withheld. Values are shown as the
publisher published them.
NameRequiredDescriptionDefault
dataset_idYesAn id from find_datasets.
file_indexNoWhich file of the dataset (from 0); default: the first CSV or JSON.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive, open-world behavior, and the description adds genuinely new operational facts: a 20-row sample cap, a 5 MB read limit, and that personal-data-looking columns (names, IDs, emails, phones) are withheld. That privacy-filtering disclosure is exactly the kind of trait annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short paragraphs, front-loaded with what is returned before the constraints. Each sentence carries a distinct fact (return shape, file scope and size cap, PII withholding, fidelity of values) with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return structure, yet it still summarizes the payload (columns, sample rows, licence). Combined with annotations covering the safety profile and complete schema coverage, an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and both parameters are already documented there (dataset_id from find_datasets, file_index selection with a stated default). The prose adds no parameter-level syntax or format detail beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (read) plus resource (datos.gob.es dataset) and enumerates exactly what is returned: columns, up to 20 sample rows, and the licence. This clearly separates it from the search-oriented sibling find_datasets.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description establishes the operating context (only CSV and JSON files listed in the catalogue, only the first 5 MB) and the schema ties dataset_id back to find_datasets, so an agent can infer the follow-up-after-search workflow. It stops short of an explicit when-not-to-use statement or naming an alternative tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rentsRentsA
Read-onlyIdempotent
Inspect

How housing rents have changed in a place: INE's rent index (IPVA, 2015 = 100) with the change over the last year, five years and since 2015, against province, region and Spain.

Covers municipalities over 10,000 residents, districts of provincial capitals, provinces and
regions (not the Basque Country or Navarra). Gives changes, not rents in euros.
NameRequiredDescriptionDefault
placeYesPlace name or INE code: municipality ('Valladolid' or '47186'), province ('41'; a bare name like 'Sevilla' means the city), autonomous community ('Cataluña' or 'CA09'), district ('4718603') or census tract ('4718603012'). 'Name, Province' picks between same-named towns.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this a read-only, idempotent, open-world read, so the safety profile is covered. The description adds behavioral substance beyond that: geographic coverage limits, the exclusion of two regions, and the crucial unit caveat that outputs are index changes rather than euro rents. It doesn't state update frequency or the reference period granularity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight paragraphs, front-loaded with the core purpose before coverage caveats. Coverage of provinces and regions is mentioned in both paragraphs, a minor redundancy, but nothing is wasted overall.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be documented — and the description still adds the key interpretive context that values are changes, not euro amounts. Combined with the full parameter documentation and geographic scope, an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single `place` parameter has 100% schema description coverage, including the accepted code formats and disambiguation syntax, so the schema does the heavy lifting. The description adds nothing about parameter syntax or format beyond what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — how housing rents have changed — and names the exact data source (INE's IPVA, 2015 = 100) plus the measures returned (1/5-year and since-2015 change). The line 'Gives changes, not rents in euros' sharply differentiates it from sibling tools like income or price_band that might otherwise be confused with rent costs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Coverage is spelled out precisely (municipalities over 10,000 residents, districts of provincial capitals, provinces, regions) and exclusions are stated (not the Basque Country or Navarra), which functions as implicit when-not guidance. It stops short of naming an alternative tool to use for excluded areas or for different geographies.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolve_placeResolve a Spanish placeA
Read-onlyIdempotent
Inspect

Find the INE code and level (CCAA, province, municipality, district, tract) for a place in Spain.

Use this first when a question names a place. Returns the best match first, with
alternatives (e.g. 'Valencia' is both a city and a province). Handles accents, Basque,
Catalan and Galician names, and common English names (Seville, Catalonia).
Neighbourhood names are not supported; use districts or tracts from `demographics`
or `income` with `sub_areas`.
NameRequiredDescriptionDefault
queryYesPlace name or INE code, e.g. 'A Coruña', 'Mérida, Badajoz', '08'.

Output Schema

NameRequiredDescription
dataYes
checksNo
sourcesYes
confidenceYesLowest confidence across inputs: high, medium or low. Never state a conclusion more strongly than this.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds real behavioral context beyond that: best match returned first with alternatives for ambiguous names ('Valencia'), and multilingual/accent handling. It doesn't discuss rate limits or result counts, but with an output schema present that gap is minor.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core action, then usage, then the ambiguity/unsupported-input caveats. No filler and every sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be restated, annotations cover the safety profile, and the single parameter is fully documented. The description covers entry conditions, ambiguity behavior, and an unsupported input class — nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter and schema coverage is 100%, including examples ('A Coruña', 'Mérida, Badajoz', '08'), so the schema already carries the semantics. The description's mention of ambiguity is about results rather than the query parameter itself, so it adds little param-level detail. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Find the INE code and level (CCAA, province, municipality, district, tract) for a place in Spain.' It even enumerates the output level taxonomy, so an agent can distinguish this geocoding/resolution tool from data-fetching siblings like demographics or income.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this first when a question names a place', and names the when-not case with an alternative: neighbourhood names are unsupported, use districts or tracts from `demographics` or `income` with `sub_areas`. That is a direct routing rule to specific siblings.

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.

  1. 13 tool updatesv0.1.1
    • Addedbusinesses
    • Addedcatchment
    • Addedchart
    • Addedcompare_areas
    • Addedcrime
    • Changeddemographics1 field changed
      • addedOutput schema / $defs / Place / properties / official_name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "INE's form of the name when it differs ('Palmas de Gran Canaria, Las').",
        +  "title": "Official Name"
        +}
    • Addedfind_datasets
    • Changedincome1 field changed
      • addedOutput schema / $defs / Place / properties / official_name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "INE's form of the name when it differs ('Palmas de Gran Canaria, Las').",
        +  "title": "Official Name"
        +}
    • Addedmarket_size
    • Addedprice_band
    • Addedread_dataset
    • Addedrents
    • Changedresolve_place1 field changed
      • addedOutput schema / $defs / Place / properties / official_name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "INE's form of the name when it differs ('Palmas de Gran Canaria, Las').",
        +  "title": "Official Name"
        +}
  2. 3 tool updatesv0.1.0
    • First observeddemographics
    • First observedincome
    • First observedresolve_place

TDQS

A4.1/5.0

Scored across 13 tools

Disambiguation4/5

Most tools have clearly distinct purposes, but the business/market cluster (businesses, market_size, compare_areas, catchment) overlaps enough that careful reading is needed to pick the right one. Their scopes differ by geography and output, so descriptions help avoid misselection.

Naming Consistency3/5

All names use snake_case, but the set mixes noun resource names (rents, businesses, demographics, income, crime) with verb_noun action names (resolve_place, read_dataset, compare_areas, find_datasets). The pattern is readable but not fully consistent.

Tool Count5/5

With 13 tools, the server is well within the ideal 3–15 range. Each tool appears to serve a distinct analytical or helper purpose, so none feel redundant or excessive.

Completeness4/5

The surface covers core location and market analytics (places, demographics, income, businesses, market sizing, crime, rents, pricing) plus dataset discovery and charting. Minor gaps remain, such as full dataset download, housing sale prices, and employment/transport data, but find_datasets and read_dataset provide partial workarounds.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server providing access to Spain's National Statistics Institute (INE) Tempus3 JSON API, enabling querying of Spanish statistical data through natural language.
    384 npm
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables querying demographic, spending, and market data for every place in Europe, offering tools to analyze markets, describe areas, reach audiences, compare and rank places, sample personas, resolve locations, and run structured population queries—all as privacy-protected aggregates.
    -
  • A
    license
    A
    quality
    C
    maintenance
    Official cadastral parcels from 29 European countries for AI agents: by reference in 27 and by coordinates in all 29, plus address search, outlines, neighbours, SIGPAC enclosures, terrain, ground motion, solar and agricultural potential and investment scores. Remote server at https://mcp.parcelgps.com/mcp (nothing to install) or npm catastro-gps-mcp. Free key: 250 calls/month.
    9
    358 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to resolve places and statistical variables, then retrieve harmonised public statistics such as population, income, health, employment, and emissions with publisher provenance and child-place comparisons.
    437 npm
    MIT