
A clean interface to the WHO Global Health Observatory's 3,059 health indicators across 194 member states. You get six tools that handle the full query workflow: search indicators by keyword, fetch metadata to see which dimensions an indicator supports, then pull actual data rows with filters for country, region, year, and sex. The server wraps the WHO GHO OData API and handles things like pagination limits, uncertainty intervals, and filter validation. Runs via stdio locally or connects to a public hosted instance at who-gho.caseyjhand.com. Built on the mcp-ts-core framework, so it includes structured error recovery and works identically in Claude Desktop, Cursor, or any MCP client. Reach for this when you need programmatic access to comparative health statistics without manually parsing WHO's web interface.
Query WHO Global Health Observatory data — 3,059 indicators across 194 member states with country, region, year, and sex filters via MCP. STDIO or Streamable HTTP.
6 tools for working with WHO Global Health Observatory data:
| Tool | Description |
|---|---|
who_search_indicators | Search the GHO indicator catalog by keyword in indicator names |
who_list_indicators | Browse the full indicator catalog with pagination |
who_get_indicator_metadata | Fetch indicator names and supported filter dimensions for up to 10 codes |
who_list_dimensions | List all dimension type codes available in the GHO API |
who_list_dimension_values | List valid codes and labels for a dimension type (COUNTRY, REGION, SEX, etc.) |
who_query_indicator_data | Query data rows for an indicator with spatial, temporal, and dimension filters |
who_search_indicatorsSearch the WHO GHO indicator catalog by keyword.
"life expectancy", "immunization", "mortality", "diabetes", or "HIV"who_query_indicator_dataoffset) over the filtered result set; reports totalCount, hasMore, pageInfo, nextOffsetwho_list_indicatorsBrowse the full indicator catalog with offset-based pagination.
limit (default 50, max 500) and offsettotal and hasMore for iterationwho_get_indicator_metadataFetch metadata for one to ten indicator codes in a single call.
COUNTRY, SEX, REGION, AGEGROUP)who_query_indicator_data to confirm which filter dimensions are validdimensions: [] plus a dimensionsNote pointing at dim1Type/dim2Type on a sample data row, not a not-foundnotFound rather than raising an errorwho_list_dimensionsList all dimension type codes available in the GHO API.
COUNTRY, REGION, SEX, WORLDBANKINCOMEGROUP, AGEGROUPwho_list_dimension_valueswho_list_dimension_valuesList valid filter values for a single dimension type.
parentCode, parentLabel, parentDimension)parent_code narrows hierarchical dimensions — dimension: "COUNTRY", parent_code: "EUR" returns the 58 country entries in the WHO European RegionCode with offset-based pagination (offset); returns totalCount, hasMore, pageInfo, nextOffsetGHO (3,103 values) and DHSMICSGEOREGION (4,932) need pagingparent_code that matches nothing returns an empty page, not an error; only an unfiltered empty result means the dimension does not existwho_query_indicator_datawho_query_indicator_dataQuery data rows for a single WHO GHO indicator.
country_codes (ISO 3166-1 alpha-3), region_codes (WHO regions), or income_group_codes (World Bank groups)year_from / year_toSEX_BTSX (both), SEX_FMLE, SEX_MLE — only applies when the indicator uses SEX as its first cross-cutting dimensiondim1_value for indicators using non-SEX cross-cutting dimensionslow/high) via include_uncertainty (default true)sort: year_desc default or year_asc) with offset-based pagination (offset); returns totalRows, hasMore, pageInfo, nextOffset| Type | URI | Description |
|---|---|---|
| Resource | who://indicator/{indicatorCode}/metadata | Indicator name and supported filter dimensions for a single code |
| Resource | who://dimension/{dimensionCode}/values | First 100 values for a dimension type |
| Resource | who://dimension/{dimensionCode}/values{?limit,offset} | One explicit page of a dimension type's values |
| Resource | who://dimension/{dimensionCode}/values{?limit,offset,parentCode} | One explicit page, narrowed to a parent code |
The three dimension-value URIs are registered separately because the MCP SDK's RFC 6570 matcher treats every query variable as required — a single template with optional variables would stop matching the bare URI. Supply every variable a template names.
who_search_indicators — find indicator codes by keywordwho_get_indicator_metadata — confirm which filter dimensions the indicator supportswho_query_indicator_data — fetch data with country/region/year/sex filtersTo look up filter codes: who_list_dimensions → who_list_dimension_values.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauth)in-memory, filesystem, Supabase, Cloudflare KV/R2/D1WHO GHO-specific:
Agent-friendly output:
truncated, truncatedNote, hasMore) so agents can decide whether to paginaterecovery hints on every failure pathAdd the following to your MCP client configuration file.
{
"mcpServers": {
"who-gho-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/who-gho-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"who-gho-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/who-gho-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"who-gho-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/who-gho-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/who-gho-mcp-server.git
cd who-gho-mcp-server
bun install
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
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_LOG_LEVEL | Log level (debug, info, warning, error, etc.) | info |
MCP_GC_PRESSURE_INTERVAL_MS | Opt-in Bun-only forced-GC pressure loop (ms). Try 60000 if RSS grows under sustained HTTP load. | 0 (disabled) |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
GHO_BASE_URL | WHO GHO OData API base URL (override for custom/mirrored deployments) | https://ghoapi.azureedge.net/api/ |
GHO_REQUEST_TIMEOUT_MS | HTTP request timeout in milliseconds | 30000 |
OTEL_ENABLED | Enable OpenTelemetry | false |
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/mcp-server/tools | Tool definitions (*.tool.ts). Six tools across indicator discovery, dimension lookup, and data queries. |
src/mcp-server/resources | Resource definitions. Indicator metadata and dimension values resources. |
src/services/gho | WHO GHO OData API service layer — HTTP client, query builder, 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:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.