Skip to main content
Glama
malkreide

amtsblatt-mcp

by malkreide

🇨🇭 Part of the Swiss Public Data MCP Portfolio

📰 amtsblatt-mcp

Version License: MIT Python 3.11+ MCP No Auth Required CI

MCP server for amtsblattportal.ch — the Swiss official gazette portal (SHAB + 27 cantonal gazettes). Public procurement and official notices, person-data rubrics excluded by design.

🇩🇪 Deutsche Version

Overview

The Amtsblattportal publishes roughly 2.79 million official notices: public procurement, cantonal and communal announcements, enactments, spatial planning — and also bankruptcies, debt collection, inheritance calls and civil-status records naming natural persons.

This server exposes only the first group. Rubrics carrying systematic natural-person data are not queryable, and no tool accepts a person's name, birth date or address. That is a deliberate data-protection decision, explained in Data Protection & Scope.

Anchor demo query: "Which public tenders did canton Ticino publish this month?"

Demo

Demo: Claude using gazette_search_procurement and gazette_get_publicationgazette_search_procurement(canton="TI", only_language=True, language="it")gazette_get_publication(id=…)

For procurement in any other canton — including Zürich, Bern and Basel-Stadt — use swiss-procurement-mcp; see Boundary with swiss-procurement-mcp.

Related MCP server: ch-eli-mcp

Features

  • Fail-closed green allow-list — 49 released rubrics out of 152; everything else is blocked by default, including rubrics the upstream adds later

  • Explanatory refusals — a blocked rubric returns why, never a silent empty result and never a workaround hint

  • Procurement-aware — knows that only AR and TI still publish tenders here, that BS wound down during 2024 and BL/VS are historical archives, that OB-ZG was never filled after the simap switch, and that ZH routes everything through simap.ch — so it explains instead of returning nothing. Activity is measured, not read off the rubric label

  • Deadline arithmetic in Europe/Zurich, the legally relevant timezone

  • Honest multilingual counts — the portal publishes one record per language with a different publication number each; identical editions are collapsed, translated ones are reported via language_mix rather than guessed at, and only_language=True gives a single-language view

  • Defensive XML parsing — the schema is per-sub-rubric; no rubric-specific path is hard-coded, and entity-escaped HTML bodies are unescaped and stripped

  • Egress allow-list, retry with backoff, structured JSON logging

  • Markdown or JSON output with per-response attribution + provenance

Prerequisites

  • Python 3.11+

  • No API key. The read API of amtsblattportal.ch is freely accessible.

Installation

pip install amtsblatt-mcp
# or, without installing:
uvx amtsblatt-mcp

From source:

git clone https://github.com/malkreide/amtsblatt-mcp
cd amtsblatt-mcp
pip install -e ".[dev]"

Configuration

Claude Desktop

{
  "mcpServers": {
    "amtsblatt": {
      "command": "uvx",
      "args": ["amtsblatt-mcp"]
    }
  }
}

Cloud deployment (streamable-http)

export MCP_TRANSPORT=streamable-http
export MCP_API_KEY="$(openssl rand -hex 32)"   # mandatory — fails loud if unset
export PORT=8000
amtsblatt-mcp

The endpoint is /mcp.

Migrating from SSE. Until 0.18.0 this server spoke SSE only, on /sse + /messages. MCP spec 2026-07-28 reclassifies HTTP+SSE as deprecated with a twelve-month removal window and removes protocol-level sessions, so streamable-http is now the default. MCP_TRANSPORT=sse still works and still carries the full bearer-auth, rate-limit and CORS stack — it logs a warning at startup naming the deadline. Update the client URL when you switch: the path change is the part that breaks silently.

Variable

Default

Purpose

MCP_TRANSPORT

stdio

stdio, streamable-http (alias http), or the deprecated sse

MCP_HOST

127.0.0.1

HTTP bind address. Defaults to loopback; set 0.0.0.0 to expose on all interfaces (the Docker image does this deliberately).

MCP_STATELESS

(unset)

1 runs streamable-http with no session tracking at all. Removes session hijacking and session affinity as questions rather than answering them (SEC-009, SCALE-002). Opt-in, because a stateless server cannot resume an interrupted stream or push server-initiated notifications. Ignored on sse, which has no stateless mode.

MCP_CORS_ORIGINS

(unset)

Comma-separated origins allowed to call the endpoint from a browser. Unset means no cross-origin browser access at all — stdio and non-browser clients are unaffected. Mcp-Session-Id is exposed and accepted for the listed origins, so a browser client can hold a session. * is honoured but logs a warning and disables credentials, because browsers reject a wildcard origin together with credentials.

MCP_API_KEY

Bearer token; required on every HTTP transport

MCP_RATE_LIMIT / MCP_RATE_WINDOW

60 / 60

Sliding-window rate limit

RUBRICS_TTL

86400

Taxonomy cache TTL (seconds)

LOG_LEVEL

INFO

DEBUG | INFO | WARNING | ERROR. Structured JSON, one object per line, always on stderr — stdout carries the MCP protocol on a stdio transport.

Logging

Built on structlog. Every event emitted during a tool call carries that call's correlation_id, bound via contextvars — so a retry or an egress denial logged deep in the HTTP path can be joined to the request that caused it, without threading context through every signature.

