MCP server for Swiss official gazettes (SHAB + cantonal) — procurement and notices, no person data
Drift inferred · capture-to-capture
tool count over time
07-20 14:53 now
5t
6t
transport stdio · streamable-http · http · sse
verified
reported
listed in the official MCP registry counts 4 tools · 0 res
· 0 prompts
permission surface via code analysis
tools
-
gazette_get_publication
-
gazette_search_detailed
-
gazette_search_procurement
-
gazette_source_status
prompt-surface
shipped agent-instruction files + hidden-content / dangerous-code findings —
quoted from the analyzed source
analyzed commit d44c425 · analyzer v30 · 2w ago
danger signals1
- suspicious endpoint 169.254.169.254 (cloud metadata) malkreide-amtsblatt-mcp-d44c425/tests/test_publication.py :241
await client.get("http://169.254.169.254/latest/meta-data/")
evidence-backed
findings quoted directly from the published source artifact — not inferred
code files: 52
filesystem 13
- fs malkreide-amtsblatt-mcp-d44c425/audits/2026-07-20T212024-Z-amtsblatt-mcp/_build_findings.py :107
with open(path, "w", encoding="utf-8") as fh: - fs malkreide-amtsblatt-mcp-d44c425/audits/2026-07-20T212024-Z-amtsblatt-mcp/_build_results.py :6
catalog = json.load(open(sys.argv[1])) # parse_catalog --format json (dict keyed by id) - fs (weak) malkreide-amtsblatt-mcp-d44c425/scripts/check_version_sync.py :35
from pathlib import Path - fs (weak) malkreide-amtsblatt-mcp-d44c425/scripts/measure_coverage_matrix.py :29
from pathlib import Path - fs (weak) malkreide-amtsblatt-mcp-d44c425/scripts/update_tool_hashes.py :20
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_live.py :125
from pathlib import Path - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_protocol_version.py :15
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_publication.py :392
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_secrets.py :73
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_security_doc.py :25
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_tool_hashes.py :23
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_tool_naming.py :80
import pathlib - fs (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_version.py :15
import pathlib
shell / exec 2
- shell (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_logging.py :19
import subprocess - shell (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_publication.py :198
import subprocess
network 17
- net malkreide-amtsblatt-mcp-d44c425/audits/2026-07-20T212024-Z-amtsblatt-mcp/_build_findings.py :15
observed="Each upstream request created a fresh `httpx.AsyncClient` via `_make_client()` inside `_get_json` / `_get_text` / `_probe_endpoint` (server.py:262,278,1478). No FastMCP lifespan existed; no - net malkreide-amtsblatt-mcp-d44c425/audits/2026-07-20T212024-Z-amtsblatt-mcp/_build_results.py :155
"No FastMCP lifespan; a fresh httpx.AsyncClient is created per request via _make_client() in _get_json/_get_text/_probe_endpoint (server.py:247,262,278,1478)" - net (weak) malkreide-amtsblatt-mcp-d44c425/scripts/measure_coverage_matrix.py :31
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/scripts/measure_procurement_coverage.py :27
import httpx - net malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/_envelope.py :21
import httpx - net malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/_http.py :29
import httpx - net malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/_net.py :38
import socket - net malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/constants.py :24
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/conftest.py :4
`httpx.AsyncClient` is shared across tool calls — which is the point — but the - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_aggregation.py :19
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_allowlist.py :12
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_empty_results.py :33
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_error_paths.py :38
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_publication.py :9
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_retry_policy.py :6
it caught no network errors at all. `client.get` raising `httpx.ConnectError` - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_search.py :9
import httpx - net (weak) malkreide-amtsblatt-mcp-d44c425/tests/test_ssrf.py :15
import socket
secrets 1
- secrets malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/server.py :161
api_key = SecretStr(os.environ.get("MCP_API_KEY", "").strip())
tool registrations 4
- gazette_get_publication malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/tools/publication.py :78
- gazette_search_detailed malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/tools/search.py :231
- gazette_search_procurement malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/tools/search.py :476
- gazette_source_status malkreide-amtsblatt-mcp-d44c425/src/amtsblatt_mcp/tools/status.py :57
declared dependencies 15
- mcp@>=2.0.0,<3
- structlog@>=24.1,<27
- httpx@>=0.27.0
- pydantic@>=2.0.0
- starlette@>=0.37,<2
- tzdata@>=2024.1; sys_platform ==
- pytest@>=8.0.0
- pytest-asyncio@>=0.23.0
- pytest-cov@>=5.0.0
- respx@>=0.21.0
- ruff@>=0.4.0
- opentelemetry-api@>=1.27.0
- opentelemetry-sdk@>=1.27.0
- opentelemetry-exporter-otlp-proto-http@>=1.27.0
- opentelemetry-instrumentation-httpx@>=0.48b0