termdat-mcp
MCP server for TERMDAT, the terminology database of the Swiss Federal Administration, giving AI agents officially validated designations of Swiss authorities, departments, and legal acts across DE/FR/IT/EN with source references and validation status.
README
🇨🇭 Part of the Swiss Public Data MCP Portfolio — 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.
🏷️ termdat-mcp
Official, validated Swiss administrative designations across DE / FR / IT / EN — with source references and validation status.
Overview
MCP server for TERMDAT, the terminology database of the Swiss Federal Administration, maintained by the Federal Chancellery. It gives an AI agent the officially validated designations of Swiss authorities, departments and legal acts across DE / FR / IT / EN — with source references and validation status.
Discovered through i14y-mcp, which catalogues TERMDAT as data service ff0c37eb-2f7c-4ff6-996e-d22b77bf52fc.
What this is — and what it is not. TERMDAT is not a subject dictionary. It is a certified name-plate archive: it will not tell you what «Sonderpädagogik» means, but it will tell you the official name of the authority responsible for it, and what that authority is called in French.
Measured coverage (live, 2026-07-19, German search over the Terminus field):
| Search term | Hits |
|---|---|
| Departement | 20 |
| Bildung | 13 |
| Verordnung | 8 |
| Schule | 5 |
| Behörde | 4 |
| Sonderpädagogik | 3 |
| Volksschule · Lehrperson · Schulleitung · Unterricht · Kindergarten | 0 |
The thirteen «Bildung» hits are organisational names — Bildungsdirektion, Erziehungsdepartement, Departement für Volkswirtschaft und Bildung — not pedagogical concepts. Plan accordingly: this server is strong for authority naming, official titles and abbreviations, and largely silent on domain vocabulary.
Features
- Seven read-only tools over the official TERMDAT public v2 API.
- Official designations across DE / FR / IT / EN, with source reference and validation status on every response.
- Communication QA: check up to 25 terms in one call against validated designations.
- Vocabulary cache (24 h TTL) for the 140 collections and 23 classifications, with stale-serve fallback.
- Retry with exponential backoff (2/4/8 s); explicit
MaxEntryCountto avoid silent truncation. - Dual transport:
stdio(local) and SSE (cloud). - No authentication required — public, unauthenticated API (No-Auth-First).
🎯 Anchor demo query
«What are the official French and Italian names of the education directorates of the German-speaking cantons?»
Resolved with list_classifications → search_terms → translate_term.
Prerequisites
- Python 3.10+
uv/uvx(recommended) orpip- Network access to
api.termdat.bk.admin.ch— no API key needed
Installation
uvx termdat-mcp
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"termdat": {
"command": "uvx",
"args": ["termdat-mcp"]
}
}
}
Quickstart
# Run locally over stdio (default transport)
uvx termdat-mcp
# From a checkout, without installing
PYTHONPATH=src python -m termdat_mcp
Configuration
All configuration is via environment variables. Defaults are safe for local use.
| Variable | Default | Purpose |
|---|---|---|
TERMDAT_MCP_TRANSPORT |
stdio |
Transport: stdio (local) or sse / streamable-http / http (cloud) |
HOST |
127.0.0.1 |
Bind host (SSE transport only). Loopback by default; set HOST=0.0.0.0 only inside a container |
PORT |
8000 |
Bind port (SSE transport only) |
TERMDAT_MCP_CORS_ORIGINS |
[] |
SSE only: explicit allowed browser origins (default-deny; never a wildcard in production) |
TERMDAT_MCP_LOG_LEVEL |
INFO |
structlog level (JSON to stderr) |
TERMDAT_MCP_VOCAB_TTL |
86400 |
Vocabulary cache TTL in seconds |
Configuration is loaded once into a typed Settings object (pydantic-settings).
Cloud (Render / Railway):
TERMDAT_MCP_TRANSPORT=sse PORT=8000 termdat-mcp # exposes /sse
Available Tools
| Tool | Purpose |
|---|---|
search_terms |
Search TERMDAT with field flags, collection and classification filters |
translate_term |
Official equivalent of an administrative term in another national language |
check_terms |
Communication QA: check up to 25 terms against validated designations |
get_entries |
Fetch known entries by numeric ID |
list_collections |
The ~140 terminology collections (filter values) |
list_classifications |
The 23 subject classifications, e.g. BILD = education |
api_status |
Availability; never returns silently empty |
All tools are annotated readOnlyHint: true, destructiveHint: false.
MCP primitives. This server uses only the Tools primitive. TERMDAT answers
are live queries with no stable resource hierarchy to expose as Resources, and
there are no server-authored Prompts. The seven tools are small and closely
related, so they live in a single server.py rather than a tools/ package.
Architecture
┌─────────────────┐ stdio / SSE ┌──────────────────────────┐
│ MCP host │ ───────────────► │ termdat-mcp │
│ (Claude, IDE) │ ◄─────────────── │ │
└─────────────────┘ │ vocabulary cache (24 h) │
│ 140 collections │
│ 23 classifications │
└────────────┬─────────────┘
│ httpx + retry (2/4/8 s)
▼
https://api.termdat.bk.admin.ch/v2
├── /Search (SearchTerm + InLanguageCode)
├── /Entry (EntryIds)
├── /Collection (140 values)
└── /Classification ( 23 values, incl. BILD)
Architecture decision
This server uses Architecture A (live API only), with caching limited to the two controlled vocabularies.
Rationale (verified live on 2026-07-19):
- The API publishes a complete OpenAPI 3.0.4 specification at
/swagger/v2/swagger.jsonand declares no security schemes — unauthenticated access, No-Auth-First satisfied. - Server-side search works properly, including 11 field flags and filters by collection and classification. There is no reason to mirror the database locally, and no bulk dump is offered.
/Collection(140 entries) and/Classification(23 entries) change rarely and are needed to make filter arguments legible to an agent, so they are cached with a 24-hour TTL and a stale-serve fallback.
Consequences:
- Every search is a live call;
provenanceislive_apiexcept for vocabulary lookups. - Validation errors arrive as clean RFC 9110 payloads and are surfaced rather than swallowed.
Project Structure
termdat-mcp/
├── src/termdat_mcp/
│ ├── __init__.py
│ ├── __main__.py # entry point; dual transport (stdio / SSE)
│ ├── client.py # httpx client, retry, vocabulary cache
│ ├── models.py # Pydantic models
│ └── server.py # MCP tool definitions
├── tests/
│ ├── test_client.py # offline, respx-mocked
│ └── test_live.py # hits the real TERMDAT API
├── README.md
├── README.de.md
├── CHANGELOG.md
├── LICENSE
└── pyproject.toml
Safety & Limits
- Read-only. Every tool is annotated
readOnlyHint: true,destructiveHint: false; the server never writes to TERMDAT. - No credentials handled. The API is unauthenticated; the server stores and forwards no secrets.
- No silent empties.
api_statusand error paths surface failures instead of returning an empty result that looks complete. - Truncation is explicit.
MaxEntryCountis always sent andtruncatedis reported (see Known Limitations). - Licence caution. TERMDAT content carries no licence statement; every response repeats this in
source. Clarify terms with the Federal Chancellery before republishing downstream. - Egress allow-list. Requests can only reach
api.termdat.bk.admin.ch(HTTPS), enforced before every call by a frozenALLOWED_HOSTSset — no user input can redirect egress. Seedocs/network-egress.md. - Loopback by default. SSE binds to
127.0.0.1;0.0.0.0is an explicit container opt-in that warns on stderr. SSE also sets default-deny CORS, exposing onlyMcp-Session-Id. - Errors are masked. Upstream/internal error detail is logged to stderr (structlog JSON) and never returned to the model.
- Accepted risks (ADRs): DNS pinning (ADR 0001) and stateful load balancing (ADR 0002) are deliberately deferred — low risk for a single-instance, single-host, no-auth server.
- Container. A hardened, non-root
Dockerfileis provided for SSE deployments.
Known Limitations
- Administrative scope only. See the coverage table above.
check_termsreturnsnot_found, never «incorrect», precisely because absence from TERMDAT is not evidence of error. MaxEntryCounthas a silent default of ~25. Omitting it looks like a complete result set. This server always sends the parameter explicitly and reportstruncated.- Multilingual variants are opt-in. Without
OutLanguageCode, entries return German designations only.translate_termsets it for you. - No licence statement. The I14Y catalogue record carries
license: null. Clarify terms with the Federal Chancellery before republishing TERMDAT content downstream. Every response repeats this insource. - Entry-level language coverage varies. Not every entry exists in all four languages;
translate_termomits entries without a target-language variant rather than inventing one.
Live probe findings (2026-07-19)
| Endpoint | HTTP | Status | Note |
|---|---|---|---|
/swagger/v2/swagger.json |
200 | ✅ | OpenAPI 3.0.4, 132 KB, securitySchemes: [] |
/v2/Search |
200 | ✅ | requires SearchTerm, InLanguageCode, ReturnType |
/v2/Entry |
200 | ✅ | requires EntryIds, InLanguageCode |
/v2/Collection |
200 | ✅ | 140 values |
/v2/Classification |
200 | ✅ | 23 values, incl. BILD (education) |
/v2/ (root) |
404 | ❌ | no index; the I14Y record points here |
InLanguageCode=deu / de-CH |
400 | ❌ | only two-letter ISO codes, case-insensitive |
Probe note: a correction worth recording. An earlier probe concluded that OutLanguageCode filters the result set, because adding it appeared to drop all hits. It does not. Two variables had been changed at once — the parameter and the search term — and the term itself («Volksschule») genuinely has zero hits. Verified afterwards across four broad terms: result counts are identical with and without OutLanguageCode; the parameter is purely additive. A regression test (test_out_language_is_additive_not_filtering) now guards this.
Rule of thumb: change one variable per probe call, or the API will confess to a crime it did not commit.
Project Phase
This server is in Phase 1 (read-only). All tools are annotated
readOnlyHint: true / destructiveHint: false and only ever query the public
TERMDAT v2 API — there are no write, send, or filesystem capabilities.
| Phase | Scope | Status |
|---|---|---|
| 1 — Read-only | Search, translate and check administrative designations | ✅ current |
| 2 — Write-capable | (none planned) | — |
| 3 — Multi-agent | (none planned) | — |
A transition to a later phase would require a re-audit and human-in-the-loop controls before any write-capable tool is added.
MCP Protocol Version
The protocol version is negotiated at the initialize handshake by the
mcp Python SDK (pinned to >=1.2.0 in
pyproject.toml). The SDK is kept current via monthly Dependabot PRs
(.github/dependabot.yml); protocol-relevant bumps are noted in
CHANGELOG.md.
Testing
PYTHONPATH=src pytest tests/ -m "not live" # offline, respx-mocked
PYTHONPATH=src pytest tests/ -m live # hits the real API
PYTHONPATH=src ruff check src tests
Changelog
See CHANGELOG.md.
Security
See SECURITY.md for the security posture, hardening controls, and how to report a vulnerability.
Contributing
Issues and pull requests are welcome. Please keep tools read-only, run ruff check and the offline test suite before submitting, and add a CHANGELOG.md entry under [Unreleased] for user-facing changes.
Maintainers: see PUBLISHING.md for the step-by-step PyPI release process (Trusted Publishing via GitHub Release).
License
MIT for this server — see LICENSE. TERMDAT content remains subject to the Federal Chancellery's terms.
Author
Hayal Oezkan · github.com/malkreide
Credits & Related Projects
- Data: TERMDAT, Swiss Federal Chancellery (BK).
- Catalogue entry: I14Y data service
ff0c37eb… - Discovery server: i14y-mcp
- Portfolio index: swiss-public-data-mcp
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。