Level

Emitted when

DEBUG

a tool call was entered (tool_call_started) — tells you whether a hung call ever started

INFO

a tool call finished cleanly, with latency

WARNING

upstream retry, egress denied, auth failure, rate limit

ERROR

a tool call raised

Records carry the exception type only — never its message and never an upstream response body.

{"event":"tool_call_started","tool":"gazette_search_procurement","correlation_id":"23221af26ae640c7","level":"debug","timestamp":"2026-07-27T22:20:07.494276Z"}
{"status":"ok","latency_ms":312,"event":"tool_call","tool":"gazette_search_procurement","correlation_id":"23221af26ae640c7","level":"info","timestamp":"2026-07-27T22:20:07.806Z"}

Ship these to your SIEM and alert on auth_failed, rate_limited, egress_denied, green_gate_violation and blocked_publication_requested — the last two mean something tried to reach a rubric this server does not serve.

Available Tools

Tool

Signature

Notes

gazette_search_publications

(keyword?, rubric?, sub_rubric?, canton?, date_start?, date_end?, limit=20, page=0, language='de', only_language=False)

Green rubrics enforced. Without rubric, all green rubrics are injected — a keyword-only query can never reach a blocked one.

gazette_search_detailed

same filters + top_n=3

Aggregated. Search and full text for the top top_n hits in one call, fetched in parallel. Same green gate on every expanded document; blocked ones are withheld and counted, never rendered.

gazette_search_procurement

(keyword?, canton?, date_start?, date_end?, include_inactive=False, limit=20, page=0, language='de', only_language=False)

OB-* rubrics plus the gazette-native sub-rubrics AR-VS40, AR-OW40, BA-SH40. A canton with neither gets a simap.ch explainer and no HTTP call. No CPV — the source has none.

gazette_get_publication

(id, response_format='markdown')

Full official text from XML. Re-checks the rubric after fetching; content from a blocked rubric is discarded.

gazette_list_rubrics

(language='de', rubric_class='green', response_format='markdown')

rubric_class='all' shows the full taxonomy with traffic-light classes and reasons — listed ≠ queryable.

gazette_source_status

(response_format='markdown')

Reachability, latency, cache age, scope metrics.

All tools are readOnlyHint=True.

Example use cases

Question

Tool chain

Tenders in Ticino this quarter

gazette_search_procurement(canton="TI", only_language=True, language="it")

Procurement simap.ch does not have

gazette_search_procurement(canton="VS") — 150 Valais awards, none on simap

Tenders in any other canton

→ use swiss-procurement-mcp

What is even queryable here?

gazette_list_rubrics()

Why can't I search bankruptcies?

gazette_list_rubrics(rubric_class="all")

Zoning changes in Zurich

gazette_search_publications(rubric="RP-ZH")

Full text of a notice

gazette_get_publication(id="fbf0ff9e-…")

Everything published about one company

→ use register-mcp

Data Protection & Scope

The Amtsblattportal systematically publishes personal data of natural persons. Those publications are public — but making them systematically queryable by name through an AI agent is a repurposing the publication never intended, and a profiling instrument under the revised Swiss FADP (revDSG).

Four rules follow, and they are enforced in code, not in documentation:

  1. Allow-list, never block-list. Not explicitly green ⇒ not queryable. New upstream rubrics are closed by default.

  2. No person-based search entry in any tool signature.

  3. No persistence. Publications have statutory deletion periods; a cache outliving them would actively undermine them. Only the taxonomy is cached.

  4. Blocked ⇒ explained. Never a silent empty result, never a hint at circumvention.

What is excluded

🔴 Konkurse (KK), Schuldbetreibungen (SB), Schuldenrufe (LS, SR), Nachlass (NA), Erbschaft/Testament/Ableben (ES, TE-*, VA-*), Familie & Zivilstand (FZ-*, BV-*, BU-*), gerichtliche Vorladungen (UV, GB-*, GE-*, SJ-BE), Baugesuche (BP-*), Grundbuch (GR-*), Meldungskatalog GR (AA-GR).

🟡 Deferred: Steuerwesen, Anzeigen, Bewilligungen, Bildungs- und Kirchenwesen and the general catch-all rubrics.

The full audit trail — including three documented extensions to the source specification — is in docs/rubric-classification.md.

How much each decision covers is measured, not estimated. docs/coverage-matrix.md enumerates the source's own rubric axis and marks this server's reach into it: 84.2 % of 2 804 063 publications are reachable, 12.6 % blocked by decision, 3.3 % still unclassified. The insolvency group alone is 321 704 publications — present in the source, out of reach here on purpose. Without that figure, "out of scope" and "not in the source" read the same in a review, and this repository made exactly that mistake once (see ARCH-003 in SECURITY.md).

The boundary with register-mcp

For publications about a specific company, use register-mcp. It keeps full rubric access — including a firm's own bankruptcy — but only ever keyed on a company UID. A firm's insolvency is corporate data, not natural-person profiling, and UID scoping makes name-based enumeration impossible.

amtsblatt-mcp has the opposite shape: broad search, narrow rubrics. It does not expose the upstream uids parameter at all.

Boundary with swiss-procurement-mcp

simap.ch is the primary source for Swiss public procurement — all 26 cantons plus the Confederation, with CPV and BKP codes, awards and publication history. Use swiss-procurement-mcp for procurement questions.

amtsblattportal.ch is the primary source for official notices — commercial register, spatial planning, enactments, cantonal and communal announcements. That is what this server is for; procurement is 6 of its 49 released rubrics.

Procurement here is largely a second publication of the same tenders, and that is now measured rather than assumed. A publication's XML carries <simapPublicationNumber> when it originates on simap.ch, which joins the two corpora exactly. Over the full 2026 OB-TI corpus, 503 of 546 records (92.1%) carry one; three of the six OB-* rubrics say as much in their own labels (OB-BL — "über Simap importiert (I N A K T I V)").

The exception is small and sharply bounded: AR-VS40 (Valais, 150 awards), AR-OW40 (Obwalden, 7), BA-SH40 (Schaffhausen, 2) and the Ticino sub-rubric OB-TI65 ("Avvisi di gara non CIAP") carry no simap reference at all. That is the one part of this portal's procurement coverage swiss-procurement-mcp cannot reach, and gazette_search_procurement serves it for cantons VS, OW and SH even though they have no active OB-* rubric. Numbers and method in docs/simap-overlap.md.

The two servers stay separate on purpose: different sources, different reuse terms, and a fail-closed rubric gate that only means something while it covers every tool in the server. See docs/procurement-coverage.md for the numbers.

Maturity & phase

Phase 1 — read-only. All six tools are read-only; there is no write path and none is planned. See ROADMAP.md for the phase-specific backlog, what is deliberately not planned, and what a phase transition would require.

The scope restriction that matters most here is not the phase but the green allow-list — rubrics carrying systematic natural-person data are not queryable, enforced in code and re-checked after every fetch. That does not change with phase. See Data Protection & Scope.

SDK and dependency updates arrive as Dependabot PRs, so a breaking protocol or SDK change is reviewed deliberately rather than drifting in silently.


Architecture

   Claude / MCP client
            │
      amtsblatt-mcp
            │
   ┌────────┴────────┐
   │  green gate     │  ← rubrics.py: fail-closed allow-list
   └────────┬────────┘     (checked at the tool AND at the query builder)
            │
   ┌────────┴────────┐
   │  param allow-   │  ← Silent Ignore guard
   │  list + quirks  │  ← Silent Empty guard (taxonomy validation)
   └────────┬────────┘  ← plausibility guard (corpus-size check)
            │
   ┌────────┴────────┐
   │ egress allow-   │
   │ list (httpx)    │
   └────────┬────────┘
            │
  amtsblattportal.ch/api/v1
   /publications · /publications/{id}/xml · /rubrics · /tenants

Architecture A (live-API-only). The endpoints answer stably without authentication, so no bulk dump is maintained.

Verified upstream quirks (live-checked 2026-07-20)

Quirk

Behaviour

Defence

Silent Ignore

An unknown parameter name returns HTTP 200 and the full corpus. canton=ZH (singular typo) silently drops the filter.

Query params built exclusively from ALLOWED_GAZETTE_PARAMS; plausibility guard rejects results > 2 000 000.

Silent Empty

An unknown rubric value returns HTTP 200 with total: 0 — indistinguishable from a real no-hit.

Every code validated against the taxonomy before the call.

Metadata only

The list endpoint and GET /publications/{id} both return content: null.

Full text only via /publications/{id}/xml.

Sorting ignored

pageRequest.sortOrders is accepted with 200 but has no effect; sortOrders comes back [].

Sorted client-side.

Missing publicationStates

Returns 401, not 400 — it does not mean credentials are required.

Always injected; the 401 message says so.

No page-size cap

pageRequest.size=2000 returns 2000 items.

Client-side cap of 100.

Inconsistent plurals

rubrics/cantons/subRubrics are plural, keyword/tenant singular.

Exact spellings encoded, not a pluralisation rule.

Known Limitations

  • Uneven cantonal coverage. Only 16 of 29 mandates expose their own rubric taxonomy; AG, FR, GE, GL, JU, LU, NE, UR are still incomplete.

  • Deletion periods. Publications drop out of the API over time — hence pass-through only.

  • Procurement boundary. Most cantons, including Zürich, route tenders through simap.ch, outside this portal. There is no OB-ZH, and no CPV classification exists here. What this portal has and simap does not is listed in docs/simap-overlap.md; gazette_get_publication reports simap_publication_number so a mirror is distinguishable from an original.

  • Procurement coverage, measured (publicationStates=PUBLISHED, 2026-07-27, records per calendar year — reproduce with python scripts/measure_procurement_coverage.py):

    Rubric

    2022

    2023

    2024

    2025

    2026

    Latest

    Status

    OB-TI

    517

    491

    625

    607

    546

    2026-07-27

    active

    OB-AR

    95

    85

    79

    56

    40

    2026-05-22

    active

    OB-BS

    1 149

    1 058

    319

    15

    2

    2026-05-20

    wound down during 2024

    OB-VS

    0

    1 052

    1

    0

    0

    2024-01-05

    archive — simap import until end of 2023

    OB-BL

    0

    74

    0

    0

    0

    2023-03-30

    archive — labelled «I N A K T I V»

    OB-ZG

    0

    0

    0

    0

    0

    never filled

    Only TI and AR still publish actively. OB-BS is the instructive case: its label is a plain "Öffentliches Beschaffungswesen" with no inactive marker, so only the volume reveals the migration — which is why active is measured, never read. Use include_inactive=True to reach the BS, BL and VS archives. Details in docs/procurement-coverage.md.

  • No push. Polling only; no subscription or webhook mechanism.

  • Legally binding text is the signed PDF, not this API.

MCP Protocol Version

Served via the initialize handshake

2024-11-052025-11-25 — the handshake ceiling

Served via the per-request envelope

2026-07-28

Who picks

The client's first request, once per connection. A request carrying the 2026-07-28 _meta envelope opens a modern connection; anything else opens a handshake connection.

Pinned in

MCP_PROTOCOL_VERSION in _app.py, re-exported from server.py

SDK

mcp[cli]>=2.0.0,<3

Cache hints

tools/list and server/discover: ttlMs 300000, cacheScope public

The MCP Python SDK negotiates the protocol version in the session layer and offers no constructor parameter for it, so the version cannot be pinned by configuration. It is pinned as a declared constant and enforced by detection:

  • At runtime, a mismatch logs a protocol_version_drift event at WARNING. The server keeps working.

  • In CI, tests/test_protocol_version.py fails.

An SDK bump should break our build, not the runtime of someone who upgraded mcp in their own environment.

Update policy

  • Dependabot opens SDK update PRs monthly (.github/dependabot.yml).

  • When an update moves the protocol version, the CI test fails. The fix is not to edit the constant blindly: read the spec changelog, verify the server still behaves — especially the green allow-list invariants — then bump the constant, this section and CHANGELOG.md in one commit.

  • Protocol-version bumps are called out explicitly in CHANGELOG.md, not folded into a dependency-bump line.

Cache hints

Spec 2026-07-28 gives every cacheable result a ttlMs and a cacheScope. The SDK defaults both to «immediately stale, never shared», so a server that passes no cache_hints is not neutral — it asks every client to re-list on every connection. This server's tool list is registered at import and identical for every caller, so it is announced as cacheable for five minutes and shareable across authorization contexts (CACHE_HINTS in _app.py).

public rests on that second property, not on convenience: the green allow-list is enforced per request inside the tools, never by hiding a tool from a caller. The day a tool list becomes caller-dependent, the scope has to become private in the same commit.


Primitives: tools only

This server exposes tools and neither resources nor prompts. A decision, not an omission (ARCH-008).

Why not resources. Resources address identifiable, listable content the client can enumerate and cache. This corpus is 2.79 million publications that grows daily, and — more importantly — not all of it is servable. Rubrics carrying systematic personal data are excluded by design, and that exclusion is enforced at two points: a pre-request green gate on the filters, and a post-fetch gate on the returned document.

A resource URI would put a publication id in the client's hands as an enumerable address. Since ids are opaque, the rubric behind one cannot be known until the document is fetched — which is exactly why the post-fetch gate exists. Exposing publications as resources would mean either enumerating ids we have not gated yet, or gating at fetch time anyway, at which point the resource abstraction buys nothing and costs a second content path to keep the guarantee on. This repo has already learned that lesson once: the aggregated tool needed the gate extracted into a shared helper precisely because a second path to content is where such guarantees quietly stop holding.

One candidate was checked concretely:

Candidate

Why it stays a tool

gazette_list_rubrics

Genuinely resource-shaped — a finite, slow-changing taxonomy, already cached with a TTL. But its whole purpose is to communicate that listed ≠ queryable: it renders traffic-light classes and the reason each blocked rubric is blocked. As a resource that framing would be a document the model may or may not read; as a tool it is an answer to a question the model asked.

Why not prompts. Question templates would duplicate guidance the tool docstrings already carry, in a second place that can drift out of sync with the allow-list. Given that the docstrings are what tell the model which rubrics are reachable, one source is safer than two.

Return shapes: rendered text, not models

Tools return str — Markdown by default, JSON via response_format='json' — rather than Pydantic models. This is a documented deviation from SDK-002, made deliberately rather than by neglect.

The rendered output is not a serialisation of an internal object; it is composed for the reader. It carries the provenance line, the scope statement (green_rubrics_only), the deduplication warning when language variants were merged, and the explanation a blocked rubric returns instead of data. Those are the parts that keep the model from drawing wrong conclusions, and they are prose, not fields.

Returning a model would either drop them or smuggle them back in as string fields, which is the same thing with more ceremony. The json format already covers the machine-readable case for callers that want it.

What would change this: a caller that needs to compute over results rather than read them. At that point the right move is typed models on the JSON path specifically, not a wholesale change of what every tool returns.


Testing

pip install -e ".[dev]"
PYTHONPATH=src pytest tests/ -m "not live"   # 75 tests, no network
PYTHONPATH=src pytest tests/ -m live         # hits the real API
ruff check src/ tests/ scripts/
ruff format --check src/ tests/ scripts/
python scripts/check_version_sync.py

These are the same gates CI runs, over the same directories. The dev extra pins ruff to the version CI installs, so a local run and a CI run agree.

The suite covers the mandatory portfolio set: green-rubric search with source URL, blocked rubric → explanation with zero HTTP calls, canton filtering, Europe/Zurich deadline arithmetic against a fixed "today", pagination across a page boundary, language deduplication, boolean normalisation, and API-unreachable handling. Fixtures are shortened real responses, consistently anonymised — no real personal data.

Project Structure

amtsblatt-mcp/
├── src/amtsblatt_mcp/
│   ├── rubrics.py       # Fail-closed green allow-list — the scope decision
│   ├── server.py        # MCPServer, 5 tools, quirk guards, XML parsing
│   ├── _log.py          # Structured JSON logging + per-tool call events
│   ├── _middleware.py   # Bearer auth + sliding-window rate limit (SSE only)
│   └── _otel.py         # Optional OpenTelemetry wiring
├── tests/
│   ├── test_allowlist.py    # Data-protection invariants (own CI job)
│   ├── test_search.py       # Search, procurement, pagination, dedup, errors
│   ├── test_publication.py  # XML parsing, deadlines, egress allow-list
│   └── fixtures.py          # Anonymised real responses
├── docs/
│   ├── rubric-classification.md   # Why each of the 152 rubrics is open/closed
│   ├── procurement-coverage.md    # Measured OB-* volume; why `active` is measured
│   ├── coverage-matrix.md         # Measured reach: which part of the corpus the tools cover
│   └── simap-overlap.md           # Mirror vs. original, joined on simapPublicationNumber
├── scripts/
│   ├── measure_procurement_coverage.py
│   └── measure_coverage_matrix.py
├── Dockerfile · compose.yaml      # Hardened, non-root, read-only container
└── server.json                    # MCP registry manifest

Changelog

See CHANGELOG.md.

Contributing

See CONTRIBUTING.md. Changes to src/amtsblatt_mcp/rubrics.py require an explicit rationale in the PR description: releasing a rubric is a data-protection decision, not a feature.

Security

See SECURITY.md for reporting and operator hardening notes.

License

MIT — see LICENSE. Data-source notice: NOTICE.md.

Data source: amtsblattportal.ch, operated by SECO / State Secretariat for Economic Affairs on behalf of the Swiss Confederation. Freely usable, but without warranty of completeness or accuracy. Only the signed PDF of a publication is legally binding.

Author

Hayal Oezkan · malkreide

Part of the Swiss Public Data MCP Portfolio:

  • register-mcp — Zefix commercial register with a company-UID join to the gazettes

Available Tools

6 tools
gazette_get_publicationA
Read-onlyIdempotent

Retrieve the full text of one publication once you have its id from a search. Refuses ids whose rubric is not released, after fetching — the rubric is not knowable from the id alone.

Einzelne Publikation inkl. amtlichem Volltext (aus dem XML, defensiv geparst).

Die Listen-API liefert nur Metadaten — der eigentliche Inhalt steht ausschliesslich im rubrikspezifischen XML unter /publications/{id}/xml. Das Schema ist pro Subrubrik verschieden; Pflichtfelder sind meta und der Publikationstext, bei HR-Rubriken zusätzlich die Firmenangaben. Alles Übrige landet best-effort in additional_fields.

Nach dem Abruf wird die Rubrik der Publikation erneut gegen die Freigabe-Liste geprüft: eine ID aus einer gesperrten Rubrik liefert die Scope-Erklärung statt des Inhalts.

Args: params (PublicationInput): - id (str): Publikations-ID (UUID) - response_format (str): 'markdown' oder 'json'

Returns: str: Volltext, Metadaten, allfällige Eingabefrist und Zusatzfelder.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description provides extensive behavioral details beyond annotations, including: the source is XML, schema varies per subrubric, required fields, best-effort handling of additional_fields, and a secondary check on rubric release that may refuse some IDs. No contradiction with annotations (readOnlyHint, idempotentHint, destructiveHint).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (use case, technical details, args, returns) and is front-loaded with the purpose. However, it is somewhat verbose with mixed languages (German and English) and some redundancy (e.g., 'Einzelpublikation inkl. amtlichem Volltext' repeats the use case).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (one parameter, output schema present), the description covers usage, edge cases (refused IDs), and return values at a high level. It is complete enough for an agent to use correctly, though it could mention that output structure depends on rubric type.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description lists both parameters (id and response_format) with brief additional context (example for id, default value for response_format). The input schema already provides similar descriptions, so the description adds limited extra value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the use case: 'Retrieve the full text of one publication once you have its id from a search.' It clearly identifies the verb (retrieve), resource (full text of publication), and distinguishes from sibling tools like gazette_search_publications which are for searching.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies that the tool should be used after obtaining an ID from a search ('once you have its id from a search'). However, it does not explicitly state when not to use this tool or provide alternatives among siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gazette_list_rubricsA
Read-onlyIdempotent

Discover which rubrics exist and which this server serves, before searching. Call this when a search returns nothing to tell "no such publications" apart from "that rubric is deliberately not served".

Rubrik-Taxonomie des Amtsblattportals mit Ampel-Klassierung.

Voraussetzung für gültige Filter: Rubrik-Codes werden in den Such-Tools gegen diese Taxonomie UND gegen die Freigabe-Liste validiert. Standardmässig werden nur die erschlossenen («grünen») Rubriken gezeigt.

