Skip to main content
Glama
ahmedvnabil

Humanitarian MCP

by ahmedvnabil

Humanitarian MCP

Trusted humanitarian data — refugees, conflict, hunger, funding — as one clean, citable interface for AI assistants and research code.

Humanitarian MCP — open humanitarian data, one MCP interface

CI Release Docker npm Research: citable MCP License: MIT


What is Humanitarian MCP?

Humanitarian MCP is an open-source server that gives AI assistants and analysis scripts reliable, normalized, read-only access to trusted humanitarian datasets: 75 years of UNHCR displacement statistics, World Bank context indicators, HDX crisis data (conflict events, food security, humanitarian funding, internal displacement), and ReliefWeb situation reports.

MCP in one paragraph: the Model Context Protocol is an open standard — think "USB for AI tools" — that lets any AI application (Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, custom agents) plug into external systems through one protocol. A server like this one exposes tools the model can call, resources it can read, and prompts it can reuse. Connect it once, and every question your assistant answers about displacement is grounded in the real numbers instead of its training data. New to MCP? Read docs/how-mcp-works.md.

Humanitarian data is public but hostile to programmatic use — different country-code schemes, different schemas, silent failure modes (details below). This project normalizes multiple humanitarian datasets into one consistent record shape, one country-code scheme (ISO3), one interface, with the citation attached to every payload.

Related MCP server: UNHCR Chart Generation MCP Server

Why this project exists

Every trap below is real, encoded in this codebase, and covered by tests:

Problem

Example

What this server does

Country-code chaos

UNHCR's internal codes disagree with ISO3 for 99 of 232 countries. Egypt is ARE in UNHCR-speak — which is the UAE's ISO code. Ask a raw API "refugees in ARE?" and you silently get the wrong country.

Everything speaks ISO3. Names resolve fuzzily in English and Arabic («مصر», «الأردن», «السودان»).

Schema babel

UNHCR returns {items: [...]}, the World Bank returns [meta, rows], HAPI returns {data: [...]} — each with different field names, pagination and update cadence.

One NormalizedRecord shape across all sources: country_code, year, population, metrics, source, dataset.

Dirty cells

Numeric values arrive as numbers, numeric strings, or "-".

Cleaned once, at the provider layer. Missing stays missing — never silently zero.

Silent empties

Most query mistakes return an empty list, not an error. An AI confidently reports "no data".

Errors come back as actionable text: "No country matched 'Atlantis'. Try search_country first."

Aggregation traps

IDP assessment rounds must not be summed (double-counts people); funding coverage must be recomputed, never averaged; IPC projections must not be mixed with current analyses.

Each dataset's aggregation semantics are encoded and unit-tested.

Misleading absolute numbers

Lebanon and Germany host similar refugee counts. Per 1,000 residents, they are worlds apart.

normalize_by: "population" | "gdp" — denominators matched per year, denominator year disclosed on every row.

Missing citations

Models paraphrase numbers with no provenance.

Every payload carries its source; exports attach a reproducible extraction manifest and optional codebook.

Without a trusted middleware, an LLM pointed at raw humanitarian APIs re-discovers these traps every session — and the failure mode is not a crash, it is a plausible-looking wrong number. This server exists so that never happens.

Architecture

flowchart TD
    U["You"] --> C["Claude Desktop · Claude Code · Cursor · VS Code · Windsurf<br/>or your own MCP agent"]
    C -->|"MCP (stdio or Streamable HTTP)"| S["Humanitarian MCP<br/>21 tools · 11+ resources · 8 prompts"]
    S --> R["Provider registry<br/>(tools never see provider internals)"]
    R --> P1["UNHCR provider<br/>displacement · demographics · asylum"]
    R --> P2["World Bank provider<br/>population · GDP · poverty"]
    R --> P3["HDX/HAPI provider<br/>conflict · food security · funding · IDPs"]
    R --> P4["ReliefWeb provider<br/>situation reports · narrative context"]
    P1 & P2 & P3 & P4 --> H["Shared HTTP layer<br/>retry · backoff · rate limit · ETag · cache · offline mode"]
    H --> A1[("api.unhcr.org")]
    H --> A2[("api.worldbank.org")]
    H --> A3[("hapi.humdata.org")]
    H --> A4[("api.reliefweb.int")]

Three invariants hold everywhere: (1) nothing provider-specific leaks outside src/providers/<id>/; (2) every tool is read-only and annotated as such; (3) errors reach the model as actionable text, never stack traces. Deep dive: docs/architecture.md.

Two ways to use it

TL;DR — researchers and organizations who care about control: self-host. Everyone who just wants answers: use the hosted endpoint.

🖥️ Self-hosted

☁️ Hosted endpoint

Setup

Install Node/Docker, run the server

None — paste one URL

Who runs it

You, on your machine or infra

Maintainer-operated at humanitarian-mcp.zad.tools

Privacy

Queries never leave your machine (except to the public data APIs)

Queries pass through the hosted server

Offline / fieldwork

✅ full offline mode with a warmed cache

❌ needs internet

Configuration

Every knob: providers, cache, rate limits

Fixed server-side

Updates

You pull releases

Updated for you (caching, normalization, rate limiting, source fixes, monitoring handled)

Version

Always the latest release

Rolling; may briefly lag the newest release — check /api/status

Guarantees

Yours to make

Best-effort community service, no SLA today

Cost

Free (MIT)

Free today; free and paid plans may be introduced later

Best for

Researchers, NGOs with data policies, enterprises, air-gapped fieldwork

Quick starts, demos, journalists, students

Mode 1 — Self-hosted

You install and run the server yourself. You own everything: the process, the cache, the configuration. Your MCP client talks to it over stdio (desktop) or HTTP (remote/containers). Full instructions in Installation below.

// Claude Desktop — claude_desktop_config.json
{
  "mcpServers": {
    "humanitarian": {
      "command": "node",
      "args": ["/absolute/path/to/humanitarian-mcp/dist/index.js"],
    },
  },
}

Mode 2 — Hosted endpoint

No infrastructure. Connect any Streamable-HTTP-capable MCP client to:

https://humanitarian-mcp.zad.tools/mcp
  • claude.ai / Claude Desktop (remote connector): add a custom connector with that URL.

  • Claude Code: claude mcp add --transport http humanitarian https://humanitarian-mcp.zad.tools/mcp

  • Anything that speaks HTTP: see examples/http-client.md — the endpoint is stateless JSON-RPC, no session juggling.

No API key is required today. The service is operated on a best-effort basis by the maintainer; free and paid tiers may be introduced in the future — nothing beyond what you see here is promised. If you need guarantees, self-host: it is the same code.

Features

Data access

  • 21 semantic, read-only tools — full reference: country profiles, comparisons, yearly series, demographics, asylum applications/decisions with recognition rates, conflict events, food security (IPC), humanitarian funding, situation reports, rankings, trend analysis with anomaly detection, (loudly caveated) naive forecasts

  • 11+ MCP resources (country://EGY, report://SDN, chart://UGA, metadata://providers…) with URI autocompletion

  • 8 built-in prompts (situation summary, donor briefing, crisis overview, anomaly hunt…)

Country intelligence

  • Fuzzy name resolution in English and Arabic — «مصر», "egypt", EGY, "DRC", "ivory coast" all land correctly; Arabic matching folds hamza/alef forms, taa marbuta and the definite article («الأردن» = «الاردن» = «اردن»)

  • The UNHCR↔ISO3 code mismatch (99/232 countries) handled invisibly

Analytics

  • normalize_by: per-capita (per 1,000 residents) and per-GDP (per US$1bn) comparisons, rankings and charts, with per-year denominator matching

  • Regression, year-over-year, CAGR, z-score anomaly detection

  • Charts as Chart.js / Vega-Lite / Mermaid / SVG; maps as GeoJSON

Research reproducibility

  • Extraction manifest on every export: exact arguments, timestamp, server version, citation — a repeatable recipe for a paper's appendix

  • Optional variable-level codebook matching exactly the exported columns

  • CSV / JSON / Markdown / GeoJSON export; CSV manifests ride in # comment lines (pd.read_csv(..., comment="#"))

  • Runnable Python & R notebooks reproducing four research workflows

  • CITATION.cff + JOSS paper draft in paper/

Operations

  • Two transports: stdio (desktop) and stateless Streamable HTTP (remote) + a built-in dashboard with a query playground

  • Serious caching: memory or SQLite (zero native deps), TTL + ETag revalidation, stale-while-revalidate, full offline mode for fieldwork

  • Polite by design: token-bucket rate limiting, retries with backoff, identified User-Agent, strictly read-only

  • Docker image + compose for organizational self-hosting

Live data sources

Provider

Datasets

What it contributes

Key

UNHCR Refugee Statistics (default)

population, demographics, asylum-applications, asylum-decisions

The displacement backbone: refugees, asylum-seekers, IDPs, stateless and others of concern, 1951–present, by origin and asylum country; age/sex breakdowns; asylum decisions with recognition rates

none

World Bank Indicators (default)

context-indicators

The denominators: national population, GDP, GDP per capita, extreme-poverty rates — what turns "how many" into "how heavy a burden"

none

HDX HAPI (opt-in)

conflict-events, food-security, humanitarian-funding, idps

The crisis context, citing original producers: conflict events & fatalities (ACLED), IPC food-insecurity phases (IPC), appeal requirements vs funding (OCHA FTS), IDP stocks (IOM DTM)

free app identifier (.env.example)

ReliefWeb (opt-in)

situation-reports

The narrative context: situation-report counts per country-year plus the latest report titles, publishers and links (UN OCHA / ReliefWeb) — what grounds trends and anomalies in published reporting

pre-approved appname (.env.example)

Example questions

Real prompts, real production numbers (extracted 2026-07-10 — figures are revised upstream over time):

  • "What are the top refugee-hosting countries per capita?" → Lebanon 130.7 per 1,000 residents, Chad 63.0, Moldova 56.6, Jordan 55.7 — a very different list than the absolute ranking.

  • "Was there anything unusual in Sudan's displacement data?" → 2023 flagged as an anomaly (z ≈ +2.6, +78.8% YoY), coinciding with the April 2023 war.

  • "Relate Sudan's conflict to its displacement since 2022." → conflict fatalities 2,770 → 21,020 → 22,987 (2022–2024, ACLED) alongside IDPs 3.78M → 9.05M → 11.56M (IOM DTM).

  • "How well is Sudan's humanitarian response funded?" → 58.5% of requirements in 2023, 76.4% in 2024 (OCHA FTS).

  • "«قارن بين عدد اللاجئين في مصر والأردن»" → works — country resolution is bilingual.

  • "Export Jordan's series as citation-ready CSV with a codebook."export_data({..., include_codebook: true}).

More worked conversations with tool traces: examples/conversations.md.

Why researchers like it

  • Citable: GitHub's Cite this repository button (CITATION.cff); a JOSS paper is drafted in paper/.

  • Reproducible: every export carries a manifest (exact call, timestamp, server version, source citation) — paste it in your appendix and anyone can re-run the extraction.

  • Documented data: include_codebook: true generates variable-level documentation (meaning, unit, derivation — including how recognition rates and funding coverage are computed) for exactly the columns you exported.

  • Join-ready: every row carries ISO3, so merges against World Bank / V-Dem / UCDP panels need no country-name crosswalk.

  • Honest methods: end-year stock semantics, denominator years, truncation and forecast naivety are stated in the output, not hidden.

  • Fieldwork-ready: warm the SQLite cache once, then HMCP_OFFLINE=1 gives the full toolset with zero connectivity.

Start here: docs/for-researchers.md · notebooks.

Installation

Requires Node.js ≥ 20 for source installs (SQLite cache uses built-in node:sqlite on Node ≥ 22.5; older Nodes fall back to memory automatically). Docker route needs only Docker.

From npm — no clone needed

npx humanitarian-mcp --version   # → humanitarian-mcp 0.6.0

Register it with Claude Code in one line:

claude mcp add humanitarian -- npx -y humanitarian-mcp

Claude Desktop — one click (no terminal)

Download humanitarian-mcp.mcpb from the latest release and double-click it. Done.

From source

git clone https://github.com/ahmedvnabil/humanitarian-mcp
cd humanitarian-mcp
npm install
npm run build
node dist/index.js --version   # → humanitarian-mcp 0.6.0

Docker

docker run -p 8642:8642 -v hmcp-cache:/data ghcr.io/ahmedvnabil/humanitarian-mcp
# → MCP endpoint at http://localhost:8642/mcp + dashboard at http://localhost:8642

Or docker compose up -d with the provided compose.yaml.

Connect your client (self-hosted, stdio)

{
  "mcpServers": {
    "humanitarian": {
      "command": "node",
      "args": ["/absolute/path/to/humanitarian-mcp/dist/index.js"]
    }
  }
}

Sample with cache tuning: examples/claude-desktop-config.json.

claude mcp add humanitarian -- node /absolute/path/to/humanitarian-mcp/dist/index.js
{
  "mcpServers": {
    "humanitarian": {
      "command": "node",
      "args": ["/absolute/path/to/humanitarian-mcp/dist/index.js"]
    }
  }
}
{
  "servers": {
    "humanitarian": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/humanitarian-mcp/dist/index.js"]
    }
  }
}
{
  "mcpServers": {
    "humanitarian": {
      "command": "node",
      "args": ["/absolute/path/to/humanitarian-mcp/dist/index.js"]
    }
  }
}

Then ask: "What are the top refugee-hosting countries this year?"

Enable the HDX crisis datasets (optional)

# one-time: generate a free identifier (base64 of app-name:email — not a secret)
curl 'https://hapi.humdata.org/api/v2/encode_app_identifier?application=<your-app>&email=<your-email>'

HMCP_PROVIDERS=unhcr,worldbank,hdx HMCP_HDX_APP_ID=<identifier> node dist/index.js

Enable ReliefWeb situation reports (optional)

# one-time: request a pre-approved appname (short form, reviewed by ReliefWeb)
# https://apidoc.reliefweb.int/parameters#appname

HMCP_PROVIDERS=unhcr,worldbank,reliefweb HMCP_RELIEFWEB_APPNAME=<appname> node dist/index.js

All configuration knobs: .env.example.

Verify without any client

npm run dashboard   # → http://localhost:8642 — providers, health, live logs, query playground
npm run inspect     # → official MCP Inspector

In --http mode, GET /health is a dependency-free liveness probe for uptime monitors, and every other route is rate limited per client IP (HMCP_HTTP_RATE_LIMIT_RPM, default 120/min) so a public endpoint cannot be used to exhaust the upstream quotas all providers share.

Repository tour

Path

What lives there

src/

The server. providers/ (one directory per data source — the only place provider quirks may exist), tools/, resources/, prompts/, shared/ (HTTP, cache, rate limiting, stats, country matching), viz/, http/ (Streamable HTTP + dashboard)

docs/

tools.md (tool reference) · architecture.md · for-researchers.md · how-mcp-works.md (MCP primer) · adding-providers.md · development.md · index.html (Arabic landing page, served at humanitarian-mcp.zad.tools)

examples/

Client configs, worked conversations with tool traces, HTTP client recipes, runnable Python/R notebooks

tests/

153 tests: MCP compliance suite (official SDK client ↔ real server), fixture-based provider suites (no network), unit tests

paper/

JOSS paper draft (paper.md + paper.bib)

marketing/

Launch kit: platform-native announcement drafts

Dockerfile / compose.yaml

Organizational self-hosting (image published to GHCR on every release)

.github/

CI (Node 20/22/24), release automation (npm + .mcpb + Docker on tag), issue templates incl. a provider-request template

Development

npm run dev            # stdio server via tsx
npm run dev:http       # HTTP + dashboard on :8642
npm test               # vitest — unit + integration + MCP compliance
npm run check          # typecheck + lint + format + tests (run before pushing)
npm run build          # emit dist/

Releases: bump the version, tag v*, push — CI publishes the GitHub release with the .mcpb bundle, the Docker image to GHCR, and (once the npm token is configured) the npm package. Full guide: docs/development.md · adding a data source: docs/adding-providers.md.

Roadmap

✅ Completed

  • v0.1.0 — UNHCR provider, 17 tools, resources, prompts, caching/offline, dashboard, compliance suite

  • v0.2.0 — release automation (npm workflow + .mcpb), CITATION.cff, Arabic country names, reproducible extraction manifests

  • v0.3.0 — World Bank provider + normalize_by per-capita / per-GDP analytics

  • v0.4.0 — HDX/HAPI provider (conflict, food security, funding, IDPs) + 3 crisis tools + Docker/GHCR

  • v0.5.0 — codebooks, Python/R notebooks, JOSS paper draft

  • v0.5.1 — HDX fixes from the first live verification round (per-theme admin levels, server-side year windows, pagination)

  • v0.6.0 — ReliefWeb provider (situation reports + latest report links), situation_reports tool, crisis_overview prompt, hardened public HTTP mode (per-IP rate limiting, GET /health), bilingual landing page

  • Published to npmnpx humanitarian-mcp is live

🚧 In progress

  • Zenodo DOI per release

  • JOSS paper review & submission

  • npm provenance signing on future releases (via the release workflow once its token is configured)

🔭 Future (contributions welcome)

  • ReliefWeb disasters dataset (the situation-reports pipeline already shipped)

  • Full Arabic report generation (locale: "ar")

  • UNHCR Operational Data Portal situations

  • Sturdier statistics (confidence intervals, changepoint detection)

  • Redis cache backend

FAQ

No. MCP (Model Context Protocol) is the plumbing standard that connects AI apps to tools. You paste a config or double-click the .mcpb file; your assistant does the rest. Curious anyway? docs/how-mcp-works.md.

No — UNHCR and World Bank need none. Only the optional HDX datasets need a free "app identifier" (base64 of your app name + email, generated in one curl; not a secret).

No. It is an independent open-source project. All data is © its original producers (UNHCR, World Bank, ACLED, IPC, OCHA, IOM via HDX), and every payload carries that attribution.

Because the failure mode is silent wrong answers: UNHCR's ARE is Egypt, but ISO's ARE is the UAE; empty results look like "no data"; "-" cells break math. This server encodes those traps once, with 153 tests. See Why this project exists.

It is as fresh as the sources: UNHCR publishes end-year (and mid-year) statistics, the World Bank annual indicators, HDX themes on their producers' cadence. The server caches responses (default 1 h fresh, stale-while-revalidate after) — it never makes data older than the source.

Usually one of: news quotes flows ("X arrived this month") while these are stocks ("X present at year-end"); different population categories (refugees vs all people of concern); or upstream revisions — UNHCR revises series retroactively. Record your extraction date (the manifest does it for you).

Each category is a separate metric (refugees, idps, asylum_seekers, stateless…), and the codebook defines every one. The population headline per dataset is documented in docs/tools.md and in generated codebooks.

asylum = people hosted in the country (default); origin = people displaced from it. Mixing them up is the most common analysis error — the server's instructions teach connected models this convention up front.

normalize_by: "population" divides by the country's population of the same year (World Bank), scales per 1,000 residents, re-sorts the ranking, and discloses the denominator year on every row. "gdp" does the same per US$1bn. Countries lacking denominator data are counted, never silently dropped.

Yes — country resolution covers official UN Arabic names for 100% of countries served, plus common variants, with spelling-variant folding («الأردن» = «الاردن» = «اردن»). Tool output is currently English; full Arabic report generation is on the roadmap.

Yes. npm run dashboard gives you a query playground and a plain HTTP bridge (POST /api/call) — the Python/R notebooks use exactly that. The /mcp endpoint is also plain JSON-RPC (examples/http-client.md).

