Search UNESCO World Heritage sites, intangible heritage, biosphere reserves, and Global Geoparks.
One address for any MCP client. No sign-in needed on this server.
9 read
Grouped by tool name. At most: only reads or looks up information.
Odel charges nothing per call. The publisher may charge for its own service.
Search UNESCO World Heritage sites, intangible heritage, biosphere reserves, and Global Geoparks via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://unesco-heritage.caseyjhand.com/mcp
UNESCO's World Heritage List, Intangible Cultural Heritage lists, Biosphere Reserves, and Global Geoparks. Search and read full records, check the List of World Heritage in Danger, and find sites, reserves, or geoparks near any point. No API key required.
| Tool | Description |
|---|---|
unesco_search_sites | Search World Heritage sites by keyword, country, category, region, criteria, inscription years, Danger-list or transboundary status, or distance from a point |
unesco_get_site | Fetch a site's full record: statement of Outstanding Universal Value, criteria with meanings, component parts, coordinates, and image credit |
unesco_search_intangible_heritage | Search the three intangible heritage lists by keyword, country, list, inscription years, multinational status, or linked World Heritage site |
unesco_get_intangible_heritage_element | Fetch an element's full record: description, list, countries, concept terms, linked sites, and image credit |
unesco_search_biosphere_reserves | Search biosphere reserves by keyword, country, region, MAB regional network, designation years, transboundary or SIDS status, or distance from a point |
unesco_get_biosphere_reserve | Fetch a reserve's full record: ecological and socio-economic profile, zoned areas and population, review years, and coordinates |
unesco_search_geoparks | Search UNESCO Global Geoparks by keyword, country, designation years, transnational status, or distance from a point |
unesco_get_geopark | Fetch a geopark's full record: introduction, description, account of sustaining local communities, recorded area and population, and coordinates |
unesco_list_reference | Decode criteria, countries (name to ISO code), regions, intangible heritage lists, and MAB networks; report dataset coverage and data dates |
| Resource | Description |
|---|---|
unesco://site/{id_no} | One World Heritage site record |
unesco://intangible-heritage/{ich_ref} | One intangible heritage element record |
unesco://biosphere-reserve/{mab_id} | One biosphere reserve record |
unesco://geopark/{ugg_id} | One UNESCO Global Geopark record |
Each resource mirrors a get tool.
unesco_search_sites toolquery, country (ISO 3166-1 alpha-2 or alpha-3), category, region, criteria (every listed criterion required), in_danger, transboundary, inscribed_from / inscribed_to, and near (latitude, longitude, radius_km up to 5000, default 100), which matches a site through its representative point or any of its componentslimit, up to 10,000, is served as 50 and says so in notice), continued with next_cursor; sort takes relevance, name, inscribed_newest, inscribed_oldest, area_largest, danger_listed_newest, or distance; include_description: false leaves row descriptions outin_danger: true is the List of World Heritage in Danger; totalCount and facets (category, region, Danger status, criteria, top 10 countries) cover the whole match; rows carry matched_in when query is set, and distance_km to the nearest of the site's points (with nearest_component when a component is nearer) when near is setunesco_get_site toolid_no: a number, a digit string, or the site's whc.unesco.org page URL; max_components lists up to 1000 component parts (default 20; a larger value, up to 10,000, is served as 1000 and says so in notice)criteria[] with meanings and source: "recorded" | "inferred", States Parties with ISO codes, coordinates, area, secondary_years, Danger-list year, names in six languages, and the main image with its creditdescription_language (en, fr, es, ru, ar, zh) returns UNESCO's description in that language and names it in description_language; where UNESCO publishes none, the English one comes back as en with a notice. The statement of Outstanding Universal Value is English onlycomponents_total is UNESCO's count and components_unparsed the entries that could not be read; an unknown id fails as site_not_foundunesco_search_intangible_heritage toolquery, country, list (Representative List, Urgent Safeguarding List, Register of Good Safeguarding Practices; RL / USL / Art18 accepted), multinational, world_heritage_site (an id_no), and inscribed_from / inscribed_tolimit, up to 10,000, is served as 50 and says so in notice), continued with next_cursor; rows omit the description and carry primary concepts and linked world_heritage_sitesfacets cover list, multinational status, the top 10 countries, and the top 10 concept termsunesco_get_intangible_heritage_element toolich_ref: a number, a digit string, or the element's ich.unesco.org page URLconcepts, linked world_heritage_sites, UNESCO page, and the main image with its caption and credit; an unknown ref fails as element_not_founddescription_language: "fr" returns UNESCO's French description (English and French are the only languages UNESCO publishes), with the same English fallback and notice as unesco_get_siteunesco_search_biosphere_reserves toolquery (name, introduction, and ecological or socio-economic text; there is no biome field, so search habitat words), country, region, regional_network (name or acronym), transboundary, sids, designated_from / designated_to, and nearlimit, up to 10,000, is served as 50 and says so in notice), continued with next_cursor; sort takes relevance, name, designated_newest, designated_oldest, area_largest, or distance; include_description: false leaves row introductions outmab_id; facets cover region, regional network, transboundary and SIDS status, and the top 10 countriesunesco_get_biosphere_reserve toolmab_id, matched without regard to case or accents0 can mean none or unreported; an unknown id fails as biosphere_reserve_not_foundunesco_search_geoparks toolquery (name, introduction, description, and community account; search landform words such as volcanic or karst), country, transnational, designated_from / designated_to, and near, measured to each geopark's one pointlimit, up to 10,000, is served as 50 and says so in notice), continued with next_cursor; sort takes relevance, name, designated_newest, designated_oldest, area_largest, or distance; include_description: false leaves row introductions outfacets cover transnational status and the top 10 countries; a year bound whose range starts at or before 2015 adds a notice that geoparks recognized before the designation existed are dated 2015unesco_get_geopark toolugg_id (such as EUFR10), in any casepopulation is absent when UNESCO records none), coordinates, introduction, description, the account of sustaining local communities, website, and UNESCO page; an unknown id fails as geopark_not_foundunesco_list_reference tooltopic: criteria, countries, regions, intangible_lists, biosphere_networks, or datasetsfilter keeps matching rows; on countries, a country name, an ISO code, or a common former name returns the codes every country input accepts, with the country's count of sites, intangible elements, reserves, and geoparksdatasets reports each dataset's record count, data_as_of, license, attribution line, and coverage notesunesco://site/{id_no} resourceunesco_get_site record with up to 20 components (components_total carries the full count) and the English description, plus sources, as application/json; id_no comes from unesco_search_sitesunesco://intangible-heritage/{ich_ref} resourceunesco_get_intangible_heritage_element record with the English description, plus sources, as application/json; ich_ref comes from unesco_search_intangible_heritageunesco://biosphere-reserve/{mab_id} resourceunesco_get_biosphere_reserve record plus sources, as application/json; mab_id comes from unesco_search_biosphere_reserves, percent-encoded when it holds non-ASCII lettersunesco://geopark/{ugg_id} resourceunesco_get_geopark record plus sources, as application/json; ugg_id comes from unesco_search_geoparksBuilt on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
UNESCO-specific:
whc001 (World Heritage List), ich001 (Intangible Heritage List), mab001 (Man and the Biosphere Programme), and eg0001 (UNESCO Global Geoparks) each load on first use as an in-memory snapshot (two upstream requests) and refresh every 24 hours; searching, facets, and distance run locally, and a failed refresh keeps serving the previous snapshotRetry-AfterAgent-friendly output:
sources names each dataset with its data_as_of date, license, and credit linetotalCount, facets, and an applied_filters echo of the filters and sort the server ranmatched_in says which field tier matched; a zero-hit notice names the filter whose removal would match the most recordsunknown_country, invalid_year_range, sort_needs_input, cursor_mismatch, invalid_cursor, *_not_found, snapshot_unavailable) carry a recovery hint naming the next call; snapshot_unavailable is retryable with retryAfter when the Data Hub is unreachable, and not retryable when it rejects the request or serves data the server cannot useAll four datasets come from the UNESCO Data Hub and are licensed CC BY-SA 4.0. Credit UNESCO when you reuse the data; every response's sources block carries a ready-made credit line. Under ShareAlike, adapted data must be shared under the same license.
Images are not covered by that license. Each World Heritage and intangible heritage image keeps its own copyright, and its holder and photographer travel with the image record. The server returns image links but never fetches or proxies them.
This server is an independent project and is not affiliated with or endorsed by UNESCO.
A public instance is available at https://unesco-heritage.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"unesco-heritage-mcp-server": {
"type": "streamable-http",
"url": "https://unesco-heritage.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"unesco-heritage-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/unesco-heritage-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"unesco-heritage-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/unesco-heritage-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"unesco-heritage-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/unesco-heritage-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/unesco-heritage-mcp-server.git
cd unesco-heritage-mcp-server
bun install
cp .env.example .env
# edit .env to change the transport, port, or log level
The server has no settings of its own; these framework variables apply.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_HTTP_HOST | HTTP server host. | 127.0.0.1 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. .env.example and the Docker image set stateless. | auto |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <app-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the common framework overrides.
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more
bun run test # Runs the test suite
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point: registers the tools and resources, serves the server instructions from src/mcp-server/instructions.ts, and starts and stops the service. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/mcp-server/resources | One record resource per dataset. |
src/mcp-server/shared | Input schemas and normalizers, enrichment fields, and markdown helpers shared by the tools and resources. |
src/services/unesco-datahub | UNESCO Data Hub service: snapshot loading and refresh, row validation and repair, search and facets, the ISO 3166 table, and vocabularies. |
tests/ | Unit tests over synthetic fixtures, mirroring the src/ structure. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging and ctx.enrich for attribution, totals, and noticescreateApp() arrays in src/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.