Mit rubric_class='all' erscheint die vollständige Taxonomie inklusive der gesperrten Rubriken mit Begründung — zur Transparenz über den Scope-Entscheid. Aufgeführt zu sein bedeutet nicht durchsuchbar zu sein; nur 🟢 ist abfragbar.

Args: params (RubricsInput): - language (str): 'de', 'fr', 'it', 'en' - rubric_class (str): 'green' (Standard) oder 'all' - response_format (str): 'markdown' oder 'json'

Returns: str: Rubriken mit Code, Name, Ampel-Klasse und Subrubriken.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds significant behavioral context beyond annotations: it explains default filtering to green rubrics, the effect of rubric_class='all', and the important caveat that listing does not imply searchability. Annotations already cover safety, so the description enriches understanding of data semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is structured but contains a German sentence that may not add value for an agent. The Args section repeats schema info. While it is organized with headings, it could be more concise. Score 3.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers usage context, parameter behavior, and output overview. Given the presence of an output schema, the brief description of the return value is sufficient. It explains when to use and what to expect, making it contextually complete. Score 4.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description includes an Args section that mirrors the schema parameters but adds explanatory context, such as the meaning of 'green' vs 'all' and language options. Since the schema already contains descriptions, the description provides moderate added value. Score 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the tool's purpose: to discover available rubrics and their server status, with a clear use case for search troubleshooting. It distinguishes from sibling search tools by positioning this as a prerequisite.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: when searches return nothing. It explains the purpose of distinguishing between missing publications and unavailable rubrics. While it doesn't explicitly state when not to use, the sibling tools are search-oriented, making the distinction clear. Score 4 due to lack of explicit negative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gazette_search_detailedA
Read-onlyIdempotent

Answer a question needing both the hit list and each hit's full text in one step. Prefer this over a search followed by N gazette_get_publication calls.

Sucht Publikationen UND liefert den Volltext der obersten Treffer — ein Aufruf.

Aggregierter Einstieg für den häufigen Fall «finde Bekanntmachungen und zeig mir, was drinsteht». Ohne dieses Tool braucht dieselbe Frage 1 + N Aufrufe: einmal gazette_search_publications, dann gazette_get_publication je Treffer. Hier laufen die Detailabrufe parallel, die Wartezeit ist also die des langsamsten Einzelabrufs statt ihrer Summe.

Filter und Semantik sind identisch mit gazette_search_publications — einschliesslich der Freigabeliste: ohne rubric werden alle freigegebenen Rubriken injiziert, und jeder abgerufene Volltext durchläuft dasselbe Post-Fetch-Green-Gate. Eine Publikation aus gesperrter Rubrik wird auch hier verworfen und nie gerendert.

Für Ausschreibungen mit Volltext in einem Aufruf: rubric='OB-<Kanton>' setzen, z.B. rubric='OB-TI'. gazette_search_procurement bleibt der bequemere Einstieg, wenn nur die Trefferliste gebraucht wird — es kennt die Kanton-zu-Rubrik-Auflösung und die inaktiven Kantone.

Wann stattdessen die Einzeltools:

  • Nur die Trefferliste gewünscht → gazette_search_publications (billiger).

  • Volltext zu einer bekannten ID → gazette_get_publication.

  • Mehr als 5 Volltexte → suchen und die gewünschten gezielt einzeln holen.

Args: params (DetailedSearchInput): - top_n (int): Anzahl Volltexte (1–5, Standard 3) - übrige Felder: identisch zu gazette_search_publications

Returns: str: Trefferliste plus Volltext der obersten top_n Publikationen.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, etc., but the description adds substantial behavioral context: parallel execution of detail fetches ('Hier laufen die Detailabrufe parallel'), the green gate filtering ('Post-Fetch-Green-Gate'), identical semantics with gazette_search_publications, and that top_n defaults to 3. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with sections (<use_case>, explanation, when-to-use alternatives, args). It is front-loaded with the primary use case. However, it is somewhat lengthy (multiple paragraphs) and could be more concise without losing important details. Each sentence contributes, but some repetition exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (aggregated search+full text, parallel calls, relationship with multiple siblings, procurement shortcut), the description is remarkably complete. It covers the behavioral model, green gate filtering, identical filters to sibling, when to use alternatives, and the top_n parameter. The output schema exists, so return values are handled.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explicitly defines top_n (including range and default) and mentions that other fields are identical to gazette_search_publications. While the schema provides detailed descriptions for all parameters, the description could be more explicit about key parameters like rubric, canton, etc. It adds some value but not full compensation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: to answer a question needing both hit list and full text in one step. It uses specific verbs ('Sucht... UND liefert') and distinguishes from siblings by explaining it's an aggregated tool that saves multiple calls. The differentiation from gazette_search_publications, gazette_get_publication, and gazette_search_procurement is explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool and when to use alternatives. It lists specific scenarios ('Nur die Trefferliste gewünscht → gazette_search_publications', 'Volltext zu einer bekannten ID → gazette_get_publication', 'Mehr als 5 Volltexte → einzeln holen') and also mentions the procurement shortcut with rubric='OB-<Kanton>'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gazette_search_procurementA
Read-onlyIdempotent

Find public tenders published in the gazette (Submissionen) — the procurement-specific entry point. Note only AR, BS, TI, ZG, BL and VS mirror tenders here; for full Swiss coverage including Zurich use swiss-procurement-mcp.

Sucht öffentliche Ausschreibungen (Beschaffungswesen/Submissionen).

Beschaffung ist ausschliesslich eine KANTONALE Rubrik (OB-<Kanton>), nicht föderal. Nur wenige Kantone publizieren sie hier: AR und TI (aktiv) sowie BS, BL, VS, ZG (inaktiv — BS/BL/VS nur Archiv, ZG leer).

WICHTIG — Spiegel vs. Original: Die OB-*-Rubriken sind praktisch vollständig Zweitpublikationen von simap.ch-Ausschreibungen (gemessen über den OB-TI-Jahrgang 2026: 92,1 % tragen eine simap-Publikationsnummer). Wer Beschaffung sucht, ist mit swiss-procurement-mcp an der Primärquelle besser bedient — alle 26 Kantone plus Bund, mit CPV- und BKP-Codes, Zuschlägen und Publikationsverlauf.

Was es NUR hier gibt, sind die Beschaffungs-Subrubriken AR-VS40 (Wallis, Zuschläge), AR-OW40 (Obwalden) und BA-SH40 (Schaffhausen) sowie die Ticiner Subrubrik OB-TI65 («Avvisi di gara non CIAP»): keine davon trägt eine simap-Nummer. Kanton VS, OW und SH liefern deshalb Treffer, obwohl sie keine aktive OB-*-Rubrik haben. Die meisten Kantone — inklusive Zürich — publizieren Ausschreibungen über simap.ch, das NICHT Teil dieser Quelle ist; eine Abfrage für einen solchen Kanton liefert eine Erklärung statt eines leeren Ergebnisses. Die Quelle kennt keine CPV-Codes.

Args: params (ProcurementInput): - keyword (Optional[str]): Freitext (kein CPV-Code) - canton (Optional[str]): Kantonskürzel; ohne Angabe alle aktiven - date_start / date_end (Optional[str]): Zeitraum YYYY-MM-DD - include_inactive (bool): inaktive Rubriken (BL/BS/VS/ZG) einbeziehen - limit (int): 1–100 (Standard 20), page (int): 0-basiert - language (str), only_language (bool), response_format (str)

Hinweis zur Trefferzahl: Ticino publiziert überwiegend it/fr, Appenzell A.Rh. de/fr — je Sprache ein eigener Datensatz mit eigener Publikationsnummer. Identische Titel werden zusammengefasst, übersetzte bleiben getrennt; die Trefferzahl kann daher über der Zahl verschiedener Ausschreibungen liegen. only_language=True erzwingt eine einzelne Sprachfassung.

Returns: str: Ausschreibungen (neueste zuerst) mit Datum, Kanton, Titel, Sprache, ID.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint, destructiveHint, idempotentHint), the description adds critical behavioral context: that results come from simap.ch mirror, which cantons are active/inactive, language duplication behavior, and unique subrubrics. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with sections and bullet points. However, it is somewhat lengthy and repeats language behavior details. Could be more concise, but the structure aids readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Comprehensive: covers data source, canton coverage, language handling, pagination, unique features (subrubrics without simap numbers), comparison with alternative tool, and return format. Given complexity and presence of annotations/output schema, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite schema description coverage being 0%, the description includes a detailed Args section that explains each parameter's purpose and constraints (e.g., 'kein CPV-Code', 'Freitext'). Adds context beyond schema property descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: finding public tenders (Submissionen) in the gazette. It specifies procurement-specific entry point and distinguishes from siblings by noting it's for procurement. It also mentions which cantons are covered and points to an alternative for full Swiss coverage.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Excellent guidance: explicitly states when to use this tool (for gazette procurement), when not to use it (full Swiss coverage requires swiss-procurement-mcp). Details limitations (only certain cantons, no CPV codes, duplicate entries due to languages) and gives alternative tool name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gazette_search_publicationsA
Read-onlyIdempotent

Search the released gazette rubrics by keyword, rubric, canton and date — the general entry point when the question is "what was officially published about X?". Combine rubric with canton: a bare rubric filter is silently ignored upstream.

Sucht amtliche Publikationen im Amtsblattportal (SHAB + kantonale Amtsblätter).

Durchsucht ausschliesslich die freigegebenen («grünen») Rubriken: Handels- register, öffentliche Beschaffung, kantonale und kommunale Bekanntmachungen, Beschlüsse und Rechtsetzung, politische Rechte, Raumplanung sowie Umwelt/ Verkehr/Energie. Rubriken mit systematischen Personendaten — Konkurse, Schuldbetreibungen, Erbschaft, Zivilstand, gerichtliche Vorladungen, Baugesuche — sind bewusst nicht erschlossen und liefern eine Erklärung statt Daten. Ein Personennamen-Sucheinstieg existiert nicht.

Ohne rubric werden alle freigegebenen Rubriken injiziert, sodass eine reine Stichwortsuche niemals eine gesperrte Rubrik erreichen kann.

