Senado BR MCP

SSE

by sidneybissoli

1.3k downloads Not rated yet

About

Brazilian Federal Senate open data over MCP — 90 tools across the legislative process, Senate administration (CEAPS expenses, payroll, contracts) and the e-Cidadania portal. Cloudflare Workers, Streamable HTTP, no auth. Responses in pt-BR.

Details

Transport
SSE

Explore

Setting up with Highlight

This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:

  1. Download and install Highlight from highlightai.com/download
  2. Navigate to the plugins tab and select "Add Custom Plugin"
  3. Configure the plugin with the settings below
    Plugin Name Senado BR MCP
    Command (node, npx, python, etc.)

    Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.

  4. Enable "Start Automatically" if you want the plugin to start when Highlight launches

senado_legislatura_atual

Retorna informações sobre a legislatura vigente, incluindo número, período e datas de início/fim.

senado_tipos_materia

Lista os tipos de matérias legislativas válidos com sigla, nome completo e descrição. Útil para usar em buscas.

senado_partidos

Lista partidos com representação atual no Senado, incluindo sigla, nome completo e número de senadores.

senado_ufs

Lista unidades federativas com número de senadores atualmente em exercício por estado.

senado_listar_senadores

Lista senadores em exercício ou de uma legislatura específica. Pode filtrar por UF e partido.

senado_buscar_senador_por_nome

Busca senadores por nome (útil quando não se tem o código). Retorna lista de senadores correspondentes.

senado_obter_senador

Obtém informações detalhadas de um senador específico, incluindo dados biográficos, mandatos e comissões.

senado_votacoes_senador

Lista votações nominais de um senador, mostrando como votou em cada matéria. Sem período informado, usa o ano corrente.

senado_senador_detail

Visão agregada e enriquecida de um senador, combinando mandatos, filiações e profissão numa única chamada.

senado_senador_historico

Histórico funcional de um senador: licenças oficiais, comissões das quais é membro, cargos ocupados em comissões ou histórico acadêmico.

senado_senadores_afastados

Lista os senadores atualmente afastados (fora de exercício), com partido e UF.

senado_buscar_materias

Busca matérias legislativas por tipo (PEC, PL, PLP, MPV), número, ano, palavras-chave, autor ou situação de tramitação. Informe pelo menos um critério.

senado_obter_materia

Obtém detalhes completos de uma matéria legislativa, incluindo ementa, autoria, situação atual, relator, deliberação e norma gerada.

senado_tramitacao_materia

Obtém histórico de tramitação de uma matéria (informes legislativos), em ordem cronológica.

senado_textos_materia

Lista documentos apresentados numa matéria (texto inicial, emendas, pareceres, requerimentos) com URLs para download, dos mais recentes aos mais antigos.

senado_listar_votacoes

Lista votações do plenário do Senado por ano, podendo filtrar por mês ou período específico.

senado_votacoes_recentes

Obtém as votações mais recentes do plenário (últimos N dias). Útil para acompanhar atividade legislativa recente.

senado_obter_votacao

Obtém detalhes de uma votação específica, incluindo votos nominais de cada senador. Use codigoSessao (código da sessão plenária) para buscar todas as votações daquela sessão.

senado_votos_materia

Obtém resultado de votações de uma matéria, incluindo placar e, opcionalmente, votos nominais de cada senador.

senado_search_votacoes

Busca votações por múltiplos critérios combinados: período, processo, matéria, parlamentar e tipo de voto. Mais flexível que senado_listar_votacoes.

senado_listar_comissoes

Lista comissões do Senado. Pode filtrar por tipo (permanente, temporária, CPI, mista) e status (ativa/inativa).

senado_obter_comissao

Obtém detalhes de uma comissão, incluindo presidente, vice-presidente e finalidade.

senado_membros_comissao

Lista membros atuais de uma comissão, incluindo cargo (presidente, vice, titular, suplente).

senado_reunioes_comissao

Lista reuniões agendadas ou realizadas de uma comissão, com data, hora, local e pauta.

