MCP server for Swiss federal finances (EFV): budget, debt, forecasts & spending by department
claude mcp add swiss-efv-mcp -- uvx swiss-efv-mcp{
"mcpServers": {
"swiss-efv-mcp": {
"command": "uvx",
"args": ["swiss-efv-mcp"]
}
}
}MCP Servers overview
> 🇨🇭 Part of the [**Swiss Public Data MCP Portfolio**](https://github.com/malkreide/swiss-public-data-mcp) — open-source MCP servers connecting AI agents to Swiss public and open data.
> This is a private project. It is independent of any employer or institutional affiliation.
# 🏛️ swiss-efv-mcp
[](CHANGELOG.md)
[](https://github.com/malkreide/swiss-efv-mcp/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/)
[](https://modelcontextprotocol.io/)
[](#architecture-decision)
[](https://github.com/malkreide/swiss-public-data-mcp)
> MCP server for Swiss federal finances (EFV): budget, debt, forecasts and spending by task and institution.
[🇩🇪 Deutsche Version](README.de.md)
## Overview
This server closes the fiscal gap in the portfolio's Economics & Finance cluster.
`swiss-snb-mcp` already covers monetary policy; `swiss-efv-mcp` adds the **state
budget** — federal revenue, expenditure, balance, debt ratios (with forecasts to
2029), a hierarchical budget drill-down, and spending by department. Data comes
from the Eidgenössische Finanzverwaltung (EFV) via opendata.swiss (OGD Schweiz).
## Features
- Five read-only tools over the curated EFV FS/GFS dump files.
- Headline series 1990–2029 per household (bund, ktn, gdn, staat, sv) and model
(FS / GFS); every point carries `is_projection` so actuals and plan/forecast
years are unambiguous.
- Hierarchical federal-budget drill-down and spending by department / unit.
- 24 h TTL in-memory cache with stale-serve fallback; retry with exponential
backoff (2/4/8 s); `dump_status` never returns empty silently.
- Dual transport: `stdio` (local) and SSE (cloud).
- No authentication required — public open-government data (No-Auth-First).
## 🎯 Anchor Demo Query
> *"How has the federal balance developed since the SNB rate turnaround in 2022 —
> and which task areas absorbed the growth in spending?"*
```
fiscal_headline(variable="saldo", household="bund", year_from=2021)
fiscal_budget_breakdown(topic="Ausgaben nach Aufgabengebiet", level=2)
```
Cross-read with `swiss-snb-mcp`, this connects the interest-rate cycle to the
federal deficit — something neither server can answer alone.
## Prerequisites
- Python 3.11+
- [`uv` / `uvx`](https://docs.astral.sh/uv/) (recommended) or `pip`
- Network access to `data.finance.admin.ch` and `efv.admin.ch` — no API key needed
## Installation
```bash
uvx swiss-efv-mcp # zero-install run (once published to PyPI)
# or
pip install swiss-efv-mcp
```
Claude Desktop (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"swiss-efv": {
"command": "uvx",
"args": ["swiss-efv-mcp"]
}
}
}
```
## Quickstart
```bash
# Run locally over stdio (default transport)
uvx swiss-efv-mcp
# From a checkout, without installing
PYTHONPATH=src python -m swiss_efv_mcp
```
## Configuration
All configuration is loaded once into a typed `Settings` object
(`pydantic-settings`). The legacy unprefixed names below keep working; the
canonical names use the `EFV_MCP_` prefix. Defaults are safe for local use.
| Variable | Default | Purpose |
|-------------|-------------|----------------------------------------------------------------------------|
| `TRANSPORT` | `stdio` | Transport: `stdio` (Claude Desktop) or `sse` / `streamable-http` (cloud) |
| `HOST` | `127.0.0.1` | Bind host (SSE only). Loopback by default; set `0.0.0.0` **only** in a container |
| `PORT` | `8000` | Bind port (SSE only) |
| `EFV_MCP_LOG_LEVEL` | `INFO` | structlog level (JSON to stderr) |
| `EFV_MCP_CORS_ORIGINS` | `[]` | SSE only: explicit allowed browser origins (default-deny; comma-separated or JSON) |
| `EFV_MCP_OTEL_ENABLED` | `false`| Enable OpenTelemetry tracing (requires the `otel` extra); standard `OTEL_*` env vars configure export |
Cloud (Render / Railway):
```bash
TRANSPORT=sse PORT=8000 swiss-efv-mcp # exposes /sse
```
## Available Tools
| Tool | Purpose |
|---|---|
| `fiscal_headline` | Revenue / expenditure / balance / debt ratios over 1990–2029, per household and model; every point flags `is_projection` |
| `fiscal_budget_breakdown` | Hierarchical federal budget by topic (Ausgaben nach Art / nach Aufgabengebiet, Einnahmen, Bilanz, …) |
| `fiscal_by_institution` | Spending per department / administrative unit since 2007 (Personalausgaben, Informatik, external services, FTE) |
| `fiscal_list_dimensions` | Discover valid parameter values — call this first to build correct arguments |
| `fiscal_status` | Cache freshness and upstream health per dataset; never returns empty silently |
| `dump_status` | **Deprecated** alias of `fiscal_status` (kept for backward compatibility; removed in a future minor) |
All tools are **read-only**: each is annotated `readOnlyHint: true`,
`destructiveHint: false`, only issues HTTP GETs against the EFV dump files, and
has no write, send, or filesystem capability.
**MCP primitives.** This server uses only the **Tools** primitive. The EFV data
are sliced live from cached dumps with no stable resource hierarchy to expose as
*Resources*, and there are no server-authored *Prompts*. The five tools are small
and closely related, so they live in a single `server.py` rather than a `tools/`
package.
## Architecture
```
┌──────────────────────────────┐
Claude / Agent ──▶ │ swiss-efv-mcp (FastMCP) │
│ 5 tools · Pydantic v2 env. │
└───────────────┬──────────────┘
│ fetch + retry + TTL cache
┌───────────────────────┴───────────────────────┐
▼ ▼
data.finance.admin.ch efv.admin.ch/dam
fs_dashboard/main_extern.csv bundeshaushalt_de.csv
(headline, 1990–2029) institutionen_de.csv
```
## Architecture decision
This server uses **Architecture C (Dump-first)**.
Rationale (verified live on 2026-07-24):
- The EFV FS/GFS dashboard has **no filtered query API**; it serves static CSV
dumps that its front-end filters in the browser.
- Three curated files are small enough to fetch-and-cache whole (516 KB / 5 MB /
1 MB). They cover the headline aggregates, the hierarchical budget and the
by-institution view — i.e. the answerable questions.
- The full detail cubes (`standardauswertung.csv` 157 MB, `fir_art_funk.csv`
1.23 GB) are **out of scope for v0.1.0**; loading them per request is not
viable. A future Phase 2 would pre-process them into SQLite/Parquet.
Consequences:
- Files are cached in memory with a 24 h TTL; stale cache is preferred over an
empty response when upstream is down.
- Retry with exponential backoff on all HTTP; `dump_status` always returns a
readable state.
## Project Structure
```
swiss-efv-mcp/
├── src/swiss_efv_mcp/
│ ├── __init__.py
│ ├── __main__.py # entry point; dual transport (stdio / SSE+CORS)
│ ├── client.py # dump-first data layer: egress allow-list, retry, UA, TTL cache
│ ├── logging_config.py # structlog JSON to stderr
│ ├── models.py # Pydantic v2 envelopes (source + provenance)
│ ├── server.py # 5 FastMCP tools (annotated) + testable *_impl functions
│ └── settings.py # typed pydantic-settings config
├── tests/ # respx mock tests + hardening tests + @pytest.mark.live
├── docs/ # network-egress.md + accepted-risk ADRs
├── audits/ # MCP best-practice audit runs (findings, report, summary)
├── README.md · README.de.md · CHANGELOG.md · SECURITY.md · CONTRIBUTING.md
├── Dockerfile · server.json · LICENSE
└── pyproject.toml
```
## Safety & Limits
- **Read-only.** Every tool is annotated `readOnlyHint: true`, only issues HTTP
GETs against the EFV dump files, and has no write, send, or filesystem capability.
- **Egress allow-list.** An immutable `ALLOWED_HOSTS` frozenset + `assert_host_allowed()`
is enforced before every request (HTTPS-only, two fixed EFV hosts). URLs are
hardcoded constants; no user input builds a URL. See [`docs/network-egress.md`](docs/network-egress.md).
- **TLS on.** httpx certificate verification is on by default and never disabled.
- **No credentials.** The endpoints are public OGD; no API keys or secrets are
stored or forwarded. A browser `User-Agent` is injected because the endpoints
`403` the default httpx/curl UA (see Known limitations) — do not remove it.
- **Error masking.** `mask_error_details=True` plus client-side masking keep raw
upstream/internal detail out of tool results; full detail goes only to the
structlog stderr log.
- **Input bounds.** Tool arguments carry explicit Pydantic constraints (year
`1900–2100`, `level 1–8`, string `max_length`).
- **Graceful degradation.** Retry with exponential backoff (2/4/8 s); a stale
cache is served over an empty response; `dump_status` always returns a readable
state and never a silent empty.
- **Loopback + default-deny CORS.** SSE binds to `HOST`, default `127.0.0.1`; set
`HOST=0.0.0.0` **only** inside a container (the provided [`Dockerfile`](Dockerfile) does).
Browser origins must be listed explicitly via `EFV_MCP_CORS_ORIGINS`.
- **Audited.** Reviewed against the portfolio MCP best-practice catalogue
(44 appWhat people ask about swiss-efv-mcp
What is malkreide/swiss-efv-mcp?
+
malkreide/swiss-efv-mcp is mcp servers for the Claude AI ecosystem. MCP server for Swiss federal finances (EFV): budget, debt, forecasts & spending by department It has 0 GitHub stars and was last updated today.
How do I install swiss-efv-mcp?
+
You can install swiss-efv-mcp by cloning the repository (https://github.com/malkreide/swiss-efv-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is malkreide/swiss-efv-mcp safe to use?
+
malkreide/swiss-efv-mcp has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.
Who maintains malkreide/swiss-efv-mcp?
+
malkreide/swiss-efv-mcp is maintained by malkreide. The last recorded GitHub activity is from today, with 0 open issues.
Are there alternatives to swiss-efv-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy swiss-efv-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/malkreide-swiss-efv-mcp)<a href="https://claudewave.com/repo/malkreide-swiss-efv-mcp"><img src="https://claudewave.com/api/badge/malkreide-swiss-efv-mcp" alt="Featured on ClaudeWave: malkreide/swiss-efv-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!