querido-diario-mcp-server
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., "@querido-diario-mcp-serverFind mentions of 'licitação' in Belo Horizonte gazettes since January 2024."
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.
querido-diario-mcp-server
Community-built, unofficial open-source MCP server for the Querido Diário public API. Querido Diário is a project of Open Knowledge Brasil. This repository is not an official Open Knowledge Brasil project unless explicitly adopted by the organization, and is not affiliated with, endorsed by, or supported by it.
A local-first Model Context Protocol server that gives MCP clients (Claude, Cursor, Codex, and others) read-only, structured access to Brazilian municipal official gazettes indexed by Querido Diário — without a hosted backend, a platform login, or a proprietary service in between.
Why this exists
There is another repository, mcp-dir/querido_diario-mcp, that points MCP clients at a proprietary hosted implementation. This project is different on purpose:
The actual server implementation is open source — every line that talks to the Querido Diário API and to the MCP protocol is in this repository, not behind someone else's endpoint.
Local-first. You run the process yourself (
uv run querido-diario-mcp-server); there is no account, API key, or hosted proxy involved.It calls the public Querido Diário API directly, over plain
httpx, using the same endpoints documented at docs.queridodiario.ok.org.br.Transparent architecture. The HTTP integration (
client.py) is fully decoupled from the MCP protocol boundary (server.py) and is unit-testable without a network connection.Typed end to end. Pydantic models for every request/response shape, strict Pyright checking, and a clean, purpose-built exception hierarchy instead of raw dictionaries and stringly-typed errors.
Deliberately small. Three focused tools, not twenty. See Limitations for what is intentionally out of scope.
Related MCP server: mcp-dados-brasil
Architecture
src/querido_diario_mcp_server/
__init__.py # package version + main() entry point
config.py # environment-driven configuration (QD_API_BASE_URL, timeouts)
errors.py # QDError exception hierarchy (integration-level failures)
models.py # Pydantic domain models mirroring the upstream API contract
client.py # async httpx client for the Querido Diário HTTP API — no MCP imports
server.py # MCP protocol boundary: MCPServer instance, lifespan, tool definitionsclient.py knows nothing about the Model Context Protocol; it is a small, typed wrapper around three upstream endpoints that can be tested entirely with httpx.MockTransport. server.py is the only module that imports the MCP SDK: it validates tool arguments, translates QDErrors into ToolErrors an LLM can read and self-correct from, and returns typed structured output. A single httpx.AsyncClient connection pool is created once, in the server's lifespan, and reused across every tool call.
Tools
Only three tools are exposed, all read-only.
Tool | Purpose |
| Find Brazilian municipalities by (partial) name and resolve their 7-digit IBGE territory ID. Optional |
| Fetch one municipality's details by its exact 7-digit IBGE territory ID. |
| Full-text search over published gazette content, filterable by city, publication date range, page size/offset, and sort order. |
search_gazettes uses OpenSearch's "simple query string" syntax upstream: bare words are OR'd together, +term requires a term, -term excludes it, and "exact phrase" matches literally — e.g. '"João da Silva"' for an exact name.
Example interaction
User: "Find mentions of ACME Ltda in Porto Alegre gazettes from January to July 2026."
1. search_cities(city_name="Porto Alegre") -> resolves territory_id "4314902"
2. search_gazettes(
query='"ACME Ltda"',
territory_ids=["4314902"],
published_since="2026-01-01",
published_until="2026-07-31",
)Other things you can ask an MCP client connected to this server:
"Which Querido Diário municipality entry corresponds to Torres, RS?"
"Search for public procurement references to artificial intelligence in Porto Alegre gazettes."
"Get the Querido Diário entry for IBGE territory ID 3550308."
Installation
Requires uv and Python 3.12 (uv will install the interpreter for you if it's missing).
git clone https://github.com/lucaspmgomess/querido-diario-mcp-server.git
cd querido-diario-mcp-server
uv sync
uv run pytestRunning it
uv run querido-diario-mcp-serverThis starts the server on stdio, the transport MCP desktop clients expect. It has no interactive output by design — it's meant to be launched by an MCP client, not run standalone in a terminal.
MCP Inspector
To poke at the tools interactively during development:
uv run mcp dev src/querido_diario_mcp_server/server.py:mcpThis opens the MCP Inspector in your browser, connected to this server over stdio.
Claude Desktop / Claude Code
Add to your MCP client configuration (Claude Desktop's claude_desktop_config.json, or a project-level .mcp.json for Claude Code):
{
"mcpServers": {
"querido-diario": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/querido-diario-mcp-server", "run", "querido-diario-mcp-server"]
}
}
}Cursor
Add the same shape to .cursor/mcp.json (project-level) or your global Cursor MCP settings:
{
"mcpServers": {
"querido-diario": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/querido-diario-mcp-server", "run", "querido-diario-mcp-server"]
}
}
}Codex CLI
Add to ~/.codex/config.toml:
[mcp_servers.querido-diario]
command = "uv"
args = ["--directory", "/absolute/path/to/querido-diario-mcp-server", "run", "querido-diario-mcp-server"]Environment variables
Variable | Default | Purpose |
|
| Base URL of the Querido Diário API. Override to point at a local/staging instance (see Upstream API status). |
Upstream API status
The default base URL, https://api.queridodiario.ok.org.br, is the address documented at docs.queridodiario.ok.org.br, and it is independently confirmed by three sources, not just the docs page:
The live frontend's own
env.jssetswindow.__env.apiUrl = 'https://api.queridodiario.ok.org.br', and the checked-in source (okfn-brasil/querido-diario-frontend,src/env.jsandsrc/app/env.service.ts) matches it byte for byte.The frontend's HTTP services (e.g.
territory.service.ts) build requests as${apiUrl}/cities,${apiUrl}/cities/{id}— bare paths, no/apior other prefix — exactly what this client sends.The production Traefik
IngressRouteinokfn-brasil/querido-diario-deployment(k8s/base/api/ingressroute.yaml) routesHost(api.queridodiario.ok.org.br), any path, straight to the API service on port 8080, with noPathPrefixrequirement; the productionConfigMapsetsQUERIDO_DIARIO_API_ROOT_PATH: "". There is also a same-domainqueridodiario.ok.org.br/api/*route, but it's a 302 redirect tohttps://api.queridodiario.ok.org.br/*(seeapi-redirectmiddleware), not a second valid origin — so there is no undocumented path prefix or runtime override to find.
As of this writing, live requests to every path implied by the above (/health, /cities, /gazettes, /docs, with and without an /api prefix) return a generic 404 page not found that does not match FastAPI's JSON-shaped 404 — it reads as Traefik's own "no router matched this request" fallback rather than a response from the FastAPI application itself, consistent with a DNS, TLS, or ingress-routing problem in front of the API rather than a wrong URL. This was verified by direct curl requests on 2026-08-31 (initial check) and reconfirmed on the same date after this investigation; it is infrastructure this codebase cannot fix, and no alternative endpoint is documented or evidenced anywhere in the upstream source, so none is guessed here.
Because of this, the request/response contract implemented in client.py and models.py was verified against the upstream FastAPI source at okfn-brasil/querido-diario-api (api/api.py) rather than a live Swagger UI, per that repository being the authoritative contract when the hosted docs/API are unreachable. If you have access to a working instance (production, once the outage above is resolved, or a local instance per the upstream repos' own setup docs), point QD_API_BASE_URL at it and the client works unchanged.
Development
uv sync # install runtime + dev dependencies
uv run ruff check . # lint
uv run ruff format --check . # formatting check
uv run pyright # static type checking (strict mode)
uv run pytest --cov # test suite, with coverageThe four checks above (everything but uv sync) all must pass before a change is considered complete; this is exactly what CI runs.
Tests
Unit tests for client.py mock the HTTP boundary with httpx.MockTransport — no test depends on network access or a live Querido Diário instance. They cover successful requests, query parameter serialization (repeated territory_ids, exact query-string preservation, date ranges, pagination, sorting), empty results, and upstream failure modes (404, 400/422, 5xx, malformed/non-JSON bodies, timeouts, connection errors).
Integration tests for server.py drive the real MCPServer instance through the MCP SDK's in-process Client (no subprocess, no open port) and assert on tool discoverability, input schemas, structured tool output, and that both input-validation failures and upstream integration failures surface as clean MCP tool errors rather than raw Python tracebacks or leaked HTML error pages.
Security / read-only design
This server only issues
GETrequests to a small, fixed set of upstream endpoints. It has no write path anywhere.It never fetches an arbitrary URL supplied by a tool caller, and it never automatically dereferences the
url/txt_urlfields the upstream API returns for a gazette — doing either would be a server-side request forgery (SSRF) primitive. Following those links, if you need the full gazette text, is left to the client/user.All tool arguments are validated before use: territory IDs must be exactly 7 digits, dates must parse as ISO
YYYY-MM-DDwithpublished_since <= published_until,sizeis capped,offsetmust be non-negative, andsort_byis constrained to the three values the upstream API accepts.Upstream error bodies are never forwarded verbatim — HTML error pages and oversized bodies are replaced with a short, safe summary before reaching an MCP client.
No secrets, credentials, or telemetry are involved; the only configuration is the API base URL.
Limitations
Deliberately not implemented in this phase: arbitrary URL fetching, full gazette text/PDF download, OCR, write operations of any kind, a database, crawling or background jobs, LLM summarization, and a web interface. server.py's module docstring explains the read-only, no-arbitrary-fetch design specifically (see Security / read-only design above); the rest are simply out of scope for a deliberately small, focused Phase 1 server.
Attribution
This project calls the public Querido Diário API but does not vendor or copy any of its implementation. Querido Diário is built and maintained by Open Knowledge Brasil and its community; see okfn-brasil/querido-diario (scrapers) and okfn-brasil/querido-diario-api (public API) for the upstream project this server integrates with.
Contributing
Issues and pull requests are welcome. Please run the full check suite (ruff check, ruff format --check, pyright, pytest --cov) before opening a PR, and keep new tools/behavior scoped to what's documented above — this project intentionally stays small.
License
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
- AlicenseAqualityBmaintenanceExposes official IBGE data as MCP tools, including Brazilian localities, SIDRA statistical aggregates, and population indicators.11MIT
- AlicenseNot gradedqualityBmaintenanceMCP server that provides real-time access to Brazilian public data from 6 official sources via 11 read-only tools, including Pix, IBGE, Câmara dos Deputados, Senado Federal, Diário Oficial da União, and Agência Brasil, with no API key required.MIT
- AlicenseNot gradedqualityCmaintenanceEnables querying official data from the Prefeitura de Recife (Recife City Hall) through a hosted, read-only MCP server. Supports MCP over HTTP with usage-based prepaid billing.MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for querying municipal debt clearance certificates (Certidão Negativa de Débitos) from the Canela/RS city government. Enables read-only certificate lookups via natural language in MCP-compatible clients.MIT
Related MCP Connectors
Brazilian legal stack in one MCP: lawsuits, court publications, case law, tenders, certificates.
MCP server for Brazilian Federal Senate open data (legislative, administrative, e-Cidadania).
IBGE: geography, census, economy and health from the official APIs, with provenance. 21 tools.
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/lucaspmgomess/querido-diario-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server