Metadata-Version: 2.4
Name: mcp-nbb
Version: 0.1.0
Summary: MCP server for the National Bank of Belgium SDMX statistical API
Project-URL: Homepage, https://github.com/lacausecrypto/mcp-nbb
Project-URL: Repository, https://github.com/lacausecrypto/mcp-nbb
Project-URL: Issues, https://github.com/lacausecrypto/mcp-nbb/issues
Project-URL: Changelog, https://github.com/lacausecrypto/mcp-nbb/blob/main/CHANGELOG.md
Author: mcp-nbb contributors
License: MIT
License-File: LICENSE
Keywords: belgium,mcp,model-context-protocol,nbb,sdmx,statistics
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: aiolimiter>=1.1.0
Requires-Dist: cachetools>=5.0.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: platformdirs>=4.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: python-dateutil>=2.8.0
Requires-Dist: rapidfuzz>=3.0.0
Requires-Dist: stamina>=24.0.0
Requires-Dist: structlog>=24.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-recording>=0.13.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Requires-Dist: vcrpy>=6.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# mcp-nbb

[![CI](https://github.com/lacausecrypto/mcp-nbb/actions/workflows/ci.yml/badge.svg)](https://github.com/lacausecrypto/mcp-nbb/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/mcp-nbb.svg)](https://pypi.org/project/mcp-nbb/)
[![Python](https://img.shields.io/pypi/pyversions/mcp-nbb.svg)](https://pypi.org/project/mcp-nbb/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![MCP compatible](https://img.shields.io/badge/MCP-compatible-blue)](https://modelcontextprotocol.io)

**MCP server for the [National Bank of Belgium](https://www.nbb.be/) SDMX statistical API.**

Exposes the 221 NBB dataflows (194 BE2 + 27 IMF/SDDS) as **6 LLM-friendly
tools** and **3 browsable resources**, with a bundled enriched catalogue so
the LLM can discover, describe, and query dataflows without redundant API
calls.

- **Upstream**: `https://nsidisseminate-stat.nbb.be/rest` (NSI Web Service v8)
- **Transport**: stdio (standard MCP)
- **Python**: 3.11+
- **Platforms**: Linux, macOS, Windows
- **221 dataflows** classified into 14 categories — see [DATAFLOWS_CATALOG.md](DATAFLOWS_CATALOG.md)

---

## Install

### From PyPI (recommended)

```bash
# With uv (runs without installing globally)
uvx mcp-nbb

# Or install into a regular venv
pip install mcp-nbb
```

### From source

```bash
git clone https://github.com/lacausecrypto/mcp-nbb.git
cd mcp-nbb
pip install -e .
```

The package ships with the full enriched catalogue (~9 MB under
`src/nbb_mcp/data/catalog/`). No build step is required for regular use.

---

## Claude Desktop configuration

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` on
macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows, or the
equivalent on Linux.

### Using `uvx` (recommended once published to PyPI)

```json
{
  "mcpServers": {
    "nbb": {
      "command": "uvx",
      "args": ["mcp-nbb"]
    }
  }
}
```

### From a local editable install

**macOS / Linux**:

```json
{
  "mcpServers": {
    "nbb": {
      "command": "/Users/you/projects/mcp-nbb/.venv/bin/mcp-nbb"
    }
  }
}
```

**Windows**:

```json
{
  "mcpServers": {
    "nbb": {
      "command": "C:\\Users\\you\\projects\\mcp-nbb\\.venv\\Scripts\\mcp-nbb.exe"
    }
  }
}
```

Restart Claude Desktop — the 6 `nbb_*` tools appear in the MCP panel.

---

## Tools

| Tool | API calls | Purpose |
|---|---|---|
| `nbb_search(query, …)` | 0 | Fuzzy search over the 221 local fiches (en/fr/nl/de). |
| `nbb_describe(dataflow_id, …)` | 0 (default) | Full enriched fiche — dimensions, codelists, key template, common queries. `force_refresh=True` revalidates live. |
| `nbb_query(dataflow_id, key=…, filters=…)` | 1 | Generic data fetch. Either `key` (raw SDMX) or `filters` (`{"FREQ":"D","EXR_CURRENCY":"USD"}`). |
| `nbb_quick(topic, …)` | 1 | Topic-based shortcut for 18 common queries — see topic table below. |
| `nbb_compare(series, …)` | N | Align 2-5 series on a common time index, downsampling finer frequencies via closing aggregation. |
| `nbb_status()` | 0 | Diagnostic snapshot: catalog, cache, API config. |

### `nbb_quick` topics

| Topic | Dataflow | Parameters |
|---|---|---|
| `exchange_rate` | `BE2/DF_EXR` | `currency`, `frequency` |
| `policy_rate` | `BE2/DF_IRESCB` | — |
| `mortgage_rate` | `BE2/DF_MIR` | — |
| `long_term_yield` | `BE2/DF_IROLOYLD` | — |
| `inflation_hicp` | `BE2/DF_HICP_2025` | — |
| `inflation_national` | `BE2/DF_NICP_2025` | — |
| `ppi` | `BE2/DF_PPI` | — |
| `industrial_production` | `BE2/DF_INDPROD` | — |
| `gdp` / `gdp_growth` | `BE2/DF_QNA_DISS` | — |
| `unemployment_rate` | `BE2/DF_UNEMPLOY_RATE` | — |
| `employment` | `BE2/DF_EMPLOY_DISS` | — |
| `government_debt` | `BE2/DF_CGD` | — |
| `government_deficit` | `BE2/DF_NFGOV_NET_DISS` | — |
| `current_account` | `BE2/DF_BOPBPM6` | — |
| `consumer_confidence` | `BE2/DF_CONSN` | — |
| `business_confidence` | `BE2/DF_BUSSURVM` | — |
| `trade_balance` | `BE2/DF_EXTERNAL_TRADE_OVERVIEW` | — |

### Resources

| URI | Content |
|---|---|
| `nbb://catalog` | Markdown index of all 221 dataflows by category. |
| `nbb://dataflow/{agency}/{dataflow_id}` | Full enriched fiche for one flow. |
| `nbb://category/{category}` | All flows in a category. |

---

## Example prompts in Claude

> "What's the EUR/USD exchange rate over the last month?"
> → `nbb_quick("exchange_rate", currency="USD", frequency="D", last_n_observations=30)`

> "Compare Belgian GDP growth to the unemployment rate since 2020."
> → `nbb_compare([{dataflow_id:"DF_QNA_DISS",label:"GDP"}, {dataflow_id:"DF_UNEMPLOY_RATE",label:"Unemployment"}], start_period="2020-Q1")`

> "Find NBB dataflows about consumer credit."
> → `nbb_search("consumer credit")` → `nbb_describe(...)` → `nbb_query(...)`.

---

## Configuration (environment variables)

All settings have sensible defaults; override via environment variables.

| Variable | Default | Purpose |
|---|---|---|
| `NBB_API_BASE_URL` | `https://nsidisseminate-stat.nbb.be/rest` | SDMX REST base URL |
| `NBB_API_TIMEOUT` | `30` | Per-request timeout (s) |
| `NBB_USER_AGENT` | browser UA | **Required for the WAF** — default is a valid Chrome UA string |
| `NBB_ORIGIN` | `https://dataexplorer.nbb.be` | **Required for the WAF** |
| `NBB_HTTP_CACHE_ENABLED` | `true` | Persistent disk cache |
| `NBB_HTTP_CACHE_PATH` | OS cache dir | Override cache location (defaults to `platformdirs.user_cache_dir`) |
| `NBB_MEMORY_CACHE_TTL_DATA` | `300` | TTL for data responses (s) |
| `NBB_MEMORY_CACHE_TTL_STRUCTURE` | `3600` | TTL for structure responses (s) |
| `NBB_RATE_LIMIT_REQUESTS` | `100` | Self-imposed rate limit (req/period) |
| `NBB_RATE_LIMIT_PERIOD` | `60` | Rate limit window (s) |
| `NBB_RETRY_ATTEMPTS` | `3` | Retries on transient errors |
| `NBB_LOG_LEVEL` | `INFO` | `DEBUG`/`INFO`/`WARNING`/`ERROR` |
| `NBB_LOG_FORMAT` | `json` | `json` or `console` |

The default cache path resolves to:
- **Linux**: `~/.cache/mcp-nbb/`
- **macOS**: `~/Library/Caches/mcp-nbb/`
- **Windows**: `%LOCALAPPDATA%\mcp-nbb\Cache\`

---

## Refreshing the catalogue

The bundled `src/nbb_mcp/data/catalog/` snapshot is regenerated by fetching
the DSD + codelists for each of the 221 dataflows:

```bash
mcp-nbb-build-catalog --force
```

Options:

- `--force` — rebuild every fiche, ignoring existing ones.
- `--limit N` — only process the first N flows (debug).
- `--only BE2/DF_EXR,BE2/DF_HICP_2025` — rebuild specific flows.
- `--concurrency 5` — parallel DSD requests.

A full rebuild takes ~80 seconds against the live API. Catalogue footprint is
capped at ~9 MB by truncating codelists to 200 codes per dimension (some IMF
flows have 65 000+ codes).

A weekly GitHub Action (`build-catalog.yml`) rebuilds the catalogue and opens
a PR if drift is detected.

---

## Troubleshooting

### "WAF returned an HTML redirect"

The NBB API is behind a WAF that returns an HTML 200 redirect for any request
without a browser-like `User-Agent` and an `Origin: https://dataexplorer.nbb.be`
header. The client injects both by default. If you override `NBB_USER_AGENT`,
keep a genuine-looking browser string.

### "HTTP 404 NoResultsFound" on a data query

The SDMX key didn't match any series. Use `nbb_describe(dataflow_id)` to see
valid codes, or pass `filters={}` / `key="all"` to retrieve everything and
then narrow via `start_period`/`end_period`.

### "Too many observations, truncated"

Every data response is capped at `max_observations=200` by default. Increase
via `nbb_query(max_observations=1000)` or narrow the query with a period
window.

### Catalogue not found

If you run without the bundled `src/nbb_mcp/data/catalog/`, run
`mcp-nbb-build-catalog` once to populate it.

---

## Development

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full dev workflow. Short form:

```bash
pip install -e ".[dev]"
pytest                     # full suite (unit + integration + E2E)
pytest -m "not e2e"        # fast subset
ruff check src tests
mcp-nbb-build-catalog      # refresh the bundled catalogue
mcp-nbb                    # run the server (stdio)
```

CI runs on Linux, macOS and Windows with Python 3.11 and 3.12. See
[DATAFLOWS_CATALOG.md](DATAFLOWS_CATALOG.md) for the classified inventory.

---

## Security

Please report vulnerabilities privately — see [SECURITY.md](SECURITY.md).

## License

[MIT](LICENSE) — see `LICENSE` for the full text.

## Disclaimer

This project is **not affiliated with or endorsed by** the National Bank of
Belgium. It is an independent client of their public SDMX REST API. The
browser-like `User-Agent` and `Origin` headers are required by the upstream
WAF and used solely to access public statistical data. Users are responsible
for complying with NBB's terms of use.
