Skip to main content
Glama
Satyampatel779

country-analytics-mcp

README.md
# 🌍 country-analytics-mcp

**Ask an AI plain-language questions about world economics β€” answered live from three public APIs that disagree with each other.**

![Python](https://img.shields.io/badge/Python-3.10%2B-blue) ![MCP](https://img.shields.io/badge/MCP-streamable%20HTTP%20%2B%20stdio-8A2BE2) ![Azure](https://img.shields.io/badge/Hosted%20on-Azure%20Container%20Apps-0078D4) ![Keys](https://img.shields.io/badge/API%20keys-none-brightgreen)

> *"What was France's GDP in 2022 in US dollars?"* Β· *"Convert that to euros at the Dec 30 2022 rate."* Β· *"What's Europe's total GDP β€” and who did you exclude, and why?"*

GDP, population, GDP per capita, regional totals in your currency, rankings β€” reconciled **live** (nothing hard-coded, no keys, no accounts) and fully **traceable**: every answer names its countries, years, FX rate, and exclusions.

---

## ⚑ Step 1 β€” Connect it to your AI (60 seconds, nothing to install)

The server is already running on Azure. Paste this URL into your AI client:

```
https://country-analytics-mcp.grayriver-35df865c.eastus.azurecontainerapps.io/mcp
```

### 🟠 Claude (claude.ai or Claude Desktop)

1. **Settings β†’ Connectors β†’ Add custom connector**
2. Name: `country-analytics` Β· URL: the one above Β· no authentication
3. **Add**, then start a chat and ask away β€” Claude picks the tools itself.

### 🟒 ChatGPT

1. **Settings β†’ Apps & Connectors β†’ Advanced settings** β†’ enable **Developer mode**
2. Back in **Connectors** β†’ **Create**: name `country-analytics`, MCP server URL as above, Authentication: **None** β†’ save
3. In a new chat, enable the connector (via the composer's tools / Developer mode menu) and ask your question.

*(Custom connectors require a paid plan on both platforms; exact menu names shift occasionally.)*

### πŸ” No paid plan? MCP Inspector works too

```bash
npx @modelcontextprotocol/inspector
```

Transport **Streamable HTTP** β†’ paste the URL β†’ **Connect** β†’ call the 8 tools from a form UI.

> πŸ’€ The app scales to zero when idle β€” the *first* request after a quiet spell takes ~10 extra seconds to cold-start. Health check: [`/health`](https://country-analytics-mcp.grayriver-35df865c.eastus.azurecontainerapps.io/health)

## πŸ’¬ Step 2 β€” Things worth asking

| Ask this… | …and notice |
|---|---|
| *How many countries does the source list for Europe?* | 53 β€” and 5 of them have no World Bank data (it says which) |
| *France's GDP in 2022, in USD?* | exact World Bank figure, year pinned |
| *Now in euros, at the Dec 30 2022 rate* | conversion pinned to the ECB rate, date echoed back |
| *Europe's total GDP in euros?* | the answer states its scope, FX date, and every excluded country |
| *Same, but using the World Bank's definition of Europe* | a **different set** (Central Asia in, Malta out β€” yes, really) |
| *Top 5 European countries by GDP per capita* | rankings with the year each value actually came from |
| *What couldn't you reconcile for Europe?* | the full flagged-issues ledger |

---

## πŸ’» Run it locally (clean checkout β†’ connected client)

No hosted dependency required β€” the same server runs on your machine with Python 3.10+:

```bash
git clone https://github.com/Satyampatel779/country-analytics-mcp.git
cd country-analytics-mcp
python -m venv .venv
.venv\Scripts\pip install .            # macOS/Linux: .venv/bin/pip install .
```

| Transport | Command |
|---|---|
| **stdio** (Claude Desktop, Inspector) | `.venv\Scripts\python -m country_analytics.server` |
| **HTTP** at `http://127.0.0.1:8000/mcp` | `set MCP_TRANSPORT=http` then the same command (`export` on macOS/Linux) |
| **Docker** (identical to the hosted image) | `docker build -t cam . && docker run -p 8000:8000 cam` |

**Claude Desktop (stdio):** merge [client-configs/claude_desktop_config.json](client-configs/claude_desktop_config.json) into your `claude_desktop_config.json` (Settings β†’ Developer β†’ Edit Config), fix the absolute path, restart:

```json
{
  "mcpServers": {
    "country-analytics": {
      "command": "C:\\path\\to\\country-analytics-mcp\\.venv\\Scripts\\python.exe",
      "args": ["-m", "country_analytics.server"]
    }
  }
}
```

**MCP Inspector (stdio or HTTP):** step-by-step in [client-configs/mcp_inspector.md](client-configs/mcp_inspector.md).

### βœ… Prove it works

```bash
.venv\Scripts\pip install ".[dev]"
.venv\Scripts\python -m pytest -q       # 11 live tests, both MCP transports
```

Expected values are cross-checked against **independent direct fetches** of the same live APIs β€” not constants.

---

## πŸ”§ What's under the hood

Three keyless public services, each speaking a different protocol, joined on **ISO2 codes** (never names β€” the sources spell them differently):

| Source | Protocol | Provides |
|---|---|---|
| [Countries GraphQL](https://countries.trevorblades.com/) | GraphQL | Which countries are on a continent (ISO2, name, currency) |
| [World Bank Indicators](https://api.worldbank.org/v2) | REST, `[metadata, data]` arrays | GDP (`NY.GDP.MKTP.CD`, current US$) & population (`SP.POP.TOTL`) by year |
| [Frankfurter](https://api.frankfurter.dev/v1) | REST | ECB FX rates, latest or pinned to a date |

### The 8 tools

| Tool | Answers |
|---|---|
| `list_continents()` | continent codes + country counts |
| `list_countries(continent)` | the full source list with join status per country |
| `get_country_metric(country, metric, year, currency, fx_date)` | one country, one number, fully traced |
| `region_total(continent, metric, year, currency, scope, fx_date, missing_policy)` | regional totals β€” every assumption a parameter |
| `rank_countries(continent, metric, year, top_n, currency, scope, order)` | top-N / bottom-N |
| `convert_currency(amount, from, to, date)` | pinned or latest FX conversion |
| `list_reconciliation_issues(continent)` | everything excluded, unmatched, or flagged β€” with reasons |
| `describe_methodology()` | join key, defaults, and which parameters change them |

### Judgment calls are parameters, not hard-coded

- **`scope`** β€” geographic continent (default) vs. the World Bank region: for Europe the WB set adds Central Asia and *drops Malta* (the World Bank files it under MENA β€” flagged, of course).
- **`year`** β€” pinned exactly, or `latest` walks back past null years *per country* and reports the year used.
- **`missing_policy`** β€” exclude-and-list (default) or walk back to the most recent earlier value.
- **`fx_date`** β€” defaults to the pinned year's last trading day (2022 β†’ 2022-12-30); pin any date you like.
- **Refuses to guess** β€” currencies outside Frankfurter's 30 (Serbian dinar, hryvnia…) return the supported list instead of an invented rate.

## πŸ“„ More

- **[WRITEUP.md](WRITEUP.md)** β€” sources & join choices, every disagreement found, every assumption, production notes (≀1 page, written for a non-technical stakeholder).
- **[samples/sample_run_output.md](samples/sample_run_output.md)** β€” a real timestamped run: the reconciled Europe table, computed metrics, and the flagged-issues list, kept as a reference in case a source is down during evaluation.

TDQS

A4/5.0

Scored across 8 tools

Disambiguation4/5

Tools are mostly distinct: list_continents, list_countries, and get_country_metric target different granularities, while region_total and rank_countries differ by aggregation vs ranking. However, both region_total and rank_countries share identical scope/year/currency semantics and could be confused for aggregate queries, and get_country_metric is buried despite its importance.

Naming Consistency5/5

All tool names follow a clear verb_noun pattern (list_continents, get_country_metric, region_total, convert_currency, describe_methodology). The only slight deviation is region_total and rank_countries which omit an explicit verb, but they remain readable and consistent within the set.

Tool Count5/5

Eight tools is well-scoped for a country analytics server: listing entities, fetching metrics, aggregating, ranking, converting currency, and explaining reconciliation/methodology. Each tool earns its place without redundancy.

Completeness5/5

The surface covers the full lifecycle: discovery (continents, countries), retrieval (get_country_metric), aggregation (region_total), ranking (rank_countries), currency conversion, and transparency tools (list_reconciliation_issues, describe_methodology). No obvious gaps for the stated domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues