MCP server exposing Brazilian government APIs (public, Serpro, Conecta gov.br) through a catalog-driven gateway that loads OpenAPI specs on demand
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add govbr-apis-mcp -- uvx govbr-apis-mcp{
"mcpServers": {
"govbr-apis-mcp": {
"command": "uvx",
"args": ["govbr-apis-mcp"],
"env": {
"TRANSPARENCIA_API_KEY": "<transparencia_api_key>"
}
}
}
}TRANSPARENCIA_API_KEYMCP Servers overview
# govbr-apis-mcp
[](https://github.com/thalisantunes/govbr-apis-mcp/actions/workflows/ci.yml)
<!-- mcp-name: io.github.thalisantunes/govbr-apis-mcp -->
MCP server that turns Brazilian government APIs into Claude-callable tools through a
**catalog-driven gateway**: instead of one tool per endpoint (hundreds — would blow up
client context), five generic tools operate over a local YAML catalog of 116 APIs.
Only the entries that declare an `openapi_url` have a spec to load: today the Câmara dos
Deputados and the Portal da Transparência, 2 of the 116. For those, `describe_api` loads
the OpenAPI spec on demand. Every other callable entry (see the "Callable today?" column
below) is reached through `call_api` alone, using the endpoints in its description and
`docs_url`.
## Catalog tiers
| Tier | File | Access model | Callable today? |
|------|------|--------------|-----------------|
| `public` | `src/govbr_apis_mcp/catalog_data/public.yaml` | Free — no auth or free API key (IBGE, Banco Central, Câmara, Senado, Portal da Transparência, DataJud, Ipeadata, dados.gov.br…) | Yes |
| `serpro` | `src/govbr_apis_mcp/catalog_data/serpro.yaml` | Serpro commercial (loja.serpro.gov.br) — OAuth2 client credentials per contracted API, paid per call | With a Serpro contract: set the `SERPRO_*` variables |
| `meia-entrada` | `src/govbr_apis_mcp/catalog_data/meia_entrada.yaml` | Eligibility sources for half-price tickets (student CIE, ID Jovem, PcD, e-MEC) — see [docs/meia-entrada.md](docs/meia-entrada.md) and the [POC](poc/README.md) | CIE yes (DNE and FESN); the rest is manual |
| `conecta` | `src/govbr_apis_mcp/catalog_data/conecta.yaml` | [Conecta gov.br](https://www.gov.br/conecta/catalogo/) — **restricted to public-sector entities**; 95 APIs indexed as stubs for discovery | Not yet (adhesion pending) |
The Conecta tier exists so the catalog reflects the whole landscape now, and becomes
callable later by filling in `base_url` + credentials — the OAuth2 client-credentials
flow is already implemented (Serpro uses the same one).
## Tools
- `search_catalog(query, category?)` — accent-insensitive keyword search; reports total
matches and whether the list was truncated.
- `list_apis(category?, status?, limit?)` — enumerate entries, callable ones first (by the
catalog's status, not by whether your credentials are set; filter it: ~95 Conecta stubs
otherwise dominate the output).
- `describe_api(api_id, path?, method?)` — catalog metadata + OpenAPI operation list;
with `path`, parameter/request/response schemas ($refs inlined, depth-limited). Reads
OpenAPI 3 and Swagger 2.0, as JSON or YAML.
- `call_api(api_id, path, method?, query?, body?, headers?)` — invoke an endpoint; base URL
and auth resolved from the catalog entry.
- `method` is GET, HEAD, POST, PUT, PATCH, DELETE or OPTIONS; anything else returns an
error with `allowed_methods`. A `body` is accepted only with POST, PUT and PATCH.
- `path` is relative to the `base_url`. `.` and `..` segments (after up to three rounds of
percent-decoding, with `\` read as `/` and `;` parameters removed) and any path that
leaves the `base_url` prefix are rejected. So is a `#` (a fragment is never sent; write a
literal one as `%23`) or a control character.
- A query string embedded in `path` is merged with `query`; a key in `query` replaces the
embedded one, and a list value repeats the key.
- Caller headers are matched case-insensitively, with `_` equal to `-`. `Authorization`,
`Proxy-Authorization`, `Host`, `Cookie` and `Accept-Encoding`, plus connection, proxy,
forwarding and method-override headers, are dropped and reported in `ignored_headers`
(the full list is in `server.py`). The managed credential is applied last and always wins.
A header with an invalid name or value is not ignored: it fails the call with an `error`.
- Method, body, headers and path are validated before any OAuth2 token is requested, and
invalid input comes back as `{"error": ...}`.
- A `3xx` is not followed: the response carries its `location` (redacted, resolved
against the requested URL). Response bodies are cut at 60,000 characters.
- `credentials_status(api_id?)` — which env vars each API needs and whether they're set,
plus `callable`: whether `call_api` would accept the entry right now (`available` and
`unstable` entries; `requires_contract` ones only once their env vars are set).
## POC: meia-entrada de estudante
Fluxo funcional ponta a ponta (código da CIE → decisão de elegibilidade), incluindo
modo demo sem credencial: [`poc/README.md`](poc/README.md).
## Install
```bash
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest
```
Register in Claude Code (`.mcp.json` or `claude mcp add`):
```json
{
"mcpServers": {
"govbr-apis": {
"command": "/path/to/govbr-apis-mcp/.venv/bin/govbr-apis-mcp",
"env": {
"TRANSPARENCIA_API_KEY": "...",
"DATAJUD_API_KEY": "..."
}
}
}
}
```
From PyPI: `uvx govbr-apis-mcp` (set `"command": "uvx"` and `"args": ["govbr-apis-mcp"]`
in the entry above; no checkout needed). Each release is published to PyPI and to the MCP
Registry automatically (`publish.yml`).
Or run it in a container. The server speaks stdio, so keep `-i`:
```bash
docker build -t govbr-apis-mcp . && docker run -i --rm -e TRANSPARENCIA_API_KEY=... govbr-apis-mcp
```
## Credentials
All secrets come from env vars declared per entry in the catalog (`auth_config`).
Nothing is stored in the repo. `.env.example` lists the variables. Entries with a free key
carry a `signup_url`; Serpro credentials come with the contract, at loja.serpro.gov.br.
`credentials_status` reports readiness.
The server does not read `.env` files, and MCP clients start it with a minimal environment,
so an `export` in your shell may never reach it. Put the variables in the client's `env`
block (the example above, or `claude mcp add -e KEY=value`). For a container, copy
`.env.example` to a git-ignored file such as `.env.local`, fill in the copy and pass it
with `docker run --env-file .env.local`. Never put real values in `.env.example`: it is
versioned.
API keys (the value together with any prefix) are stripped of surrounding whitespace and
must be printable ASCII; otherwise the call fails with `credential in <VAR> contains
invalid characters`, without echoing the value. OAuth2 client ids and secrets are only
stripped: they travel base64-encoded, so any text works. The access token the endpoint
returns must be printable ASCII too. When the token endpoint fails, the call returns an
`error` and the `token_url`, with neither the response body nor any secret.
Auth profiles: `none`, `api_key` (static header, optional value prefix — e.g.
DataJud's `APIKey <key>`), `oauth2_client_credentials` (token endpoint + id/secret,
in-memory token cache; used by Serpro today, by Conecta after adhesion).
## Extending the catalog
Add an entry to a YAML file in `src/govbr_apis_mcp/catalog_data/`. The directory is package
data, so the wheel, `uvx` and the Docker image all carry the catalog. Minimum fields:
`id`, `name`, `provider`, `category`, `status`, `auth`. Add `openapi_url` when the API
publishes a spec — `describe_api` then works with zero code. Regenerate the Conecta
tier with `.venv/bin/python scripts/scrape_conecta.py`. It leaves the file alone when the
page yields no APIs, an id the catalog would reject, or fewer than half the current
entries (`--force` overrides only the last check).
Entries are validated on load: ids must be filename-safe, URLs must be `https` on an
allowlisted host (`*.gov.br`, `*.leg.br`, `*.jus.br` plus a few named hosts), and a hostname
may only contain `[a-z0-9.-]` (write internationalized names in punycode). This is a
security boundary, not style — the catalog decides where your credentials are sent. Add a
host with `GOVBR_EXTRA_ALLOWED_HOSTS` only if you trust it with them; the same hostname
rule applies to it.
To override entries without forking (e.g. filling in Conecta base URLs after adhesion),
point `GOVBR_EXTRA_CATALOG_DIR` at a directory of `.yaml` or `.yml` files whose same-id
entries win. A directory that does not exist or holds no entries is an error, and so is an
id repeated inside it; an empty value counts as unset. `GOVBR_CATALOG_DIR` replaces the
base catalog entirely and should be treated as trusted input.
## Development
```bash
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/ruff check .
.venv/bin/ruff format --check .
.venv/bin/pytest
```
CI runs ruff on Python 3.12 and the test suite on 3.11–3.14, then builds the wheel and
loads the catalog from a clean install.
## Security notes
- Responses are never written to disk. Only OpenAPI specs are cached, in
`$XDG_CACHE_HOME/govbr-apis-mcp/` (or `~/.cache/govbr-apis-mcp/`) for 24 hours, under a
file name derived from `sha256(api_id + "\n" + openapi_url)`: never the id itself, and a
changed `openapi_url` never serves the old spec. OAuth2 tokens live in memory only.
- `call_api` does not follow redirects — credentialed requests cannot be steered to
another host by a `3xx`; the response carries the (redacted) `location` instead. It always
sends `Accept-Encoding: identity`, so a server has no reason to compress. The
60,000-character cut counts decoded text, though: a server that compresses anyway can
still inflate a small chunk before the cut (an accepted risk; see the roadmap).
- Cookies an API sets are never stored or sent back, so one API cannot plant a cookie that
another would receive.
- Spec fetches follow redirects only by hand: at most 5 hops, and every URL (the first
and each `Location`) must be `https` on an allowlisted host before it is requested.
The body is capped at 5 MiB, JSON and YAML are accepted (YAML with aliases, including
merge keys that rely on them, is refused), and the document What people ask about govbr-apis-mcp
What is thalisantunes/govbr-apis-mcp?
+
thalisantunes/govbr-apis-mcp is mcp servers for the Claude AI ecosystem. MCP server exposing Brazilian government APIs (public, Serpro, Conecta gov.br) through a catalog-driven gateway that loads OpenAPI specs on demand It has 0 GitHub stars and its last recorded update is dated 2026-10-19.
How do I install govbr-apis-mcp?
+
You can install govbr-apis-mcp by cloning the repository (https://github.com/thalisantunes/govbr-apis-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is thalisantunes/govbr-apis-mcp safe to use?
+
Our security agent has analyzed thalisantunes/govbr-apis-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains thalisantunes/govbr-apis-mcp?
+
thalisantunes/govbr-apis-mcp is maintained by thalisantunes. The last recorded GitHub activity is dated 2026-10-19, with 0 open issues.
Are there alternatives to govbr-apis-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy govbr-apis-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/thalisantunes-govbr-apis-mcp)<a href="https://claudewave.com/repo/thalisantunes-govbr-apis-mcp"><img src="https://claudewave.com/api/badge/thalisantunes-govbr-apis-mcp" alt="Featured on ClaudeWave: thalisantunes/govbr-apis-mcp" width="320" height="64" /></a>More MCP Servers
Reverse engineer anything with agents, from app behavior down to native binaries.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev