Who Gho Mcp Server

io.github.cyanheadsPublished by GitHub account cyanheadsv0.4.0Updated Oct 28, 2026

WHO Global Health Observatory — 3,102 indicators across 194 member states.

VerifiedStreamable HTTPWeb executableLocation & LifestyleData & Analytics

Overview

AI-generated overview

Queries WHO Global Health Observatory statistics — 3,102 indicators across 194 member states — letting an assistant search indicators and pull data by…

What you can do
  • Search and browse the WHO GHO indicator catalog, with keyword search, pagination and indicator-code lookup
  • Fetch indicator metadata: full names and supported dimension types, in batches of ten codes per call
  • List dimension types and their valid codes and labels, including country, region, sex, income group and age group, with parent-code narrowing
  • Query indicator data rows with country, region or income-group filters, year ranges, sex and positional dimension values, returning values with uncertainty bounds and paging
  • Read indicator metadata and dimension value pages as resources for clients that inject context instead of calling tools
When to use it
Useful when an assistant needs authoritative global health figures — disease incidence, sanitation, HIV and similar indicators — for comparisons across countries, regions or years, or when exploring what the WHO GHO catalog covers.
Requirements
Either the public hosted Streamable HTTP endpoint, or a local process via npx or bunx (Node.js 24+ or Bun 1.4+) or Docker. No API key: the upstream WHO GHO API is public. Optional environment variables cover transport type, HTTP host, port and endpoint path, auth mode, log level, GHO base URL and request timeout.
Before you install
Read-only queries against a public API; no credentials are requested. Self-hosted HTTP deployments default to no authentication (MCP_AUTH_MODE=none), so anyone who can reach the port can use it — set jwt or oauth before exposing it. LOG_TOOL_FAILURE_PAYLOADS can log failed tool arguments and results with only key-name redaction.

Installation

In SourceWeft

  1. Open Who Gho Mcp Server in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.

Use with an agent

Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.

Read https://sourceweft.com/mcp/io.github.cyanheads%2Fwho-gho-mcp-server/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.

Read the install guide the agent follows

Other MCP clients

Add this to your client's mcpServers config.

{
  "mcpServers": {
    "who-gho": {
      "type": "http",
      "url": "https://who-gho.caseyjhand.com/mcp"
    }
  }
}

README

@cyanheads/who-gho-mcp-server

Query WHO Global Health Observatory data — 3,102 indicators across 194 member states with country, region, year, and sex filters via MCP. STDIO or Streamable HTTP.

6 Tools • 4 Data Resources • 1 Skill


Overview

Global health statistics from the WHO Global Health Observatory: 3,102 indicators across 194 member states. Search indicators and query data by country, region, income group, sex, and year.

Tools

ToolDescription
who_search_indicatorsSearch the GHO indicator catalog by keyword in indicator names
who_list_indicatorsBrowse the full indicator catalog with pagination
who_get_indicator_metadataFetch indicator names and dimension types, processing 10 codes per call with continuation for larger batches
who_list_dimensionsList all dimension type codes available in the GHO API
who_list_dimension_valuesList valid codes and labels for a dimension type (COUNTRY, REGION, SEX, etc.)
who_query_indicator_dataQuery data rows for an indicator with spatial, temporal, and dimension filters

Resources

ResourceDescription
who://indicator/{indicatorCode}/metadataIndicator name and supported filter dimensions for a single code
who://dimension/{dimensionCode}/valuesFirst 100 values for a dimension type
who://dimension/{dimensionCode}/values{?limit,offset}One explicit page of a dimension type's values
who://dimension/{dimensionCode}/values{?limit,offset,parentCode}One explicit page, narrowed to a parent code

Each mirrors data also reachable via who_get_indicator_metadata and who_list_dimension_values — useful for clients that inject resources as context but don't call tools.

Agent skill

who-gho-guide covers dimension-position discovery, complete country comparisons, and countries versus regional aggregates. It ships with plugin installs, npm, Docker, and the MCPB bundle. MCP clients can discover its SKILL.md through resources/list or the io.modelcontextprotocol/skills extension (skills/list, skills/get, and resources/directory/read); the server also exposes the skill://{+path} resource template.

Capability reference

who_search_indicators tool

  • Each whitespace-separated word must match a substring in the indicator name, in any order; no stemming or fuzzy expansion. If names have no matches, an exact indicator-code lookup is attempted.
  • Returns indicator codes and display names for use with who_query_indicator_data
  • Offset-based pagination (offset, default 0) with limit default 20, max 100; reports totalCount, hasMore, pageInfo, nextOffset
  • An offset at or beyond totalCount returns an empty page; a no_results error is raised only when nothing matches at all

