Market sizing, prices, rents, crime and locations in Spain from INE and other public data
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
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.
Place 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.
How to rank sub-areas: 'count', 'per_10k_residents' or 'per_km2'.
What 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.
For a municipality, also count by 'district' or census 'tract'. Default 'none'.
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.
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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_by | string | How to rank sub-areas: 'count', 'per_10k_residents' or 'per_km2'. |
| category | any | What 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_areas | string | For a municipality, also count by 'district' or census 'tract'. Default 'none'. |
{
"type": "object",
"title": "businessesArguments",
"required": [
"place"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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_by": {
"enum": [
"count",
"per_10k_residents",
"per_km2"
],
"type": "string",
"title": "Rank By",
"default": "count",
"description": "How to rank sub-areas: 'count', 'per_10k_residents' or 'per_km2'."
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Category",
"default": null,
"description": "What 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_areas": {
"enum": [
"none",
"district",
"tract"
],
"type": "string",
"title": "Sub Areas",
"default": "none",
"description": "For a municipality, also count by 'district' or census 'tract'. Default 'none'."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| near* | string | Address as 'street number, municipality' (e.g. 'Calle Sierpes 40, Sevilla'), or coordinates as 'lat, lon'. Floor and door are ignored and never stored. |
| category | any | Optional business category, to add market size and opportunity score. |
| radius_m | integer | Radius in metres (e.g. 500, 800, 1500). |
| walk_minutes | any | Use the area reachable on foot in this many minutes instead of a circle. |
{
"type": "object",
"title": "catchmentArguments",
"required": [
"near"
],
"properties": {
"near": {
"type": "string",
"title": "Near",
"description": "Address as 'street number, municipality' (e.g. 'Calle Sierpes 40, Sevilla'), or coordinates as 'lat, lon'. Floor and door are ignored and never stored."
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Category",
"default": null,
"description": "Optional business category, to add market size and opportunity score."
},
"radius_m": {
"type": "integer",
"title": "Radius M",
"default": 800,
"maximum": 10000,
"minimum": 100,
"description": "Radius in metres (e.g. 500, 800, 1500)."
},
"walk_minutes": {
"anyOf": [
{
"type": "integer",
"maximum": 30,
"minimum": 3
},
{
"type": "null"
}
],
"title": "Walk Minutes",
"default": null,
"description": "Use the area reachable on foot in this many minutes instead of a circle."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| kind* | string | 'opportunity' (needs category; ranks areas within the place), 'income' (by district or tract), 'age_pyramid' or 'population_trend'. |
| place* | string | Place 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. |
| category | any | Business category, for kind 'opportunity'. |
| sub_areas | string | For 'income': districts or tracts. |
{
"type": "object",
"title": "chartArguments",
"required": [
"kind",
"place"
],
"properties": {
"kind": {
"enum": [
"opportunity",
"income",
"age_pyramid",
"population_trend"
],
"type": "string",
"title": "Kind",
"description": "'opportunity' (needs category; ranks areas within the place), 'income' (by district or tract), 'age_pyramid' or 'population_trend'."
},
"place": {
"type": "string",
"title": "Place",
"description": "Place 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."
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Category",
"default": null,
"description": "Business category, for kind 'opportunity'."
},
"sub_areas": {
"enum": [
"district",
"tract"
],
"type": "string",
"title": "Sub Areas",
"default": "district",
"description": "For 'income': districts or tracts."
}
}
}Rank areas by market per competing business for a category (the opportunity score). 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".
| Argument | Type | Description |
|---|---|---|
| level | string | 'district' or 'tract' within a municipality; 'municipality' within a province or region. |
| limit | integer | How many areas to return, best first. |
| within* | string | A municipality (compares its districts or tracts) or a province or region (compares its municipalities). |
| category* | string | Business 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'). |
{
"type": "object",
"title": "compare_areasArguments",
"required": [
"within",
"category"
],
"properties": {
"level": {
"enum": [
"auto",
"municipality",
"district",
"tract"
],
"type": "string",
"title": "Level",
"default": "auto",
"description": "'district' or 'tract' within a municipality; 'municipality' within a province or region."
},
"limit": {
"type": "integer",
"title": "Limit",
"default": 20,
"maximum": 40,
"minimum": 1,
"description": "How many areas to return, best first."
},
"within": {
"type": "string",
"title": "Within",
"description": "A municipality (compares its districts or tracts) or a province or region (compares its municipalities)."
},
"category": {
"type": "string",
"title": "Category",
"description": "Business 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')."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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. |
{
"type": "object",
"title": "crimeArguments",
"required": [
"place"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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_areas | string | For a municipality, also list its 'district's or census 'tract's. Default 'none'. |
{
"type": "object",
"title": "demographicsArguments",
"required": [
"place"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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_areas": {
"enum": [
"none",
"district",
"tract"
],
"type": "string",
"title": "Sub Areas",
"default": "none",
"description": "For a municipality, also list its 'district's or census 'tract's. Default 'none'."
}
}
}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).
| Argument | Type | Description |
|---|---|---|
| limit | integer | How many datasets to return. |
| place | any | Optional place; datasets about it are preferred. |
| query* | string | Topic; Spanish works best, e.g. 'turismo', 'aparcamiento', 'licencias'. |
{
"type": "object",
"title": "find_datasetsArguments",
"required": [
"query"
],
"properties": {
"limit": {
"type": "integer",
"title": "Limit",
"default": 10,
"maximum": 25,
"minimum": 1,
"description": "How many datasets to return."
},
"place": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Place",
"default": null,
"description": "Optional place; datasets about it are preferred."
},
"query": {
"type": "string",
"title": "Query",
"description": "Topic; Spanish works best, e.g. 'turismo', 'aparcamiento', 'licencias'."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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. |
| years | integer | Years of history for the trend (max 9). |
| rank_by | string | Metric used to rank sub-areas. |
| sub_areas | string | For a municipality, rank its 'district's or census 'tract's. Default 'none'. |
{
"type": "object",
"title": "incomeArguments",
"required": [
"place"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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."
},
"years": {
"type": "integer",
"title": "Years",
"default": 5,
"maximum": 9,
"minimum": 1,
"description": "Years of history for the trend (max 9)."
},
"rank_by": {
"enum": [
"net_income_per_person",
"net_income_per_household",
"median_income_per_consumption_unit"
],
"type": "string",
"title": "Rank By",
"default": "net_income_per_person",
"description": "Metric used to rank sub-areas."
},
"sub_areas": {
"enum": [
"none",
"district",
"tract"
],
"type": "string",
"title": "Sub Areas",
"default": "none",
"description": "For a municipality, rank its 'district's or census 'tract's. Default 'none'."
}
}
}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: market per business against the region (1.0 = same as the region), not a forecast of openings. Every assumption is 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".
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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. |
| category* | string | Business 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'). |
| competitors | any | Override the estimated number of competing businesses. |
| capture_share | any | Share of the market one business could win (0-1), to estimate obtainable revenue. |
| spend_per_household | any |
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.
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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. |
| category | any | Market category, to uprate with its own CPI group (e.g. 'gym', 'restaurant'). |
| price_month | any | Month the reference price applied, YYYY-MM, to uprate it to today. |
| reference_place | string | Where the reference price applies: 'ES' (Spain, default) or a place. |
| reference_price* | number | Price elsewhere, in euros, e.g. 39.9 for a monthly gym fee. |
{
"type": "object",
"title": "price_bandArguments",
"required": [
"place",
"reference_price"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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."
},
"category": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Category",
"default": null,
"description": "Market category, to uprate with its own CPI group (e.g. 'gym', 'restaurant')."
},
"price_month": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Price Month",
"default": null,
"description": "Month the reference price applied, YYYY-MM, to uprate it to today."
},
"reference_place": {
"type": "string",
"title": "Reference Place",
"default": "ES",
"description": "Where the reference price applies: 'ES' (Spain, default) or a place."
},
"reference_price": {
"type": "number",
"title": "Reference Price",
"description": "Price elsewhere, in euros, e.g. 39.9 for a monthly gym fee."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| dataset_id* | string | An id from find_datasets. |
| file_index | any | Which file of the dataset (from 0); default: the first CSV or JSON. |
{
"type": "object",
"title": "read_datasetArguments",
"required": [
"dataset_id"
],
"properties": {
"dataset_id": {
"type": "string",
"title": "Dataset Id",
"description": "An id from find_datasets."
},
"file_index": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
],
"title": "File Index",
"default": null,
"description": "Which file of the dataset (from 0); default: the first CSV or JSON."
}
}
}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.
| Argument | Type | Description |
|---|---|---|
| place* | string | Place 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. |
{
"type": "object",
"title": "rentsArguments",
"required": [
"place"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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."
}
}
}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). Districts and tracts are shown with the OpenStreetMap neighbourhood names inside them ('Valladolid distrito 10 (Parquesol, Girón, La Victoria)'), and a neighbourhood name ('Parquesol, Valladolid', 'Gràcia, Barcelona') returns the INE district that contains it.
| Argument | Type | Description |
|---|---|---|
| query* | string | Place name or INE code, e.g. 'A Coruña', 'Mérida, Badajoz', '08'. |
{
"type": "object",
"title": "resolve_placeArguments",
"required": [
"query"
],
"properties": {
"query": {
"type": "string",
"title": "Query",
"description": "Place name or INE code, e.g. 'A Coruña', 'Mérida, Badajoz', '08'."
}
}
}| Override INE's yearly spend per household on the category, in euros. |
{
"type": "object",
"title": "market_sizeArguments",
"required": [
"place",
"category"
],
"properties": {
"place": {
"type": "string",
"title": "Place",
"description": "Place 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."
},
"category": {
"type": "string",
"title": "Category",
"description": "Business 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')."
},
"competitors": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Competitors",
"default": null,
"description": "Override the estimated number of competing businesses."
},
"capture_share": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Capture Share",
"default": null,
"description": "Share of the market one business could win (0-1), to estimate obtainable revenue."
},
"spend_per_household": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Spend Per Household",
"default": null,
"description": "Override INE's yearly spend per household on the category, in euros."
}
}
}