gov.br APIs MCP
A catalog-driven gateway over Brazilian government APIs, loading OpenAPI specs on demand.
What can you do with gov.br APIs MCP?
search_catalog(query, category?)— accent-insensitive keyword search; reports totallist_apis(category?, status?, limit?)— enumerate entries, callable ones first (by thedescribe_api(api_id, path?, method?)— catalog metadata + OpenAPI operation list;call_api(api_id, path, method?, query?, body?, headers?)— invoke an endpoint; base URLcredentials_status(api_id?)— which env vars each API needs and whether they're set,
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
govbr-apis-mcpclaude mcp add gov-br-apis-mcp -e 'TRANSPARENCIA_API_KEY=<your transparencia_api_key>' -e 'DATAJUD_API_KEY=<your datajud_api_key>' -e 'DADOSGOV_API_KEY=<your dadosgov_api_key>' -e 'SERPRO_CPF_CLIENT_ID=<your serpro_cpf_client_id>' -e 'SERPRO_CPF_CLIENT_SECRET=<your serpro_cpf_client_secret>' -e 'SERPRO_CNPJ_CLIENT_ID=<your serpro_cnpj_client_id>' -e 'SERPRO_CNPJ_CLIENT_SECRET=<your serpro_cnpj_client_secret>' -e 'SERPRO_DATAVALID_CLIENT_ID=<your serpro_datavalid_client_id>' -e 'SERPRO_DATAVALID_CLIENT_SECRET=<your serpro_datavalid_client_secret>' -e 'MEIAENTRADA_CODIGO_ACESSO=<your meiaentrada_codigo_acesso>' -e 'GOVBR_CATALOG_DIR=<GOVBR_CATALOG_DIR>' -e 'GOVBR_EXTRA_CATALOG_DIR=<GOVBR_EXTRA_CATALOG_DIR>' -e 'GOVBR_EXTRA_ALLOWED_HOSTS=<GOVBR_EXTRA_ALLOWED_HOSTS>' -e 'XDG_CACHE_HOME=<XDG_CACHE_HOME>' -- uvx govbr-apis-mcp==0.2.0
{
"mcpServers": {
"gov-br-apis-mcp": {
"command": "uvx",
"args": [
"govbr-apis-mcp==0.2.0"
],
"env": {
"TRANSPARENCIA_API_KEY": "<your transparencia_api_key>",
"DATAJUD_API_KEY": "<your datajud_api_key>",
"DADOSGOV_API_KEY": "<your dadosgov_api_key>",
"SERPRO_CPF_CLIENT_ID": "<your serpro_cpf_client_id>",
"SERPRO_CPF_CLIENT_SECRET": "<your serpro_cpf_client_secret>",
"SERPRO_CNPJ_CLIENT_ID": "<your serpro_cnpj_client_id>",
"SERPRO_CNPJ_CLIENT_SECRET": "<your serpro_cnpj_client_secret>",
"SERPRO_DATAVALID_CLIENT_ID": "<your serpro_datavalid_client_id>",
"SERPRO_DATAVALID_CLIENT_SECRET": "<your serpro_datavalid_client_secret>",
"MEIAENTRADA_CODIGO_ACESSO": "<your meiaentrada_codigo_acesso>",
"GOVBR_CATALOG_DIR": "<GOVBR_CATALOG_DIR>",
"GOVBR_EXTRA_CATALOG_DIR": "<GOVBR_EXTRA_CATALOG_DIR>",
"GOVBR_EXTRA_ALLOWED_HOSTS": "<GOVBR_EXTRA_ALLOWED_HOSTS>",
"XDG_CACHE_HOME": "<XDG_CACHE_HOME>"
}
}
}
}
Environment variables
TRANSPARENCIA_API_KEYsecret API key for the Portal da Transparencia APIDATAJUD_API_KEYsecret API key for the CNJ DataJud APIDADOSGOV_API_KEYsecret API key for the dados.gov.br portal API (free, generated in the user profile)SERPRO_CPF_CLIENT_IDsecret OAuth2 client ID for the Serpro CPF API (commercial contract)SERPRO_CPF_CLIENT_SECRETsecret OAuth2 client secret for the Serpro CPF API (commercial contract)SERPRO_CNPJ_CLIENT_IDsecret OAuth2 client ID for the Serpro CNPJ API (commercial contract)SERPRO_CNPJ_CLIENT_SECRETsecret OAuth2 client secret for the Serpro CNPJ API (commercial contract)SERPRO_DATAVALID_CLIENT_IDsecret OAuth2 client ID for the Serpro Datavalid API (commercial contract)SERPRO_DATAVALID_CLIENT_SECRETsecret OAuth2 client secret for the Serpro Datavalid API (commercial contract)MEIAENTRADA_CODIGO_ACESSOsecret Access code (codigoAcesso) for the CIE validator used for meia-entrada, issued to the venue or producerGOVBR_CATALOG_DIRDirectory of catalog YAML files that replaces the packaged catalog (trusted input)GOVBR_EXTRA_CATALOG_DIRDirectory of catalog YAML files whose entries are added to the catalog, overriding same-id onesGOVBR_EXTRA_ALLOWED_HOSTSComma-separated extra hostnames catalog URLs may use; add one only if you trust it with the credentials sent thereXDG_CACHE_HOMEBase directory of the OpenAPI spec cache (a govbr-apis-mcp folder is created below it); defaults to ~/.cache
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Contents
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 and the POC | CIE yes (DNE and FESN); the rest is manual |
conecta | src/govbr_apis_mcp/catalog_data/conecta.yaml | Conecta gov.br — 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; withpath, 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.methodis GET, HEAD, POST, PUT, PATCH, DELETE or OPTIONS; anything else returns an error withallowed_methods. Abodyis accepted only with POST, PUT and PATCH.pathis relative to thebase_url..and..segments (after up to three rounds of percent-decoding, with\read as/and;parameters removed) and any path that leaves thebase_urlprefix 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
pathis merged withquery; a key inqueryreplaces the embedded one, and a list value repeats the key. - Caller headers are matched case-insensitively, with
_equal to-.Authorization,Proxy-Authorization,Host,CookieandAccept-Encoding, plus connection, proxy, forwarding and method-override headers, are dropped and reported inignored_headers(the full list is inserver.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 anerror. - Method, body, headers and path are validated before any OAuth2 token is requested, and
invalid input comes back as
{"error": ...}. - A
3xxis not followed: the response carries itslocation(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, pluscallable: whethercall_apiwould accept the entry right now (availableandunstableentries;requires_contractones 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.
Install
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest
Register in Claude Code (.mcp.json or claude mcp add):
{
"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:
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 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
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 fromsha256(api_id + "\n" + openapi_url): never the id itself, and a changedopenapi_urlnever serves the old spec. OAuth2 tokens live in memory only. call_apidoes not follow redirects — credentialed requests cannot be steered to another host by a3xx; the response carries the (redacted)locationinstead. It always sendsAccept-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 behttpson 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 must carryopenapiorswagger. A compressed response is refused and the whole download has a 60-second deadline; both come back asspec_error. - The
httpxandhttpcoreloggers stay at WARNING, so httpx logs no request URL (query string included). - Entries flagged
pii: truereturn personal data (CPF, name, photo) into the client transcript. Today:meiaentrada-cie-validador,fesn-cie-validador(callable without any credential: whoever holds a use code gets the holder's data) and the three Serpro entries.
Roadmap
- [ ] Conecta adhesion as a public-sector entity → fill gateway base URLs + credentials
- [ ] Per-API OpenAPI URLs for Conecta entries (linked from each detail page)
- [ ] Serpro trial-mode toggle (call
-trialbase URLs with the published demo token) - [ ] Per-call cost guard for paid Serpro APIs
- [ ] Bounded decompression for compressed upstream responses
- [ ] Pleito à SNJ para a API
conecta-id-jovem(admite instituição privada) - [ ] Fallback documental para CIE fora da base DNE (DCEs e entidades estaduais)
License
MIT - see LICENSE.
Frequently asked questions
What is gov.br APIs MCP?
A catalog-driven gateway over Brazilian government APIs, loading OpenAPI specs on demand.
How do I install gov.br APIs MCP?
It runs on your machine. In Claude Code: claude mcp add gov-br-apis-mcp -e 'TRANSPARENCIA_API_KEY=<your transparencia_api_key>' -e 'DATAJUD_API_KEY=<your datajud_api_key>' -e 'DADOSGOV_API_KEY=<your dadosgov_api_key>' -e 'SERPRO_CPF_CLIENT_ID=<your serpro_cpf_client_id>' -e 'SERPRO_CPF_CLIENT_SECRET=<your serpro_cpf_client_secret>' -e 'SERPRO_CNPJ_CLIENT_ID=<your serpro_cnpj_client_id>' -e 'SERPRO_CNPJ_CLIENT_SECRET=<your serpro_cnpj_client_secret>' -e 'SERPRO_DATAVALID_CLIENT_ID=<your serpro_datavalid_client_id>' -e 'SERPRO_DATAVALID_CLIENT_SECRET=<your serpro_datavalid_client_secret>' -e 'MEIAENTRADA_CODIGO_ACESSO=<your meiaentrada_codigo_acesso>' -e 'GOVBR_CATALOG_DIR=<GOVBR_CATALOG_DIR>' -e 'GOVBR_EXTRA_CATALOG_DIR=<GOVBR_EXTRA_CATALOG_DIR>' -e 'GOVBR_EXTRA_ALLOWED_HOSTS=<GOVBR_EXTRA_ALLOWED_HOSTS>' -e 'XDG_CACHE_HOME=<XDG_CACHE_HOME>' -- uvx govbr-apis-mcp==0.2.0. For other clients, paste the JSON configuration from this page into their MCP settings.
Does gov.br APIs MCP need an API key?
Yes. It expects TRANSPARENCIA_API_KEY, DATAJUD_API_KEY, DADOSGOV_API_KEY, SERPRO_CPF_CLIENT_ID, SERPRO_CPF_CLIENT_SECRET, SERPRO_CNPJ_CLIENT_ID, SERPRO_CNPJ_CLIENT_SECRET, SERPRO_DATAVALID_CLIENT_ID, SERPRO_DATAVALID_CLIENT_SECRET, MEIAENTRADA_CODIGO_ACESSO, which you set in its configuration.
Is gov.br APIs MCP open source?
Yes. Its code is on GitHub under the MIT license.
Who maintains gov.br APIs MCP?
It is published by thalisantunes. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.