# io.github.cyanheads/unhcr-refugees-mcp-server (remote · unhcr-refugees.caseyjhand.com)

Query UNHCR refugee, IDP, and stateless populations, asylum decisions, returns, and resettlement.

- Trust score: 88/100 (high trust)
- Change this week: +5
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

## Components

- remote · `unhcr-refugees.caseyjhand.com`: 88/100 (this document), [markdown](https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees.md), [page](https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees)
- npm · `@cyanheads/unhcr-refugees-mcp-server`: 39/100, [markdown](https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/cyanheads-unhcr-refugees-mcp-server.md), [page](https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/cyanheads-unhcr-refugees-mcp-server)

## Channel facts

- Endpoint: `https://unhcr-refugees.caseyjhand.com/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `0.3.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-11-05.

- **Endpoint Security**: 83/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - No authorisation is required to call this server. Nothing on it is marked destructive, but we can't show that an anonymous caller can only read: full credit needs the server to list at least one tool and every tool to be verifiably read-only. We use a best-effort check of tool names and descriptions to tell read-only tools from tools that change things, so some genuinely read-only tools may not get full credit. Names that start with a read verb (get, list, read, search and similar) and accurate readOnlyHint annotations help. Meet that to earn full credit, or require authorisation.
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC is configured correctly; the domain's records validate against the full chain to the root.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 72/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 5153 tokens (~572/item across 9 items; 8 tools + 1 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 100/100
  - No destabilizing schema changes in the last 30 days.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 8 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 10 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the io.github.cyanheads/unhcr-refugees-mcp-server server?

