fds-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@fds-mcpWho has to answer a freedom-of-information request about the city of Bonn, and under which act?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
fds-mcp — FragDenStaat.de for AI assistants
An MCP server for FragDenStaat.de, the German freedom-of-information platform built on froide.
Prepare a German freedom-of-information request by asking for it in plain language. Your assistant finds the authority that has to answer and proves why it is the right one, names the act that applies and the deadline it sets, tracks the requests you already sent, collects the replies and their attachments, and writes a new request to a local file that you read before anything leaves your machine.
What is MCP, and what does it do here?
MCP, the Model Context Protocol, is the standard that
lets an AI assistant use outside tools — roughly what an extension does for a browser.
fds-mcp is one such tool. Install it once and Claude, or any other MCP client, gains 15
tools that speak to FragDenStaat.de, the German
freedom-of-information platform built on froide.
Four of them need no account and no token: searching authorities, reading an act, and working out who is responsible for a given place all work straight away.
Other froide instances
froide is the Django software underneath FragDenStaat.de, and its own README names a second production portal: fragdenstaat.at. Point this server at one with
export FDS_MCP_BASE_URL=https://fragdenstaat.atOnly https origins without a path or credentials are accepted, and the host allowlist that
keeps the bearer token from following a link to a stranger is derived from this value — so
with .at configured, fragdenstaat.de is a foreign host and is refused.
What that buys you, measured against fragdenstaat.at on 2026-09-05 and kept as live tests:
| work, with no account |
| cannot work there — |
the token-bound tools | need an OAuth application registered on that instance |
the pre-send rule set | encodes German FOI law and is not portable. Treat submitting through another instance as unverified |
What it looks like
You: Who has to answer a freedom-of-information request about the city of Bonn, and under which act?
The assistant calls
check_jurisdiction("Bonn"), gets the region chain andKommunalverwaltung Bonn(authority 3495), thenget_authority(3495)for the acts that apply and their deadlines — and reports the API URLs it used, so you can check the answer instead of believing it.
Submitting is possible too, but it is deliberately the hardest thing this server does.
⚠️ POST /api/v1/request/ sends immediately and irreversibly
FragDenStaat's REST API has no draft mode, no preview and no undo. The moment a
POST /api/v1/request/ succeeds, the e-mail is on its way to the authority, the request
is public (by default) under CC0, and it cannot be recalled.
Worse, MakeRequestSerializer has no law_type field. The API therefore always
files under publicbody.default_law, and because froide sorts by ("-meta", "-priority")
that is almost always the combined meta act — not the specific act you meant. For a
municipality in Rhineland-Palatinate, asking for the LTranspG (law 16) through the API
silently files under "LTranspG, VIG" (law 18) instead.
Because of this, the recommended exit of this server is build_submit_url, which
hands you a prefilled web form with the correct law_type and lets you press send
yourself. submit_request exists, defaults to dry_run=True, and refuses unless five
independent gates all agree — see Safety model.
Related MCP server: What Do They Know
Documentation
What the API can and cannot do — every limit we hit, how we measured it, the dead ends we tried, and the mistakes we made along the way
OAuth setup, with screenshots — registering the application, scopes, the redirect-URI rules, and what to do when the local HTTPS listener is blocked
README.de.md and docs/oauth-setup.de.md — the same documents in German. US English is the source; the German version follows it.
Installation
pip install fds-mcpOr run it without installing anything, straight from PyPI:
uvx fds-mcp serveFrom a checkout, for development:
git clone https://github.com/notDIRK/fds-mcp.git
cd fds-mcp
pip install -e ".[dev]"Requires Python 3.10 or newer.
Register it with your MCP client
The server speaks stdio. For Claude Code:
claude mcp add fds -- fds-mcp serveFor a client that reads a JSON config:
{
"mcpServers": {
"fds": {
"command": "fds-mcp",
"args": ["serve"]
}
}
}Or without installing it at all:
{
"mcpServers": {
"fds": {
"command": "uvx",
"args": ["fds-mcp", "serve"]
}
}
}The four green tools work immediately, with no account and no token.
OAuth setup
The yellow and red tools need an OAuth 2.0 bearer token. FragDenStaat supports exactly
two authentication schemes for its API — OAuth2 and session cookies. There is no
personal API key and no Basic Auth (froide's own docs/api.rst claims otherwise; it is
out of date).
1. Register an application
Log in and open https://fragdenstaat.de/account/applications/register/. All account
pages are protected by recent_auth_required, so you may be asked for your password
again.
Field | Value |
Name | anything, e.g. |
Client type |
|
Authorization grant type |
|
Redirect URI |
|
Only the schemes https and fragdenstaat are accepted. http://localhost/... is
rejected at registration time — this is OAUTH2_PROVIDER.ALLOWED_REDIRECT_URI_SCHEMES on
the server. That is why the default redirect is an HTTPS loopback listener with a
self-signed certificate that fds-mcp generates for you (via openssl), and why the
fallback is fragdenstaat://callback with a manual paste.
2. Configure and log in
fds-mcp configure --client-id <your-client-id>
fds-mcp loginlogin runs Authorization Code + PKCE (S256), opens your browser, and catches the
redirect on https://localhost:8765/callback. Your browser will warn about the
self-signed certificate — that is the local listener; accept it.
Without a browser or without openssl:
fds-mcp login --manual # uses fragdenstaat://callback, you paste the URL backTokens land in ~/.config/fds-mcp/tokens.json with mode 0600. Refresh happens
automatically; refresh tokens are valid for 180 days.
fds-mcp status # config, token and throttle state
fds-mcp whoami # the authenticated account
fds-mcp logout --revokeScopes
fds-mcp requests read:user read:request make:request by default. Override with
fds-mcp configure --scopes "read:user read:request" if you never want to submit.
Scope | Needed for |
| identifying your own account ( |
| your own, including non-public, requests |
|
|
| documenting postal mail (not yet implemented) |
Nothing here grants deletion. If you drop make:request, submit_request can never
work, and everything else still does.
Tools
Tool | Tier | Auth | Side effect |
| 🟢 green | none | none |
| 🟢 green | none | none |
| 🟢 green | none | none |
| 🟢 green | none | none |
| 🟡 yellow | token, read only | none |
| 🟡 yellow | token, read only | none |
| 🟡 yellow | token, read only | none |
| 🟡 yellow | token, read only | none |
| 🟡 yellow | token, read only | writes a local file |
| 🟡 yellow | token, read only | none |
| 🟡 yellow | token, read only | writes a local YAML file if |
| 🔴 red | none | writes a local YAML file, no network at all |
| 🔴 red | none | reads the API for L01–L05 |
| 🔴 red | none | writes a local |
| 🔴 red | token + | sends the request, irreversibly |
| 🔴 red, opt-in | a logged-in browser profile | sends the reply, irreversibly |
All four red tools take dry_run: bool = True.
send_reply_via_browser is the sixteenth tool and is not registered unless
FDS_MCP_BROWSER_SEND=1 is set. Without that variable it does not appear in the tool
list at all. Read Sending replies before you switch it on.
check_jurisdiction returns its evidence
It walks /georegion/?name=<place> up its part_of chain and asks
/publicbody/?regions=<id> at every level, then returns the region chain, the matching
authorities, and the list of API URLs it used. That matters in Rhineland-Palatinate,
where an Ortsgemeinde is often not listed on FragDenStaat at all while the
Verbandsgemeindeverwaltung that administers it is.
build_submit_url is two-step for long requests
Measured on 2026-09-05: fragdenstaat.de answers GET URLs above roughly 4096 bytes
with HTTP 400 (4086 bytes → 200, 4106 bytes → 400). A typical 4000-character request
exceeds that once URL-encoded. Above the limit the tool returns a short URL that prefills
subject and law_type, plus the body in a .body.txt file next to your draft, which you
paste into the form.
What FragDenStaat's API cannot do
These are frontend-only, with no REST equivalent. The server does not pretend otherwise:
replying to an authority —
POST /api/v1/message/only creates postal messages (OnlyPostalMessagesWritable), andsubject/contentare read-only serializer fields. E-mail replies go through/anfrage/<slug>/send/message/, a CSRF-protected Django view that ignores bearer tokens. See Sending replies;choosing the legal basis — no
law_typein the serializer;drafts —
RequestDraftis not registered in the API router;setting status, resolution, tags or the law after the fact; publishing a request; filing an objection or escalating to the state information commissioner.
Sending replies
An e-mail reply to an authority cannot be sent through the FragDenStaat API. Not with
a different payload, not with an extra scope, not with a better token. Three
measurements, taken on 2026-09-05 and kept honest by tests/test_api_contract.py:
POST /api/v1/message/withkind: "email"answers HTTP 400 and reports, under the keykind: "Nachrichten dieser Art können nicht über die API erstellt werden." That is froide'sOnlyPostalMessagesWritable.The identical call with
kind: "post"also answers 400 — the probe deliberately carries an unresolvable request URI, so nothing can be created either way — but it carries nokinderror. That is the calibration. Without it the first measurement would prove nothing: a 400 could just as well come from the invalid URI, from the endpoint refusing every POST, or from a missing scope.POST https://fragdenstaat.de/anfrage/<slug>/send/message/answers HTTP 302 to/account/login/— identically with and without a bearer token, same status, sameLocation. The web view is session + CSRF only. OAuth is not a way around point 1.
So the honest answer is: a human sends the reply. build_reply_draft is what makes that
short.
build_reply_draft
Looks the request up, validates your text, and hands back the finished message, a subject
in froide's own format (AW: <title> [#<id>]) and the URL of the form. It writes nothing
to the network — there is no argument that makes it send.
A follow-up is validated differently from a request, and the difference is easy to get
wrong. froide frames a new request with the act's letter_start/letter_end; it does not
frame a follow-up at all. The textarea arrives prefilled with
Guten Tag,
…
Mit freundlichen Grüßen
<your name>and exactly what stands in it is what the authority receives. Hence:
R19requires a salutation and a closing formula, each exactly once — the inverse ofR10, which forbids both while the frame is in play;R04rejects the placeholder…(U+2026) that is sitting in that form right now. It is the single most likely mistake on this path;R06keeps e-mail addresses and IBANs out of a thread that is public and CC0;the subject is capped at 230 characters.
Every result carries one more warning, unconditionally: the form has your postal address prefilled, behind a checkbox labelled "Adresse mitsenden". On a public request, ticking it publishes where you live, under CC0, permanently. Leave it unticked unless the authority has explicitly asked for your postal address.
send_reply_via_browser — optional, off by default
There is a way to automate the last step anyway: drive the form in a browser that carries
your logged-in session. This server can do that, and it is not switched on. It is
registered only when FDS_MCP_BROWSER_SEND=1 is set, and it needs an extra:
pip install 'fds-mcp[browser]'
python -m playwright install chromium
export FDS_MCP_BROWSER_SEND=1It never composes text. It sends the subject and body of a reply draft file that
build_reply_draft wrote and a human then approved — there is no other input it takes.
Five gates:
the file is a reply draft with
status: approved, andsend_addressis false;no
ERRORfinding is open under the follow-up rules;confirmation_tokenmatches, byte for byte, the token a human wrote into the file;the local ledger says another message stays inside
2/5min,6/6h,8/24h. froide does not enforcemessage_throttleon this path in a way we can rely on, so this brake is voluntary;in the form itself: "Adresse mitsenden" is off, the recipient can be read and is reported, subject and message read back byte for byte after being typed, no U+2026, and exactly one salutation and one closing formula. Anything it cannot find, it treats as a failure — a form that changed shape is a form it must not press buttons in.
Afterwards it asks the API whether a new message actually exists on the request. If none
does, the outcome is reported as unconfirmed and the draft is not marked sent.
Unclear is not failure and it is not success.
What you are accepting when you switch this on
Browser automation defeats the principle that a human performs the last action. Every other exit in this server ends with a person clicking send. This one does not.
Next to a general-purpose file-writing tool, gates 1 and 3 are not gates. They are two values in a YAML file on your disk. No tool in this server can set either —
build_reply_draftalways writesstatus: draftand the placeholder token. But most MCP hosts also give the model awrite_filetool, and a model that can write files can writestatus: approvedand a token of its own choosing. Combine that with a prompt injection out of an authority's reply — text this server reads and labels as untrusted, but still puts in front of the model — and post to a public authority goes out with no human in the loop. It cannot be recalled.The browser carries a logged-in session of yours. A malfunction acts with your full rights on fragdenstaat.de: your requests, your account pages, your address.
Countermeasures, in order of effectiveness:
leave the feature off. Unset
FDS_MCP_BROWSER_SENDand the tool does not exist.use a separate browser profile with no other logins, via
FDS_MCP_BROWSER_PROFILE. The session in that profile is the blast radius.put the draft directory out of reach of your other tools with
FDS_MCP_DRAFT_DIR. Gates 1 and 3 are only worth something while nothing else can write that file.keep
dry_run=Truein normal use. It fills the form and stops before the click.
Safety model
Seven rules are enforced in code, not merely documented. Each has tests in
tests/test_security_gates.py that prove it bites.
submit_requestaborts unless the draft'sstatusisapproved— a human sets that.It aborts while any
ERRORfinding is open.It aborts when
law.wunsch_id != law.api_default_id, because the API cannot setlaw_typeand would file under the wrong act.It aborts unless
confirmation_tokenmatches, byte for byte, the token a human wrote into the draft file. A tool must not invent that token.Every red tool has
dry_run: bool = Trueas its default.A local ledger checks
5/5min,6/6h,10/24h,20/7dbefore any POST and aborts with a clear message instead of retrying. FragDenStaat's terms of use B.1.4 lock an account for a month for attempting to circumvent the limits.The HTTP client refuses every non-GET method unless
allow_write=Truewas set explicitly. Only one function in the package ever sets it.
send_reply_via_browser has its own chain of five, listed under
Sending replies, with tests in tests/test_browser_send.py. It also
has a gate the others do not need: rule 0, the tool is not registered at all unless
FDS_MCP_BROWSER_SEND=1.
The rule set
Offline rules R01–R19 reproduce what froide's web form enforces — which is
considerably more than the REST API validates. Live rules L01–L06 check against the
API: the authority exists and still has that name, the desired law is actually offered,
the recomputed API default matches what the draft claims, no duplicate request exists,
no sentence of your text is already in the law's own letter template, and the finished
letter contains every element it should.
Notable ones:
R06refuses e-mail addresses and IBANs in the body. Public requests are CC0 and visible to everyone — do not put other people in them.R10treats a salutation or a closing formula as an error whenfull_text=false: froide frames the text itself with the law'sletter_start/letter_end, so writing either yourself sends a doubled greeting.R12is an error forsubmit_via: apiand only a hint forsubmit_via: web_form— the web form can choose the act, the API cannot.R18andL06check the letter the authority receives, not the body you wrote. Withfull_text=falsethe act'sletter_start/letter_endsupply part of the text, so an element may come from either side;L06fetches the frame and reports what neither half supplies. Six elements: legal basis (the onlyERROR), cost pre-notification, cost cap, deadline, forwarding when the body is not responsible, electronic reply.The cost cap is why this exists. A real request went out without one, because the LTranspG
letter_enddoes ask to be told the expected costs but names no ceiling and no fallback to free inspection on the premises. Everything else was covered by the template, which is exactly why reading the body alone found nothing.R19is the inverse ofR10and applies only to follow-ups — see Sending replies.
Where the server is allowed to write
Three tool arguments are file paths chosen by the model, and the same model reads authority replies and attachments — text written by third parties. So the paths are constrained rather than trusted:
draft paths must end in
.yaml/.yml, are resolved before they are checked (a symlink is judged by its target), andsave()refuses to overwrite a file that is not itself a draft;download_attachmentwill not create a directory, and the attachment's file name is stripped to its basename with everything outside[A-Za-z0-9._ -]replaced;attachments are only ever fetched from
fragdenstaat.deandmedia.frag-den-staat.de, and the bearer token is never sent anywhere else.
Four environment variables tighten this further, and are recommended whenever the server runs unattended:
Variable | Effect |
| every draft path must stay inside this directory ( |
| every |
|
|
| browser profile directory for that tool. Point it at a profile logged in to fragdenstaat.de and nothing else |
Results that carry third-party text (get_messages, get_request,
list_attachments, download_attachment) name those fields in an
untrusted_content key. They are data. They do not choose file paths, URLs, tool calls
or confirmation tokens.
The draft lifecycle
draft ──validate_draft──▶ validated ──a human edits the file──▶ approved ──submit_request──▶ submittedA reply draft has its own, ending in sent rather than submitted, and only
send_reply_via_browser can reach that state — and only after the API has confirmed that
a new message exists.
Only a human moves a draft to approved, and only by editing the YAML file.
Know the limit of that sentence. Gate 1 (status: approved) and gate 4
(confirmation_token) are two values in a file on your disk. No tool in this server
can set either of them — create_request_draft always writes status: draft and the
placeholder token, and there is no tool that promotes a draft. But most MCP hosts give
the model a general-purpose file-writing tool as well, and a model that can write files
can write status: approved and a token of its own choosing. Combined with a prompt
injection out of an authority's reply, that is a path to a real submission.
So, if you run this alongside a filesystem tool:
keep
submit_requestout of the picture entirely by configuring scopes withoutmake:request— then no token this server holds can ever POST a request;or set
FDS_MCP_DRAFT_DIRto a directory your other tools do not write to;or leave the recommended exit in place and use
build_submit_url, where the send button is in your browser and not in a tool call;and leave
FDS_MCP_BROWSER_SENDunset. The same reasoning applies tosend_reply_via_browser, one step more sharply: it has no scope you can withhold, only a browser session you own.
Gates 2, 3, 5 and 7 do not depend on the file and hold regardless: the rule set runs
against live API data, the law check compares against the recomputed API default, the
throttle ledger is separate state, and the HTTP client refuses non-GET everywhere except
in submit_request.
Development
pip install -e ".[dev]"
python -m pytest -m "not live" # offline suite
python -m pytest -m live # hits fragdenstaat.deNetwork access is blocked by default via pytest-socket; only tests marked live may
reach fragdenstaat.de.
The live suite is read-only GETs with exactly two exceptions, both in
tests/test_api_contract.py, both of which cannot create anything: the message POSTs
carry an unresolvable request URI, and the web-form POST carries an empty body. No test
opens a browser and no test sends a message. The tests that need a token skip, rather
than fail, when ~/.config/fds-mcp/tokens.json is absent.
The CLI also works without an MCP client:
fds-mcp validate examples/request-draft.yaml
fds-mcp validate examples/request-draft.yaml --liveFacts, and where they come from
Everything this server asserts about the API was verified against fragdenstaat.de on
2026-09-05, against okfde/froide@bc6c2fa and okfde/fragdenstaat_de@88bfbba. The
source references are in the docstrings, down to file and line. If you find a claim that
is wrong or has gone stale, that is a bug — please open an issue.
The API is documented at https://fragdenstaat.de/api/ with an OpenAPI 3.0.3 schema at
https://fragdenstaat.de/api/v1/schema/ and a Swagger UI at
https://fragdenstaat.de/api/v1/schema/swagger-ui/. (/api/v1/docs/, which froide's own
docs mention, returns 404.)
Please use this responsibly
FragDenStaat is run by a non-profit and paid for by donations. Every request you file costs a public authority real working time. The rate limits are 5 requests per 5 minutes and 20 per week for a reason. This server is built to help you file better requests, not more of them.
Requests filed with public: true — the default — publish the entire e-mail
correspondence, all approved attachments and all uploaded documents to the world under
CC0.
Disclaimer
This project is not affiliated with, endorsed by, or connected to the Open Knowledge Foundation Deutschland e.V., FragDenStaat, or the froide project. It is an independent third-party client that talks to a public API. All trademarks belong to their owners.
This is not legal advice.
License
MIT — see LICENSE. Copyright 2026 Dirk Wolbeck.
Available Tools
15 toolsbuild_reply_draftA
Prepare a follow-up message to an authority. YELLOW: reads the API, sends nothing.
The counterpart of ``build_submit_url`` for a request that already exists. It looks
the request up, validates the text against the rules that apply to a follow-up, and
hands back the finished text plus the URL of the form. **Pressing send stays with
you**, and there is no tool argument that changes that: replying is not possible
through the API at all. Measured 2026-09-05 (tests/test_api_contract.py):
``POST /api/v1/message/`` refuses ``kind: "email"``, and the web view at
``/anfrage/<slug>/send/message/`` answers 302 to the login page whether or not a
bearer token is attached.
A follow-up is validated differently from a request. froide does **not** frame it:
the textarea arrives prefilled with a salutation, the placeholder U+2026 and a
closing formula, and exactly what stands in it is what the authority receives. So
R19 requires a salutation and a closing formula — the inverse of R10 — R04 rejects
the placeholder that is sitting in the form right now, R06 keeps e-mail addresses and
IBANs out of a public thread, and the subject is capped at 230 characters.
Args:
request_id: numeric id of your existing request.
text: the complete message, salutation and closing formula included.
subject: reply subject. Defaults to "AW: <title> [#<id>]".
path: optional path to a ``.yaml`` file to write the draft to. Needed only if you
intend to use ``send_reply_via_browser`` later; the file is written with
``status: draft`` and a placeholder confirmation token.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | ||
| text | Yes | ||
| subject | No | ||
| request_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does so thoroughly. It discloses that the tool only reads and never sends, that no argument changes this, that the API contract was verified, and that follow-up validation differs from request validation. This is exceptionally transparent about side effects and constraints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the key purpose and safety statement, followed by behavioral context and a structured Args section. It is long but information-dense; some of the API-test evidence could be shortened, but it does earn its place by substantiating the 'sends nothing' claim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no annotations and no output schema, the description is remarkably complete. It explains what the tool does, what it returns conceptually, validation rules, parameter semantics, the file-writing side effect, and the hard limit that sending is impossible through the API. No critical decision-relevant information appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must fully compensate for every parameter. It does: request_id is explained as the numeric id of an existing request, text must include salutation and closing formula, subject has a documented default, and path is described with its exact purpose and file behavior. This adds substantial meaning beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with a specific verb and resource: 'Prepare a follow-up message to an authority.' It immediately clarifies the key behavioral distinction from sibling tools: 'reads the API, sends nothing.' It also names itself as the counterpart of build_submit_url, which clearly differentiates it from related tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly frames this tool as being for an existing request, in contrast to build_submit_url. It also gives a clear exclusion: replying is not possible through the API at all, so no tool argument can turn this into a send. The path parameter is explicitly tied to the condition of later using send_reply_via_browser, which gives clear when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
build_submit_urlA
Build the prefilled web form URL — the recommended way out. RED tier.
This is the only route on which the legal basis can actually be chosen
(``?law_type=...``); the REST API's MakeRequestSerializer has no such field. Sending
stays with the human.
fragdenstaat.de answers GET URLs above roughly 4096 bytes with HTTP 400 (measured
2026-09-05). Longer drafts therefore get a two-step answer: a short URL that
prefills subject and law_type, plus the body in a sidecar text file.
Args:
path: path to the draft YAML file.
dry_run: True (default) does not write the sidecar .body.txt file.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| dry_run | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden and does a good job: it discloses the 4096-byte GET URL limit, the two-step sidecar fallback, and dry_run side-effect. It does not fully specify the return contract, but the core behavioral traits are clearly revealed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the summary and then gives the critical constraints and parameter docs. Every sentence carries information, including the measured URL-length limit that explains the side-car behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-paramter tool with no annotations and no output schema, the description covers purpose, key constraints, side effects, and parameter semantics. It leaves the exact return format implicit, but the core workflow is sufficiently complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must document parameters, and it does: path is explained as a draft YAML file path, and dry_run's default and side-effect are described. This adds real meaning beyond the bare schema fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific verb+resource: "Build the prefilled web form URL," and positions it as the recommended route. It also distinguishes it from the REST API by noting it is the only route where legal basis can be chosen, so an agent can tell it apart from related tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit guidance: it is the recommended way out, the only route that supports law_type, and sending stays with the human. It implicitly warns against using the REST API for this purpose, though it does not name a specific sibling alternative for automatic submission.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_deadlinesA
Your open requests whose statutory deadline has passed. YELLOW.
froide exposes no "deadline expired" flag; it is computed from ``due_date`` against
the current time, exactly as the frontend does.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the disclosure burden. It usefully explains that froide stores no 'deadline expired' flag and that the value is computed from due_date against the current time, matching frontend behavior. This gives an agent useful context about why the result set is time-dependent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded with the essential meaning. The only minor issue is the unexplained 'YELLOW' label, which adds slight ambiguity but does not bloat the text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that the tool takes no parameters and has no output schema, the description is sufficiently complete: it states what the tool returns and explains the deadline computation. It could mention return format or pagination, but those are not essential for a zero-argument listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there are no parameter semantics to document. The baseline of 4 applies because the description does not need to compensate for any schema gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool's result as the user's open requests whose statutory deadline has passed, which distinguishes it from list_my_requests and get_request. It lacks an explicit verb like 'lists' or 'returns', but the meaning is unambiguous and matches the tool name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage is implied: use this when you need to see open requests with expired statutory deadlines. However, it does not explicitly compare with sibling tools such as list_my_requests or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_jurisdictionA
Which authority covers a given place? GREEN — returns the evidence trail.
Resolves ``/georegion/?name=<place>``, walks its ``part_of`` chain upwards, and asks
``/publicbody/?regions=<id>`` level by level, from the most specific outwards. It
stops at the **first level that yields any authority**, because that is the body
actually responsible; the remaining, wider levels are reported by id only.
This matters in states such as Rhineland-Palatinate, where an *Ortsgemeinde* is often
not listed on fragdenstaat.de at all while the *Verbandsgemeindeverwaltung* that runs
its administration is.
Args:
place_name: name of the municipality, district or state.
include_wider: also list the authorities of the wider levels. Off by default —
at country level that is thousands of bodies and tells you nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| place_name | Yes | ||
| include_wider | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden, and it delivers: it explains the resolution algorithm, the stopping rule ('first level that yields any authority'), why that rule matters, and what happens at wider levels ('reported by id only'). It also discloses the default behavior of include_wider and its rationale, giving substantial behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded, moving from purpose to algorithm to example to parameters. Every section earns its place, though the initial 'GREEN —' fragment is cryptic and slightly distracting without explanation. Overall it is efficiently structured with little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of an output schema and annotations, the description explains the input semantics, the algorithm, the stopping condition, and the nature of the returned evidence trail. It does not specify the exact response structure or edge cases such as unknown places or levels with no authorities, so it is strong but not fully exhaustive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description fully compensates: place_name is defined as 'name of the municipality, district or state', and include_wider is explained semantically ('also list the authorities of the wider levels') plus its default and why it defaults to false. This adds real meaning beyond the raw schema titles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with the precise question 'Which authority covers a given place?' and then explains the resolution mechanism by walking the georegion and publicbody hierarchy. This clearly identifies a specific verb+resource behavior and distinguishes it from sibling tools like search_authorities or get_authority by focusing on place-to-jurisdiction resolution rather than keyword search or direct lookup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear use case: determining the responsible authority for a municipality, district, or state, with a concrete Rhineland-Palatinate example. It also explains when include_wider is inappropriate ('at country level that is thousands of bodies'), but it does not explicitly name alternatives or state when not to use this tool versus search_authorities.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_request_draftA
Write a local YAML draft. RED tier, but performs NO network traffic at all.
The file starts in status ``draft`` with a placeholder confirmation token. A human
has to read the text, set ``status: approved`` and replace ``confirmation_token``
before anything can be submitted.
Args:
path: where to write the YAML file.
subject: request subject, 8-230 characters.
body: the request text, at most 5000 characters.
publicbody_id: recipient authority id.
law_wunsch_id: the law you want to file under.
law_api_default_id: the law the REST API would apply — see get_authority().
law_wunsch_law_type: law_type of the desired law, e.g. "IFG" or "UIG".
publicbody_name: authority name, for the L01 cross-check.
publicbody_email: authority e-mail, for the L01 cross-check.
ermittelt_ueber: how responsibility was established (a URL or a sentence).
public: whether the request will be public. Public means CC0 and visible to all.
full_text: True sends your text verbatim, False lets froide frame it.
submit_via: "web_form" (human presses send) or "api" (immediate dispatch).
dry_run: True (default) returns the draft without writing the file.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | ||
| path | Yes | ||
| public | No | ||
| dry_run | No | ||
| subject | Yes | ||
| full_text | No | ||
| submit_via | No | web_form | |
| law_wunsch_id | Yes | ||
| publicbody_id | Yes | ||
| ermittelt_ueber | No | ||
| publicbody_name | No | ||
| publicbody_email | No | ||
| law_api_default_id | No | ||
| law_wunsch_law_type | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full behavioral burden and does so thoroughly. It discloses that no network traffic occurs, that the file begins with status 'draft' and a placeholder confirmation token, that a human must approve/replace the token, and that dry_run returns the draft without writing the file.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the most critical facts (local draft, no network, human approval required), followed by a compact Args list. Every sentence adds value; the length is justified by the 14 parameters it documents.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no annotations or output schema, the description gives the agent everything needed to call the tool correctly: the purpose, the safety profile, the approval workflow, parameter constraints, and dry_run behavior. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the Args list describes all 14 parameters with useful semantics: constraints (subject 8-230 chars, body max 5000), meanings ('public' means CC0), options (submit_via choices), and cross-tool references (law_api_default_id -> get_authority()). This fully compensates for the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Write a local YAML draft', which clearly distinguishes this from submission, validation, or retrieval tools. It further clarifies scope with 'performs NO network traffic at all' and explains this is a preparatory step before a human approves and submits.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for usage: this is a local, network-free drafting step that requires human approval before submission. It does not explicitly name alternatives or exclusion conditions, but the workflow context ('before anything can be submitted') makes the intended position in the process clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
download_attachmentA
Download one attachment into a local directory. YELLOW: reading only.
The directory has to exist already: this tool will not create a path, because
``target_dir`` is a model-chosen argument and the file name comes from the API, and
together they were enough to drop a file into e.g. ~/.config/autostart/. Set
``FDS_MCP_DOWNLOAD_DIR`` to confine downloads to one directory.
Args:
attachment_id: numeric attachment id (from list_attachments).
target_dir: an existing local directory.
| Name | Required | Description | Default |
|---|---|---|---|
| target_dir | Yes | ||
| attachment_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full burden and handles it well. It labels the operation as read-only, warns that it writes a file locally, explicitly says it will not create directories, and explains the security rationale along with the FDS_MCP_DOWNLOAD_DIR confinement option. This is substantive behavioral context beyond the schema or annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The one-sentence purpose is front-loaded and the Args list is terse. The second paragraph is longer, but it earns its length by explaining a real path-injection risk and the recommended confinement mechanism, so it is not padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter download tool, the description covers purpose, input source, directory preconditions, and safety configuration. It omits details like return values or overwrite behavior, but those are minor for a download operation and no output schema exists to supply them.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description fully compensates: attachment_id is explained as the numeric id from list_attachments, and target_dir is explained as an existing local directory with a usage constraint. Both required parameters receive meaning beyond their bare types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the verb, resource, and destination clearly: 'download one attachment into a local directory.' It also identifies the attachment_id source as list_attachments, so an agent can distinguish this tool from sibling listing and request tools without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit preconditions: target_dir must already exist, and the tool will not create a path. It also points to attachment_id as coming from list_attachments, which tells the agent where to get its input. It does not name alternatives, but no sibling tool performs the same download function, so the preconditions are sufficient guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_authorityA
Full record for one public body, including its laws. GREEN.
The API does not expose ``default_law``, so the law the REST API would apply is
recomputed here the way froide's ``get_applicable_law()`` does it
(``order_by('-meta', '-priority')``). That default is almost always the *meta* law,
which is why the API cannot be used to file under a specific act.
Args:
id: numeric public body id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full transparency burden and it excels: it discloses that the API does not expose default_law, that the default is recomputed using a specific ordering, that it is almost always the meta law, and that this means the API cannot be used to file under a specific act. This is valuable behavioral information beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence front-loads the core purpose, and the rest is a tight caveat plus parameter note. The technical detail about froide's order_by is dense but earns its place because it explains why the tool behaves as it does. No unnecessary filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter retrieval tool with no output schema and no annotations, this description covers the essential bases: what the tool returns, how the default law is computed, a key limitation, and the argument semantics. It could add explicit sibling routing or expected return structure, but it is largely complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 does so by defining id as 'numeric public body id', which adds real semantic meaning beyond the schema's generic integer title 'Id'. For a single-parameter tool, this is sufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns the full record for one public body, including its laws, and identifies the resource as a public body. It distinguishes itself from search_authorities by emphasizing singular retrieval, though it does not explicitly name the sibling alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied: use this when you need a complete record for a known public body by id. However, there is no explicit guidance about when to prefer this over search_authorities or get_law, and no stated exclusions beyond the filing limitation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_lawC
One freedom-of-information act with its deadline rules. GREEN.
Args:
id: numeric law id, e.g. from ``get_authority(...)["laws"]``.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral burden. It does not disclose whether the operation is read-only, what the response shape is, whether there are errors, or what 'GREEN' means. The name suggests retrieval, but the description itself offers no behavioral detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loads the core resource before the args. The unexplained 'GREEN.' and odd capitalization slightly hurt clarity, but there is no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description should explain return expectations and usage context. It only says the result is a freedom-of-information act with deadline rules and gives the id source; it does not describe response fields, errors, or how this relates to siblings like check_deadlines and get_authority. For a one-parameter geter this is below minimally complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only states that id is an integer and required; the description adds that it is a numeric law id and, more valuably, that it comes from get_authority(...)['laws']. Since schema description coverage is 0%, this provenance meaningfully supplements the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The phrase 'One freedom-of-information act with its deadline rules' clearly identifies the resource and the relevant content, and the example ties the id to get_authority(...)['laus']. It lacks an explicit verb like 'retrieve', and 'GREEN' is unexplained, but an agent can infer this returns a single law by id.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus siblings like search_authorities, get_authority, or check_deadlines. The only usage hint is that the id comes from get_authority(...)['laws'], which explains parameter provenance rather than selection context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_messagesB
All messages of a request, oldest first. YELLOW.
Args:
request_id: numeric request id.
| Name | Required | Description | Default |
|---|---|---|---|
| request_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It does disclose useful behavior: the result covers all messages and is ordered oldest first. However, it omits pagination/limits, error behavior, permissions, and any explanation of what 'YELLOW.' means, so the behavioral profile is incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core sentence is short and front-loaded, and the Args section is appropriately compact for one parameter. The dangling 'YELLOW.' does not earn its place and creates ambiguity, which prevents a higher score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter getter without an output schema, the definition conveys the basic return subject and ordering. It lacks detail on the message shape, failure modes, and the meaning of 'YELLOW,' leaving some uncertainty for an agent that needs to consume the response or handle errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter is described as 'numeric request id,' which essentially restates the schema's integer type and 'Request Id' title. Since schema description coverage is 0%, the description needed to add operational meaning such as where to obtain the id, constraints, or an example, and it does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies a concrete operation and resource: it returns all messages for a request, oldest first. This is specific enough to separate it from sibling tools like get_request or list_attachments, though it does not name alternatives and the stray 'YELLOW.' marker is unexplained.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'of a request' implies the intended context: use this when you need the message thread for a specific request_id. It gives no explicit when-not-to-use guidance and does not point to alternatives such as get_request for request metadata or list_attachments for files.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_requestB
One FOI request in detail. YELLOW (public requests work without a token).
Args:
id: numeric request id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the behavioral disclosure burden. It does convey an auth-related trait: 'public requests work without a token.' However, it does not explain what happens for non-public requests, whether the operation is read-only, error behavior, or rate limits. The 'YELLOW' label is only partially explained. Some useful behavioral context is present, but notable gaps remain.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely compact: a one-line purpose, a brief auth note, and an argument definition. Every sentence carries useful information and the core purpose is front-loaded. There is no redundancy with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter getter, the description covers the essential call: what it returns and what parameter is needed. However, with no output schema and no annotations, it leaves out details about what 'in detail' includes, how non-public requests are authenticated, and possible failure modes. It is adequate for a basic call but not fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema description coverage at 0%, the description adds the crucial semantic that 'id' is a numeric request id, going beyond the schema's bare integer type. It tells the agent which identifier to pass. It is minimal but sufficient for a single parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as returning a single FOI request's details ('One FOI request in detail'). This distinguishes it from list-oriented siblings like list_my_requests, though it does not explicitly name an alternative. The verb and resource are clear enough for an agent to understand what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no guidance about when to use this tool versus siblings such as list_my_requests or search_authorities. It implies the agent should already have a request id, but it does not state that a prior lookup is needed or mention any exclusions or alternatives. This leaves usage context entirely to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_attachmentsB
Attachments belonging to one message. YELLOW.
Args:
message_id: numeric message id (from get_messages).
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description is the only source of behavioral info. It only states the resource; it does not disclose whether the operation is read-only, what is returned, or any side effects. The unexplained 'YELLOW.' label adds ambiguity rather than transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is appropriately tiny and front-loaded. However 'YELLOW.' is an unexplained fragment that does not earn its place; without known tool conventions, it confuses more than it clarifies.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter list operation, the essential call data is present and the prerequisite is stated. Yet without an annotations safety profile or output schema, the description should at least note that this lists metadata and that download_attachment is the sibling for retrieving content; that distinction is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only provides title/type, and description coverage is 0%. The description compensates by explaining that message_id is the numeric id from get_messages, which gives provenance and reduces ambiguity enough for the sole parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource ('attachments') and scope ('belonging to one message'), and the tool name supplies the 'list' verb. However, the sentence is a noun phrase and does not explicitly differentiate from download_attachment, so it is clear but not fully explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parameter line tells the agent to obtain message_id from get_messages, establishing a prerequisite and a minimal usage context. But it does not say when to prefer this over download_attachment or any other sibling, nor when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_my_requestsA
Your own FOI requests. YELLOW: needs a token (scope read:request), read only.
Args:
status: optional filter, e.g. "awaiting_response" or "resolved".
limit: maximum number of requests to return.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| status | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description discloses that the operation is read-only, requires a token with scope read:request, and is limited to the caller's own requests. That is meaningful behavioral context. It does not mention response format or pagination beyond the limit parameter, but for a simple list operation the core behavior is clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the resource and safety profile, followed by two parameter lines. No filler or repetition of schema defaults.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity list tool with no output schema, it covers purpose, auth, read-only behavior, and all parameters. It could additionaly state the shape of the returned request objects, but that is not essential for basic invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description cover age is 0%, yet the description compensates by explaining both parameters: status is an optional filter with concrete example values, and limit is the maximum number of results. This adds meaning the schema's titles and defaults alone do not provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource as the user's own FOI requests, which distinguishes it from siblings like get_request or search_authorities. It lacks an explicit verb, though the tool name 'list' carries the action. Overall clear and specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the scope ('your own') and an authorization prerequisite, which gives context for when to call it. It does not explicitly name alternatives or say when not to use it, so routing to siblings is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_authoritiesA
Search public bodies on fragdenstaat.de. GREEN: no auth, no side effects.
Args:
query: free-text search, e.g. a town or an authority name.
jurisdiction: optional filter — numeric id, slug ("rheinland-pfalz") or
name ("Rheinland-Pfalz"). The API itself only accepts the id.
limit: maximum number of results (server page size is 50).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| jurisdiction | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and explicitly discloses 'no auth, no side effects,' which is critical behavioral information. It also reveals the API-only-id caveat for jurisdiction. It could go further by describing the response shape, but the safety and side-effect profile is transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence is purposeful: the opening states the action, the GREEN tag summarizes safety in one token, and each parameter gets a compact line with no redundancy. The most important operational detail is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter read-only search, the description covers the service, auth, side effects, and each parameter, including the jurisdiction id conversion caveat. It does not explicitly state the return shape, which would be more important here because no output schema exists, but the gap is minor given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides only names, types, and defaults, so the description must add meaning. It fully compensates: query gets a free-text explanation with examples, jurisdiction gets accepted formats and the API-only-id constraint, and limit gets its maximum-result meaning plus the server page-size hint. This gives an agent everything needed to construct arguments correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Search public bodies on fragdenstaat.de.' This clearly identifies it as a discovery/list-search tool and distinguishes it from siblings like get_authority, which implies direct retrieval. The scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool should be used when an agent needs to find public bodies by free-text, but it does not explicitly state when not to use it or name alternatives such as get_authority for known IDs. The GREEN safety note adds operational context but not routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_requestA
Actually POST the request to fragdenstaat.de. RED tier — IRREVERSIBLE.
``POST /api/v1/request/`` sends the e-mail to the authority immediately. There is no
draft, no preview and no undo. Five gates therefore have to agree, in this order:
1. the draft's status is ``approved`` (a human set it),
2. no ERROR finding is open,
3. ``law.wunsch_id == law.api_default_id`` — the API cannot set law_type, so a
mismatch would file the request under the wrong act,
4. ``confirmation_token`` matches the value a human wrote into the draft file,
5. the local throttle ledger says another submission stays inside
5/5min, 6/6h, 10/24h, 20/7d.
Args:
path: path to the approved draft YAML file.
confirmation_token: must equal the ``confirmation_token`` inside the draft file.
dry_run: True (default) runs every gate and reports, but sends nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| dry_run | No | ||
| confirmation_token | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full responsibility for behavioral disclosure. It clearly states that the action is IRREVERSIBLE, sends immediately, has no draft/preview/undo, and enumerates the exact gate conditions that control whether the request is actually submitted. This is unusually complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence carries necessary safety-critical information. The irreversibility warning is front-loaded, the gates are listed in a clear numbered order, and the parameter explanations are tightly integrated rather than repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-risk, irreversible submission tool with no annotations and no output schema, the description covers the essential context: preconditions, gate order, parameter constraints, safety default behavior, and the fact that no undo is possible. Nothing needed to decide whether and how to invoke it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must explain the parameters itself. It does: path is the approved draft YAML file, confirmation_token must match the value inside that draft, and dry_run defaults to true and prevents any sending. Every parameter is given meaningful semantics beyond its bare schema definition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('POST the request'), a target resource ('fragdenstaat.de'), and a clear scope ('sends the e-mail to the authority immediately'). It also distinguishes itself from sibling draft/build/validate tools by emphasizing this is the actual irreversible submission step, not a draft or preview.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives strong contextual guidance: the five gates must agree before submission, and dry_run is presented as a safe way to test every gate without sending. It does not explicitly name sibling alternatives such as validate_draft or build_submit_url, so the when-not-to-use guidance is implied rather than fully explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_draftA
Run the rule set against a draft. RED tier.
Offline rules R01-R16 always run. The live rules L01-L04 (authority exists, law is
offered, API default law, duplicate check) need the network and therefore only run
with ``dry_run=False``.
Args:
path: path to the draft YAML file.
dry_run: True (default) runs offline rules only and does not touch the file.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| dry_run | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the transparency burden, and it does: offline rules R01-R16 always run, live rules L01-L04 require network and only run with dry_run=False, and dry_run=True does not touch the file. The main unknown is what happens if dry_run=False, but the key side-effect and network dependencies are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, then behavior, then arguments, with no fluff. There is slight redundancy between the live-rules paragraph and the dry_run argument explanation, but it does not hurt readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Invocation is well specified, but there is no output schema and the description never says what validate_draft returns or how the agent should interpret the result. Because no annotations or output schema exist, this is a meaningful gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the description fully compensates: path is explained as a YAML file path, and dry_run is described as controlling offline-only vs live execution, including the default and side-effect. This adds real meaning beyond the schema's bare names and types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action and object: 'Run the rule set against a draft,' which makes the tool's validation role clear and distinguishes it from sibling build/create/submit tools. It does not explicitly name or contrast a sibling tool, so it stops short of 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete conditions for when offline-only vs live validation runs, directly explaining how dry_run changes execution. It omits an explicit 'use before submitting' statement and does not name alternatives, but the context is clear enough.
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.
15 tool updates
v0.1.0- First observed
build_reply_draft - First observed
build_submit_url - First observed
check_deadlines - First observed
check_jurisdiction - First observed
create_request_draft - First observed
download_attachment - First observed
get_authority - First observed
get_law - First observed
get_messages - First observed
get_request - First observed
list_attachments - First observed
list_my_requests - First observed
search_authorities - First observed
submit_request - First observed
validate_draft
TDQS
Every tool maps to a distinct resource or action: authority lookup, jurisdiction resolution, request retrieval, message/attachment access, deadline checks, and the draft/submit pipeline. Even the several draft-related tools are clearly separated by request vs reply and validate/build/submit roles.
Tool names mostly follow a clear verb_noun pattern like list_my_requests, get_request, download_attachment, and submit_request. Minor inconsistencies exist, such as create_request_draft vs build_reply_draft and get_messages vs list_attachments, but the overall convention remains predictable.
With 15 tools, the server is at the upper edge of a well-scoped set but each tool earns its place. The count reflects a complete workflow: discovery, retrieval, attachments, deadlines, draft validation, URL generation, and submission.
The domain is well covered: authority and law lookup, request/message/attachment retrieval, deadline checking, request drafting/validation/submission, and reply drafting all exist. The main gap is that reply submission is not provided by any tool, though the description explains this is an API limitation and the workflow hands off to a human.
Related MCP Connectors
Resolve any government entity worldwide and submit service requests. Open civic data for AI agents.
Verified, citable German & EU law for any LLM. Daily updates from official sources, hosted in DE.
Verified, citable German & EU law for any LLM. Daily updates from official sources, hosted in DE.
US Federal Register for AI agents: rules, notices, executive orders, agency lookup. No keys.
Related MCP Servers
- FlicenseAqualityBmaintenanceProvides access to the official German Federal Legal Information Portal (rechtsinformationen.bund.de) enabling AI agents to search German federal laws, court decisions, and legal documentation with authoritative citations from official sources.523-
- AlicenseBqualityCmaintenanceMCP server for UK Freedom of Information research. Connects AI assistants to WhatDoTheyKnow — the UK's largest FOI request platform to search requests, read responses, look up public authorities, and draft new requests.8MIT
- AlicenseNot gradedqualityDmaintenanceCite-grade German legal-text infrastructure for LLM agents, providing access to federal, Länder, and EU laws with cryptographic provenance.2Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables querying 6,870 German federal statutes, case law, and legislative preparatory works directly from AI assistants and MCP-compatible clients.1474Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/notDIRK/fds-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server