Releases: malkreide/swiss-road-mobility-mcp
Release list
v0.5.4
[0.5.4] - 2026-07-31
Fixed
-
Der gehärtete SSE-Pfad wies unter jedem echten Hostnamen mit 421 ab
(SEC-005)._run_sse()baute die App mitmcp.sse_app()ohnehost. Unter
mcp 2.x ist das kein neutraler Default: das SDK leitet daraus seine
Host-Allow-List ab und aktiviert bei loopback-artigem Wert automatisch
127.0.0.1:*. Da der Default127.0.0.1ist, traf das genau das
MCP_HOST=0.0.0.0-Deployment aus Dockerfile und render.yaml.Der Server hat zwei SSE-Pfade, und nur einer war betroffen: der
Fallbackmcp.run(transport="sse", host=…)gibt den Bind weiter, dort sah das
SDK die echte Adresse. Betroffen war der gehärtete Pfad — also der, der
ausgeliefert wird.Der Bind reist jetzt mit, und eine echte Allow-List entsteht aus dem neuen
MCP_ALLOWED_HOSTS. Ohne diese Variable bleibt der Schutz auf einem
Nicht-Loopback-Bind bewusst aus und der Aufrufer warnt.Das ist unabhängig von
MCP_AUTH_TOKEN: die Bearer-Prüfung sagt, wer fragt,
die Host-Prüfung, unter welchem Namen der Server angesprochen wird. Ein
Rebinding-Angriff bringt ein gültiges Token per Konstruktion mit. -
Der
except Exception-Fallback ist jetzt im Test sichtbar. Er verwirft
bei jedem Fehler im gehärteten Aufbau still Auth, Rate-Limit und
Allow-List. Ein Test hält fest, dass der gehärtete Pfad wirklich genommen
wird; eine Fixture patchtmcp.run, damit ein Fallback im Test nicht einen
echten Server startet. Ohne das liess ein Mutationstest die Suite hängen
statt sie scheitern zu lassen — nachgemessen und behoben.13 neue Tests, darunter der tragende Fall „richtiger Hostname, falscher Port".
Der Positivfall wird bewusst an der Verdrahtung geprüft statt end-to-end: ein
erlaubter Host öffnet einen endlosen Event-Stream, auf den der TestClient
wartet. Mutationsgetestet in beide Richtungen.Geprüft mit den wörtlichen CI-Kommandos: 102 passed / 27 deselected,
ruff check src/clean, Versions-Sync OK.
Fixed
- User-Agent no longer reports a stale version.
__version__was a
hand-maintained literal in__init__.pythat nothing forced anyone to bump.
It sat at0.5.0while the package had moved on to0.5.3, so every outbound
request advertised a version three patch releases old to GBFS operators, the
EV charging feeds and DATEX II. It is now read from the installed
distribution metadata (importlib.metadata), which is generated from
pyproject.toml— a value nobody has to remember to bump cannot go stale.
Running from a bare source checkout yields0.0.0+sourcerather than a
plausible-looking wrong number. Guarded bytests/test_version.py.
v0.5.0 — Security, Observability & SDK Hardening
Security-, observability- and SDK-maturity hardening release. Implements the full
remediation of the 2026-06-03 audit — 25 of 29 non-pass findings resolved, 4
documented out-of-scope. Re-audit verdict: production_ready (40/44 pass, 0 critical/high failures).
Backward compatible: tool JSON-text output is preserved; structured output (
structuredContent+outputSchema) is added on top.
🔒 Security
- SSE auth + rate limiting — optional
MCP_AUTH_TOKENBearer gate + per-IP limiter (SEC-009) - Egress allow-list enforced per request incl. redirect hops + resolved-IP guard rejecting non-public IPs (SEC-004/021/005)
- Default SSE bind
127.0.0.1(0.0.0.0 only inside containers) (SEC-016) - Strict input validation — Pydantic
strict=True+extra="forbid"(SEC-018) - Error masking — exception/upstream details logged server-side only, never to the LLM (OBS-002)
- Container hardening — multi-stage build, non-root user, healthcheck (SEC-007/SCALE-004)
📈 Observability
- Structured errors
{isError, error:{code,message}}(OBS-001) - JSON logging to stderr via
MCP_LOG_FORMAT/MCP_LOG_LEVEL(OBS-003) - Optional OpenTelemetry tracing —
tracingextra (OBS-006)
🧩 SDK maturity
- Lifespan-managed shared HTTP client (SDK-001)
Contextprogress + logging in multi-step tools (SDK-003)- Structured tool outputs with
outputSchema(SDK-002) - CORS exposes
Mcp-Session-Idfor browser clients (SDK-004) - New MCP Resource
roadmobility://data-sources+ Promptplan_trip(ARCH-008)
🛠 Quality & ops
- respx-mocked offline tests + in-memory MCP-session E2E tests; CI runs
pytest -m "not live"(OPS-001) docker-compose.ymlwith resource limits +docs/OPERATIONS.mdrunbook (SCALE-006)- Dependabot + major-pinned deps (ARCH-012)
- New docs:
docs/ARCHITECTURE.md,docs/SECURITY.md,docs/OPERATIONS.md - Versioning unified to a single source of truth
⚪ Out of scope (documented)
Gateway tool allow-list / poisoning detection (SEC-014/015) and horizontal-scaling session affinity (SCALE-002/003) — only relevant behind a multi-server gateway or multi-replica deployment.
Full changelog: v0.4.0...v0.5.0
v0.4.0 – Swiss Road Mobility MCP
ci: add PyPI publish workflow