io.github.cyanheads/unhcr-refugees-mcp-server is a hosted endpoint at https://unhcr-refugees.caseyjhand.com/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add --transport http cyanheads-unhcr-refugees-mcp-server 'https://unhcr-refugees.caseyjhand.com/mcp'
```

### Cursor

```json
{
  "mcpServers": {
    "cyanheads-unhcr-refugees-mcp-server": {
      "url": "https://unhcr-refugees.caseyjhand.com/mcp"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "cyanheads-unhcr-refugees-mcp-server": {
      "type": "http",
      "url": "https://unhcr-refugees.caseyjhand.com/mcp"
    }
  }
}
```

### Codex

```toml
[mcp_servers.cyanheads-unhcr-refugees-mcp-server]
url = "https://unhcr-refugees.caseyjhand.com/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "cyanheads-unhcr-refugees-mcp-server": {
      "type": "remote",
      "url": "https://unhcr-refugees.caseyjhand.com/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add cyanheads-unhcr-refugees-mcp-server --url 'https://unhcr-refugees.caseyjhand.com/mcp' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  cyanheads-unhcr-refugees-mcp-server:
    url: "https://unhcr-refugees.caseyjhand.com/mcp"
```

### Netclaw

```json
{
  "McpServers": {
    "cyanheads-unhcr-refugees-mcp-server": {
      "Transport": "http",
      "Url": "https://unhcr-refugees.caseyjhand.com/mcp"
    }
  }
}
```

### Vellum

```bash
assistant mcp add cyanheads-unhcr-refugees-mcp-server -t streamable-http -u 'https://unhcr-refugees.caseyjhand.com/mcp'
```

### Other

```json
{
  "mcpServers": {
    "cyanheads-unhcr-refugees-mcp-server": {
      "type": "http",
      "url": "https://unhcr-refugees.caseyjhand.com/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-11-04 (score 88, +2)

- [security] The server rewrote its instructions, which are the text every model session reads
- [security] Tool “unhcr_dataframe_describe” rewrote its description, which is the text the model reads
- [functional] First check of Schema quality: 100
- [functional] New resource “unhcr-refugees-guide”
- [functional] Server version: 0.2.0 → 0.3.0
- [cosmetic] “unhcr_get_solutions” reworded the description of “origin”
- [cosmetic] “unhcr_get_solutions” reworded the description of “limit”
- [cosmetic] “unhcr_get_solutions” reworded the description of “asylum”
- [cosmetic] “unhcr_get_population” reworded the description of “sort_by”
- [cosmetic] “unhcr_get_population” reworded the description of “origin”
- [cosmetic] “unhcr_get_population” reworded the description of “limit”
- [cosmetic] “unhcr_get_population” reworded the description of “include_nowcast”
- [cosmetic] “unhcr_get_population” reworded the description of “asylum”
- [cosmetic] “unhcr_get_demographics” reworded the description of “origin”
- [cosmetic] “unhcr_get_demographics” reworded the description of “limit”
- [cosmetic] “unhcr_get_demographics” reworded the description of “asylum”
- [cosmetic] “unhcr_get_asylum_decisions” reworded the description of “origin”
- [cosmetic] “unhcr_get_asylum_decisions” reworded the description of “limit”
- [cosmetic] “unhcr_get_asylum_decisions” reworded the description of “asylum”
- [cosmetic] “unhcr_get_asylum_applications” reworded the description of “origin”
- [cosmetic] “unhcr_get_asylum_applications” reworded the description of “asylum”
- [cosmetic] “unhcr_get_asylum_applications” reworded the description of “limit”
- [cosmetic] “unhcr_dataframe_query” reworded the description of “row_limit”
- [cosmetic] “unhcr_dataframe_query” reworded the description of “preview”
- [cosmetic] “unhcr_dataframe_describe” reworded the description of “name”

### 2026-11-03 (score 86, +1)

- [security] Stability: 0.97 → pass

### 2026-11-01 (score 85, +1)

No change was recorded against any check on this day. Stability & Change Management went from 90 to 93. That category is still filling its 30-day observation window: 27 days of observed history at the previous scan, 28 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-30 (score 84, +1)

No change was recorded against any check on this day. Stability & Change Management went from 83 to 87. That category is still filling its 30-day observation window: 25 days of observed history at the previous scan, 26 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-27 (score 83, +1)

No change was recorded against any check on this day. Stability & Change Management went from 73 to 77. That category is still filling its 30-day observation window: 22 days of observed history at the previous scan, 23 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-25 (score 82, +1)

No change was recorded against any check on this day. Stability & Change Management went from 67 to 70. That category is still filling its 30-day observation window: 20 days of observed history at the previous scan, 21 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-23 (score 81, +1)

No change was recorded against any check on this day. Stability & Change Management went from 60 to 63. That category is still filling its 30-day observation window: 18 days of observed history at the previous scan, 19 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-21 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 53 to 57. That category is still filling its 30-day observation window: 16 days of observed history at the previous scan, 17 at this one. The score rises as the window fills, whether or not the server changes.

## MCP tools (8)

### `unhcr_list_reference` (~273 tokens)

UNHCR reference vocabulary

Decode the vocabulary the unhcr_* tools take as input: countries (ISO3, ISO2, UNHCR code, names, UNHCR and UN regions), UNHCR’s regional bureaus, each dataset’s first and latest year, population-type definitions, and the asylum authority, stage, decision-level, and unit codes. Filter countries with name_contains to turn a country name into the ISO3 code that origin and asylum take.

Input parameters:

- `name_contains` (string): For topic countries only: keep countries whose names, in UNHCR’s English spelling, contain every word given, ignoring case, accents, and punctuation, or whose ISO3, ISO2, or UNHCR code equals a word…
- `topic` (string, required): countries: every queryable country with its codes, names, and regions. regions: UNHCR's regional bureaus. coverage: first and latest year of each dataset, plus the current nowcast month. population_t…

Output parameters:

- `asylum_codes` (object): Present for topic asylum_codes.
- `countries` (array): Present for topic countries, sorted by name.
- `coverage` (array): Present for topic coverage.
- `error` (object): Present when the call failed. Absent on success.
- `notice` (string): Guidance when name_contains matched nothing or does not apply to the topic.
- `nowcast` (object): Present for topic coverage: the single current-year estimate unhcr_get_population's include_nowcast returns.
- `population_types` (array): Present for topic population_types.
- `regions` (array): Present for topic regions.
- `topic` (string): The topic returned.
- `totalCount` (number): Countries returned, after any name_contains filter.

### `unhcr_get_population` (~791 tokens)

UNHCR displacement stocks

Get UNHCR year-end displacement stocks (1951 to the latest year) by country of origin and/or asylum: refugees, asylum-seekers, other people in need of international protection, IDPs, stateless people, others of concern, and host communities, plus refugees and IDPs who returned during the year. Stocks count people in a situation on 31 December, not arrivals. Palestine refugees under UNRWA's mandate and IDMC's conflict-IDP estimate are separate series shown beside each row. Set include_nowcast for UNHCR's current-year estimate by asylum country; for sex and age breakdowns, use unhcr_get_demographics.

Input parameters:

- `asylum`: Country of asylum — where people sought or hold protection; for returns, the country they returned from — as ISO3 codes (DEU, TUR), case-insensitive, same rules and limit as origin. Omit to sum every…
- `expand` (string): List every country, one row each, for a dimension that origin or asylum leaves unfiltered: origin, asylum, or both. Default none, where an unfiltered dimension is summed into one row. Expanding a dim…
- `include_nowcast` (boolean): Append UNHCR's latest monthly estimate of refugees and asylum-seekers by asylum country: one current-year snapshot, independent of the year window. It is sorted and cut to limit on its own, and stage…
- `limit` (integer): Inline rows. Default 25; a larger value returns at most 2000 and says so. Sorting runs over the full result first; a larger result is staged as a dataframe where dataframes are enabled.
- `origin`: Country of origin — where people fled from — as ISO3 codes (SYR, AFG), case-insensitive. ISO 3166 alpha-2 codes (SY) are rewritten to ISO3 and echoed in applied_scope. UNHCR's own codes (GFR) are rej…
- `sort_by` (string): Order of the full result before the inline cut. year (default) orders by year, then origin ISO3, then asylum ISO3; a count field orders largest first, nulls last. The nowcast is ordered by refugees o…
- `stage` (boolean): Stage the full result as a dataframe even when it fits inline, e.g. to join it with another unhcr_get_* result in unhcr_dataframe_query. Where dataframes are unavailable it is ignored, and the notice…
- `year_from` (integer): First year of the window. When omitted, the window starts at the dataset's first year. A year before the dataset's first year is clamped to it and the clamp is reported; a window entirely outside the…
- `year_to` (integer): Last year of the window. When omitted, the window runs to the latest published year (latest_year in the result). A year past the latest published year is clamped to it and the clamp is reported.

Output parameters:

- `applied_scope` (object): The scope actually sent upstream, including clamped years and code rewrites.
- `attribution` (object): Attribution UNHCR requires when these figures are reused.
- `cap` (number): The limit that was applied.
- `complete` (boolean): False when the server row cap stopped the upstream fetch; the notice says how many upstream rows were fetched and how to narrow.
- `data_notes` (array): How to read the counts: stock or flow, rounding, the meaning of null, caveats.
- `dataset` (object): Present when the full result was staged as a dataframe; read its columns with unhcr_dataframe_describe, then query it with unhcr_dataframe_query.
- `error` (object): Present when the call failed. Absent on success.
- `footnotes` (array): UNHCR caveats matching rows of the full result, at most 20. Caveats on inline rows come before those only on rows past the cut; within each group, country-specific first, then in the order of the fir…
- `footnotes_total` (integer): Caveats matching the full result, before the cap.
- `latest_year` (integer): Newest year this dataset publishes.
- `measure` (string): stock: people in a situation on 31 December; flow: events during the year.
- `notice` (string): Guidance for this result: empty-result hints, year and limit clamps, where the full set was staged, or how to narrow.
- `nowcast` (array): UNHCR's current-year estimate by asylum country, sorted and cut to limit apart from rows: largest first by refugees or asylum_seekers when sort_by names one (nulls last, ties by asylum ISO3), otherwi…
- `nowcast_dataset` (object): Present when the nowcast was staged as its own dataframe, because it overflowed limit or stage was set: columns year, month, asylum_iso3, asylum_unhcr_code, asylum_name, asylum_unhcr_region, asylum_u…
- `nowcast_total` (integer): Nowcast rows before the cut at limit. Present whenever nowcast is.
- `rows` (array): Inline rows, sorted, up to limit.
- `shown` (number): Rows returned inline.
- `total_rows` (integer): Rows in the full result before the inline cut. When complete is false, the result is built from only the upstream rows fetched before the cap, so rows and summed counts can fall short of the complete…
- `truncated` (boolean): True when rows were cut at limit.

### `unhcr_get_demographics` (~722 tokens)

UNHCR demographics

Get UNHCR year-end stocks (2001 to the latest year) broken down by population type, sex, and age band (0–4, 5–11, 12–17, 18–59, 60+, unknown age), by country of origin and/or asylum. Coverage is partial: each row gives the share of its total that UNHCR could disaggregate by sex, and age bands are null where no breakdown exists. These totals come from a separate collection and need not match unhcr_get_population.

Input parameters:

- `asylum`: Country of asylum — where people sought or hold protection; for returns, the country they returned from — as ISO3 codes (DEU, TUR), case-insensitive, same rules and limit as origin. Omit to sum every…
- `expand` (string): List every country, one row each, for a dimension that origin or asylum leaves unfiltered: origin, asylum, or both. Default none, where an unfiltered dimension is summed into one row. Expanding a dim…
- `limit` (integer): Inline rows. Default 25; a larger value returns at most 2000 and says so. Sorting runs over the full result first; a larger result is staged as a dataframe where dataframes are enabled.
- `origin`: Country of origin — where people fled from — as ISO3 codes (SYR, AFG), case-insensitive. ISO 3166 alpha-2 codes (SY) are rewritten to ISO3 and echoed in applied_scope. UNHCR's own codes (GFR) are rej…
- `population_types` (array): Keep only these population types, case-insensitive: REF refugees, ASY asylum-seekers, OIP other people in need of international protection, IDP internally displaced, STA stateless, OOC others of conc…
- `sort_by` (string): Order of the full result before the inline cut. year (default) orders by year, then origin ISO3, then asylum ISO3, then population type; total orders largest first, nulls last.
- `stage` (boolean): Stage the full result as a dataframe even when it fits inline, e.g. to join it with another unhcr_get_* result in unhcr_dataframe_query. Where dataframes are unavailable it is ignored, and the notice…
- `year_from` (integer): First year of the window. When omitted, the window starts at the dataset's first year. A year before the dataset's first year is clamped to it and the clamp is reported; a window entirely outside the…
- `year_to` (integer): Last year of the window. When omitted, the window runs to the latest published year (latest_year in the result). A year past the latest published year is clamped to it and the clamp is reported.

Output parameters:

- `applied_scope` (object): The scope actually sent upstream, including clamped years and code rewrites.
- `attribution` (object): Attribution UNHCR requires when these figures are reused.
- `cap` (number): The limit that was applied.
- `complete` (boolean): False when the server row cap stopped the upstream fetch; the notice says how many upstream rows were fetched and how to narrow.
- `data_notes` (array): How to read the counts: stock or flow, rounding, the meaning of null, caveats.
- `dataset` (object): Present when the full result was staged as a dataframe; read its columns with unhcr_dataframe_describe, then query it with unhcr_dataframe_query.
- `error` (object): Present when the call failed. Absent on success.
- `footnotes` (array): UNHCR caveats matching rows of the full result, at most 20. Caveats on inline rows come before those only on rows past the cut; within each group, country-specific first, then in the order of the fir…
- `footnotes_total` (integer): Caveats matching the full result, before the cap.
- `latest_year` (integer): Newest year this dataset publishes.
- `measure` (string): stock: people in a situation on 31 December; flow: events during the year.
- `notice` (string): Guidance for this result: empty-result hints, year and limit clamps, where the full set was staged, or how to narrow.
- `rows` (array): Inline rows, sorted, up to limit.
- `shown` (number): Rows returned inline.
- `total_rows` (integer): Rows in the full result before the inline cut. When complete is false, the result is built from only the upstream rows fetched before the cap, so rows and summed counts can fall short of the complete…
- `truncated` (boolean): True when rows were cut at limit.

### `unhcr_get_asylum_applications` (~777 tokens)

UNHCR asylum applications

Get asylum applications lodged per year (2000 to the latest year) by country of origin and/or asylum, split by default into application stage — new, repeat, appeal, and the combined stages some countries report — so new claims are not added to appeals of old ones. Counts given as cases are never added to counts of persons; each row states its unit. Decode stage, authority, and decision-level codes with unhcr_list_reference (topic asylum_codes).

Input parameters:

- `asylum`: Country of asylum — where people sought or hold protection; for returns, the country they returned from — as ISO3 codes (DEU, TUR), case-insensitive, same rules and limit as origin. Omit to sum every…
- `expand` (string): List every country, one row each, for a dimension that origin or asylum leaves unfiltered: origin, asylum, or both. Default none, where an unfiltered dimension is summed into one row. Expanding a dim…
- `limit` (integer): Inline rows. Default 25; a larger value returns at most 2000 and says so. Sorting runs over the full result first; a larger result is staged as a dataframe where dataframes are enabled.
- `origin`: Country of origin — where people fled from — as ISO3 codes (SYR, AFG), case-insensitive. ISO 3166 alpha-2 codes (SY) are rewritten to ISO3 and echoed in applied_scope. UNHCR's own codes (GFR) are rej…
- `sort_by` (string): Order of the full result before the inline cut. year (default) orders by year, then origin ISO3, then asylum ISO3; applied orders largest first, nulls last.
- `split_by` (array): Procedure dimensions kept as separate rows: authority (government, UNHCR, or joint), stage (new, repeat, appeal, …), decision_level. Every dimension left out is summed. Default ["stage"]; [] gives on…
- `stage` (boolean): Stage the full result as a dataframe even when it fits inline, e.g. to join it with another unhcr_get_* result in unhcr_dataframe_query. Where dataframes are unavailable it is ignored, and the notice…
- `stages` (array): Keep only these application stages before summing, case-insensitive: N new, R repeat, A appeal, NA new and appeal together, NR new and repeat together, FA first and appeal, J judiciary, BL backlog, S…
- `year_from` (integer): First year of the window. When omitted, the window starts at the dataset's first year. A year before the dataset's first year is clamped to it and the clamp is reported; a window entirely outside the…
- `year_to` (integer): Last year of the window. When omitted, the window runs to the latest published year (latest_year in the result). A year past the latest published year is clamped to it and the clamp is reported.

Output parameters:

- `applied_scope` (object): The scope actually sent upstream, including clamped years and code rewrites.
- `attribution` (object): Attribution UNHCR requires when these figures are reused.
- `cap` (number): The limit that was applied.
- `complete` (boolean): False when the server row cap stopped the upstream fetch; the notice says how many upstream rows were fetched and how to narrow.
- `data_notes` (array): How to read the counts: stock or flow, rounding, the meaning of null, caveats.
- `dataset` (object): Present when the full result was staged as a dataframe; read its columns with unhcr_dataframe_describe, then query it with unhcr_dataframe_query.
- `error` (object): Present when the call failed. Absent on success.
- `latest_year` (integer): Newest year this dataset publishes.
- `measure` (string): stock: people in a situation on 31 December; flow: events during the year.
- `notice` (string): Guidance for this result: empty-result hints, year and limit clamps, where the full set was staged, or how to narrow.
- `rows` (array): Inline rows, sorted, up to limit.
- `shown` (number): Rows returned inline.
- `total_rows` (integer): Rows in the full result before the inline cut. When complete is false, the result is built from only the upstream rows fetched before the cap, so rows and summed counts can fall short of the complete…
- `truncated` (boolean): True when rows were cut at limit.

### `unhcr_get_asylum_decisions` (~827 tokens)

UNHCR asylum decisions

Get asylum decisions per year (2000 to the latest year) by country of origin and/or asylum: recognized as refugees, complementary protection, rejected, and otherwise closed, with UNHCR's Refugee Recognition Rate and Total Protection Rate computed over substantive decisions (otherwise-closed cases excluded). By default all decision levels are summed and each row lists the levels it includes; appeal-stage decisions can concern people already decided at first instance, so split_by decision_level or filter decision_levels to FI for first-instance rates. Cases and persons are never added together.

Input parameters:

- `asylum`: Country of asylum — where people sought or hold protection; for returns, the country they returned from — as ISO3 codes (DEU, TUR), case-insensitive, same rules and limit as origin. Omit to sum every…
- `decision_levels` (array): Keep only these decision levels before summing, case-insensitive: NA new applications, FI first instance, AR administrative review, RA repeat/reopened, IN US Citizenship and Immigration Services, EO…
- `expand` (string): List every country, one row each, for a dimension that origin or asylum leaves unfiltered: origin, asylum, or both. Default none, where an unfiltered dimension is summed into one row. Expanding a dim…
- `limit` (integer): Inline rows. Default 25; a larger value returns at most 2000 and says so. Sorting runs over the full result first; a larger result is staged as a dataframe where dataframes are enabled.
- `origin`: Country of origin — where people fled from — as ISO3 codes (SYR, AFG), case-insensitive. ISO 3166 alpha-2 codes (SY) are rewritten to ISO3 and echoed in applied_scope. UNHCR's own codes (GFR) are rej…
- `sort_by` (string): Order of the full result before the inline cut. year (default) orders by year, then origin ISO3, then asylum ISO3; a count field orders largest first, nulls last. Rates are not sortable, since rates…
- `split_by` (array): Procedure dimensions kept as separate rows: authority (government, UNHCR, or joint) and decision_level (first instance, administrative review, …). Every dimension left out is summed. Default [] sums…
- `stage` (boolean): Stage the full result as a dataframe even when it fits inline, e.g. to join it with another unhcr_get_* result in unhcr_dataframe_query. Where dataframes are unavailable it is ignored, and the notice…
- `year_from` (integer): First year of the window. When omitted, the window starts at the dataset's first year. A year before the dataset's first year is clamped to it and the clamp is reported; a window entirely outside the…
- `year_to` (integer): Last year of the window. When omitted, the window runs to the latest published year (latest_year in the result). A year past the latest published year is clamped to it and the clamp is reported.

Output parameters:

- `applied_scope` (object): The scope actually sent upstream, including clamped years and code rewrites.
- `attribution` (object): Attribution UNHCR requires when these figures are reused.
- `cap` (number): The limit that was applied.
- `complete` (boolean): False when the server row cap stopped the upstream fetch; the notice says how many upstream rows were fetched and how to narrow.
- `data_notes` (array): How to read the counts: stock or flow, rounding, the meaning of null, caveats.
- `dataset` (object): Present when the full result was staged as a dataframe; read its columns with unhcr_dataframe_describe, then query it with unhcr_dataframe_query.
- `error` (object): Present when the call failed. Absent on success.
- `latest_year` (integer): Newest year this dataset publishes.
- `measure` (string): stock: people in a situation on 31 December; flow: events during the year.
- `notice` (string): Guidance for this result: empty-result hints, year and limit clamps, where the full set was staged, or how to narrow.
- `rows` (array): Inline rows, sorted, up to limit.
- `shown` (number): Rows returned inline.
- `total_rows` (integer): Rows in the full result before the inline cut. When complete is false, the result is built from only the upstream rows fetched before the cap, so rows and summed counts can fall short of the complete…
- `truncated` (boolean): True when rows were cut at limit.

### `unhcr_get_solutions` (~629 tokens)

UNHCR durable solutions

Get durable solutions per year (1959 to the latest year) by country of origin and/or asylum: refugees who returned home, refugees resettled to a third country, refugees naturalised, and IDPs who returned. The asylum country means something different per column: the country refugees returned from, the country they were resettled to, the country that naturalised them; IDP returns sit on the origin country itself. Null means the figure was not collected for that country and year, not zero.

Input parameters:

- `asylum`: Country of asylum — where people sought or hold protection; for returns, the country they returned from — as ISO3 codes (DEU, TUR), case-insensitive, same rules and limit as origin. Omit to sum every…
- `expand` (string): List every country, one row each, for a dimension that origin or asylum leaves unfiltered: origin, asylum, or both. Default none, where an unfiltered dimension is summed into one row. Expanding a dim…
- `limit` (integer): Inline rows. Default 25; a larger value returns at most 2000 and says so. Sorting runs over the full result first; a larger result is staged as a dataframe where dataframes are enabled.
- `origin`: Country of origin — where people fled from — as ISO3 codes (SYR, AFG), case-insensitive. ISO 3166 alpha-2 codes (SY) are rewritten to ISO3 and echoed in applied_scope. UNHCR's own codes (GFR) are rej…
- `sort_by` (string): Order of the full result before the inline cut. year (default) orders by year, then origin ISO3, then asylum ISO3; a count field orders largest first, nulls last.
- `stage` (boolean): Stage the full result as a dataframe even when it fits inline, e.g. to join it with another unhcr_get_* result in unhcr_dataframe_query. Where dataframes are unavailable it is ignored, and the notice…
- `year_from` (integer): First year of the window. When omitted, the window starts at the dataset's first year. A year before the dataset's first year is clamped to it and the clamp is reported; a window entirely outside the…
- `year_to` (integer): Last year of the window. When omitted, the window runs to the latest published year (latest_year in the result). A year past the latest published year is clamped to it and the clamp is reported.

Output parameters:

- `applied_scope` (object): The scope actually sent upstream, including clamped years and code rewrites.
- `attribution` (object): Attribution UNHCR requires when these figures are reused.
- `cap` (number): The limit that was applied.
- `complete` (boolean): False when the server row cap stopped the upstream fetch; the notice says how many upstream rows were fetched and how to narrow.
- `data_notes` (array): How to read the counts: stock or flow, rounding, the meaning of null, caveats.
- `dataset` (object): Present when the full result was staged as a dataframe; read its columns with unhcr_dataframe_describe, then query it with unhcr_dataframe_query.
- `error` (object): Present when the call failed. Absent on success.
- `footnotes` (array): UNHCR caveats matching rows of the full result, at most 20. Caveats on inline rows come before those only on rows past the cut; within each group, country-specific first, then in the order of the fir…
- `footnotes_total` (integer): Caveats matching the full result, before the cap.
- `latest_year` (integer): Newest year this dataset publishes.
- `measure` (string): stock: people in a situation on 31 December; flow: events during the year.
- `notice` (string): Guidance for this result: empty-result hints, year and limit clamps, where the full set was staged, or how to narrow.
- `rows` (array): Inline rows, sorted, up to limit.
- `shown` (number): Rows returned inline.
- `total_rows` (integer): Rows in the full result before the inline cut. When complete is false, the result is built from only the upstream rows fetched before the cap, so rows and summed counts can fall short of the complete…
- `truncated` (boolean): True when rows were cut at limit.

### `unhcr_dataframe_describe` (~173 tokens)

Describe staged dataframes

Describe a dataframe (df_XXXXX_XXXXX) staged by the unhcr_get_* tools — any response carrying a dataset or nowcast_dataset handle staged its full result here — or list them all where this deployment allows listing. Each entry gives the source tool, query parameters, creation and expiry time, row count, whether the upstream fetch was complete, and the column schema. Read the columns here before writing SQL for unhcr_dataframe_query.

Input parameters:

- `name` (string): One dataframe to describe, as df_XXXXX_XXXXX (uppercase letters and digits): the dataset.name or nowcast_dataset.name a unhcr_get_* result returned, or a register_as name. Omit to list every staged d…

Output parameters:

- `dataframes` (array): Staged dataframes, newest first. Empty when none are staged.
- `error` (object): Present when the call failed. Absent on success.
- `notice` (string): Guidance when nothing is staged or the named dataframe is gone.

### `unhcr_dataframe_query` (~396 tokens)

Query staged dataframes

Run a single-statement SELECT against the dataframes staged by the unhcr_get_* tools. Check a dataframe’s columns with unhcr_dataframe_describe first. Writes, DDL, DROP, COPY, PRAGMA, ATTACH, file references, external-data functions, engine introspection, dynamic table lookup, and system catalogs are rejected; query() accepts only a single SQL string literal, checked by the same gate. Optional register_as saves the result as a new dataframe with a fresh TTL. Recompute rates from summed counts rather than averaging rate columns.

Input parameters:

- `preview` (integer): Rows returned inline; 0 returns only the columns and counts. Default 25; a larger value returns at most 1500, or row_limit when lower, and says so.
- `register_as` (string): Save the result as a new dataframe under this name (df_ plus two groups of 5 uppercase letters or digits, e.g. df_ABCDE_12345) with a fresh TTL, to chain analyses. The name must not already be staged…
- `row_limit` (integer): Most rows the query materializes. Default 1000; a larger value materializes at most 10000 and says so. When more rows match, row_count_capped is true; use register_as to keep the full result.
- `sql` (string, required): One DuckDB SELECT against df_XXXXX_XXXXX tables, at most 20,000 characters — joins, aggregates, window functions, and CTEs work. SUM and COUNT results come back as JSON strings (BIGINT); CAST(… AS DO…

Output parameters:

- `attribution` (object): Attribution UNHCR requires when these figures are reused.
- `cap` (number): The cap that bound: preview when lower than row_limit, otherwise row_limit.
- `columns` (array): Column names in projection order.
- `complete` (boolean): False when any original source fetch was incomplete, independently of display truncation.
- `error` (object): Present when the call failed. Absent on success.
- `evicted` (array): Older dataframes dropped, oldest first, to keep the staged total within the 1,000,000-row budget once register_as saved this result; they can no longer be queried. Present only when any were evicted.
- `expires_at` (string): ISO 8601 expiry of the new dataframe, when register_as was set.
- `incomplete_sources` (array): Original incomplete upstream dataframe handles; retained through saved descendants.
- `notice` (string): Guidance for this result: a clamped count, an incomplete source, an empty result, or rows withheld by preview or row_limit.
- `registered_as` (string): The new dataframe, when register_as was set.
- `row_count` (integer): Rows the query produced, up to row_limit; with register_as, every row of the saved result. When row_count_capped is true this is the cap, not the full size.
- `row_count_capped` (boolean): True when more rows matched than row_limit allowed through.
- `rows` (array): The first preview rows of the result, one object per row keyed by column name. BIGINT values (SUM, COUNT) arrive as strings.
- `shown` (number): Rows returned inline.
- `truncated` (boolean): True when preview or row_limit withheld rows.

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees#diagnostics

## Score history

- 2026-11-05: 88
- 2026-11-04: 88
- 2026-11-03: 86
- 2026-11-02: 85
- 2026-11-01: 85
- 2026-10-31: 84
- 2026-10-30: 84
- 2026-10-29: 83
- 2026-10-28: 83
- 2026-10-27: 83
- 2026-10-26: 82
- 2026-10-25: 82
- 2026-10-24: 81
- 2026-10-23: 81
- 2026-10-22: 80
- 2026-10-21: 80
- 2026-10-20: 79
- 2026-10-19: 79
- 2026-10-18: 79
- 2026-10-17: 78
- 2026-10-16: 78
- 2026-10-15: 78
- 2026-10-14: 77
- 2026-10-13: 77
- 2026-10-12: 76
- 2026-10-11: 76
- 2026-10-10: 75
- 2026-10-07: 74
- 2026-10-06: 73
- 2026-10-04: 72

## Common questions

### What is the io.github.cyanheads/unhcr-refugees-mcp-server server?

io.github.cyanheads/unhcr-refugees-mcp-server is listed in the public MCP registry as io.github.cyanheads/unhcr-refugees-mcp-server. Query UNHCR refugee, IDP, and stateless populations, asylum decisions, returns, and resettlement. This page covers its hosted endpoint (https://unhcr-refugees.caseyjhand.com/mcp).

### Is the io.github.cyanheads/unhcr-refugees-mcp-server server safe to use?

io.github.cyanheads/unhcr-refugees-mcp-server scores 88 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the io.github.cyanheads/unhcr-refugees-mcp-server server expose?

io.github.cyanheads/unhcr-refugees-mcp-server exposes 8 tools: unhcr_list_reference, unhcr_get_population, unhcr_get_demographics, unhcr_get_asylum_applications, unhcr_get_asylum_decisions, and 3 more. Their descriptions and schemas cost roughly 4,588 tokens of context every time the server is loaded.

### Does the io.github.cyanheads/unhcr-refugees-mcp-server server require authentication?

No. We connected to io.github.cyanheads/unhcr-refugees-mcp-server without credentials and it answered, so anything it exposes is reachable by anyone who knows the address.

### Is the io.github.cyanheads/unhcr-refugees-mcp-server server still maintained?

io.github.cyanheads/unhcr-refugees-mcp-server is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What did VerifyMCP test on the io.github.cyanheads/unhcr-refugees-mcp-server server?

VerifyMCP ran 13 checks on io.github.cyanheads/unhcr-refugees-mcp-server, covering TLS certificate, Authorization, HTTPS, HSTS header and 9 more. Supply Chain Security and Provenance & Transparency do not apply to a hosted endpoint, so they were not tested. The score does not measure everything, and the scoring documentation lists what it leaves out.

## Links

- Remote endpoint: https://unhcr-refugees.caseyjhand.com/mcp
- Repository: https://github.com/cyanheads/unhcr-refugees-mcp-server
- Changelog RSS feed: https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees.xml
- Changelog JSON feed: https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees/changelog.json
- Trust report (JSON): https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees.json
- HTML version of this page: https://verifymcp.io/servers/cyanheads-unhcr-refugees-mcp-server/unhcr-refugees
