Skip to main content
Glama

🇨🇭 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

Version CI License: MIT Python 3.10+ MCP Auth: none Portfolio

Official, validated Swiss administrative designations across DE / FR / IT / EN — with source references and validation status.

🇩🇪 Deutsche Version

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 MaxEntryCount to avoid silent truncation.

  • Dual transport: stdio (local) and Streamable HTTP (cloud). Both serve MCP protocol revision 2026-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

Demo: Claude using search_terms and translate_term

Prerequisites

  • Python 3.10+

  • uv / uvx (recommended) or pip

  • 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 streamable-http / http (cloud). sse is accepted as a deprecated alias and now serves Streamable HTTP on /mcp — it warns on startup

HOST

127.0.0.1

Bind host (HTTP transport only). Loopback by default; set HOST=0.0.0.0 only inside a container

PORT

8000

Bind port (HTTP transport only)

TERMDAT_MCP_CORS_ORIGINS

[]

HTTP only: explicit allowed browser origins (default-deny; never a wildcard in production). Comma-separated, e.g. https://a.example,https://b.example

TERMDAT_MCP_ALLOWED_HOSTS

[]

HTTP only: inbound Host allow-list. Comma-separated, e.g. mcp.example.ch,mcp.example.ch:443. Needed for a non-loopback bind — without it the Host header is not checked at all

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).

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 /mcp

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 / 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.json and 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; provenance is live_api except 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.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_status and error paths surface failures instead of returning an empty result that looks complete.

  • Truncation is explicit. MaxEntryCount is always sent and truncated is reported (see Known Limitations).

  • Terms of use are stated, not guessed. Every response repeats them in source: reuse and republication require the source www.termdat.ch to 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 frozen ALLOWED_HOSTS set — no user input can redirect egress. See docs/network-egress.md.

  • Loopback by default. The HTTP transport binds to 127.0.0.1; 0.0.0.0 is an explicit container opt-in that warns on stderr. It also sets default-deny CORS, exposing only Mcp-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 Dockerfile is provided for hosted deployments.

Known Limitations

  • Administrative scope only. See the coverage table above. check_terms returns not_found, never «incorrect», precisely because absence from TERMDAT is not evidence of error.

  • MaxEntryCount has a silent default of ~25. Omitting it looks like a complete result set. This server always sends the parameter explicitly and reports truncated.

  • CollectionIds / ClassificationIds have a silent default of VARIA. An ID-less /v2/Search covers 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.

  • SearchTerm is 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, Abbreviation and Phraseology are on unless explicitly disabled, so a partial flag set can only widen a search. This server sends all eleven flags explicitly, which is what makes fields able to narrow.

  • Multilingual variants are opt-in. Without OutLanguageCode, entries return German designations only. translate_term sets 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/Entry returns 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 source www.termdat.ch named, 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 in source.

  • Entry-level language coverage varies. Not every entry exists in all four languages; translate_term omits 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.

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 (=VARIA)

all 23 classifications

+ free-text fields

+ * wildcard

Quellensteuer

0

1

3

6

Pensionskasse

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

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 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.py

Changelog

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

Available Tools

7 tools
api_statusA
Read-only

Availability of the TERMDAT API. Never returns silently empty.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
sourceNo
messageYes
reachableYes
provenanceYes
collectionsNo
retrieved_atYesISO-8601 UTC timestamp
classificationsNo

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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_termsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
termsYes
languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
caveatNo
sourceNo
checkedYes
resultsYes
languageYes
not_foundYes
validatedYes
provenanceYes
retrieved_atYesISO-8601 UTC timestamp

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters2/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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_entriesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
entry_idsYes
in_languageNoDE
out_languageNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNoSet when the search returned nothing; suggests how to widen it
sourceNo
entriesYes
returnedYes
truncatedYesTrue if the result hit max_results — narrow the query or raise the limit
provenanceYes
in_languageYes
search_termYes
out_languageNo
retrieved_atYesISO-8601 UTC timestamp

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters2/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_classificationsB
Read-only

List the 23 subject classifications (e.g. BILD = education), for classification_ids.

ParametersJSON Schema
NameRequiredDescriptionDefault
languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
kindYes
countYes
sourceNo
valuesYes
languageYes
provenanceYes
retrieved_atYesISO-8601 UTC timestamp

TDQS

B3.2/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters1/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_collectionsA
Read-only

List the ~140 TERMDAT collections, for use as collection_ids filters.

ParametersJSON Schema
NameRequiredDescriptionDefault
languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
kindYes
countYes
sourceNo
valuesYes
languageYes
provenanceYes
retrieved_atYesISO-8601 UTC timestamp

TDQS

A3.6/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters2/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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_termsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
detailNo
fieldsNo
in_languageNoDE
max_resultsNo
search_termYes
out_languageNo
collection_idsNo
classification_idsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNoSet when the search returned nothing; suggests how to widen it
sourceNo
entriesYes
returnedYes
truncatedYesTrue if the result hit max_results — narrow the query or raise the limit
provenanceYes
in_languageYes
search_termYes
out_languageNo
retrieved_atYesISO-8601 UTC timestamp

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_termA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
termYes
max_resultsNo
to_languageNoFR
from_languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
hitsYes
termYes
sourceNo
provenanceYes
to_languageYes
retrieved_atYesISO-8601 UTC timestamp
from_languageYes
total_entriesYes

TDQS

A4.4/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 7 tool updatesv0.2.0
    • Changedapi_status1 field changed
      • changedOutput schema / properties / source / default
        Previous 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)."
    • Changedcheck_terms2 fields changed
      • changedOutput schema / properties / caveat / default
        Previous 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."
      • changedOutput schema / properties / source / default
        Previous 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)."
    • Changedget_entries1 field changed
      • changedOutput schema / properties / source / default
        Previous 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)."
    • Changedlist_classifications1 field changed
      • changedOutput schema / properties / source / default
        Previous 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)."
    • Changedlist_collections1 field changed
      • changedOutput schema / properties / source / default
        Previous 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)."
    • Changedsearch_terms1 field changed
      • changedOutput schema / properties / source / default
        Previous 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)."
    • Changedtranslate_term1 field changed
      • changedOutput schema / properties / source / default
        Previous 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. 2 tool updatesv0.1.1
    • Changedget_entries1 field changed
      • addedOutput schema / properties / hint
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Set when the search returned nothing; suggests how to widen it",
        +  "title": "Hint"
        +}
    • Changedsearch_terms2 fields changed
      • changedInput schema / properties / fields / default
        Previous value: -"Terminus"New value: +""
      • addedOutput schema / properties / hint
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Set when the search returned nothing; suggests how to widen it",
        +  "title": "Hint"
        +}
  3. 7 tool updatesv0.1.0
    • First observedapi_status
    • First observedcheck_terms
    • First observedget_entries
    • First observedlist_classifications
    • First observedlist_collections
    • First observedsearch_terms
    • First observedtranslate_term

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation4/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness5/5

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

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers