Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
FDS_MCP_BASE_URLNoBase URL of the FragDenStaat instance. Only https origins without a path or credentials are accepted.https://fragdenstaat.de
FDS_MCP_DRAFT_DIRNoEvery draft path must stay inside this directory (: -separated list).
FDS_MCP_BROWSER_SENDNoSet to '1' to register the send_reply_via_browser tool. Unset or any other value disables the tool.
FDS_MCP_DOWNLOAD_DIRNoEvery download_attachment target must stay inside this directory.
FDS_MCP_BROWSER_PROFILENoBrowser profile directory for the send_reply_via_browser tool. Point it at a profile logged in to fragdenstaat.de and nothing else.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
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).
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.
get_lawC

One freedom-of-information act with its deadline rules. GREEN.

Args:
    id: numeric law id, e.g. from ``get_authority(...)["laws"]``.
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.
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.
get_requestB

One FOI request in detail. YELLOW (public requests work without a token).

Args:
    id: numeric request id.
get_messagesB

All messages of a request, oldest first. YELLOW.

Args:
    request_id: numeric request id.
list_attachmentsB

Attachments belonging to one message. YELLOW.

Args:
    message_id: numeric message id (from get_messages).
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.
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.
build_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.
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.
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.
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.
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.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

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/notDIRK/fds-mcp'

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