gribs_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., "@gribs_mcpsearch for posts about climate protection"
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.
gribs_mcp
MCP server for gribs.net — the Grünen-intern (party-internal), login-pflichtige KPV-Bayern platform hosting the Antragsbörse (Musteranträge, Beschlüsse, Positionspapiere) and secondary sections like Wissenswert, Mitgliederbriefe, and Mitgliederversammlungen.
This server exposes gribs.net content to AI harnesses (OpenCode) via the Model Context Protocol, giving an AI assistant read-only access to search and browse Antragsbörse posts and fetch the newest public posts. It is read-only by design — no writing, no triage, no uploads — and only surfaces content the running user is already authorized to see (login is handled via the user's own gribs.net credentials, cached locally).
Every politically relevant result carries a source URL and retrieval timestamp (Quellenpflicht) so downstream tools can cite where a claim came from and when it was fetched.
Tools
All tools are async, annotated readOnlyHint=True, and clamp limit parameters to [1, MAX]. Every result model carries url: str and retrieved_at: datetime (UTC).
Tool | Description | Returns |
| Full-text search across a gribs section (default: Antragsbörse). Up to 50 hits. Pass |
|
| Fetch a single post (antrag) in full detail. |
|
| Resolve a WordPress |
|
| Enumerate the top-level (L1) sub-categories within a section (e.g. Umwelt, Soziales, …). |
|
| Drill into the category tree without a search query. Returns subcategories for intermediate nodes; leaves return an empty expansion (use |
|
| Fetch the newest posts from the public gribs.net homepage (no login required). Enrichment is concurrent. |
|
| Extract download links (PDFs and download-looking anchors) from a post body. |
|
Quellenpflicht: every tool that returns politically relevant data includes url + retrieved_at on each item. This is enforced at the Pydantic model layer, not by convention.
Related MCP server: mcp-moncompte
Library stack
Aufgabe | Library | Lizenz |
MCP framework | MIT | |
HTTP client | BSD-3-Clause | |
Output models | MIT | |
HTML parsing (structure) | MIT | |
Article body extraction | Apache-2.0 | |
OS credential/cookie storage | MIT |
No Playwright. gribs.net's simple form-POST login (no SSO, no JS handshake, no CSRF) does not require a browser — pure httpx is sufficient and dramatically simpler. There is no uv run playwright install step.
Setup
# 1. Install dependencies (uv manages a virtualenv automatically).
uv sync
# 2. Store your gribs.net credentials in the OS keyring.
# This prompts for email + password via getpass (password is not echoed)
# and optionally performs a test login to verify the credentials work.
uv run python -m gribs_mcp.auth
# 3. (Optional) Smoke-test the server over stdio.
uv run gribs-mcpFor CI / headless setups, fall back to environment variables (the keyring is checked first, then env vars):
export GRIBS_EMAIL="you@example.org"
export GRIBS_PASSWORD="…"Cookies are cached in the OS keyring under service name gribs_mcp and are automatically refreshed when they expire (30-day TTL) or when the API returns 401/403. There is no browser profile to manage.
Configure in OpenCode
Register gribs-mcp as a stdio MCP server in your opencode.json (analog to allgaeuer_zeitung_mcp):
{
"mcp": {
"gribs_mcp": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "/path/to/gribs_mcp", "gribs-mcp"],
"enabled": true
}
}
}Replace /path/to/gribs_mcp with the absolute path to this checkout. The gribs-mcp script entry point is defined in pyproject.toml ([project.scripts]).
Development
uv sync # install dev deps
uv run ruff check # lint (E/F/I/UP/B/SIM ruleset)
uv run ruff format --check # format check
uv run mypy src/ # strict type check
uv run pytest # tests (deterministic, no live HTTP)All four gates must pass before merging. Tests use HTML/JSON fixtures under tests/fixtures/ — no live gribs.net calls, so they run offline and deterministically.
Architecture
src/gribs_mcp/
├── __main__.py # main() -> mcp.run(transport="stdio")
├── server.py # FastMCP instance + 7 @mcp.tool definitions (read-only)
├── models.py # Pydantic v2 models (frozen) with Quellenpflicht fields
├── client.py # httpx.AsyncClient + cookie jar + auth retry (GribsClient)
├── parsers.py # Pure HTML/JSON parsers (selectolax + trafilatura)
└── auth.py # keyring credential + cookie cache (30-day TTL)Key design decisions:
httpx-only login — gribs.net uses a plain form-POST to
/users/ajax_loginwith no SSO, no JS handshake, no CSRF token. A browser (Playwright) would be pure overhead. The client does a singlehttpx.AsyncClient.postand captures theSet-Cookiesession cookie.Keyring cookie cache — credentials and session cookies are persisted in the OS keyring (service
gribs_mcp), not on disk. A 30-day TTL plus per-cookieexpireschecks gate freshness; on 401/403 the client clears the cache and re-logs in (serialized by anasyncio.Lockto avoid concurrent-login races).JSON vs HTML response handling — gribs is inconsistent:
/members/structure,/members/singlepost, and/members/expandStructurereturn JSON{error, ...}with HTML snippets inside;/members/searchand/post/recentpostsreturn raw HTML. The client has separate_post_form_json/_post_form_htmlpaths sharing one retry helper.HTML-entity-encoded onclick args — the live
structexp(...)calls innavigationHTML encode their object's quotes as". Parsers callhtml.unescape()before parsing the JS object (shared_parse_js_objecthelper).Concurrent enrichment —
recent_postsfetches the scaffold, then fires allpostWidgetFillenrichment calls concurrently viaasyncio.gather(3 parallel requests for the default 3 posts). Order is preserved (gather guarantees positional ordering).Read-only tools + Quellenpflicht — every tool is annotated
readOnlyHint=True; every politically relevant output model carriesurl: str+retrieved_at: datetime(UTC) at the Pydantic schema level, so a missing source is a type error, not a convention violation.
Categories (live-verified)
The category parameter on search_antraege, list_categories, and list_antraege_in_category accepts these names:
Category name | cat_id | Status |
| 1 | verified |
| 2 | verified |
| 5 | verified |
| 6 | verified |
| 7 | verified |
| 8 | verified |
| 9 | verified |
Known limitations / roadmap
list_antraege_in_categoryon leaf nodes returns an empty expansion — gribs.net's/members/expandStructurereturns a search form (not post listings) when called on a leaf subcategory. To list posts in a subcategory, callsearch_antraegewith the samel1/l2/l3ids and a broad query (e.g. 'a' or 'der' — gribs doesn't support an empty searchstring).extract_downloadskeyword heuristic — links are included if the URL ends in.pdfOR the anchor text contains a download keyword (download/pdf/antrag/vorlage/beschluss/musterantrag/herunterladen). This may produce false positives (e.g. a non-download link mentioning "antrag") or miss downloads with non-standard anchor text. Theis_pdfflag distinguishes confirmed PDFs.
Reverse-engineering notes
Key facts about the gribs.net API (verified live 2026-07-18):
Login:
POST /users/ajax_loginwithemail,password,keep=true. No SSO, no CSRF. Returns a 15-byte non-JSON status; success is signalled bySet-Cookie.API shape: all calls are POST
application/x-www-form-urlencodedwith headerX-Requested-With: XMLHttpRequest. Responses are either JSON{error, ...}with HTML snippets inside (structure, singlepost, expandStructure) or raw HTML (search, recentposts).ID duality: posts have an internal
post_id(needed by/members/singlepost) AND a WordPresswp-ID (returned by/members/searchin?wp=<id>deep-links), plus an optional?h=<hash>share link. Useresolve_post_idto bridgewp_id→post_id.wp_id → post_id resolution:
GET /?wp=<id>withfollow_redirects=Truereturns the member page at/members/home/wp-<id>, which contains"post_id":"<N>"in a JSON-ish JS blob.Recent posts:
/post/recentpostsreturns only scaffolds (post_id + spinner); the browser lazy-loads each teaser via/members/postWidgetFillwithpost_id+caller. Therecent_poststool does this concurrently.
License
MIT (placeholder pending final decision).
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server for searching Swiss court decisions from federal and cantonal courts via entscheidsuche.ch. Enables full-text search, law reference lookup, and filtering by canton, court level, and date without API keys.81MIT
- AlicenseNot gradedqualityCmaintenanceRead-only MCP server exposing the catalog of articles from moncompte.org. Enables AI agents to search and retrieve article content via tools.MIT
- AlicenseNot gradedqualityDmaintenanceA production-ready MCP server that provides access to the German Bundestag's parliamentary documentation system (DIP API).1MIT
- AlicenseAqualityBmaintenanceMCP server for live X/Twitter and web search, driven by your locally logged-in Grok CLI and leveraging your X Premium or SuperGrok subscription quota.31MIT
Related MCP Connectors
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
MCP server for Google search results via SERP API
MCP server for French (BOAMP) + EU (TED) public procurement data via TenderAPI.
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/croesnick/gribs_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server