Args: params (SearchInput): - keyword (Optional[str]): Volltext-Suchbegriff - rubric / sub_rubric (Optional[str]): freigegebene Codes - canton (Optional[str]): Kantonskürzel - date_start / date_end (Optional[str]): Zeitraum YYYY-MM-DD - limit (int): 1–100 (Standard 20), page (int): 0-basiert - language (str): bevorzugte Sprache - only_language (bool): nur diese Sprachfassung - response_format (str): 'markdown' oder 'json'

Hinweis zur Trefferzahl: Das Portal publiziert eine Bekanntmachung je Sprache als eigenen Datensatz mit eigener Publikationsnummer. Sprachfassungen mit identischem Titel werden zusammengefasst, übersetzte bleiben getrennt — die Trefferzahl kann daher über der Zahl verschiedener Bekanntmachungen liegen. language_mix weist die Verteilung aus, only_language=True erzwingt eine einzelne Sprachfassung.

Returns: str: Trefferliste mit Datum, Kanton, Rubrik, Titel, Sprache, ID und URL.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint, idempotentHint, and destructiveHint=false. The description adds significant context: which rubrics are included/excluded, behavior when no rubric is provided, language deduplication and hit count nuance, and the effect of the only_language parameter. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a use-case statement, search scope, exclusions, parameter list, and a note on hit count. It is front-loaded. While slightly lengthy, every section provides necessary context for an AI agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (multiple parameters, special behavior on rubrics and language), the description is comprehensive. It covers search scope, excluded rubrics, parameter details, return format, and edge cases like language deduplication and hit count. The return value is adequately described even without an explicit output schema shown.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already includes detailed descriptions for each parameter, so baseline is 3. The tool description adds extra value by explaining the effect of combining rubric with canton, the injection of all rubrics when rubric is omitted, and the hit count and language deduplication behavior, which go beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it searches official publications in gazette rubrics by keyword, rubric, canton, and date. It positions itself as the general entry point for 'what was officially published about X?' and distinguishes from siblings by mentioning specific use cases and what it does not cover (e.g., personal data rubrics).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use the tool ('general entry point'), and clearly states what it does not handle (rubrics with personal data, person name search). It implies alternatives for excluded cases, though it does not name sibling tools directly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gazette_source_statusA
Read-onlyIdempotent

Check whether amtsblattportal.ch is reachable and what the released scope is. Call this when a search returns nothing and you need to distinguish an empty result from a source that could not be asked — the two are not the same answer.

Status des Amtsblattportals, Cache-Alter und Umfang der Freigabe-Liste.

Prüft die Erreichbarkeit des Upstreams, meldet das Alter des Taxonomie-Caches und wie viele Rubriken erschlossen sind.

Args: params (StatusInput): - response_format (str): 'markdown' oder 'json'

Returns: str: Erreichbarkeit, Latenz, Cache-Alter und Scope-Kennzahlen.

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint, idempotentHint, and destructiveHint. The description adds value by detailing what the tool actually measures (reachability, cache age, scope count) and that it's a non-mutating status check. No contradictions with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description includes a <use_case> tag, a German sentence, an English sentence, and an 'Args:'/'Returns:' block. While structured and informative, it is somewhat verbose with language mixing and could be more concise without losing clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple status-check tool with rich annotations and an output schema, the description covers all necessary information: what it checks, when to use it, and what it returns (reachability, latency, cache age, scope metrics). It is fully complete for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite schema description coverage being 0% per metric, the description explicitly documents the single parameter (response_format) and its valid values ('markdown' or 'json') in the 'Args' section. This compensates well for the lack of schema-level descriptions, adding practical meaning for the agent.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool checks reachability of amtsblattportal.ch, cache age, and released scope. The <use_case> tag explicitly distinguishes this status-check tool from the sibling search tools, making its purpose highly specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance: 'Call this when a search returns nothing and you need to distinguish an empty result from a source that could not be asked.' This tells the agent exactly when to use this tool versus the search siblings, which is textbook usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 10 tool updatesv0.17.0
    • Addedgazette_get_publication
    • Addedgazette_list_rubrics
    • Addedgazette_search_detailed
    • Addedgazette_search_procurement
    • Addedgazette_search_publications
    • Addedgazette_source_status
    • Removedget_publication
    • Removedsearch_procurement
    • Removedsearch_publications
    • Removedsource_status
  2. 4 tool updatesv0.1.2
    • First observedget_publication
    • First observedsearch_procurement
    • First observedsearch_publications
    • First observedsource_status

TDQS

A4.4/5.0
Disambiguation5/5

Each tool serves a distinct purpose: general search, detailed search with full text, procurement-specific search, single publication retrieval, rubric listing, and source status. No two tools overlap in functionality, making agent selection unambiguous.

Naming Consistency5/5

All tools follow a consistent 'gazette_verb_noun' pattern (e.g., gazette_search_publications, gazette_list_rubrics). The naming is predictable and uniform, with clear verb-noun pairs.

Tool Count5/5

With 6 tools, the server is well-scoped for interacting with the Swiss official gazette. Each tool is justified, covering search, retrieval, status, and metadata, without unnecessary extras.

Completeness4/5

The tool set covers all essential operations: searching (list and detailed), single publication retrieval, rubric discovery, and status checks. Minor gaps include lack of bulk retrieval beyond 5 items, but the domain is well-served.

Maintenance

ActivityActive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/amtsblatt-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server