who_list_indicators tool

  • No keyword required — browse the 3,102-indicator catalog
  • Offset-based pagination via limit (default 50, max 500) and offset
  • Returns totalCount and hasMore for iteration

who_get_indicator_metadata tool

  • Accepts up to 1,000 indicator codes and processes the first 10 in parallel; submit returned unprocessedCodes next. With GHO_CLAMP_LIMITS=false, batches over 10 are rejected.
  • Returns the full indicator name and supported dimension types (e.g. COUNTRY, SEX, REGION, AGEGROUP) for each resolved code
  • Indicators with no dimension listing upstream return dimensions: [] plus a dimensionsNote pointing at a sample data row's dimension type/value pairs. Metadata does not identify dimension positions.
  • Codes resolving to neither a catalog entry nor dimension rows land in notFound; the call fails when no processed code resolves and no unprocessed codes remain

who_list_dimensions tool

  • No inputs — returns every dimension type code and human-readable title in the GHO catalog
  • Common types: COUNTRY, REGION, SEX, WORLDBANKINCOMEGROUP, AGEGROUP
  • Use to discover codes before calling who_list_dimension_values

who_list_dimension_values tool

  • Returns codes and labels for the dimension's values (e.g. the 234 country entries, the 43 WHO region codes), plus optional parent-hierarchy fields (parentCode, parentLabel, parentDimension)
  • parent_code narrows hierarchical dimensions — dimension: "COUNTRY" with parent_code: "EUR" returns the 58 countries in the WHO European Region
  • Deterministic ordering by Code; offset-based pagination (offset) with limit default 100, max 500 — GHO (3,103 values) and DHSMICSGEOREGION (4,932) need paging
  • A parent_code that matches nothing returns an empty page for a known dimension; unknown dimensions fail even with a parent filter
  • An unpaired UTF-16 surrogate in dimension fails as a typed malformed_identifier validation error

who_query_indicator_data tool

  • Spatial filters are mutually exclusive per call: country_codes (WHO country codes, including historical entries), region_codes (WHO aggregate rows), or income_group_codes (World Bank aggregate rows) — supplying more than one is a validation error
  • year_from / year_to time range; sex (SEX_BTSX, SEX_FMLE, SEX_MLE) applies only when the indicator's first cross-cutting dimension is SEX. dim1_value, dim2_value, and dim3_value select observed positional values; discover positions from returned type/value pairs, not metadata. sex overrides dim1_value with a notice.
  • include_uncertainty (default true) adds low/high bounds; sort (year_desc default or year_asc) with a total row ordering so paging never repeats or drops rows
  • Offset-based pagination with limit default 200, max 1000; reports totalRows, hasMore, pageInfo, nextOffset
  • Typed failure reasons: indicator_not_found, no_data, ambiguous_spatial_filter, invalid_year_range, invalid_query, malformed_identifier

who://indicator/{indicatorCode}/metadata resource

  • Indicator name and supported filter dimensions as application/json
  • indicatorCode comes from who_search_indicators or who_list_indicators
  • Empty dimensions carries a dimensionsNote when the upstream dimension table lists none for the code, rather than reporting a missing indicator
  • Returns a 404 error only when the code resolves to neither a catalog name nor any dimension rows

who://dimension/{dimensionCode}/values resource

  • Bare URI returns the first 100 values for the dimension (dimensionCode from who_list_dimensions), as application/json
  • Registered separately from the two paged variants below because the MCP SDK's RFC 6570 matcher treats every URI query variable as required — one template cannot serve both a bare and a paged form
  • An unfiltered empty result means the dimension code does not exist

who://dimension/{dimensionCode}/values{?limit,offset} resource

  • limit (1–500) and offset must both be present in the URI — the query variables are required, not optional
  • Same page fields as the bare URI: totalCount, hasMore, nextOffset, and an optional notice
  • An offset at or beyond totalCount returns an empty page, not an error

who://dimension/{dimensionCode}/values{?limit,offset,parentCode} resource

  • Adds parentCode to narrow to one parent value, e.g. parentCode="EUR" for countries in the WHO European Region; limit, offset, and parentCode must all be present in the URI
  • A parentCode that matches nothing returns an empty page for a known dimension; unknown dimensions fail even with a parent filter
  • Same output shape as the bare and paged resources: dimension, values, totalCount, hasMore, nextOffset, notice

Features

Built 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.