Self-host if you need control, privacy guarantees, offline mode, or custom configuration (it's the same MIT-licensed code). Use the hosted endpoint to be running in 30 seconds. Full comparison: Two ways to use it.

The hosted instance runs this open-source code, which keeps in-memory usage counters (per-tool call counts/latency for its dashboard) and standard server logs. It has no accounts, no API keys, and stores no personal data by design. If that is still too much, self-host.

Yes (self-hosted): run once online with HMCP_CACHE=sqlite to warm the cache, then HMCP_OFFLINE=1 serves everything from cache and fails loudly on misses.

Anything that speaks MCP: Claude Desktop & claude.ai, Claude Code, Cursor, VS Code, Windsurf, and custom agents via the official SDKs (stdio or Streamable HTTP). Config snippets are in Installation.

All three — plain Node with zero native dependencies (the SQLite cache uses Node's built-in node:sqlite). The Docker image covers anything that runs containers.

Two runtime dependencies (the MCP SDK and zod), no database server required, and the Docker image is a slim multi-stage Node build. It runs comfortably on the smallest VPS tier.

They are deliberately naive (OLS extrapolation) and say so in their own output. Use them as a baseline sanity check, never as planning figures — UNHCR publishes no such projections through this API.

The server rate-limits itself (token bucket, default 4 req/s per provider), retries with backoff, and serves stale cache when a source is down — your session degrades gracefully instead of erroring.

See Citation below — BibTeX/APA/Chicago provided, plus GitHub's "Cite this repository" button. Cite the data as its original producers (the manifests include the right citation string per dataset).

One directory, one interface, fixture-based tests — the full worked guide is docs/adding-providers.md, and there's a provider-request issue template. IOM DTM and UNHCR ODP situations are the most-wanted next providers.

Yes — that's what the Docker image and compose file are for. MIT license, commercial use fine. Keep the HTTP endpoint behind your reverse proxy/VPN (it is unauthenticated by design — see SECURITY.md).

No. Everything is aggregate national statistics from public sources. Still: these numbers represent people — present them with the care they deserve (see Data & responsibility).

Contributing

Contributions welcome — most wanted: new providers (IOM DTM, UNHCR ODP situations), country-alias corrections, and documentation in more languages. Start with CONTRIBUTING.md; the golden rules: read-only always, provider isolation, no network in tests, attribution is not optional.

Citation

Software (also available via GitHub's "Cite this repository" button — CITATION.cff; a Zenodo DOI per release is being set up):

BibTeX

@software{nabil_humanitarian_mcp_2026,
  author  = {Nabil, Ahmed},
  title   = {humanitarian-mcp: a Model Context Protocol server for humanitarian open data},
  year    = {2026},
  version = {0.6.0},
  url     = {https://github.com/ahmedvnabil/humanitarian-mcp},
  license = {MIT}
}

APA — Nabil, A. (2026). humanitarian-mcp: A Model Context Protocol server for humanitarian open data (Version 0.6.0) [Computer software]. https://github.com/ahmedvnabil/humanitarian-mcp

Chicago — Nabil, Ahmed. humanitarian-mcp: A Model Context Protocol Server for Humanitarian Open Data. V. 0.6.0. Computer software, 2026. https://github.com/ahmedvnabil/humanitarian-mcp.

Cite the data as its producers: UNHCR Refugee Data Finder; World Bank World Development Indicators (CC BY 4.0); ACLED / IPC / OCHA FTS / IOM DTM via HDX HAPI — every export's manifest carries the exact citation string for its dataset. Method notes: docs/for-researchers.md.

Data, attribution & responsibility

  • Data © its original producers: UNHCR (Refugee Data Finder), World Bank (CC BY 4.0), and via HDX HAPI: ACLED, IPC, OCHA FTS, IOM DTM. This project is unofficial and unaffiliated.

  • The server is strictly read-only and respects upstream rate limits.

  • Figures are end-year stocks; recent years may be preliminary; series get revised — record extraction dates (manifests do).

  • Forecasts are naive extrapolations, clearly labelled.

  • These numbers represent people. Present them with the care they deserve.

License

MIT — free for research, NGO, commercial and government use.

Install Server
A
license - permissive license
A
quality
A
maintenance

Maintenance

Maintainers
Response time
0dRelease cycle
4Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ahmedvnabil/humanitarian-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server