Query 29,500+ World Bank development indicators for 200+ countries across 60+ years.
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.
Query 29,500+ World Bank development indicators for 200+ countries across 60+ years via MCP. STDIO or Streamable HTTP.
World Bank Open Data: 29,500+ development indicators, poverty and inequality estimates, and the Bank's lending projects. Search indicators, query country time series, pull poverty metrics, and search active and historical projects. No API key required.
| 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, lending type, and coordinates, filterable by region, income level, and lending type |
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, the most recent N periods, or each country's latest N non-empty values, annually, quarterly, or monthly |
worldbank_get_poverty | Poverty headcount, gap, and severity at any poverty line for economies and PIP's regional, income-group, lending-group, and fragility-group aggregates, 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, financing window, and board approval date |
| Resource | Description |
|---|---|
worldbank://indicator/{indicatorId} | Indicator metadata by ID — name, description, source, unit, and topics |
worldbank://country/{countryCode} | Country metadata by ISO2, ISO3, or aggregate code — region, income level, capital, coordinates |
worldbank_list_topics tool1 Agriculture, 3 Economy & Growth) feed topic_id on worldbank_search_indicatorsworldbank_list_sources tool2 for World Development Indicators) feed source_id on worldbank_search_indicatorsworldbank_list_countries toolEAS, SSF, … plus membership groupings such as AFE, EUU, LDC), income level (LIC, LMC, UMC, HIC), and lending type (IDX, IBD, IDB, LNX), combined by AND; up to 150 per page (~50 KB)invalid_filter errorinclude_aggregates=true adds regional, income-group, and world aggregates, flagged isAggregateworldbank_get_country toolUS), ISO3 (USA), or World Bank aggregate code (EAS, HIC, WLD) — all or a list is rejected as multiple_countriescountry_not_found error with a recovery hint pointing to worldbank_list_countriesworldbank_search_indicators toolquery, topic_id, or source_id; every keyword term must match the indicator ID, name, or description, in any order; up to 100 per pageSP.DYN.LE00.IN ahead of SP.DYN.LE00.FE.IN)worldbank_get_indicator returns the wholeworldbank_get_indicator tool., _, or - — all, a list, or any other character is rejectedindicator_not_found error pointing to worldbank_search_indicatorsworldbank_get_data toolcountries as ISO2, ISO3, aggregate codes, WLD, or all alone; at most one of date_range (a year, quarter, or month, or a range of one type), mrv (the latest N periods across the countries), or mrnev (each country's own latest N values — Eritrea's GDP per capita at 2011, where mrv gives 2025 and null); frequency (annual, quarterly, monthly) picks the period form on series that publish several (CPTOTSAXN for Kenya, monthly, mrv: 3 → 2026M07–M05); up to 200 observations a page (~50 KB)isAggregate, and value: null for a missing cell, with nullCount per page and lastUpdated, the source's data vintage; every date_range, mrv, and mrnev read is checked for another query's cached answer and re-read once, and one that fails twice is an upstream_inconsistent error rather than a served resultsourceScoped with the release, classification, sector, or counterpart area applied (dimension_value)worldbank_get_poverty toolAFG), plus PIP's aggregates: WLD, regions (SSF, AFE), income groups (LMIC/LMC), lending groups (IDX, IDB, IBD, REST), and fragility groups (FCVY, FCVN; WDI's FCS is rejected with FCVY guidance, without asserting the same membership); year as a year, all, or MRV; any poverty_line, defaulting to the applied PPP vintage's international line; up to 70 estimates a page (~50 KB)estimationType separates survey rows from gap-filled ones, whose inequality fields are null, and isAggregate flags aggregate rowsfill_gaps (default true) includes gap-filled years; welfare_type and reporting_level narrow economy results, and ppp_version picks the PPP vintageworldbank_search_projects toolquery combined by AND with countries (ISO3, ISO2, or a World Bank regional code such as 3A), region, status, financial_type, and a board-approval window (approved_from/approved_to); up to 80 projects a page, newest approval firstcountryCodes chain into the other tools, a bad code or unparseable query is a typed invalid_country_code / invalid_query error, and an empty result names the filter that emptied itinclude_abstract (off by default) adds abstracts at 8 projects a page, each cut at 5,000 charactersworldbank://indicator/{indicatorId} resourceapplication/json — name, description, unit, source dataset, source organization, and topicsindicatorId comes from worldbank_search_indicators; an unknown ID returns a typed not-found error with a recovery hint, while an upstream outage or timeout keeps its own classification instead of reading as a bad IDworldbank://country/{countryCode} resourceapplication/json — ISO codes, region, income level, capital, coordinatesall or a list is rejected; an unknown code returns a typed not-found error, distinct from a transient upstream failureBuilt 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.
World Bank-specific:
searchterm parameter doesn't filternull 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 tooltotalCount, currentPage, totalPages) across all list/search/data tools, with a notice naming the pages that exist when a request runs past the endA public instance is available at https://worldbank.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"worldbank-mcp-server": {
"type": "streamable-http",
"url": "https://worldbank.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"worldbank-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/worldbank-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"worldbank-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/worldbank-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"worldbank-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/worldbank-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/worldbank-mcp-server.git
cd worldbank-mcp-server
bun install
cp .env.example .env
# edit .env and set optional overrides
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. The server declares stateless in code — it holds no per-session state — and a value set here overrides that declaration | stateless |
MCP_LOG_LEVEL | Log level (debug, info, notice, warning, error) | info |
LOG_TOOL_FAILURE_PAYLOADS | Log each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted | false |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
OTEL_ENABLED | Enable OpenTelemetry | false |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Opt-in OTLP log export (e.g. http://localhost:4318/v1/logs); the base OTEL_EXPORTER_OTLP_ENDPOINT never enables it | 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; worldbank_get_data, worldbank_list_countries, worldbank_search_projects, and worldbank_get_poverty still cap it at their own page limits | 50 |
WORLDBANK_CATALOG_CACHE_TTL_MS | Lifetime of the in-process reference caches — the indicator catalog behind keyword-only search, the country index behind isAggregate, source-scoped country codes, and poverty ISO2 codes, each source-scoped dataset's concept/country/period/dimension listings, and PIP's versions listing behind ppp_version, regions table behind aggregate codes, and economy list behind model-estimate-only economies; 0 disables them all | 3600000 |
See .env.example for the full list of optional 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 # Lint, format, typecheck, and more
bun run test # Runs the test suite
docker build -t worldbank-mcp-server .
docker run --rm -p 3010:3010 worldbank-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/worldbank-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| 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 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.