io.github.malkreide/swiss-snb-mcp
SNB data portal: exchange rates, balance sheet, policy rates, SARON, monetary aggregates
Open source Open in the app JSON README (API)
About
SNB data portal: exchange rates, balance sheet, policy rates, SARON, monetary aggregates
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- malkreide
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.4.5
- Open pull requests
- 1
- Last push
- 2026-09-01T08:59:57Z
- Repository state
- ativo
- Language
- Python
- License
- MIT
- Added
- 2026-08-29 04:00:27
- Updated
- 2026-08-29 04:00:27
- Origin id
io.github.malkreide/swiss-snb-mcp
README
> π¨π **Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)**
# π¦ swiss-snb-mcp

[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://modelcontextprotocol.io/)
[](https://data.snb.ch)

> MCP server for the Swiss National Bank (SNB) data portal β exchange rates, balance sheet, interest rates, SARON, monetary aggregates, banking statistics, and balance of payments.
[π©πͺ Deutsche Version](README.de.md)
<p align="center">
<img src="assets/demo.png" alt="Demo: Claude queries SNB banking statistics via MCP tool call" width="720">
</p>
---
## Overview
`swiss-snb-mcp` connects AI models to the official Swiss National Bank data portal at [data.snb.ch](https://data.snb.ch) via the Model Context Protocol (MCP). It provides structured access to SNB's public REST API β no authentication required.
The server covers three tiers of datasets, all confirmed against the live API:
**Phase 1 β Dedicated tools:**
- **Exchange rates** (monthly averages, month-end rates, annual averages) for the 28 currency series `devkum` publishes against CHF β including two USD forward rates, which are labelled as such
- **SNB balance sheet** (Bilanz): gold reserves, foreign exchange investments, banknotes in circulation, sight deposits, and totals
**Phase 2 β Via generic cube tools (`snb_get_cube_data` + `snb_get_cube_metadata`):**
- **SNB policy rate (Leitzins) and SARON** daily fixing, emergency facility rate, sight deposit rates
- **SARON compound rates**: Overnight, 1M, 3M, 6M
- **International money market rates**: SARON (CH), SOFR (USA), TONA (JP), SONIA (UK), β¬STR/EURIBOR (EZ)
- **Official central bank rates**: SNB, Fed, ECB, Bank of England, Bank of Japan
- **Monetary aggregates M1, M2, M3**: stock levels and year-on-year changes
**Phase 3 β Warehouse API (banking statistics) and balance of payments:**
- **Banking balance sheets** (BSTA BIL): total assets and liabilities by bank group β annual and monthly
- **Banking income statements** (BSTA EFR): operating income, expenses, taxes by bank group β annual
- **Balance of payments**: current account, capital account, financial account (quarterly)
- **International investment position**: components by investment type (quarterly)
- **Generic warehouse access**: raw access to any SNB Warehouse cube by ID
**Anchor demo query:** *"What was the EUR/CHF exchange rate during the 2015 Franc shock, and where does the SNB policy rate stand today compared to the Fed and ECB?"*
---
## Features
- π± **Exchange rates** β monthly CHF rates for EUR, USD, JPY, GBP, CNY and 23 more series
- π
**Annual averages** β year-by-year rates from 1980 onwards
- ποΈ **SNB balance sheet** β gold, foreign exchange investments, banknotes, sight deposits (monthly)
- π **Currency conversion** β convert any amount to CHF using official SNB rates
- π **Policy rate & SARON** β daily fixing, Leitzins, compound rates (1M/3M/6M)
- π **International rate comparison** β SNB, Fed, ECB, Bank of England, Bank of Japan side by side
- π° **Monetary aggregates** β M1, M2, M3 stock levels and year-on-year growth
- π¦ **Banking statistics** β balance sheets and income statements by bank group (12 groups)
- π **Balance of payments** β current account, IIP, and international investment position
- π **Generic cube access** β query any SNB data cube or Warehouse cube by ID
- π **No authentication required** β fully public SNB data portal
---
## Prerequisites
- Python 3.11+
- `uv` or `pip`
- MCP-compatible client (Claude Desktop, Claude Code, or any MCP host)
---
## Installation
**Via uvx (recommended β no permanent installation needed):**
```bash
uvx swiss-snb-mcp
```
**Via pip:**
```bash
pip install swiss-snb-mcp
```
**From source:**
```bash
git clone https://github.com/malkreide/swiss-snb-mcp.git
cd swiss-snb-mcp
pip install -e .
```
---
## Usage / Quickstart
**Claude Desktop β add to `claude_desktop_config.json`:**
```json
{
"mcpServers": {
"swiss-snb-mcp": {
"command": "uvx",
"args": ["swiss-snb-mcp"]
}
}
}
```
**Config file locations:**
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
Try it immediately in Claude Desktop:
> *"What is the current EUR/CHF exchange rate according to the SNB?"*
> *"Show me the SNB balance sheet for the last 12 months β gold and foreign reserves."*
---
## Configuration
No API key or authentication required. The SNB data portal is fully public.
**Optional environment variable:**
| Variable | Default | Description |
|---|---|---|
| `SNB_TIMEOUT` | `15` | HTTP request timeout in seconds |
---
## Available Tools
### Phase 1 β Dedicated Tools
| Tool | Description |
|---|---|
| `snb_get_exchange_rates` | Monthly CHF rates for EUR, USD, JPY, GBP, CNY and 22 more currencies |
| `snb_get_annual_exchange_rates` | Annual average rates, data from 1980 |
| `snb_get_balance_sheet` | SNB Bilanz positions in millions CHF (monthly) |
| `snb_convert_currency` | Convert any amount to CHF using official SNB rates |
### Phase 2 β Generic Cube Tools
| Tool | Description |
|---|---|
| `snb_get_cube_data` | Generic access to any SNB cube by ID |
| `snb_get_cube_metadata` | Inspect dimensions and filter values of any cube |
### Phase 3 β Warehouse API (Banking Statistics) and Balance of Payments
| Tool | Description |
|---|---|
| `snb_get_banking_balance_sheet` | Banking balance sheets by bank group (monthly/annual, assets/liabilities) |
| `snb_get_banking_income` | Banking income statements by bank group (annual) |
| `snb_get_balance_of_payments` | Balance of payments and international investment position (quarterly) |
| `snb_get_warehouse_data` | Generic access to any SNB Warehouse cube by ID |
| `snb_get_warehouse_metadata` | Inspect dimensions and last update of a Warehouse cube |
### Resources (static catalogs)
Discovery aids served as MCP resources rather than tools so they don't crowd the tool manifest:
| URI | Description |
|---|---|
| `data://snb/currencies` | All 28 currency IDs with labels and units |
| `data://snb/balance-sheet-positions` | Asset and liability position IDs |
| `data://snb/cubes` | All verified Cube-API IDs (Phase 1β2) + discovery guide |
| `data://snb/warehouse-cubes` | Available Warehouse cube IDs (BSTA) |
| `data://snb/bank-groups` | All 12 bank group IDs with labels |
### Example Use Cases
| Query | Tool |
|---|---|
| *"What is the current EUR/CHF rate?"* | `snb_get_exchange_rates` |
| *"Convert CHF 10,000 to USD"* | `snb_convert_currency` |
| *"Show SNB gold reserves over the last year"* | `snb_get_balance_sheet` |
| *"What is the current SNB policy rate?"* | `snb_get_cube_data` (cube: `snbgwdzid`) |
| *"How do SNB, Fed and ECB rates compare?"* | `snb_get_cube_data` (cube: `snboffzisa`) |
| *"What is the SARON 3M compound rate?"* | `snb_get_cube_data` (cube: `zirepo`) |
| *"How fast is M3 money supply growing?"* | `snb_get_cube_data` (cube: `snbmonagg`) |
| *"Total assets of all Swiss banks?"* | `snb_get_banking_balance_sheet` |
| *"Income statement of cantonal banks?"* | `snb_get_banking_income` (bank_group: `G10`) |
| *"Switzerland's balance of payments?"* | `snb_get_balance_of_payments` |
| *"Which cubes are available?"* | resource `data://snb/cubes` |
β [More use cases by audience](EXAMPLES.md) β
---
## Safety & Limits
| Aspect | Details |
|--------|---------|
| **Access** | Read-only (`readOnlyHint: true`) β the server cannot modify or delete any data |
| **Personal data** | No personal data β all sources are aggregated, public macroeconomic statistics |
| **Rate limits** | SNB Warehouse API has WAF protection (HTTP 503 after ~100 rapid requests); the server retries automatically with exponential backoff (max 3 retries, delays 2/4/8s) |
| **Timeout** | 15 seconds per API call |
| **Authentication** | No API keys required β both APIs (`/api/cube/` and `/api/warehouse/cube/`) are publicly accessible |
| **Data source** | [Swiss National Bank β data.snb.ch](https://data.snb.ch) |
| **Terms of Service** | Subject to SNB's [Terms of Use](https://www.snb.ch/en/the-snb/mandates-goals/legal-framework/terms-of-use) and [Copyright](https://www.snb.ch/en/the-snb/mandates-goals/legal-framework/copyright); data is free for non-commercial use with source attribution |
---
## Architecture
```
βββββββββββββββββββ βββββββββββββββββββββββββββββ ββββββββββββββββββββββββ
β Claude / AI ββββββΆβ Swiss SNB MCP ββββββΆβ data.snb.ch β
β (MCP Host) βββββββ (MCP Server) βββββββ β
βββββββββββββββββββ β β β /api/cube/ (JSON) β
β 11 Tools Β· 5 Resources β β /api/warehouse/ β
β Stdio | SSE β β Public Β· No Auth β
β β β β
β Phase 1: dedicated tools β β Exchange rates β
β Phase 2: generic cubes β β Balance sheet β
β Phase 3: warehouse + β β Interest rates β
β banking stats β β Banking statistics β
βββββββββββββββββββββββββββββ β Balance of payments β
ββββββββββββββββββββββββ
```
### Cube Discovery Pattern
The SNB API follows a consistent cube-based structure. Read the `data://snb/cubes` resource to explore verified cube IDs, then `snb_get_cube_metadata` to inspect dimensions before querying with `snb_get_cube_data`. Phase 3 adds the Warehouse API (`/api/warehouse/cube/`) for granular banking statistics β start from the `data://snb/warehouse-cubes` and `data://snb/bank-groups` resources.
---
## Project Structure
```
swiss-snb-mcp/
βββ src/
β βββ swiss_snb_mcp/
β βββ __init__.py
β βββ server.py # Core tools and FastMCP server (Phase 1β2 + BoP)
β βββ warehouse.py # Warehouse API tools (Phase 3: banking statistics)
βββ scripts/
β βββ record_fixtures.py # records tests/fixtures/* from data.snb.ch
βββ tests/
β βββ fixtures/ # recorded responses + PROVENANCE.md (date, rule, SHA-256)
β βββ fixture_data.py # loader β a missing name is an error, not an empty dict
β βββ test_unit.py # respx-mocked unit tests (run in CI)
β βββ test_live_scenarios.py # 20 live scenarios for Phase 1β2 (nightly)
β βββ test_live_warehouse.py # 20 live scenarios for Phase 3 (nightly)
βββ pyproject.toml # Build configuration (hatchling)
βββ CHANGELOG.md
βββ CONTRIBUTING.md # Contribution guidelines (English)
βββ CONTRIBUTING.de.md # German version
βββ SECURITY.md # Security policy & posture (English)
βββ SECURITY.de.md # German version
βββ LICENSE
βββ README.md # This file (English)
βββ README.de.md # German version
```
---
## Known Limitations
- **Exchange rates:** Monthly averages only β no intraday or daily rates available via this API
- **Balance sheet:** Monthly data; some positions may have a publication lag of 1β2 months
- **Cube access:** Cube IDs are not officially documented by the SNB β read the `data://snb/cubes` resource for verified IDs
- **Historical depth:** Coverage varies by series; exchange rates go back to 1980, some interest rate series start later
- **No forecasts:** All data is historical/realised β SNB does not publish forecasts via this API
---
## MCP Protocol Version
This server speaks **two protocol eras** over the same endpoint. The client's
first request on a connection decides which one applies; a later claim from the
other era is refused.
| Era | Revision | Who reaches it |
|---|---|---|
| `initialize` handshake | `2024-11-05` β¦ **`2025-11-25`** | What today's clients speak. The server answers with the revision asked for, or with the `2025-11-25` ceiling when the request asks for something newer. |
| Per-request envelope | **`2026-07-28`** | A request carrying the `2026-07-28` `_meta` envelope opens a modern connection. |
Both revisions are pinned in
[`tests/test_protocol_version.py`](tests/test_protocol_version.py) and asserted
against the installed SDK, so a Dependabot bump of `mcp` cannot move either one
silently. This server builds no ASGI app to send an `initialize` through, so
the gate asserts the SDK constants rather than a measured response β the
weaker form, named rather than left unsaid.
Note that the SDK's `LATEST_PROTOCOL_VERSION` is an alias for the **modern**
era, not for the handshake era β pinning against it alone would leave the era
that current clients actually negotiate free to drift.
**Update policy.** When the gate fails, do not edit the constant blindly: read
the spec changelog between the two revisions, verify the server still behaves,
then move the constant, this section, `README.de.md` and
[`CHANGELOG.md`](CHANGELOG.md) together.
---
## Testing
```bash
# Unit tests (no API key required)
PYTHONPATH=src pytest tests/ -m "not live"
# Integration tests (live SNB API)
PYTHONPATH=src pytest tests/ -m "live"
# Re-record the fixtures from data.snb.ch (writes tests/fixtures/PROVENANCE.md)
python scripts/record_fixtures.py
```
The unit-test payloads are **recorded, not invented**. Source, retrieval date,
selection rule and SHA-256 per file are in
[`tests/fixtures/PROVENANCE.md`](tests/fixtures/PROVENANCE.md). A hand-written
mock encodes its author's assumption and can therefore never refute it β
production code and fixture come from the same head, so where both are wrong,
both are wrong together and the suite stays green. Each file keeps **every
series** and only shortens the value lists: the code reasons about the
dimensions and merely displays the values, so cutting "the first N series"
would have hidden exactly what three of the findings depended on.
---
## Changelog
See [CHANGELOG.md](CHANGELOG.md)
---
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on reporting issues, suggesting new SNB cube IDs, and contributing code.
---
## Security
This server is read-only, processes no personal data, and talks only to `data.snb.ch`. See [SECURITY.md](SECURITY.md) for the full security posture, audit results, and how to report a vulnerability.
---
## License
MIT License β see [LICENSE](LICENSE)
---
## Author
Hayal Oezkan Β· [github.com/malkreide](https://github.com/malkreide)
---
## Credits & Related Projects
- **Data:** [Swiss National Bank](https://data.snb.ch) β SNB data portal (public REST API)
- **Protocol:** [Model Context Protocol](https://modelcontextprotocol.io/) β Anthropic / Linux Foundation
- **Related:** [zurich-opendata-mcp](https://github.com/malkreide/zurich-opendata-mcp) β MCP server for Zurich city open data
- **Related:** [swiss-transport-mcp](https://github.com/malkreide/swiss-transport-mcp) β Swiss public transport MCP server
- **Portfolio:** [Swiss Public Data MCP Portfolio](https://github.com/malkreide)
<!-- mcp-name: io.github.malkreide/swiss-snb-mcp -->
<!-- BEGIN GENERATED: install -->
## Installation
Run via [`uv`](https://docs.astral.sh/uv/)'s `uvx` β no clone or manual install needed. Add to your MCP client config (`mcpServers` for Claude Desktop, Cursor and Windsurf; use a top-level `servers` key for VS Code in `.vscode/mcp.json`):
```json
{
"mcpServers": {
"swiss-snb-mcp": {
"command": "uvx",
"args": [
"swiss-snb-mcp"
]
}
}
}
```
<!-- END GENERATED: install -->