WHO GHO-specific:

  • Full coverage of the WHO GHO OData API v2 — indicators, dimensions, dimension values, and data queries
  • Configurable base URL and service-operation deadline (GHO_BASE_URL, GHO_REQUEST_TIMEOUT_MS) for custom or mirrored deployments
  • Parallel metadata fan-out for multi-code indicator lookups
  • Deterministic, total row/value ordering — pagination never repeats or drops rows across pages

Agent-friendly output:

  • Tool descriptions encode the cross-tool workflow — agents discover the right call order (search → metadata → query) from descriptions alone
  • Structured pagination signaling (hasMore, nextOffset, pageInfo, and truncated on the data-query tool) so agents can decide whether to page further
  • Discriminated, typed error reasons with a recovery hint on every failure path
  • Distinct empty-page vs. not-found semantics — paging past the end, an unmatched filter, and a genuinely missing code each report differently instead of colliding into one generic empty result

Getting started

Public Hosted Instance

A public instance is available at https://who-gho.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:

json
{  "mcpServers": {    "who-gho-mcp-server": {      "type": "streamable-http",      "url": "https://who-gho.caseyjhand.com/mcp"    }  }}

Self-Hosted / Local

Add the following to your MCP client configuration file.

json
{  "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):

json
{  "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:

json
{  "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:

sh
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http# Server listens at http://localhost:3010/mcp

Prerequisites

  • Bun v1.4.0 or higher (or Node.js ≥24).
  • No API key required — the WHO GHO API is public.

Installation

  1. Clone the repository:
sh
git clone https://github.com/cyanheads/who-gho-mcp-server.git
  1. Navigate into the directory:
sh
cd who-gho-mcp-server
  1. Install dependencies:
sh
bun install
  1. Configure environment:
sh
cp .env.example .env# edit .env and set optional overrides

Configuration

VariableDescriptionDefault
MCP_TRANSPORT_TYPETransport: stdio or httpstdio
MCP_HTTP_PORTHTTP server port3010
MCP_HTTP_ENDPOINT_PATHHTTP endpoint path where the MCP server is mounted/mcp
MCP_SESSION_MODEHTTP session posture: stateless, stateful, or auto. No tool asks the caller for input mid-handler, so the server declares stateless; set this only to override.stateless
MCP_PUBLIC_URLPublic origin override for TLS-terminating reverse-proxy deploymentsnone
MCP_AUTH_MODEAuthentication: none, jwt, or oauthnone
MCP_LOG_LEVELLog level (debug, info, warning, error, etc.)info
MCP_GC_PRESSURE_INTERVAL_MSOpt-in Bun-only forced-GC pressure loop (ms). Try 60000 if RSS grows under sustained HTTP load.0 (disabled)
LOGS_DIRDirectory for log files (Node.js only)<project-root>/logs
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1in-memory
GHO_BASE_URLWHO GHO OData API base URL (override for custom/mirrored deployments)https://ghoapi.azureedge.net/api/
GHO_REQUEST_TIMEOUT_MSService-operation deadline in milliseconds, covering requests, body reads, retries, and backoff30000
GHO_CLAMP_LIMITSClamp positive integer page limits to 100 for search, 500 for indicator/dimension browsing, and 1,000 for data queries, with a notice. Metadata processes 10 entries and returns continuation. false restores advertised maxima and rejection of oversized requests.true
OTEL_ENABLEDEnable OpenTelemetryfalse
OTEL_EXPORTER_OTLP_ENDPOINTOTLP base URL; traces and metrics export to /v1/traces and /v1/metrics under it. Log export is opt-in through OTEL_EXPORTER_OTLP_LOGS_ENDPOINT.none
LOG_TOOL_FAILURE_PAYLOADSLog each failed tool call's arguments and result (key-name redaction only)false

See .env.example for the full list of optional overrides.

Running the server

Local development

  • Build and run the production version:

    sh
    # One-time buildbun run rebuild
    # Run the built serverbun run start:http# orbun run start:stdio
  • Run checks and tests:

    sh
    bun run devcheck  # Lints, formats, type-checks, and morebun run test      # Runs the test suite

Docker

sh
docker build -t who-gho-mcp-server .docker run --rm -p 3010:3010 who-gho-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/who-gho-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

DirectoryPurpose
src/index.tscreateApp() entry point — registers tools/resources and inits the GHO service.
src/configServer-specific environment variable parsing and validation with Zod.
src/mcp-server/toolsTool definitions (*.tool.ts). Six tools across indicator discovery, dimension lookup, and data queries.
src/mcp-server/resourcesResource definitions. Indicator metadata and dimension values resources.
src/services/ghoWHO GHO OData API service layer — HTTP client, query builder, types.
src/utilswellFormed() — repairs unpaired UTF-16 surrogates in caller-supplied strings before they reach output, enrichment, or failure data.
tests/Unit and integration tests, mirroring the src/ structure.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for logging, ctx.state for storage
  • Register new tools and resources in the createApp() arrays
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues are welcome. Run checks and tests before submitting:

sh
bun run devcheckbun run test

License

Apache-2.0 — see LICENSE for details.

Source: README.md at commit 20caeb0

Tools

6

who_list_dimensions

List GHO Dimension Types

List all dimension type codes and human-readable titles available in the WHO Global Health Observatory API. Use this to discover valid dimension codes before calling who_list_dimension_values. Common dimensions include COUNTRY, REGION, SEX, WORLDBANKINCOMEGROUP, and AGEGROUP, but many additional types exist — this tool exposes them all.

Takes no parameters.

who_list_dimension_values

List GHO Dimension Values

List valid codes and labels for a WHO GHO dimension type such as COUNTRY, REGION, SEX, WORLDBANKINCOMEGROUP, or AGEGROUP. Use this to discover valid filter values before calling who_query_indicator_data, or to confirm the WHO code for a country, including historical codes. Use who_list_dimensions to discover all available dimension type codes. Results are paged in a deterministic order — narrow hierarchical dimensions with parent_code (e.g. the countries in one WHO region), and page the rest with offset.

Parameterslimitoffsetdimensionrequiredparent_code

who_search_indicators

Search WHO GHO Indicators

Search the WHO Global Health Observatory indicator catalog by words in the indicator name. Every whitespace-separated word must match independently as a case-insensitive substring, in any order; try "tuberculosis incidence", "sanitation basic", or "HIV". When no names match, an exact indicator-code lookup is attempted. Returns canonical indicator codes and names for who_query_indicator_data. Refine the query or page through the same result set with offset.

Parameterslimitqueryrequiredoffset

who_list_indicators

List WHO GHO Indicators

Browse the WHO Global Health Observatory indicator catalog with pagination. Use when you want to explore indicators without a keyword, or to page through the full catalog. Use who_search_indicators when you have a keyword to narrow the results.

Parameterslimitoffset

who_get_indicator_metadata

Get WHO GHO Indicator Metadata

Fetch metadata for WHO GHO indicator codes: the canonical code, full name, and supported dimensions (e.g. COUNTRY, REGION, SEX, YEAR, WORLDBANKINCOMEGROUP, AGEGROUP). Call this before who_query_indicator_data to confirm valid filter dimensions. Processes the first 10 entries and returns unprocessedCodes to submit next, accepting at most 1000 raw entries. With GHO_CLAMP_LIMITS=false, calls above 10 reject. Many valid indicators have no dimension listing upstream — those return an empty dimensions array with dimensionsNote. Processed codes absent from both the catalog and dimension table appear in notFound. No found entries raises all_not_found only when no unprocessed entries remain.

Parametersindicator_codesrequired

who_query_indicator_data

Query WHO GHO Indicator Data

Query data rows for a single WHO GHO indicator with optional spatial, temporal, and dimension filters. Returns rows with numeric values, uncertainty intervals (Low/High), and spatial/time metadata. This is the primary data-fetching tool in the find-then-query workflow: use who_search_indicators to find the indicator code, optionally call who_get_indicator_metadata to confirm which filter dimensions are valid, then call this tool. Discover positional filters from returned dim1Type/dim1, dim2Type/dim2 and dim3Type/dim3 pairs; metadata alone does not identify a slot. Spatial filters are mutually exclusive per call: provide only one of country_codes, region_codes, or income_group_codes — mixing them triggers an error. Omitting all spatial filters returns all geographies (may be large; use limit to cap). The sex filter only applies when the indicator uses SEX as its first cross-cutting dimension — if not, the filter returns empty rows; check who_get_indicator_metadata first if uncertain. Rows are returned in a deterministic order (most recent first by default), so a capped result is the top of a defined slice rather than an arbitrary sample; page through the rest with offset.

Parameterssexsortlimitoffsetyear_toyear_fromdim1_valuedim2_valuedim3_valueregion_codescountry_codesindicator_coderequired+2 more

Version history

4
  1. v0.4.0LatestOct 26, 2026
  2. v0.3.6Oct 9, 2026
  3. v0.3.5Sep 20, 2026
  4. v0.3.4Sep 16, 2026

Score

100% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 daysRequired25 pts
  • Auth declaredRequired10 pts
  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts