Releases: malkreide/termdat-mcp
Release list
v0.1.3
[0.1.3] - 2026-08-02
Fixed
-
structlogcarried no upper bound, and the index already serves a major past
the floor. The declared range wasstructlog>=24.1; PyPI has been serving
26.1.0. The artefact does not change — the resolver's answer to the next
fresh install does, and that is exactly howswiss-energy-mcp0.3.3 became
uninstallable whenmcp2.0.0 removed the module it imported.Now
structlog>=24.1,<27. The bound is measured rather than guessed: this package
installs and imports againststructlog 26.1.0today, so the cap admits what
demonstrably works and stops only the next, unknown major.
A dependency range only reaches users through a new release, hence the
version bump. No code changed.
v0.1.2
[0.1.2] — 2026-07-30
Fixed
- The User-Agent reports the actual package version again. The published
0.1.1senttermdat-mcp/0.1.0to every upstream — the version string was
hardcoded and had been left behind by earlier bumps. The version now comes
from the package metadata, so it can no longer drift from the package.
Documented
-
The public API exposes less than the website — a coverage limit of the
source, not a scope setting on our side. Follow-up to #11: @dfch supplied the
12 entry IDs the website lists for «Quellensteuer»; the API returns 7 at
maximum recall (every language, all 11 fields, infix wildcard, all
classifications and collections), and the two sets overlap in exactly 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. The one exception, 1557, is served but carries status
In Bearbeitungin a collection marked «(aufgehoben)», which suggests the
search index covers validated entries while the website also shows drafts and
repealed material.This corrects an earlier guess. The residual was described in #11 as probably
a counting difference — the website listing designations where the API counts
entries. The IDs disprove that: they are twelve distinct entries. Recorded
here so the wrong explanation does not outlive the measurement.Documented in both READMEs, and in the
search_termsdocstring, where it
matters most: a model told only that «a term may genuinely be absent» will
conclude «absent from TERMDAT», which is false for entries the website shows.
The docstring now distinguishes the two.
Fixed
- Capped
mcpat<2.mcp2.0.0, published 2026-07-28, removed
mcp.server.fastmcp— the module this server imports. With the previous
unbounded>=1.28.1every fresh resolve picked 2.0.0 and failed at import
withModuleNotFoundError, in CI and for anyone runningpip installalike.
Verified in both directions: 2.0.0 fails,<2resolves to 1.29.0 and imports
cleanly. Migrating to the 2.x API (mcp.server.mcpserver) stays a separate,
deliberate piece of work.
v0.1.1
[0.1.1] — 2026-07-27
Fixed
- MCP Registry publish was blocked by a missing ownership marker. The
registry verifies ownership of a PyPI package by looking for an
mcp-name: <server-name>marker in the published package README. The marker
was added toREADME.mdafter 0.1.0 shipped, so it never reached PyPI — and
PyPI releases are immutable, so it cannot be added to the 0.1.0 artifact
retroactively. This release carries it into the package metadata. - Search was confined to the
VARIAclassification (#11, reported by
@dfch)./v2/Searchrestricts an ID-less query to a "default set (=VARIA)",
so every unfiltered search covered 1 of 23 subject areas — and reported the
result as a normal empty answer.search_terms,translate_termand
check_termsnow send the full classification set unless the caller narrows
it. «Quellensteuer» 0 → 3 entries, «Pensionskasse» 1 → 21. fieldscould widen a search but never narrow it. UnsentField.*flags
keep their API-side default (Terminus,Name,Abbreviation,
Phraseology= true), sofields="Terminus"was a no-op. All eleven flags
are now sent explicitly.- Default field set widened to include
Definition,NoteandSource;
translate_termandcheck_termsstay on the four designation fields, so a
term merely mentioned in a definition is never reported as an equivalent. - Misleading scope caveat. The
search_termsdocstring presented an empty
result as probable out-of-scope, which invited models to invent a designation
instead of retrying. It now documents Lucene wildcards and asks for a retry;
an emptySearchResultcarries ahintfield saying the same.
Security
- SEC-016 (NeighborJack): the SSE transport now binds to
127.0.0.1by
default instead of0.0.0.0. Binding to0.0.0.0is an explicit opt-in that
logs a stderr warning when used outside a container. README/SECURITY updated. - SEC-021: code-layer egress allow-list (
ALLOWED_HOSTS+assert_host_allowed),
enforced before every request;docs/network-egress.md. - SEC-018: input bounds at the tool boundary —
max_results1–100, plus
string/list length limits onsearch_term,term,terms,entry_ids,fields. - SEC-007: hardened non-root
Dockerfilefor SSE deployments. - SEC-005 / SCALE-002: accepted-risk ADRs for DNS pinning and stateful load
balancing (docs/adr/0001,0002).
Added
- Typed configuration via
pydantic-settings(settings.py); new env vars
TERMDAT_MCP_LOG_LEVEL,TERMDAT_MCP_CORS_ORIGINS,TERMDAT_MCP_VOCAB_TTL. - Structured logging via
structlog, pinned to stderr as JSON (logging_config.py). - FastMCP
lifespanowning the shared HTTP client (cleanup on shutdown). - Explicit CORS for the SSE transport, exposing only
Mcp-Session-Id. CONTRIBUTING.md/CONTRIBUTING.de.md; scheduled/manual live-test workflow.- Expanded test suite (12 → 28 offline tests): per-tool coverage, error paths,
egress allow-list, tool-schema input bounds. - MCP best-practice audit against the portfolio catalog (68 checks, 36
applicable) underaudits/: production-ready; the 19-item hardening
backlog from that audit is addressed by the changes above.
Changed
api_statusand the client no longer forward raw upstream exception strings to
the model (OBS-002 error-detail masking); detail goes to the structured log.check_termsruns its per-term lookups concurrently (asyncio.gather) and
reports progress viactxwhen available (ARCH-007 / SDK-003).- Tools grouped rationale + MCP-primitives note documented in the READMEs.
v0.1.0 — Initial Release
First public release of termdat-mcp — an MCP server for TERMDAT, the
terminology database of the Swiss Federal Administration. Seven read-only
tools expose officially validated designations of Swiss authorities,
departments and legal acts across DE / FR / IT / EN.
Install: uvx termdat-mcp
See CHANGELOG.md for details.