mcpField
W
who-gho-mcp-server

who-gho-mcp-server

Remote
github.com/cyanheadsHealth3Updated 3d ago
Repository

About who-gho-mcp-server

who-gho-mcp-server gives researchers and public-health analysts access to WHO Global Health Observatory indicators and data, with filters for dimensions such as country, region, year, and sex. It also provides dimension resources, pagination, and an Agent skill for guiding analysis.

Key features

  1. 01Search and browse the indicator catalog
  2. 02Inspect supported indicator dimensions
  3. 03Query and filter health data
  4. 04Browse dimension codes and labels
  5. 05Return paginated, ordered results

Use cases

  1. 01Find WHO indicators on a topic
  2. 02Compare data by country, region, and year
  3. 03Filter health statistics by sex or income group

MCP support

Exposes six tools, four data resources, and an Agent skill to MCP clients over STDIO or Streamable HTTP.

Configuration

Remote servers need no local install. Pick your client, then copy the config or install in one click.

Endpointhttps://who-gho.caseyjhand.com/mcp
Copy install command
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.

Packages
npm@cyanheads/who-gho-mcp-server0.4.0

Tools

6

This tool takes no parameters.

Details

From the project 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

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Public Hosted Server: https://who-gho.caseyjhand.com/mcp


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:

{
  "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.

{
  "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
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:
git clone https://github.com/cyanheads/who-gho-mcp-server.git
  1. Navigate into the directory:
cd who-gho-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment:
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:

    # 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
    
Docker
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:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.