The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Worldbank MCP Server listing page.
Query 29,500+ World Bank development indicators for 200+ countries across 60+ years via MCP. STDIO or Streamable HTTP.
9 tools for browsing and querying the World Bank Open Data API:
| Tool | Description |
|---|---|
worldbank_list_topics | List all 21 World Bank thematic topics with descriptions |
worldbank_list_sources | List 70+ World Bank data sources (datasets) with pagination |
worldbank_list_countries | List countries and regional aggregates with ISO codes, region, income level, and coordinates |
worldbank_get_country | Fetch full metadata for a specific country or aggregate by ISO2, ISO3, or aggregate code |
worldbank_search_indicators | Search the 29,500+ indicator catalog by keyword, topic, or source |
worldbank_get_indicator | Fetch complete metadata for a single indicator: name, description, source, unit, and topics |
worldbank_get_data | Query indicator values for one or more countries across a time range or most-recent N values |
worldbank_get_poverty | Poverty headcount, gap, and severity at any poverty line, plus the Gini coefficient and decile shares, from the Poverty and Inequality Platform |
worldbank_search_projects | Search the World Bank lending portfolio by text, country, region, status, and board approval date |
worldbank_list_topicsList all 21 World Bank thematic topic categories.
worldbank_search_indicatorsworldbank_list_sourcesList the 70+ World Bank data sources (datasets).
worldbank_search_indicators by dataset origin (e.g. "2" for World Development Indicators, "6" for IDS)worldbank_list_countriesList countries and regional aggregates with metadata.
include_aggregates=true to include regional, income-group, and world aggregate entitiesworldbank_get_countryFetch full metadata for a single country or aggregate entity.
worldbank_search_indicatorsSearch the 29,500+ World Bank indicator catalog.
searchterm parameter does not filter, so keyword matching runs locally over the full catalog (or the full selected topic/source): every term must appear in the indicator ID, name, or description, in any word order, with punctuation ignoredGDP (current US$)) or ID (NY.GDP.MKTP.CD) returns it as the top hitworldbank_get_indicator resolves to the same oneNY.GDP.PCAP.CD, SP.POP.TOTL) feed directly into worldbank_get_dataquery, topic_id, source_id) alongside the resultsworldbank_get_indicatorFetch complete metadata for a known indicator ID.
worldbank_get_dataQuery indicator values for countries across time. The primary data-access tool.
"all" for every entry. At least one code is required — an empty value is rejected rather than read as "all"date_range for a period or range — annual (2020, 2010:2023), quarterly (2020Q1:2021Q4), or monthly (2020M01:2020M06) — or mrv for the N most recent available values (1–100). Mutually exclusive.date_range the API can't apply is enforced locally over the whole series, so observations outside the requested window are never returned as matchesnull values when data is not available for a country×year cell — common for sparse seriesnullCount per page to surface data sparsityisAggregate flag distinguishes all 78 regional, income-group, and lending-group aggregates from individual countriesmrv, page and page sizeworldbank_get_povertyPoverty and inequality estimates from the World Bank Poverty and Inequality Platform (PIP) — a separate dataset from the WDI series the other tools read.
poverty_line to use the international line of the PIP release currently served, which is echoed back on every rowestimationType: "survey" rows carry the full inequality block; "interpolation", "extrapolation", and "CMD estimation" rows are gap-filled estimates for years no survey covers, and their gini, mld, polarization, and decileShares are null — a gap in the source data, not an error. surveyYear, surveyAcronym, and isInterpolated sit alongside themfill_gaps defaults to true, so years the surveys don't reach come back as PIP's own estimate rather than as an empty result or a hole in the series. Survey rows win wherever one exists, so a single-year batch can carry real distributions for some economies and labelled estimates for others, and a full-history query returns a row per year with the real distribution on the survey years. Set fill_gaps=false for survey-derived rows onlywelfare_type pins results to income or consumption surveys, which are not directly comparable; thirty-five economies publish both and return a row for eachreporting_level narrows to one, and every row states its ownyear accepts a four-digit year, "all" for the full history, or "MRV" for the most recent available. Coverage starts in 1963worldbank_search_projectsThe World Bank lending portfolio — the individual loans, credits, and grants the Bank finances — rather than the statistics the other tools read. A third upstream API, on its own host, with its own envelope and conventions.
query across project names, abstracts, and objectives, combined with exact filters on countries, region, status, and a board-approval date window. Every filter is an AND, and every multi-value filter is an OR within itselfBR, IN, ZA) — the one place this server departs from the ISO3 codes its other tools take, because the Projects API keys on ISO2. Multi-country operations carry a World Bank regional code instead (3A, 4E), two characters like the rest. An ISO3 code is rejected at the schema with a message naming the difference, rather than being passed upstream where it would come back as a silent zero-hit. worldbank_get_country reports a country's iso2 field for either formstatus is a closed set (Active, Closed, Dropped, Pipeline) and region is the nine World Bank operational regions, both enforced by the schema — a typo in either can't reach upstream and read back as "no results"include_abstract is off by default. Abstracts run to a median of roughly 1,200 characters and are published for about half the portfolio, so a full page of them roughly doubles the response — turn it on once the result set is small enough to read| Type | Name | Description |
|---|---|---|
| Resource | worldbank://indicator/{indicatorId} | Indicator metadata by ID — name, description, source, unit, and topics |
| Resource | worldbank://country/{countryCode} | Country metadata by ISO2, ISO3, or aggregate code — region, income level, capital, coordinates |
Both resources return a structured not-found error with a recovery hint for an unknown ID or code. An upstream outage, timeout, or 5xx keeps its own classification, so a transient failure is distinguishable from a bad identifier.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauth)in-memory, filesystem, Supabase, Cloudflare KV/R2/D1World Bank-specific:
null observations and nullCount surfaced rather than silently droppedisAggregate flag on every country/data row to distinguish individual countries from aggregate entitiesAgent-friendly output:
worldbank_search_indicators names worldbank_list_topics for topic IDs, worldbank_get_data names worldbank_search_indicators for indicator discoveryreason codes and actionable recovery hints on every toolpage, pages, total) across all list/search/data toolsAdd the following to your MCP client configuration file.
Or with npx (no Bun required):
For Streamable HTTP, set the transport and start the server:
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Environment variables:
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_HOST | HTTP server hostname | 127.0.0.1 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path where the MCP server is mounted | /mcp |
MCP_PUBLIC_URL | Public origin override for TLS-terminating reverse-proxy deployments | none |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_SESSION_MODE | HTTP session handling: stateful, stateless, or auto. This server holds no per-session state; .env.example and the Docker image both set stateless | auto (resolves to stateful) |
MCP_LOG_LEVEL | Log level (debug, info, warning, error) | info |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
OTEL_ENABLED | Enable OpenTelemetry | false |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP exporter endpoint | none |
WORLDBANK_API_BASE_URL | World Bank Indicators API base URL override | https://api.worldbank.org/v2 |
WORLDBANK_PIP_BASE_URL | Poverty and Inequality Platform API base URL override | https://api.worldbank.org/pip/v1 |
WORLDBANK_PROJECTS_BASE_URL | Projects API base URL override | https://search.worldbank.org/api/v3 |
WORLDBANK_DEFAULT_PER_PAGE | Default page size for list/search/data operations | 50 |
WORLDBANK_CATALOG_CACHE_TTL_MS | Lifetime of the in-process reference caches — the indicator catalog behind keyword-only search and the aggregate-code set behind isAggregate; 0 disables both | 3600000 |
Build and run the production version:
Run checks and tests:
| Directory | Purpose |
|---|---|
src/mcp-server/tools | Tool definitions (*.tool.ts). Nine tools covering topics, sources, countries, indicators, data, poverty, and projects. |
src/mcp-server/resources | Resource definitions. Indicator and country metadata resources. |
src/services/worldbank | World Bank Indicators API service layer — API client and domain types. |
src/services/pip | Poverty and Inequality Platform API service layer — separate client and domain types. |
src/services/projects | Projects API service layer — separate client and domain types. |
src/config | Server-specific environment variable parsing and validation with Zod. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging, ctx.state for storagecreateApp() arraysIssues and pull requests are welcome. Run checks and tests before submitting:
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.