github Python re-analysis due

malkreide/amtsblatt-mcp

github

MCP server for Swiss official gazettes (SHAB + cantonal) — procurement and notices, no person data

maintainer
malkreide
license
MIT
first seen
2026-07-20
last seen
2026-08-24
releases · 30d
6
short id

Drift inferred · capture-to-capture

tool count over time

07-20 14:53 now
5t
6t
capabilities 4 tools
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
skills & danger signals github-tarball
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

code evidence vv0.22.1 · github-tarball
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