senado_agenda_comissoes

Obtém agenda de reuniões das comissões do Senado. Pode filtrar por data e comissão específica.

senado_reuniao_comissao

Detalhes de uma reunião de comissão: partes da pauta, itens apreciados, presidente, situação e links de pauta/resultado/ata. O código vem da agenda de comissões.

senado_requerimentos_cpi

Lista requerimentos de uma CPI (Comissão Parlamentar de Inquérito) em atividade, paginados. Use senado_listar_comissoes com tipo=cpi para descobrir as siglas.

senado_distribuicao_materias

Estatísticas de distribuição de matérias numa comissão: quantas matérias cada parlamentar tem como autor (autoria) ou como relator (relatoria). Útil para medir carga de trabalho legislativo.

senado_agenda_plenario

Obtém agenda de sessões de plenário (Senado ou Congresso Nacional), por dia ou mês, incluindo pauta com matérias a serem votadas.

senado_resultado_plenario

Resultado das sessões plenárias numa data: itens de pauta apreciados, pareceres e resultados. Escopo: Senado (sf), Congresso (cn) ou mês inteiro (mes).

senado_orientacao_bancada

Orientação de bancada nas votações de plenário: como cada liderança partidária orientou o voto, com placar da votação. Essencial para análise de disciplina partidária.

senado_vetos

Lista vetos presidenciais em apreciação pelo Congresso Nacional — por ano ou por status de tramitação.

senado_resultado_veto

Resultado da votação nominal de um veto presidencial — pelo código do veto, da matéria vetada ou do dispositivo (em vetos parciais).

senado_encontro_plenario

Detalhes de um encontro legislativo (sessão de plenário): dados gerais, pauta, resultado ou resumo. O código vem da agenda ou do resultado do plenário.

senado_tabelas_plenario

Tabelas de referência do plenário: tipos de sessão, tipos de comparecimento em votações e lista de legislaturas com sessões legislativas.

senado_search_processos

Busca processos legislativos usando o endpoint de processos da API. Oferece parâmetros de busca diferentes/complementares ao senado_buscar_materias. É obrigatório informar pelo menos um parâmetro de busca.

senado_obter_processo

Obtém detalhes completos de um processo legislativo específico, incluindo tramitação.

senado_emendas_processo

Lista emendas apresentadas a um processo legislativo, com autoria, colegiado e decisões. Informe idProcesso ou codigoMateria.

senado_relatorias_processo

Lista relatorias de processos legislativos — por processo, matéria, relator ou colegiado. Útil para saber quem relata o quê.

senado_prazos_processo

Lista prazos regimentais ou constitucionais de processos legislativos — por processo, matéria, vigência ou período.

{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "senado_ecidadania_listar_ideias", "arguments": { "ordenarPor": "apoios", "ordem": "desc", "status": "aberta" } } }

The server consumes two classes of upstream endpoints from the Senado API:

Claude Desktop / Cursor

Paste into your MCP client config file to install this server.

{
    "mcpServers": {
        "senado br mcp": {
            "server": {
                "command": "npx",
                "args": [
                    "-y",
                    "senado-br-mcp"
                ]
            }
        }
    }
}

McpServers

{
    "server": {
        "command": "npx",
        "args": [
            "-y",
            "senado-br-mcp"
        ]
    }
}

Transport

"stdio"

Package

"senado-br-mcp"

Registry

"npm"

Apublic, hostedMCP server that gives AI assistants live, structured access toBrazilian Senate open data—no installation, no account, no API key. Point your MCP client at the hosted endpoint and start asking about senators, bills, votes, expenses, and more. It runs on Cloudflare Workers over Streamable HTTP.

It exposes67 tools,4 prompts, and5 resourcesacross two domains:

- Legislative— senators; bills and their tramitation; votes; committees; plenary sessions, results and presidential vetoes; party-bloc voting orientation; speeches and stenographic transcripts; blocs and leadership; federal legislation; and citizen participation via the e-Cidadania portal.
- Administrative— CEAPS parliamentary-quota expenses; housing allowance; civil servants and payroll; overtime; interns; procurement contracts and biddings; outsourced staff; petty-cash funds; and budget execution.

