termdat-mcp
This server provides read-only MCP tools for querying TERMDAT, the Swiss Federal Administration's official terminology database, to retrieve validated administrative designations in German, French, Italian, and English.
search_terms: Search TERMDAT for official names of authorities, departments, and legal acts using Lucene syntax, with filters by collection/classification, language, and field flags.
translate_term: Get the official equivalent of an administrative term in another national language (e.g., DE→FR), including preferred and alternative designations.
check_terms: Communication QA — verify up to 25 terms against validated designations, reporting each as validated, found_unvalidated, or not_found.
get_entries: Fetch known TERMDAT entries by numeric ID with full language variants.
list_collections: List the ~140 terminology collections for use as filter values.
list_classifications: List the 23 subject classifications (e.g., BILD = education) for use as filter values.
api_status: Check availability of the TERMDAT API; never returns silently empty.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@termdat-mcpWhat is the French term for 'Bundesamt für Gesundheit'?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
🇨🇭 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.
Related MCP server: swiss-ip-mcp
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 Streamable HTTP (cloud). Both serve MCP protocol revision2026-07-28.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.
Demo
Prerequisites
Python 3.10+
Network access to
api.termdat.bk.admin.ch— no API key needed
Installation
uvx termdat-mcpClaude 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_mcpConfiguration
All configuration is via environment variables. Defaults are safe for local use.
Variable | Default | Purpose |
|
| Transport: |
|
| Bind host (HTTP transport only). Loopback by default; set |
|
| Bind port (HTTP transport only) |
|
| HTTP only: explicit allowed browser origins (default-deny; never a wildcard in production). Comma-separated, e.g. |
|
| HTTP only: inbound |
|
| structlog level (JSON to stderr) |
|
| Vocabulary cache TTL in seconds |
Configuration is loaded once into a typed Settings object (pydantic-settings).
List variables. TERMDAT_MCP_CORS_ORIGINS and TERMDAT_MCP_ALLOWED_HOSTS
take a comma-separated list — the recommended spelling, and the one the
rest of the Swiss Public Data MCP portfolio uses:
TERMDAT_MCP_ALLOWED_HOSTS="mcp.example.ch,mcp.example.ch:443"A JSON list (["mcp.example.ch"]) stays valid. Surrounding whitespace and
empty entries are dropped in both forms, so a trailing comma is harmless. A
single value needs no brackets.
TERMDAT_MCP_ALLOWED_HOSTS matters in the cloud. The SDK leaves
DNS-rebinding protection off while no allow-list is configured. Bind to
0.0.0.0 in a container without this variable and the Host header is never
validated — the server cannot derive its own public name from the bind address,
and a guessed list would reject every real request with HTTP 421. It warns on
startup when it has to fall back to that state.
Cloud (Render / Railway):
TERMDAT_MCP_TRANSPORT=streamable-http PORT=8000 termdat-mcp # exposes /mcpAvailable Tools
Tool | Purpose |
| Search TERMDAT with field flags, collection and classification filters |
| Official equivalent of an administrative term in another national language |
| Communication QA: check up to 25 terms against validated designations |
| Fetch known entries by numeric ID |
| The ~140 terminology collections (filter values) |
| The 23 subject classifications, e.g. |
| 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 / HTTP ┌──────────────────────────┐
│ 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 / Streamable HTTP)
│ ├── 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.tomlSafety & 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).Terms of use are stated, not guessed. Every response repeats them in
source: reuse and republication require the sourcewww.termdat.chto be named, and the Federal Chancellery's Terminology Section to be informed of purpose and manner beforehand (statement of 2026-08-21).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. The HTTP transport binds to
127.0.0.1;0.0.0.0is an explicit container opt-in that warns on stderr. It 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 hosted 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.CollectionIds/ClassificationIdshave a silent default ofVARIA. An ID-less/v2/Searchcovers one of 23 subject areas — the residual one — and reports the truncated result as a normal empty answer. This server sends the full classification set unless you narrow it explicitly. See issue #11.SearchTermis Lucene, and matching is on whole words. «Quellensteuer» does not match «Quellensteuerverordnung»; «Quellensteuer*» does.*,?and~are available — on an empty result, retry with a wildcard before concluding the term is absent.Field.*flags default to true where unsent.Terminus,Name,AbbreviationandPhraseologyare on unless explicitly disabled, so a partial flag set can only widen a search. This server sends all eleven flags explicitly, which is what makesfieldsable to narrow.Multilingual variants are opt-in. Without
OutLanguageCode, entries return German designations only.translate_termsets it for you.The public API exposes less than the website — deliberately. Not a scope setting, and not a defect: asked directly, the Federal Chancellery's Terminology Section confirmed on 2026-08-21 that the API covers only part of the TERMDAT records, that the selection follows the needs of the federal administration's translators, and that no fuller coverage is planned. Measured beforehand: for «Quellensteuer» the website lists 12 distinct entries and the API returns 7 at maximum recall (every language, all 11 fields, infix wildcard, all classifications and collections); the overlap is one entry, 447912. Fetching the missing IDs directly via
/v2/Entryreturns HTTP 200 with an empty body — they are not served at all, so no query can reach them. Consequence: absence from this server means absence from the API, not from TERMDAT, and there is nothing to work around. Verified 2026-07-30 with the entry IDs supplied by @dfch in issue #11.The I14Y catalogue record carries
license: null— the terms are elsewhere. Reuse and republication of TERMDAT content are permitted only with the sourcewww.termdat.chnamed, and the Terminology Section of the Federal Chancellery informed of purpose and manner beforehand (terminologie@bk.admin.ch; statement of 2026-08-21). Running this server is covered by the enquiry that produced that statement; your own downstream republication needs its own notice. Every response repeats the terms 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 |
| 200 | ✅ | OpenAPI 3.0.4, 132 KB, |
| 200 | ✅ | requires |
| 200 | ✅ | requires |
| 200 | ✅ | 140 values |
| 200 | ✅ | 23 values, incl. |
| 404 | ❌ | no index; the I14Y record points here |
| 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.
Live probe findings (2026-07-27) — search scope
Reported in issue #11: «Quellensteuer»
returned nothing while the TERMDAT website returned twelve hits. Three independent causes,
in descending order of effect. Entry counts, InLanguageCode=DE:
Query | ID-less ( | all 23 classifications | + free-text fields | + |
| 0 | 1 | 3 | 6 |
| 1 | 4 | 22 | 27 |
The first column is what this server sent before the fix. The VARIA default is the
dominant term: it hid FINANZWESEN, RECHT and twenty other subject areas behind an
answer that looked like a confident zero.
Probe note. The failure mode worth recording is not the count — it is that an
under-scoped search is indistinguishable from a genuine absence. In the reported session
the model read the empty result together with this server's own «absence usually means out
of scope» caveat and invented a plausible explanation for a term that was in the database
all along. A tool that narrows silently will be believed silently. Hence hint on empty
results, and a caveat that now tells the model to retry rather than to conclude.
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
This server speaks two protocol eras over the same endpoint, on both transports. 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 |
|
| What today's clients speak. The server answers with the revision asked for, or with the |
Per-request envelope |
| A request carrying the |
Both revisions are pinned in
tests/test_protocol_version.py and asserted
against the installed SDK, so a Dependabot bump of mcp cannot move either one
silently.
That pin alone once hid a real gap. Until 18.09.2026 the network transport
was the SDK's SSE app, which has no branch into the modern era at all — over
HTTP, 2026-07-28 was unreachable, while the constants said otherwise and
stdio served it fine. Since the switch to Streamable HTTP on /mcp, both eras
are also measured: tests/test_streamable_http.py
sends real requests of both kinds through the assembled ASGI stack and checks
the negotiated revision, the mandatory resultType, and the -32022 rejection
of an unknown modern revision.
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 together.
Testing
PYTHONPATH=src pytest tests/ -m "not live" # offline, respx-mocked
PYTHONPATH=src pytest tests/ -m live # hits the real API
python scripts/check_ruff_pin.py
ruff check src/ tests/ scripts/
ruff format --check src/ tests/ scripts/
python scripts/check_version_sync.pyChangelog
See CHANGELOG.md.
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).
Security
See SECURITY.md for the security posture, hardening controls, and how to report a vulnerability.
License
MIT for this server — see LICENSE. TERMDAT content remains subject to the Federal Chancellery's terms: name the source www.termdat.ch and inform the Terminology Section beforehand of purpose and manner of any reuse or republication (statement of 2026-08-21).
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
Available Tools
7 toolsapi_statusARead-only
Availability of the TERMDAT API. Never returns silently empty.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| source | No | |
| message | Yes | |
| reachable | Yes | |
| provenance | Yes | |
| collections | No | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
| classifications | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=true, and destructiveHint=false. The description adds one useful behavioral guarantee—'Never returns silently empty'—which goes beyond the annotations, but it does not elaborate on what the status response contains or how failures are signaled. The output schema partially covers this, so a 3 is appropriate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences with no filler. The core purpose is stated first, and the non-empty guarantee is front-loaded as an additional behavioral point. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless status tool with annotations and an output schema, the description covers the essential purpose and a key response property. It does not explicitly say 'call this to verify API availability before other requests', but that is optional given the tool name and sibling context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and an empty input schema, so the schema fully documents the argument surface. The description correctly adds no parameter details; the baseline of 4 for zero-parameter tools applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as reporting the availability of the TERMDAT API, which is distinct from the sibling search/translate/list tools. It lacks an explicit verb like 'Check', but the noun-phrase 'Availability of' is unambiguous enough to separate it from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to call this tool versus alternatives, nor is there any hint that it should be used as a precondition for other API calls. The description provides no when/when-not framing, leaving the agent to infer usage from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_termsARead-only
Check a list of terms against validated TERMDAT designations.
Intended for communication QA: verify that authority names, department titles and
abbreviations in a draft match the officially validated form. Each term is reported
as validated, found_unvalidated or not_found. Up to 25 terms per call; the
lookups run concurrently.
| Name | Required | Description | Default |
|---|---|---|---|
| terms | Yes | ||
| language | No | DE |
Output Schema
| Name | Required | Description |
|---|---|---|
| caveat | No | |
| source | No | |
| checked | Yes | |
| results | Yes | |
| language | Yes | |
| not_found | Yes | |
| validated | Yes | |
| provenance | Yes | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and destructiveHint, so the safety profile is clear. The description adds useful behavior beyond structured data: each term is reported as one of three statuses, and lookups run concurrently. It does not mention authentication or rate limits, but the read-only annotation lowers the bar.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no fluff: purpose first, then context, then behavioral details and limits. Every sentence adds information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple 2-parameter schema, output schema presence, and read-only annotations, the description is nearly complete. The main missing piece is language parameter semantics, and explicit alternative routing would help, but these are not fatal for a basic check tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description must compensate for parameter meaning. It clarifies that 'terms' are a list and repeats the 25-term cap from the schema, but it does not explain the 'language' parameter, its accepted values, or how it affects the check. This is a clear gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Check a list of terms against validated TERMDAT designations') and clarifies the exact QA use case. It is clearly distinct from siblings like search_terms, but it does not explicitly differentiate itself by naming any sibling tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides strong when-to-use guidance: 'Intended for communication QA' and lists example content (authority names, department titles, abbreviations). It does not mention when not to use it or point to an alternative, so it stops short of full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_entriesARead-only
Fetch known TERMDAT entries by their numeric IDs, with full language variants.
Use this to re-retrieve an entry you already found via search_terms (its
entry_id), e.g. to pull all four national-language designations at once.
| Name | Required | Description | Default |
|---|---|---|---|
| entry_ids | Yes | ||
| in_language | No | DE | |
| out_language | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | Set when the search returned nothing; suggests how to widen it |
| source | No | |
| entries | Yes | |
| returned | Yes | |
| truncated | Yes | True if the result hit max_results — narrow the query or raise the limit |
| provenance | Yes | |
| in_language | Yes | |
| search_term | Yes | |
| out_language | No | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark it read-only and non-destructive; the description adds useful behavioral context beyond that: it works on previously discovered entries, returns full language variants, and can surface all four national-language designations. No contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no filler. The first sentence states the operation and scope, and the second/third give concrete usage guidance. The most important info is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple ID-based lookup with an output schema and read-only annotations, the happy path is well covered: what to pass and why. The main gap is the optional language parameters, which are not explained and could affect the returned variants.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description needed to compensate. It explains entry_ids ('numeric IDs', 'entry_id') and hints at language output, but never explains in_language or out_language, their defaults, or how they interact with the 'full language variants' behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with 'Fetch known TERMDAT entries by their numeric IDs' – a specific verb, resource, and input identifier. The follow-up sentence explicitly positions it as the re-retrieval counterpart to search_terms, making it easy to distinguish from sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear use context: call this after search_terms, using the returned entry_id, to get all language designations at once. It does not explicitly state when not to use it or compare with translate_term/check_terms, so it falls short of a fully explicit routing rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_classificationsBRead-only
List the 23 subject classifications (e.g. BILD = education), for classification_ids.
| Name | Required | Description | Default |
|---|---|---|---|
| language | No | DE |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| count | Yes | |
| source | No | |
| values | Yes | |
| language | Yes | |
| provenance | Yes | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds concrete context by asserting the list has exactly 23 items and provides an example, which is helpful but does not go beyond what annotations already establish about behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, tightly worded sentence that front-loads the verb and resource, includes a concrete example, and contains no filler or redundant information. It earns its place entirely.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only list tool with an output schema present, the description is mostly adequate. The main gap is the complete absence of explanation for the 'language' parameter, which is the only way to customize the call. Annotations cover safety and the output schema covers return values, so this is a moderate, not severe, omission.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the only parameter 'language', and the description does not mention it or explain how it affects the output (e.g., the language of classification labels). Since the schema is unhelpful and the description fails to compensate, the agent has no guidance on this parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('List') and resource ('subject classifications') and gives an example mapping ('BILD = education'), making the purpose immediately clear. It does not explicitly contrast with sibling tools, but the resource is unique enough that the tool is easily distinguished from the provided siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'for classification_ids' implies that the tool returns classification IDs useful for other operations, giving a hint of when to use it. However, there is no explicit when-to-use/when-not-to-use guidance or mention of alternatives, leaving the agent to infer the usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_collectionsARead-only
List the ~140 TERMDAT collections, for use as collection_ids filters.
| Name | Required | Description | Default |
|---|---|---|---|
| language | No | DE |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| count | Yes | |
| source | No | |
| values | Yes | |
| language | Yes | |
| provenance | Yes | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint and destructiveHint annotations already establish safety; the description adds a useful scale cue (~140 collections). It does not address behavior such as language filtering, ordering, or pagination, but with annotations present this is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single well-structured sentence that front-loads the action and resource, then gives the purpose. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only list operation with an output schema and safe annotations, the description is nearly sufficient. The only real gaps are the undocumented language parameter and lack of explicit differentiation from list_classifications.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not explain the only parameter, language, at all. The schema's title and default provide minimal meaning, but the description fails to compensate for the low coverage, leaving the parameter's effect unclear.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('List') and resource ('TERMDAT collections') and states the downstream purpose ('use as collection_ids filters'). It does not explicitly distinguish the tool from the similarly named sibling list_classifications, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'For use as collection_ids filters' gives a clear reason to invoke the tool, so an agent knows when the result is needed. However, it never says when not to use it or how it compares with alternatives such as list_classifications.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_termsARead-only
Search TERMDAT for official designations of the Swiss Federal Administration.
Use this to look up the officially validated German/French/Italian/English name of an authority, department or legal act — for example to check how a body is named in another national language before citing it.
search_term is Lucene query syntax: * and ? wildcards and the ~ fuzzy
operator work. Matching is on whole words, so a compound is not found by its
parts — «Quellensteuer» does not match «Quellensteuerverordnung», but
«Quellensteuer*» does. Reach for a wildcard before concluding a term is absent.
Leave detail at True unless you want a bare hit list. With detail=False
the API omits languageDetails, and every entry comes back with an empty
variants — id, url, status and classification, but not a single designation.
That is a hit you cannot read a term from, from a tool whose purpose is terms.
Use it to count or to filter by classification, never to answer «what is this
called».
out_language adds a target language to every entry's variants — it is purely
additive and never filters the result set. fields is a comma-separated subset
of: Terminus, Name, Abbreviation, Phraseology, Definition, Note, Context, Source,
Metadata, Country, Comment; empty means Terminus, Name, Abbreviation, Phraseology,
Definition, Note, Source. By default the search spans all 23 subject
classifications; pass classification_ids or collection_ids to narrow it
(see list_classifications / list_collections).
Scope caveat: TERMDAT holds administrative nomenclature (authority names, titles of legal acts, abbreviations), not domain vocabulary — so a term may genuinely be absent. Establish that with a wildcard retry, not from a single empty result, and never fill the gap with a guessed designation.
Coverage caveat: the public API serves a subset of what termdat.bk.admin.ch shows, and the Federal Chancellery confirmed on 2026-08-21 that this is deliberate — the selection follows the needs of the federal administration's translators, and no fuller coverage is planned. Entries the website lists can be missing from the API entirely: not hidden by a filter, simply not served, so no query reaches them. So «not found here» means «not in the API», never «not in TERMDAT»: say which one you mean, and point at www.termdat.ch for the difference.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | ||
| fields | No | ||
| in_language | No | DE | |
| max_results | No | ||
| search_term | Yes | ||
| out_language | No | ||
| collection_ids | No | ||
| classification_ids | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | Set when the search returned nothing; suggests how to widen it |
| source | No | |
| entries | Yes | |
| returned | Yes | |
| truncated | Yes | True if the result hit max_results — narrow the query or raise the limit |
| provenance | Yes | |
| in_language | Yes | |
| search_term | Yes | |
| out_language | No | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint and openWorldHint, and the description substantially enriches them with concrete behavioral details: Lucene wildcard/fuzzy syntax, whole-word matching, detail=False returning unusable empty variants, out_language being purely additive, and the API's deliberate deliberate subset limitation confirmed by the Federal Chancellery. This is far more transparent than the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average, but every paragraph adds decision-relevant behavior, caveat, or parameter semantics. The core action is front-loaded, and the later sections are thematically grouped rather than rambling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists, the description still provides everything else needed for correct invocation: query syntax, filtering behavior, retry policy, scope limitations, and precise open-world semantics. An agent could use this tool correctly and interpret empty results confidently without external help.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden. It explains search_term's Lucene syntax, detail's effect on variants, out_language's additive nature, fields' comma-separated allowed values and default, and classification_ids/collection_ids narrowing — none of which is available from the schema itself. Even in_language and max_results need no explanation because their names and schema defaults are self-evident.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-plus-resource statement: 'Search TERMDAT for official designations of the Swiss Federal Administration.' It then specifies the concrete use case — looking up validated names of authorities, departments, or legal acts — and clarifies the administrative-nomenclature scope, distinguishing it from ordinary vocabulary lookup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance ('before citing it') and strong when-not-to-use rules: retry with a wildcard before concluding absence, never invent a guessed designation, and keep detail=True unless you only need counts or classification filtering. It also points to list_classifications/list_collections as the narrowing alternatives and warns that not-found-in-API does not mean not-found-in-TERMDAT.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
translate_termARead-only
Get the official equivalent of an administrative term in another national language.
Returns the preferred designation (sequence 1) plus accepted variants, per matching entry. Use this for authority names, department titles and titles of legal acts.
Matches only against designation fields, so a term merely mentioned in a
definition is never reported as an equivalent. term accepts Lucene wildcards;
on an empty result retry with term* before concluding there is no equivalent.
| Name | Required | Description | Default |
|---|---|---|---|
| term | Yes | ||
| max_results | No | ||
| to_language | No | FR | |
| from_language | No | DE |
Output Schema
| Name | Required | Description |
|---|---|---|
| hits | Yes | |
| term | Yes | |
| source | No | |
| provenance | Yes | |
| to_language | Yes | |
| retrieved_at | Yes | ISO-8601 UTC timestamp |
| from_language | Yes | |
| total_entries | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/destructive annotations, the description discloses material behavior: matches only designation fields, never terms merely mentioned in definitions, returns the preferred designation plus accepted variants, and supports Lucene wildcards with a retry hint. These details genuinely help an agent predict results without calling the tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core function, then adds return behavior, use cases, matching semantics, and retry guidance. Every sentence earns its place and there is no repetition of schema or annotation information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the annotations, an output schema, and mostly self-descriptive parameters, the description covers the key behavioral edge cases an agent needs: what fields are matched, what is returned, and how to handle empty results. It does not spell out language code semantics or pagination details, but those are either self-evident or covered by the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the burden. It does add useful meaning for the term parameter by explaining Lucene wildcard support and the retry strategy, but it does not explain to_language, from_language, or max_results beyond what the schema's names and defaults already suggest. This is partial compensation, not full coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Get the official equivalent of an administrative term in another national language.' It further narrows the tool's purpose by naming the concrete use cases (authority names, department titles, titles of legal acts), which clearly distinguishes it from sibling tools like search_terms or get_entries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit context for when to use the tool: 'Use this for authority names, department titles and titles of legal acts.' It also provides practical guidance on handling empty results with term*, but it does not explicitly name alternatives or state when not to use this tool versus a sibling, so it falls just short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.2.0- Changed
api_status1 field changed- changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
- Changed
check_terms2 fields changed- changed
Output schema / properties / caveat / defaultPrevious value: -"TERMDAT covers federal and cantonal administrative nomenclature — authority names, official titles of legal acts, abbreviations. Domain vocabulary (e.g. pedagogy) is largely absent, so 'not_found' means 'not in TERMDAT', not 'incorrect'."New value: +"TERMDAT covers federal and cantonal administrative nomenclature — authority names, official titles of legal acts, abbreviations. Domain vocabulary (e.g. pedagogy) is largely absent. And the public API deliberately serves only a subset of TERMDAT, selected for the needs of the federal administration's translators (Federal Chancellery, 2026-08-21), so 'not_found' means 'not in the public API' — never 'not in TERMDAT' and never 'incorrect'. Check www.termdat.ch for the difference." - changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
- Changed
get_entries1 field changed- changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
- Changed
list_classifications1 field changed- changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
- Changed
list_collections1 field changed- changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
- Changed
search_terms1 field changed- changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
- Changed
translate_term1 field changed- changed
Output schema / properties / source / defaultPrevious value: -"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. The I14Y catalogue record carries no explicit licence statement — clarify terms with the Federal Chancellery before republishing."New value: +"Data: TERMDAT, terminology database of the Swiss Federal Administration, Swiss Federal Chancellery (BK), via api.termdat.bk.admin.ch. Terms of use (Terminology Section, Federal Chancellery, 2026-08-21): reuse and republication are permitted only if the source www.termdat.ch is named, and the Terminology Section must be informed of the purpose and manner beforehand (terminologie@bk.admin.ch)."
2 tool updates
v0.1.1- Changed
get_entries1 field changed- added
Output schema / properties / hintAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Set when the search returned nothing; suggests how to widen it", + "title": "Hint" +}
- Changed
search_terms2 fields changed- changed
Input schema / properties / fields / defaultPrevious value: -"Terminus"New value: +"" - added
Output schema / properties / hintAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Set when the search returned nothing; suggests how to widen it", + "title": "Hint" +}
7 tool updates
v0.1.0- First observed
api_status - First observed
check_terms - First observed
get_entries - First observed
list_classifications - First observed
list_collections - First observed
search_terms - First observed
translate_term
TDQS
Scored across 7 tools
Most tools have clearly distinct purposes: searching, retrieving by ID, translating, batch QA, listing metadata, and status. search_terms and translate_term overlap somewhat since both query designations, but the descriptions make the intended use cases distinct enough for an agent to choose correctly.
Most tools follow a clear verb_noun pattern: search_terms, get_entries, translate_term, check_terms, list_collections, list_classifications. api_status is the one outlier, breaking the pattern by using noun_only style instead of something like get_status.
Seven tools is well-scoped for a read-only terminology lookup server. Each tool has a distinct role: search, retrieval, translation, QA checking, filter metadata, and API status, without redundant utilities.
The domain is Swiss administrative terminology lookup, and the tool surface covers the full lifecycle: discover entries, retrieve by ID, translate, validate batches, enumerate filters, and check API availability. There are no obvious dead ends or missing operations for a read-only API.
Maintenance
Related MCP Connectors
opendata.swiss MCP — Switzerland's federal open-data portal (CKAN catalogue).
Hosted MCP server for finding authoritative primary data sources and official portals.
Swiss federal law (Fedlex) and political data (LINDAS) for agents, every answer with sources
MCP server for the Fail Modes taxonomy — a knowledge base of AI system failure modes
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server connecting AI models to Swiss Federal Food Safety and Veterinary Office open data, enabling queries about food recalls, animal disease surveillance, food control results, and more.1173 PyPIMIT
- AlicenseAqualityAmaintenanceMCP server for querying Swiss intellectual property data (trademarks, patents, supplementary protection certificates) from the Swissreg register via natural language.1151 PyPIMIT
- AlicenseAqualityAmaintenanceMCP server for Swiss federal legislation metadata via Fedlex, enabling search and retrieval of act details with ELI URIs, SR numbers, and multilingual support.3Apache 2.0
- AlicenseBqualityDmaintenanceMCP server exposing all major Swiss official public APIs as native tools for any MCP-compatible AI agent.3412 npmMIT