You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
[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 to README.md after 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 VARIA classification (#11, reported by @dfch). /v2/Search restricts 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_term and check_terms now send the full classification set unless the caller narrows
it. «Quellensteuer» 0 → 3 entries, «Pensionskasse» 1 → 21.
fields could widen a search but never narrow it. Unsent Field.* flags
keep their API-side default (Terminus, Name, Abbreviation, Phraseology = true), so fields="Terminus" was a no-op. All eleven flags
are now sent explicitly.
Default field set widened to include Definition, Note and Source; translate_term and check_terms stay on the four designation fields, so a
term merely mentioned in a definition is never reported as an equivalent.
Misleading scope caveat. The search_terms docstring 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 empty SearchResult carries a hint field saying the same.
Security
SEC-016 (NeighborJack): the SSE transport now binds to 127.0.0.1 by
default instead of 0.0.0.0. Binding to 0.0.0.0 is 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_results 1–100, plus
string/list length limits on search_term, term, terms, entry_ids, fields.
SEC-007: hardened non-root Dockerfile for 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 lifespan owning the shared HTTP client (cleanup on shutdown).
Explicit CORS for the SSE transport, exposing only Mcp-Session-Id.
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) under audits/: production-ready; the 19-item hardening
backlog from that audit is addressed by the changes above.
Changed
api_status and the client no longer forward raw upstream exception strings to
the model (OBS-002 error-detail masking); detail goes to the structured log.
check_terms runs its per-term lookups concurrently (asyncio.gather) and
reports progress via ctx when available (ARCH-007 / SDK-003).
Tools grouped rationale + MCP-primitives note documented in the READMEs.