Data comes from three official sources — thelegislative open-data API, theadministrative open-data API, and the e-Cidadania portal. All tool responses are in Portuguese (pt-BR). SeeCHANGELOG.mdfor release history.

Point a client at the endpoint and ask in plain language — English or Portuguese:

- "How did São Paulo's senators vote in the most recent floor votes?"→senado_search_votacoes
- "Show the legislative progress of PEC 45/2019 (a constitutional amendment proposal)."→senado_buscar_materias+senado_obter_materia
- "How much was spent on the CEAPS parliamentary allowance in 2024, broken down by expense type?"→senado_ceaps

The answers come live from the Senate's official open-data APIs — exact figures with provenance, not numbers guessed from training data.

This is aremote, hosted, open-accessserver. To use it, point any MCP client at the Streamable HTTP endpoint —no install, no account, no API key, no configuration:

For OpenAI Apps SDK submission and review, the Worker also exposes a curated MCP surface:

https://senado.sidneybissoli.com/mcp/openai-app-v2

This endpoint intentionally keeps the full public MCP server intact at/mcp, but limits tool discovery to 27 high-signal, intent-oriented tools for ChatGPT app use./mcp/openai-appremains available as a legacy alias, but new ChatGPT app configurations should use/mcp/openai-app-v2so clients fetch the current tool schema. The tools still call the same handlers and return the same provenance envelope; only the advertised surface is narrower. Any ChatGPT app listing should present this as an independent open-data research app, not as an official Senate, OpenAI or ChatGPT connector.

For ChatGPT Apps, those 27 tools also advertise a shared MCP Apps UI template atui://senado-br-mcp/openai-app-dashboard-v2.html. The self-contained widget renders the returnedstructuredContentas a compact dashboard with metrics, main records, and source/provenance, without adding another model-visible data tool.

- Privacy policy:https://senado.sidneybissoli.com/privacy
- Terms of use:https://senado.sidneybissoli.com/terms

For clients that launch MCP servers as a command — and for one-command setup — use themcp-remotebridge.No build, no config, no key:

npx -y mcp-remote https://senado.sidneybissoli.com/mcp

- One-click (LobeHub):open theserver pageand clickInstall.
- Native remote URL(Claude Desktop/Code and other Streamable-HTTP clients): see
Connecting MCP Clients.

Everything belowArchitecture(Prerequisites, Setup, Deploy) isonly for optionally self-hosting your own instance— it isnotrequired to use this public server.

Prefer not to route queries through a third-party host (e.g. a newsroom policy)? Thesame serveralso runs as alocal stdio processthat talksdirectly to the official government APIs— same 67 tools, same provenance envelope, no Cloudflare in the loop. This is the npm/stdio channel, published assenado-br-mcp.

Point a command-based client (Claude Desktop/Code, etc.) at the package — npm fetches and runs it, no clone or build:

{ "mcpServers": { "senado-br": { "command": "npx", "args": ["-y", "senado-br-mcp"] } } }

To run it directly or hack on it, use the source checkout instead:

git clone https://github.com/SidneyBissoli/senado-br-mcp-cloudflare cd senado-br-mcp-cloudflare npm install npm run build node dist/cli.js # serves MCP over stdio (Ctrl+C to stop)

Parity with the hosted server:the legislative and administrative tools areidentical(same upstream APIs, same throttle/cache/provenance) — locally the L1 Cloudflare cache is a no-op, but the L0 in-memory cache still works, so results are the same. Theonlydifference is the e-Cidadania list/corpus tools: without D1 they fall back to a live scrape of the ~5 REST highlights, flagged viameta.fonte/possivelDesatualizacao; the detail tools (obter_) are identical. Logs go tostderr— stdout carries only the JSON-RPC protocol stream.

This repo bundles a ClaudeAgent Skillat.claude/skills/senado-br/that teaches Claudewhento reach for this server andhowto use its 67 tools well — a themed tool map, common question→tool playbooks, the provenance contract, and gotchas (dates, thecodigoMateriabridge, e-Cidadania's open-set listing, pagination). It points back to the server's ownsenado://catalogo/senado://guiaresources rather than duplicating them.

Claude Code auto-discovers it when you work in this repo. To use it elsewhere, copy.claude/skills/senado-br/into your~/.claude/skills/, or zip the folder and upload it in claude.ai (Settings → Features). The skill assumes thesenado-brMCP server is connected (hosted or via npx).

- Runtime:Cloudflare Workers (ESM)
- Transport:Streamable HTTP (MCP spec 2025-03-26) viacreateMcpHandlerfromagents/mcp
- Protocol:MCP over JSON-RPC —/mcphandles the full public server;/mcp/openai-app-v2exposes a curated 27-tool profile plus a shared MCP Apps widget for OpenAI app review/submission (/mcp/openai-appremains as a legacy alias)
- SDK:@modelcontextprotocol/sdk1.26.0+ (per-request McpServer instances)
- Validation:Zod schemas for all tool inputs
- Caching:2-layer (L0 memory + L1 Cache API) with SHA-256 keying
- e-Cidadania store:D1 database refreshed by a Cron Trigger (every 2h) — list tools read from D1 with a live-scrape fallback and a staleness flag; detail tools stay live with write-through (see
e-Cidadania)
- Rate limiting:Token bucket — global (8 req/s) + per-client (2 req/s)
- Upstream throttle:Max 6 concurrent requests, 10s timeout, retry with exponential backoff
- Auth:Optional Bearer token (set theAPI_KEYsecret; open access when unset). Constant-time comparison.
- Observability:Structured JSON logging + in-memory counters at/metrics; per-tool call telemetry (selection, error rate, cache-vs-live) in Cloudflare Analytics Engine, PII-free
- Liveness:Runs on Cloudflare's own global network behind a custom domain — no third-party host that can go dark. Public/healthand/status(version + last-deploy id/timestamp) make uptime and the current build verifiable; thestatusbadge above pings the live endpoint
- Tests:Vitest unit tests for parsers, helpers, cache, throttle, and auth

Not needed to use the server— it is already hosted athttps://senado.sidneybissoli.com/mcp(open access). Follow this section only if you want to run yourownprivate instance.

- Node.js 20+
-
Wrangler CLIv4+
- Cloudflare account

# Create the KV namespace wrangler kv namespace create CACHE_KV # Note the ID from the output, e.g.: # { binding = "CACHE_KV", id = "abc123..." }

Replace the placeholder KV namespace ID:

[[kv_namespaces]] binding = "CACHE_KV" id = "YOUR_KV_NAMESPACE_ID_HERE"

Optionally setALLOWED_ORIGINto restrict CORS:

[vars] ALLOWED_ORIGIN = "https://your-app.example.com"

The e-Cidadania pipeline needs aD1 databaseand aCron Trigger(both already declared inwrangler.toml— replace the database ID):

[[d1_databases]] binding = "ECIDADANIA_DB" database_name = "senado-ecidadania" database_id = "YOUR_D1_DATABASE_ID_HERE" [triggers] crons = ["0 /2   "]

Create the database (paste the returned ID above) and apply the schema:

npx wrangler d1 create senado-ecidadania npx wrangler d1 migrations apply senado-ecidadania --remote

The list tools fall back to live scraping when D1 is empty, so the server works before the first Cron run.

wrangler secret put API_KEY # Clients must then send: Authorization: Bearer <key> # When API_KEY is not set, the server is open access.
npm run dev # Dev server runs locally on port 8787 (local only). # The public MCP endpoint is https://senado.sidneybissoli.com/mcp
npm test # run all tests once npm run test:watch # watch mode npm run typecheck # tsc --noEmit
npm run deploy # Serves at https://senado.sidneybissoli.com (custom domain) and # https://senado-br-mcp.sidneybissoli.workers.dev (workers.dev fallback)

All requests go toPOST /mcpwith JSON-RPC 2.0 format.

{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "senado_listar_senadores", "arguments": { "uf": "SP", "emExercicio": true } } }
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "senado_buscar_materias", "arguments": { "palavraChave": "inteligência artificial", "tramitando": true } } }
{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "senado_search_votacoes", "arguments": { "dias": 7 } } }

Call a tool — Most popular citizen ideas

{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "senado_ecidadania_listar_ideias", "arguments": { "ordenarPor": "apoios", "ordem": "desc", "status": "aberta" } } }

The server consumes two classes of upstream endpoints from the Senado API:

Legacy endpoints (.jsonsuffix, PascalCase responses)

Used by Groups A, E, F, H, I, J, K, L, M, N. The.jsonsuffix is appended automatically byupstream.ts. None of these is marked deprecated upstream.

v3 endpoints (flat JSON arrays/objects, camelCase)

Used by Groups B, C, D. Dates must be inISO format(YYYY-MM-DD) — tools acceptYYYYMMDDand convert. ThecodigoMateriaquery param bridges legacy matéria codes to v3 processes.

Administrative API (adm.senado.gov.br/adm-dadosabertos, flat snake_case JSON)

Used by Groups O, P, Q, R viaadmFetch(no.jsonsuffix; HTTP 404 treated as empty collection). Base URL configurable viaSENADO_ADM_BASE_URL.

The e-Cidadanialistdata is persisted in aD1 database(ecidadania_current/_history/_scrape_runs, discriminated byentidade; plusecidadania_comentariosfor the audiência comment level andecidadania_detalhe_cursorfor the resumable detail backfill — added in schema v2) and read from there instead of being scraped on every call.Three cadenceswrite into it:

- adaily off-Worker GitHub Actionowns thefull corpusof the three live entities (consultas,eventos,ideias; see below) — the source of truth. Daily (not weekly) because the first-seen seriesMIN(scraped_at)is the only measurable entry-rhythm signal and every skipped day permanently shortens it (ROADMAP Etapa 2, decisão D3);
- aweekly ingest Action(.github/workflows/verify-consultas-votos.yml— historical filename) for theconsultas_votosacervo: the Senado republishes the Arquimedes CSV periodically (confirmed 2026-07-20), so the weekly run re-ingests the current vintage under the same anomaly guards as the other corpora (see below);
- an in-WorkerCron Trigger(0
/2 ,src/scraper/pipeline.ts → refreshEcidadania) does only atargeted metric spliceof the ~5 REST highlights per live entity (restcolecaomaismateria/ideia/audiencia— votos/comentários/apoios), recorded asok-metricaso it never re-breaks the corpus baseline and never touches the long tail. In v2 the eventos splicepreservesthe corpus's canonical comment count (the daily crawl is the source of truth forcomentarios, so the splice can't ping-pong it against the degraded REST count).

Both writers build payloads through the canonicalbuildXResumobuilders + sharedcontentHash, so their rows are byte-identical. Each write:

- upsertsecidadania_current(one row per item — what the tools read),
- appendsecidadania_historyonly when an item'scontent_hashchanges (time-series-ready),
- records each run inecidadania_scrape_runs.

Ananomaly guard(src/scraper/anomaly.ts,classifyRun) ensures a failed or anomalous corpus run (zero rows, or fewer thanECIDADANIA_CORPUS_MIN_PCT% of the last good run)never overwritesthe last good state.

Thelist / analysis tools(listar_,consultas_analise,sugerir_tema_enquete,consultas_votos) read from D1 viaresolveList(src/scraper/store.ts): D1-first. Because every entity is now a full corpus, a stale corpus is served from D1flagged(possivelDesatualizacao: true) rather than collapsing to the ~5-item live highlights (the original coverage bug); the live scrape is reserved for an empty D1 (cold start, before the first weekly run). Staleness usesECIDADANIA_CORPUS_STALE_MAX_MIN(~10 days). Every list response carries an additivemeta(fonte,lastScrapedAt,possivelDesatualizacao) so callers always see the data's real age and never get stale data silently.

Thedetail tools(obter_) staylive(HTML scraped with CSS-class-targeted regex) for freshness, and write their richer payload through toecidadania_detalhefire-and-forget (deduped bycontent_hash), so detail history accrues without adding latency to the response.

The three live e-Cidadania corpora are owned by thedailyAction (.github/workflows/ingest-ecidadania.yml), each with its ownscripts/ingest-ecidadania/index-.tsorchestrator emitting batchedout-.sqlthe apply step bulk-loads:

- consultas— open consultations (detailed below). In v2 each crawled matter is alsoenriched from its detail page(visualizacaomateria) forautoria/relator; those are immutable, so only rows not yet enriched are fetched.
- eventos— audiências/eventos from theprincipalaudiencia?p=NHTML listing; status comes straight from the listing block (no/processobridge). In v2 every event isenriched from its detail page(canonicaldata/hora+comissaoNomeCompleto/local/descricao/pauta/convidados/videoUrl) and itsAJAX comment fragment(canonical count + oneecidadania_comentariosrow per comment, diffed against the stored hashes and emitted asout-eventos-comentarios-
.sql).
- ideias— ideias legislativas (~113.7k) frompesquisaideia?situacao=N&p=M, crawledpersituacaobucket(the listing has no inline status) and emitted in ~10k-statement batches. In v2 the listing crawlpreservesthe immutable detail fields, and aseparate resumable backfill(index-ideias-detalhe.ts, run viaingest:ecidadania:ideias-detalhe) fills them a chunk per run — because ~113.7k detail fetches don't fit one Action, it persists a cursor inecidadania_detalhe_cursorand wraps around at the end.

The fourth entity,consultas_votos, is a separatehistoricalacervo of votes-by-UF parsed from the ~33 MB Arquimedes CSV (Proposições-com-votos.csv), aggregated to one record per matéria with avotosPorUfbreakdown. The CSV's "dados atualizados até" stamp becomes the provenancedata_vintage; it is excluded from the row hash (consultaVotoCore) so a re-ingest with unchanged votes doesn't churn_history.STATUS ATUALis uniformly "Descontinuado", hence archival, not a migration of the open consultations. Served bysenado_ecidadania_consultas_votoswith provenance pointing at the CSV (ECIDADANIA_ARQUIMEDES). It isexcluded from the daily joband owned by its ownweekly ingestAction (.github/workflows/verify-consultas-votos.yml— the filename keeps the historicalverify-prefix): the acervo was originally treated as a frozen single vintage (ROADMAP Etapa 2, decisão D1) and the weekly run onlyverifiedit, but on 2026-07-20 the Senado republished the CSV as a fresh vintage (+43 matérias, 648 updated), so the scheduled run now re-ingests the current vintage under the standard anomaly guards (empty/truncated CSV and the catastrophic floor still fail without writing;forcedispatch overrides the floor). The script's verify mode (INGEST_CONSULTAS_VOTOS_VERIFY=1/--verify) remains available as an on-demand integrity check.

Theconsultasjob is the reference implementation:

consultascovers thefull set of OPEN consultations— every matter currently in tramitação (~7.7k), not just the ~5 highlights. Confirmed on the first run: thepesquisamaterialisting isin-tramitação-only, so closed/historical consultations arenotcaptured by this source (a pre-ingestion historical backfill is out of scope). Three settled design decisions:
- Decoupled ingestion.The open set is acquired by anoff-Worker TypeScript job(scripts/ingest-ecidadania/, run by a daily GitHub Action —.github/workflows/ingest-ecidadania.yml) that paginates the HTML listing (pesquisamateria?p=1..N, the only full-coverage source for open consultations) for ids + vote counts andbulk-loads D1; the Worker only reads. The brittle, long crawl is kept out of the request/Cron path.
- Status from/processo, not HTML.A consultation runs from presentation until the end of tramitação, sostatusis a function of the matter:aberta ⟺ thecodigoMateriais in the/processotramitando=Sset, derived from robust JSON (never scraped). Every consultation enters asaberta(the listing only yields in-tramitação matters); on eachcompleterun the job re-derives status forall stored rowsby/processomembership (not by listing-absence, which can be transient), so a consultation whose matter leaves tramitação flips toencerrada. Theencerrada/todassets therefore grow over time; consultations that closedbeforethe first ingestion aren't captured (out of scope). The list/analysis tools default tostatus: aberta.
- Two reconciled cadences (one shared writer contract).The jobreusescontentHash+ theConsultaResumobuilder +classifyRunfromsrc/scraper/, so its rows are byte-identical to the Cron's. The daily job owns the long tail; the2h Cronkeeps the ~5 hot/open highlights fresh via atargeted metric splice(recorded asok-metrica, bypassing the corpusclassifyRunbaseline). Corpus freshness (possivelDesatualizacao) is computed from the laststatus='ok'run and uses a larger window (ECIDADANIA_CORPUS_STALE_MAX_MIN), and a stale consultas corpus is served from D1 flagged rather than collapsing back to the live highlights.

Write guards on the load: anincomplete crawl(any page failed) or an incomplete/processostatus universe writes only anerrorun row; even a complete crawl is rejected by acatastrophic floor(ECIDADANIA_CORPUS_MIN_PCT, default 80% of the last good corpus) to guard against a degraded page — overridable with--force/INGEST_FORCE=1for a legitimate large shrink. Run daily via the Action, or manually:

CLOUDFLARE_API_TOKEN=… npm run ingest:ecidadania # writes scripts/ingest-ecidadania/out.sql npx wrangler d1 execute senado-ecidadania --remote --file=scripts/ingest-ecidadania/out.sql

MCP uses POST for alltools/callrequests. Caching POST responses is not natively supported by the Cache API, which requires GET requests. The solution:
- Hash parameters— Tool name + sorted parameters are hashed with SHA-256
- Synthetic GET key— A synthetic URLhttps://senado-br-mcp.internal/__cache/{tool}/{hash}is constructed
- Cache API match/put— The synthetic GET URL is used withcaches.default.match()andcaches.default.put(), allowing standard Cache API operations on POST-originated data

This caching happens at thetool level(inside each tool's callback), not at the MCP transport level.

Every toolattaches aprovenance envelopeso a result is traceable back to its official source — provenance is treated as a first-class part of the answer, not an optional extra (the audience is journalists and political-science researchers, for whom an un-sourced figure is unusable). Sincev3.5.0the envelope implements the portfolio-wideprovenance contract v1.0(@sbissoli/mcp-provenance): the server builds and validates a full canonical model per response, and emits itsconciseprojection— a fixed 6-key block with explicitnullfor unknown fields. The block lives instructuredContent.provenance(parseable by clients; note the advertised per-tool output schema is permissive, so contract validation happens server-side at build time, in the package) and is mirrored as a compact source footer in the text content for clients that only render text — the data JSON itself isnotduplicated with the envelope, to keep the per-response token cost low.

Coverage spans all four upstream sources, each with its ownsource/citation/license(insrc/utils/provenance.ts):

- Senado Federal — Dados Abertos (Legislativo)—legis.senado.leg.br/dadosabertos
- Senado Federal — Dados Abertos (Administrativo)—adm.senado.gov.br/adm-dadosabertos
- Senado Federal — Execução Orçamentária e Financeira— Arquimedes/Financeiro feed atsenado.gov.br
- Senado Federal — Portal e-Cidadania—www12.senado.leg.br/ecidadania

Fields of theconciseblock (per response — one tool, one source; keys in this fixed order,nullwhen the source does not expose the value):

The canonical model behind the block also carriesdataset.id(item/series identifier, e.g.codigoMateria=137808),api_versionand per-fieldfield_sources; those are validated on every build and informattribution(below), but are not part of theconciseprojection.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.