senado-br-mcp 1.2.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +810 -408
  3. package/README.pt-BR.md +788 -0
  4. package/dist/auth.js +46 -0
  5. package/dist/cache/l0-memory.js +30 -0
  6. package/dist/cache/l1-cache-api.js +36 -0
  7. package/dist/cache/manager.js +116 -0
  8. package/dist/cli.js +37 -0
  9. package/dist/icon.js +3 -0
  10. package/dist/instrument.js +65 -0
  11. package/dist/metrics.js +40 -0
  12. package/dist/observability/call-context.js +35 -0
  13. package/dist/prompts.js +101 -0
  14. package/dist/resources.js +141 -0
  15. package/dist/scraper/anomaly.js +34 -0
  16. package/dist/scraper/ecidadania.js +442 -0
  17. package/dist/scraper/pipeline.js +180 -0
  18. package/dist/scraper/store.js +147 -0
  19. package/dist/server.js +101 -3383
  20. package/dist/status.js +21 -0
  21. package/dist/throttle/adm.js +26 -0
  22. package/dist/throttle/token-bucket.js +46 -0
  23. package/dist/throttle/upstream.js +151 -0
  24. package/dist/tools/comissoes.js +407 -0
  25. package/dist/tools/composicao.js +137 -0
  26. package/dist/tools/contratacoes.js +263 -0
  27. package/dist/tools/discursos.js +141 -0
  28. package/dist/tools/ecidadania.js +344 -0
  29. package/dist/tools/legislacao.js +92 -0
  30. package/dist/tools/materias.js +241 -0
  31. package/dist/tools/orcamento-senado.js +155 -0
  32. package/dist/tools/orcamento.js +70 -0
  33. package/dist/tools/plenario.js +344 -0
  34. package/dist/tools/processos.js +330 -0
  35. package/dist/tools/referencia.js +178 -0
  36. package/dist/tools/senadores-admin.js +193 -0
  37. package/dist/tools/senadores.js +287 -0
  38. package/dist/tools/servidores.js +219 -0
  39. package/dist/tools/supridos.js +58 -0
  40. package/dist/tools/taquigrafia.js +127 -0
  41. package/dist/tools/votacao-comissao.js +122 -0
  42. package/dist/tools/votacoes.js +143 -0
  43. package/dist/types.js +10 -0
  44. package/dist/utils/logger.js +23 -0
  45. package/dist/utils/provenance.js +160 -0
  46. package/dist/utils/validation.js +69 -0
  47. package/dist/version.js +2 -0
  48. package/package.json +42 -75
  49. package/dist/index.js +0 -3196
@@ -0,0 +1,788 @@
1
+ # Senado Brasil MCP Server
2
+
3
+ ![Cloudflare Workers](https://img.shields.io/badge/Cloudflare%20Workers-F38020?logo=cloudflare&logoColor=white)
4
+ ![MCP](https://img.shields.io/badge/MCP-Streamable%20HTTP-1f6feb)
5
+ ![Tools](https://img.shields.io/badge/tools-66-2ea44f)
6
+ [![MCP Registry](https://img.shields.io/badge/MCP-Registry-blue)](https://registry.modelcontextprotocol.io)
7
+ [![LobeHub](https://lobehub.com/badge/mcp/sidneybissoli-senado-br-mcp-cloudflare)](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare)
8
+ [![smithery badge](https://smithery.ai/badge/sidneybissoli/senado-br-mcp-cloudflare)](https://smithery.ai/servers/sidneybissoli/senado-br-mcp-cloudflare)
9
+ [![GitHub stars](https://img.shields.io/github/stars/SidneyBissoli/senado-br-mcp-cloudflare?style=flat&logo=github)](https://github.com/SidneyBissoli/senado-br-mcp-cloudflare)
10
+ [![GitHub Sponsors](https://img.shields.io/github/sponsors/SidneyBissoli?logo=githubsponsors&label=Sponsor&color=db61a2)](https://github.com/sponsors/SidneyBissoli)
11
+ [![License: MIT](https://img.shields.io/github/license/SidneyBissoli/senado-br-mcp-cloudflare)](LICENSE)
12
+
13
+ 🇺🇸 [Read in English](README.md)
14
+
15
+ Um servidor MCP **público e hospedado** que dá aos assistentes de IA acesso ao vivo e estruturado aos **dados abertos do Senado Federal do Brasil** — **sem instalação, sem conta, sem chave de API**. Aponte o seu cliente MCP para o endpoint hospedado e comece a perguntar sobre senadores, matérias, votações, despesas e muito mais. Roda em Cloudflare Workers via Streamable HTTP.
16
+
17
+ Expõe **66 ferramentas**, **4 prompts** e **5 recursos** em dois domínios:
18
+
19
+ - **Legislativo** — senadores; matérias e sua tramitação; votações; comissões; sessões plenárias, resultados e vetos presidenciais; orientação de bancada nas votações; discursos e notas taquigráficas; blocos e lideranças; legislação federal; e participação cidadã pelo portal e-Cidadania.
20
+ - **Administrativo** — despesas da cota parlamentar (CEAPS); auxílio-moradia; servidores e remunerações; horas extras; estagiários; contratos e licitações; terceirizados; suprimento de fundos; e execução orçamentária.
21
+
22
+ Os dados vêm de três fontes oficiais — a [API de dados abertos legislativos](https://legis.senado.leg.br/dadosabertos/), a [API de dados abertos administrativos](https://adm.senado.gov.br/adm-dadosabertos/swagger-ui/index.html) e o portal e-Cidadania. Todas as respostas das ferramentas são em português (pt-BR). Veja o [CHANGELOG.md](CHANGELOG.md) para o histórico de versões.
23
+
24
+ ## Veja na prática
25
+
26
+ Aponte um cliente para o endpoint e pergunte, em português:
27
+
28
+ - *"Como os senadores de São Paulo votaram nas últimas votações do plenário?"* → `senado_search_votacoes`
29
+ - *"Mostre a tramitação da PEC 45/2019."* → `senado_buscar_materias` + `senado_obter_materia`
30
+ - *"Quanto foi gasto com a cota parlamentar (CEAPS) em 2024, por tipo de despesa?"* → `senado_ceaps`
31
+
32
+ As respostas vêm ao vivo das APIs oficiais de dados abertos do Senado — valores exatos com procedência, não números chutados a partir do treino.
33
+
34
+ ## Como usar (hospedado — sem configuração)
35
+
36
+ Este é um servidor **remoto, hospedado e de acesso aberto**. Para usá-lo, aponte qualquer cliente MCP para o endpoint
37
+ Streamable HTTP — **sem instalação, sem conta, sem chave de API, sem configuração**:
38
+
39
+ ```
40
+ https://senado.sidneybissoli.com/mcp
41
+ ```
42
+
43
+ ### Instalação (qualquer cliente)
44
+
45
+ Para clientes que iniciam servidores MCP como um comando — e para uma configuração de um único comando — use a
46
+ ponte [`mcp-remote`](https://www.npmjs.com/package/mcp-remote). **Sem build, sem config, sem chave:**
47
+
48
+ ```bash
49
+ npx -y mcp-remote https://senado.sidneybissoli.com/mcp
50
+ ```
51
+
52
+ - **Um clique (LobeHub):** abra a [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**.
53
+ - **URL remota nativa** (Claude Desktop/Code e outros clientes Streamable HTTP): veja [Conectando clientes MCP](#conectando-clientes-mcp).
54
+
55
+ Tudo abaixo de *Arquitetura* (Pré-requisitos, Configuração, Deploy) é **apenas para opcionalmente auto-hospedar a sua
56
+ própria instância** — **não** é necessário para usar este servidor público.
57
+
58
+ ## Rodar localmente (npx · stdio)
59
+
60
+ Prefere não rotear suas consultas por um servidor de terceiros (ex.: política de uma redação)? O **mesmo
61
+ servidor** também roda como um **processo local stdio** que bate **direto nas APIs oficiais do governo** —
62
+ as mesmas 66 ferramentas, o mesmo envelope de proveniência, sem Cloudflare no caminho. É o canal npm/stdio,
63
+ publicado como [`senado-br-mcp`](https://www.npmjs.com/package/senado-br-mcp).
64
+
65
+ Aponte um cliente baseado em comando (Claude Desktop/Code, etc.) para o pacote — o npm baixa e executa,
66
+ sem clone nem build:
67
+
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "senado-br": {
72
+ "command": "npx",
73
+ "args": ["-y", "senado-br-mcp"]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ Para rodar direto ou mexer no código, use o checkout do fonte:
80
+
81
+ ```bash
82
+ git clone https://github.com/SidneyBissoli/senado-br-mcp-cloudflare
83
+ cd senado-br-mcp-cloudflare
84
+ npm install
85
+ npm run build
86
+ node dist/cli.js # serve o MCP por stdio (Ctrl+C para parar)
87
+ ```
88
+
89
+ **Paridade com o servidor hospedado:** as ferramentas legislativas e administrativas são **idênticas**
90
+ (mesmas APIs de origem, mesmo throttle/cache/proveniência) — localmente o cache L1 do Cloudflare vira
91
+ no-op, mas o L0 em memória continua funcionando, então o resultado é o mesmo. A **única** diferença são
92
+ as ferramentas de lista/corpus do e-Cidadania: sem D1, elas caem no scraping ao vivo dos ~5 destaques
93
+ REST, sinalizado por `meta.fonte` / `possivelDesatualizacao`; as de detalhe (`obter_*`) são idênticas.
94
+ Os logs vão para o **stderr** — o stdout carrega apenas o fluxo do protocolo JSON-RPC.
95
+
96
+ ## Arquitetura
97
+
98
+ - **Runtime:** Cloudflare Workers (ESM)
99
+ - **Transporte:** Streamable HTTP (spec MCP 2025-03-26) via `createMcpHandler` de `agents/mcp`
100
+ - **Protocolo:** MCP sobre JSON-RPC — um único endpoint `/mcp` trata POST, GET, DELETE
101
+ - **SDK:** `@modelcontextprotocol/sdk` 1.26.0+ (instâncias de McpServer por requisição)
102
+ - **Validação:** schemas Zod para todas as entradas das ferramentas
103
+ - **Cache:** 2 camadas (L0 memória + L1 Cache API) com chaveamento SHA-256
104
+ - **Store do e-Cidadania:** banco D1 atualizado por um Cron Trigger (a cada 2h) — as ferramentas de listagem leem do D1 com fallback de scraping ao vivo e flag de desatualização; as de detalhe ficam ao vivo com write-through (veja [e-Cidadania](#e-cidadania-em-d1-atualizado-por-cron))
105
+ - **Rate limiting:** Token bucket — global (8 req/s) + por cliente (2 req/s)
106
+ - **Throttle de upstream:** Máx. 6 requisições simultâneas, timeout de 10s, retry com backoff exponencial
107
+ - **Auth:** Bearer token opcional (defina o secret `API_KEY`; acesso aberto quando ausente). Comparação em tempo constante.
108
+ - **Observabilidade:** Logging estruturado em JSON + contadores em memória expostos em `/metrics`
109
+ - **Testes:** testes unitários Vitest para parsers, helpers, cache, throttle e auth
110
+
111
+ ## Auto-hospedagem (opcional)
112
+
113
+ > **Não é necessário para usar o servidor** — ele já está hospedado em `https://senado.sidneybissoli.com/mcp`
114
+ > (acesso aberto). Siga esta seção apenas se quiser rodar a sua **própria** instância privada.
115
+
116
+ ### Pré-requisitos
117
+
118
+ - Node.js 18+
119
+ - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) v4+
120
+ - Conta Cloudflare
121
+
122
+ ### Configuração
123
+
124
+ #### 1. Instalar dependências
125
+
126
+ ```bash
127
+ npm install
128
+ ```
129
+
130
+ #### 2. Criar o namespace KV
131
+
132
+ ```bash
133
+ # Cria o namespace KV
134
+ wrangler kv namespace create CACHE_KV
135
+
136
+ # Anote o ID da saída, ex.:
137
+ # { binding = "CACHE_KV", id = "abc123..." }
138
+ ```
139
+
140
+ #### 3. Configurar o wrangler.toml
141
+
142
+ Substitua o ID placeholder do namespace KV:
143
+
144
+ ```toml
145
+ [[kv_namespaces]]
146
+ binding = "CACHE_KV"
147
+ id = "YOUR_KV_NAMESPACE_ID_HERE"
148
+ ```
149
+
150
+ Opcionalmente, defina `ALLOWED_ORIGIN` para restringir o CORS:
151
+
152
+ ```toml
153
+ [vars]
154
+ ALLOWED_ORIGIN = "https://your-app.example.com"
155
+ ```
156
+
157
+ O pipeline do e-Cidadania precisa de um **banco D1** e de um **Cron Trigger** (ambos já declarados no `wrangler.toml` — substitua o ID do banco):
158
+
159
+ ```toml
160
+ [[d1_databases]]
161
+ binding = "ECIDADANIA_DB"
162
+ database_name = "senado-ecidadania"
163
+ database_id = "YOUR_D1_DATABASE_ID_HERE"
164
+
165
+ [triggers]
166
+ crons = ["0 */2 * * *"]
167
+ ```
168
+
169
+ Crie o banco (cole o ID retornado acima) e aplique o schema:
170
+
171
+ ```bash
172
+ npx wrangler d1 create senado-ecidadania
173
+ npx wrangler d1 migrations apply senado-ecidadania --remote
174
+ ```
175
+
176
+ As ferramentas de listagem caem para scraping ao vivo quando o D1 está vazio, então o servidor funciona antes da primeira execução do Cron.
177
+
178
+ #### 4. (Opcional) Habilitar autenticação
179
+
180
+ ```bash
181
+ wrangler secret put API_KEY
182
+ # Os clientes passam a enviar: Authorization: Bearer <key>
183
+ # Quando API_KEY não está definido, o servidor é de acesso aberto.
184
+ ```
185
+
186
+ #### 5. Desenvolvimento local
187
+
188
+ ```bash
189
+ npm run dev
190
+ # O servidor de dev roda localmente na porta 8787 (apenas local).
191
+ # O endpoint MCP público é https://senado.sidneybissoli.com/mcp
192
+ ```
193
+
194
+ #### 6. Testes e typecheck
195
+
196
+ ```bash
197
+ npm test # roda todos os testes uma vez
198
+ npm run test:watch # modo watch
199
+ npm run typecheck # tsc --noEmit
200
+ ```
201
+
202
+ #### 7. Deploy
203
+
204
+ ```bash
205
+ npm run deploy
206
+ # Servido em https://senado.sidneybissoli.com (domínio próprio) e
207
+ # https://senado-br-mcp.sidneybissoli.workers.dev (fallback workers.dev)
208
+ ```
209
+
210
+ ## Endpoints
211
+
212
+ | Caminho | Métodos | Descrição |
213
+ |------|---------|-------------|
214
+ | `/mcp` | POST, GET, DELETE, OPTIONS | Endpoint MCP Streamable HTTP (gerenciado por `createMcpHandler`) |
215
+ | `/health` | GET | Health check — retorna `ok` (sempre público) |
216
+ | `/metrics` | GET | Contadores em JSON: requisições, chamadas de ferramentas, acertos/erros de cache, chamadas/retries/erros de upstream, falhas de auth (sempre público) |
217
+
218
+ ## Exemplos de requisição MCP
219
+
220
+ Todas as requisições vão para `POST /mcp` no formato JSON-RPC 2.0.
221
+
222
+ ### Listar as ferramentas disponíveis
223
+
224
+ ```json
225
+ {
226
+ "jsonrpc": "2.0",
227
+ "id": 1,
228
+ "method": "tools/list"
229
+ }
230
+ ```
231
+
232
+ ### Chamar uma ferramenta — Listar senadores de SP
233
+
234
+ ```json
235
+ {
236
+ "jsonrpc": "2.0",
237
+ "id": 2,
238
+ "method": "tools/call",
239
+ "params": {
240
+ "name": "senado_listar_senadores",
241
+ "arguments": {
242
+ "uf": "SP",
243
+ "emExercicio": true
244
+ }
245
+ }
246
+ }
247
+ ```
248
+
249
+ ### Chamar uma ferramenta — Buscar matérias por palavra-chave
250
+
251
+ ```json
252
+ {
253
+ "jsonrpc": "2.0",
254
+ "id": 3,
255
+ "method": "tools/call",
256
+ "params": {
257
+ "name": "senado_buscar_materias",
258
+ "arguments": {
259
+ "palavraChave": "inteligência artificial",
260
+ "tramitando": true
261
+ }
262
+ }
263
+ }
264
+ ```
265
+
266
+ ### Chamar uma ferramenta — Votações recentes do plenário
267
+
268
+ ```json
269
+ {
270
+ "jsonrpc": "2.0",
271
+ "id": 4,
272
+ "method": "tools/call",
273
+ "params": {
274
+ "name": "senado_search_votacoes",
275
+ "arguments": {
276
+ "dias": 7
277
+ }
278
+ }
279
+ }
280
+ ```
281
+
282
+ ### Chamar uma ferramenta — Ideias de cidadãos mais populares
283
+
284
+ ```json
285
+ {
286
+ "jsonrpc": "2.0",
287
+ "id": 5,
288
+ "method": "tools/call",
289
+ "params": {
290
+ "name": "senado_ecidadania_listar_ideias",
291
+ "arguments": {
292
+ "ordenarPor": "apoios",
293
+ "ordem": "desc",
294
+ "status": "aberta"
295
+ }
296
+ }
297
+ }
298
+ ```
299
+
300
+ ## Endpoints da API de origem (upstream)
301
+
302
+ O servidor consome duas classes de endpoints upstream da API do Senado:
303
+
304
+ ### Endpoints legados (sufixo `.json`, respostas em PascalCase)
305
+
306
+ Usados pelos Grupos A, E, F, H, I, J, K, L, M, N. O sufixo `.json` é anexado automaticamente por `upstream.ts`. Nenhum deles está marcado como deprecated no upstream.
307
+
308
+ | Caminho upstream | Usado por |
309
+ |---------------|---------|
310
+ | `/senador/lista/atual` | `senado_listar_senadores` |
311
+ | `/senador/lista/legislatura/{legislatura}` | `senado_listar_senadores` (param `legislatura`) |
312
+ | `/senador/{codigo}` | `senado_obter_senador` |
313
+ | `/senador/{codigo}/licencas`, `/comissoes`, `/cargos`, `/historicoAcademico`, `/filiacoes`, `/profissao` | `senado_senador_historico` (`tipo` enum) |
314
+ | `/senador/afastados` | `senado_senadores_afastados` |
315
+ | `/senador/{codigo}/apartes` | `senado_discursos_senador` (`tipo=apartes`) |
316
+ | `/comissao/lista/colegiados` | `senado_listar_comissoes` (+ resolução sigla→código) |
317
+ | `/comissao/{codigo}` | `senado_obter_comissao` (`secao=resumo`; código numérico, não sigla) |
318
+ | `/composicao/comissao/{codigo}` | `senado_obter_comissao` (`secao=membros`) |
319
+ | `/comissao/agenda/{data}` | `senado_agenda_comissoes` |
320
+ | `/comissao/agenda/{dataInicio}/{dataFim}` | `senado_reunioes_comissao` |
321
+ | `/comissao/reuniao/{codigoReuniao}` | `senado_reuniao_comissao` |
322
+ | `/comissao/cpi/{sigla}/requerimentos` | `senado_requerimentos_cpi` (corpo vazio = sem requerimentos) |
323
+ | `/materia/distribuicao/autoria`, `/distribuicao/relatoria/{sigla}` | `senado_distribuicao_materias` |
324
+ | `/plenario/agenda/dia/{data}`, `/agenda/mes/{data}`, `/agenda/cn/...` | `senado_agenda_plenario` |
325
+ | `/plenario/resultado/{data}`, `/resultado/cn/{data}`, `/resultado/mes/{data}` | `senado_resultado_plenario` |
326
+ | `/plenario/resultado/veto/{codigo}` (+ `/materia/`, `/dispositivo/`) | `senado_resultado_veto` |
327
+ | `/plenario/votacao/orientacaoBancada/{data}` (+ período) | `senado_orientacao_bancada` |
328
+ | `/plenario/encontro/{codigo}` (+ `/pauta`, `/resultado`, `/resumo`) | `senado_encontro_plenario` |
329
+ | `/plenario/tiposSessao`, `/lista/tiposComparecimento`, `/lista/legislaturas` | `senado_tabelas_plenario` |
330
+ | `/materia/vetos/{ano}`, `/vetos/aposrcn`, `/vetos/antesrcn`, `/vetos/encerrados` | `senado_vetos` |
331
+ | `/taquigrafia/notas/{sessao\|reuniao}/{id}` | `senado_notas_taquigraficas` |
332
+ | `/taquigrafia/videos/{sessao\|reuniao}/{id}` | `senado_videos_taquigrafia` |
333
+ | `/senador/{codigo}/discursos` | `senado_discursos_senador` |
334
+ | `/plenario/lista/discursos/{dataInicio}/{dataFim}` | `senado_discursos_plenario` |
335
+ | `/discurso/texto-integral/{codigo}` | `senado_discurso_texto` (texto puro, buscado diretamente) |
336
+ | `/senador/lista/tiposUsoPalavra` | `senado_tabelas_referencia` (`tabela=tipos-uso-palavra`) |
337
+ | `/composicao/lista/blocos` | `senado_listar_blocos` |
338
+ | `/composicao/bloco/{codigo}` | `senado_obter_bloco` |
339
+ | `/composicao/lideranca` | `senado_liderancas` |
340
+ | `/composicao/mesaSF` | `senado_mesa` (`casa=senado`) |
341
+ | `/composicao/mesaCN` | `senado_mesa` (`casa=congresso`) |
342
+ | `/orcamento/lista` | `senado_orcamento_parlamentar` (`tipo=emendas`) |
343
+ | `/orcamento/oficios` | `senado_orcamento_parlamentar` (`tipo=oficios`) |
344
+ | `/legislacao/lista` | `senado_buscar_legislacao` |
345
+ | `/legislacao/{codigo}` | `senado_obter_legislacao` |
346
+ | `/legislacao/tiposNorma` | `senado_tabelas_referencia` (`tabela=tipos-norma`) |
347
+ | `/votacaoComissao/comissao/{sigla}` | `senado_votacao_comissao` (`por=comissao`) |
348
+ | `/votacaoComissao/parlamentar/{codigo}` | `senado_votacao_comissao` (`por=senador`) |
349
+ | `/votacaoComissao/materia/{sigla}/{numero}/{ano}` | `senado_votacao_comissao` (`por=materia`) |
350
+ | `/autor/lista/atual` | `senado_autores_atuais` |
351
+
352
+ ### Endpoints v3 (arrays/objetos JSON planos, camelCase)
353
+
354
+ Usados pelos Grupos B, C, D. As datas devem estar em **formato ISO** (`YYYY-MM-DD`) — as ferramentas aceitam `YYYYMMDD` e convertem. O query param `codigoMateria` faz a ponte de códigos de matéria legados para processos v3.
355
+
356
+ | Caminho upstream | Usado por |
357
+ |---------------|---------|
358
+ | `/votacao` | `senado_obter_votacao`, `senado_search_votacoes`, `senado_votos_materia`, `senado_votacoes_senador` |
359
+ | `/processo` | `senado_search_processos`, `senado_buscar_materias` |
360
+ | `/processo/{id}` | `senado_obter_processo`, `senado_obter_materia` (`secao=detalhe`/`tramitacao`) |
361
+ | `/processo/documento` | `senado_obter_materia` (`secao=textos`) |
362
+ | `/processo/emenda` | `senado_processo_detalhe` (`secao=emendas`) |
363
+ | `/processo/relatoria` | `senado_processo_detalhe` (`secao=relatorias`), `senado_obter_materia` (relator) |
364
+ | `/processo/prazo` | `senado_processo_detalhe` (`secao=prazos`) |
365
+ | `/processo/{siglas,assuntos,classes,destinos,entes,tipos-*}` | `senado_tabelas_processo` (12 tabelas de referência) |
366
+
367
+ ### API administrativa (adm.senado.gov.br/adm-dadosabertos, JSON plano em snake_case)
368
+
369
+ Usada pelos Grupos O, P, Q, R via `admFetch` (sem sufixo `.json`; HTTP 404 tratado como coleção vazia). URL base configurável via `SENADO_ADM_BASE_URL`.
370
+
371
+ | Caminho upstream | Usado por |
372
+ |---------------|---------|
373
+ | `/api/v1/senadores/despesas_ceaps/{ano}` | `senado_ceaps` (~10 MB/ano, cacheado + agregado no Worker) |
374
+ | `/api/v1/senadores/{auxilio-moradia,escritorios,aposentados}` | `senado_senadores_admin` (`tipo` enum) |
375
+ | `/api/v1/servidores/servidores/{ativos,efetivos,comissionados,inativos}` | `senado_servidores` |
376
+ | `/api/v1/servidores/remuneracoes/{ano}/{mes}` | `senado_remuneracoes_servidores` (~5.5 MB/mês) |
377
+ | `/api/v1/servidores/horas-extras/{ano}/{mes}` | `senado_horas_extras` |
378
+ | `/api/v1/servidores/quantitativos/*`, `/previsao-aposentadoria`, `/api/v1/senadores/quantitativos/senadores` | `senado_pessoal_tabelas` (quantitativos) |
379
+ | `/api/v1/servidores/{estagiarios,pensionistas,lotacoes,cargos}` | `senado_pessoal_tabelas` (listas nominais) |
380
+ | `/api/v1/contratacoes/contratos` (+ `/{id}/aditivos`) | `senado_contratos`, `senado_contratacao_detalhe` |
381
+ | `/api/v1/contratacoes/{tipo}/{id}/{itens,pagamentos,garantias}` | `senado_contratacao_detalhe` |
382
+ | `/api/v1/contratacoes/licitacoes` | `senado_licitacoes` |
383
+ | `/api/v1/contratacoes/terceirizados` | `senado_terceirizados` |
384
+ | `/api/v1/contratacoes/empresas` | `senado_empresas_contratadas` (~13 MB, exige filtro) |
385
+ | `/api/v1/contratacoes/{atas_registro_preco,notas_empenho,menores_aprendizes}` | `senado_contratacoes_lista` |
386
+ | `/api/v1/supridos/{ano}` (+ atosConcessao, empenhos, movimentacoes, transacoes) | `senado_suprimento_fundos` |
387
+ | `senado.gov.br/bi-arqs/Arquimedes/Financeiro/{Despesa,Receitas}SenadoDadosAbertos.json` | `senado_execucao_orcamentaria` (feeds JSON diários, strings decimais brasileiras normalizadas) |
388
+
389
+ ### e-Cidadania (em D1, atualizado por Cron)
390
+
391
+ Os dados de **listagem** do e-Cidadania são persistidos em um **banco D1** (`ecidadania_current/_history/_scrape_runs`, discriminado por `entidade`) e lidos de lá em vez de raspados a cada chamada. **Duas cadências** escrevem nele:
392
+
393
+ - uma **GitHub Action semanal fora do Worker** é dona do **corpus completo** de cada entidade (veja abaixo) — a fonte da verdade;
394
+ - um **Cron Trigger** in-Worker (`0 */2 * * *`, `src/scraper/pipeline.ts → refreshEcidadania`) faz apenas um **splice de métrica direcionado** dos ~5 destaques REST por entidade ao vivo (`restcolecaomaismateria/ideia/audiencia` — votos/comentários/apoios), registrado como `ok-metrica` para nunca re-quebrar a baseline do corpus nem tocar a cauda longa.
395
+
396
+ Ambos os escritores constroem os payloads pelos builders canônicos `buildXResumo` + `contentHash` compartilhado, então suas linhas são byte-idênticas. Cada escrita:
397
+
398
+ - faz **upsert** em `ecidadania_current` (uma linha por item — o que as ferramentas leem),
399
+ - **anexa** em `ecidadania_history` apenas quando o `content_hash` de um item muda (pronto para série temporal),
400
+ - registra cada execução em `ecidadania_scrape_runs`.
401
+
402
+ Um **guard de anomalia** (`src/scraper/anomaly.ts`, `classifyRun`) garante que uma execução de corpus falha ou anômala (zero linhas, ou menos que `ECIDADANIA_CORPUS_MIN_PCT`% da última boa) **nunca sobrescreva** o último bom estado.
403
+
404
+ As **ferramentas de listagem/análise** (`listar_*`, `consultas_analise`, `sugerir_tema_enquete`, `consultas_votos`) leem do D1 via `resolveList` (`src/scraper/store.ts`): D1 primeiro. Como toda entidade agora é um corpus completo, um corpus velho é servido do D1 **com flag** (`possivelDesatualizacao: true`) em vez de colapsar para os ~5 destaques ao vivo (o bug de cobertura original); o scraping ao vivo fica reservado a um D1 vazio (cold start, antes da 1ª carga semanal). O frescor usa `ECIDADANIA_CORPUS_STALE_MAX_MIN` (~10 dias). Toda resposta de listagem carrega um `meta` aditivo (`fonte`, `lastScrapedAt`, `possivelDesatualizacao`) para que os chamadores sempre vejam a idade real dos dados e nunca recebam dados velhos silenciosamente.
405
+
406
+ As **ferramentas de detalhe** (`obter_*`) ficam **ao vivo** (HTML raspado com regex direcionado por classe CSS) por frescor, e gravam o payload mais rico em `ecidadania_detalhe` em fire-and-forget (deduplicado por `content_hash`), para que o histórico de detalhe se acumule sem adicionar latência à resposta.
407
+
408
+ #### Ingestão do corpus completo (fora do Worker, semanal)
409
+
410
+ As quatro entidades do e-Cidadania são corpora completos, cada um dono de um orquestrador `scripts/ingest-ecidadania/index-*.ts` executado pela Action semanal (`.github/workflows/ingest-ecidadania.yml`), emitindo `out-*.sql` em lotes que o passo de apply carrega:
411
+
412
+ - **`consultas`** — consultas abertas (detalhado abaixo).
413
+ - **`eventos`** — audiências/eventos da listagem HTML `principalaudiencia?p=N`; o status vem direto do bloco da listagem (sem ponte por `/processo`).
414
+ - **`ideias`** — ideias legislativas (~150 mil) de `pesquisaideia?situacao=N&p=M`, varridas **por bucket de `situacao`** (a listagem não traz status inline) e emitidas em lotes de ~10k statements.
415
+ - **`consultas_votos`** — acervo **histórico** separado de votos por UF, lido do CSV Arquimedes de ~33 MB (`Proposições-com-votos.csv`), agregado a uma linha por matéria com quebra `votosPorUf`. O carimbo "dados atualizados até" do CSV vira o `reference_period` da proveniência; fica **fora** do hash da linha (`consultaVotoCore`) para que um bump semanal do carimbo sobre esses votos congelados não suje o `_history`. `STATUS ATUAL` é uniformemente "Descontinuado" — por isso é acervo, não migração das consultas abertas. Servido por `senado_ecidadania_consultas_votos` com proveniência apontando para o CSV (`ECIDADANIA_ARQUIMEDES`).
416
+
417
+ O job de `consultas` é a implementação de referência:
418
+
419
+ `consultas` cobre o **conjunto completo de consultas ABERTAS** — toda matéria atualmente em tramitação (~7,7 mil), não apenas os ~5 destaques. Confirmado na primeira execução: a listagem `pesquisamateria` é **apenas de em-tramitação**, então consultas encerradas/históricas **não** são capturadas por essa fonte (um backfill histórico pré-ingestão está fora de escopo). Três decisões de design já assentadas:
420
+
421
+ 1. **Ingestão desacoplada.** O conjunto aberto é obtido por um **job TypeScript fora do Worker** (`scripts/ingest-ecidadania/`, executado por uma GitHub Action semanal — `.github/workflows/ingest-ecidadania.yml`) que pagina a listagem HTML (`pesquisamateria?p=1..N`, a única fonte de cobertura completa para consultas abertas) buscando ids + contagens de votos e faz **bulk-load no D1**; o Worker apenas lê. O crawl frágil e longo fica fora do caminho de requisição/Cron.
422
+ 2. **Status a partir de `/processo`, não do HTML.** Uma consulta corre da apresentação até o fim da tramitação, então o `status` é função da matéria: **aberta ⟺ o `codigoMateria` está no conjunto `tramitando=S` de `/processo`**, derivado de JSON robusto (nunca raspado). Toda consulta entra como `aberta` (a listagem só traz matérias em tramitação); a cada execução **completa** o job re-deriva o status de **todas as linhas armazenadas** por presença em `/processo` (não por ausência na listagem, que pode ser transitória), de modo que uma consulta cuja matéria deixa a tramitação vira `encerrada`. Os conjuntos `encerrada`/`todas` portanto crescem com o tempo; consultas que encerraram **antes** da primeira ingestão não são capturadas (fora de escopo). As ferramentas de listagem/análise usam `status: aberta` por padrão.
423
+ 3. **Duas cadências reconciliadas (um único contrato de escrita).** O job **reutiliza** `contentHash` + o builder `ConsultaResumo` + `classifyRun` de `src/scraper/`, então suas linhas são byte-idênticas às do Cron. O job semanal cuida da cauda longa; o **Cron de 2h** mantém os ~5 destaques quentes/abertos frescos via um *splice de métrica direcionado* (registrado como `ok-metrica`, ignorando a baseline `classifyRun` do corpus). O frescor do corpus (`possivelDesatualizacao`) é calculado a partir da última execução `status='ok'` e usa uma janela maior (`ECIDADANIA_CORPUS_STALE_MAX_MIN`); um corpus de consultas velho é servido do D1 com flag em vez de colapsar de volta para os destaques ao vivo.
424
+
425
+ Guards de escrita na carga: um **crawl incompleto** (qualquer página falhou) ou um universo de status `/processo` incompleto grava apenas uma linha de execução `erro`; mesmo um crawl completo é rejeitado por um **piso catastrófico** (`ECIDADANIA_CORPUS_MIN_PCT`, padrão 80% do último bom corpus) para proteger contra uma página degradada — sobreponível com `--force` / `INGEST_FORCE=1` para uma redução grande legítima. Execute semanalmente via Action, ou manualmente:
426
+
427
+ ```bash
428
+ CLOUDFLARE_API_TOKEN=… npm run ingest:ecidadania # escreve scripts/ingest-ecidadania/out.sql
429
+ npx wrangler d1 execute senado-ecidadania --remote --file=scripts/ingest-ecidadania/out.sql
430
+ ```
431
+
432
+ ## Cache
433
+
434
+ ### Arquitetura de camadas
435
+
436
+ | Camada | Armazenamento | Escopo | Faixa de TTL | Finalidade |
437
+ |-------|---------|-------|-----------|---------|
438
+ | **L0** | `Map` em memória | Por isolate | 30-300s | Ultrarrápido, elimina requisições redundantes dentro de um isolate do Worker |
439
+ | **L1** | Cloudflare Cache API (`caches.default`) | Por colo (PoP) | 60-600s | Compartilhado entre requisições no mesmo edge |
440
+ | **L2** | KV (opcional) | Global | Variável | Reservado para dados raros e de baixa escrita |
441
+
442
+ ### Categorias de cache
443
+
444
+ | Categoria | L0 TTL | L1 TTL | Usado para |
445
+ |----------|--------|--------|----------|
446
+ | **STATIC** | 300s | 600s | Tipos de legislação, referência estática |
447
+ | **SEMI_STATIC** | 120s | 300s | Lista de partidos, lista de UFs, detalhes de comissão |
448
+ | **DYNAMIC** | 30s | 60s | Agendas, votações recentes, listas de reuniões |
449
+ | **ON_DEMAND** | 30s | 120s | Consultas específicas de matéria/senador/votação |
450
+
451
+ ### Abordagem de cache de POST
452
+
453
+ O MCP usa POST para todas as requisições `tools/call`. Cachear respostas de POST não é nativamente suportado pela Cache API, que requer requisições GET. A solução:
454
+
455
+ 1. **Hash dos parâmetros** — Nome da ferramenta + parâmetros ordenados são hasheados com SHA-256
456
+ 2. **Chave GET sintética** — Uma URL sintética `https://senado-br-mcp.internal/__cache/{tool}/{hash}` é construída
457
+ 3. **match/put na Cache API** — A URL GET sintética é usada com `caches.default.match()` e `caches.default.put()`, permitindo operações padrão da Cache API sobre dados originados de POST
458
+
459
+ Esse cache acontece no **nível da ferramenta** (dentro do callback de cada ferramenta), não no nível do transporte MCP.
460
+
461
+ ## Proveniência
462
+
463
+ **Toda ferramenta** anexa um **envelope de proveniência** para que qualquer resultado seja rastreável até sua fonte oficial — a proveniência é parte essencial da resposta, não um extra opcional (o público são jornalistas e pesquisadores em ciência política, para quem um número sem fonte é inutilizável). O envelope fica em `structuredContent.provenance` (parseável e validado pelo output schema da ferramenta) e é espelhado como um rodapé compacto de fonte no texto, para clientes que só renderizam texto — o JSON dos dados **não** é duplicado com o envelope, mantendo o custo de tokens por resposta baixo (≈170 chars fixos).
464
+
465
+ Campos (por resposta — uma ferramenta, uma fonte): `source`, `source_url` (URL canônica consultada), `dataset_id`, `reference_period` (competência/vintage do dado), `retrieved_at` (ISO-8601 da extração no upstream — preservado mesmo em cache-hit, o diferenciador nível-1), `attribution` (citação pronta) e `license`.
466
+
467
+ A cobertura abrange as quatro fontes upstream: **Dados Abertos Legislativo** (`legis.senado.leg.br`), **Dados Abertos Administrativo** (`adm.senado.gov.br`), **Execução Orçamentária** (feed Arquimedes/Financeiro em `senado.gov.br`) e **Portal e-Cidadania** (`www12.senado.leg.br/ecidadania`). Nas listas do e-Cidadania (lidas do D1) o `retrieved_at` é o `lastScrapedAt` do corpus — a idade real do dado; nos detalhes (raspados ao vivo) é o instante da chamada, com a URL canônica do item. A fidelidade do `retrieved_at` vem da camada de cache (`cachedFetchWithMeta`), que persiste o timestamp junto ao valor.
468
+
469
+ ## Inventário de ferramentas
470
+
471
+ ### Grupo H — Referência/Metadados (1 ferramenta)
472
+
473
+ | Ferramenta | Descrição |
474
+ |------|-------------|
475
+ | `senado_tabelas_referencia` | Tabelas de referência via `tabela` enum: tipos-materia, partidos, ufs, legislatura-atual, tipos-norma, tipos-uso-palavra |
476
+
477
+ ### Grupo A — Senadores (5 ferramentas)
478
+
479
+ | Ferramenta | Descrição |
480
+ |------|-------------|
481
+ | `senado_listar_senadores` | Lista senadores em exercício/por legislatura, com filtros `nome` (busca parcial sem acento), `uf` e `partido` |
482
+ | `senado_obter_senador` | Detalhe biográfico de um senador: bio, mandatos, partido, contato |
483
+ | `senado_votacoes_senador` | Como um senador votou em cada matéria (via v3 `/votacao`) |
484
+ | `senado_senador_historico` | Histórico funcional via `tipo` enum: licencas, comissoes, cargos, historico-academico, filiacoes, profissoes |
485
+ | `senado_senadores_afastados` | Senadores atualmente afastados (fora de exercício) |
486
+
487
+ ### Grupo B — Matérias (2 ferramentas, backend v3)
488
+
489
+ | Ferramenta | Descrição |
490
+ |------|-------------|
491
+ | `senado_buscar_materias` | Busca matérias por tipo, número, ano, palavra-chave, autor ou tramitação (via v3 `/processo`) |
492
+ | `senado_obter_materia` | Dados de uma matéria via `secao` enum: detalhe (situação/relator), tramitacao (histórico) ou textos (documentos) |
493
+
494
+ ### Grupo C — Processos (5 ferramentas)
495
+
496
+ | Ferramenta | Descrição |
497
+ |------|-------------|
498
+ | `senado_search_processos` | Busca processos legislativos (complementar à busca de matérias) |
499
+ | `senado_obter_processo` | Detalhes completos de um processo legislativo específico |
500
+ | `senado_processo_detalhe` | Aspecto de um processo via `secao` enum: emendas, relatorias ou prazos |
501
+ | `senado_autores_atuais` | Parlamentares autores de processos em tramitação, ordenados por produção |
502
+ | `senado_tabelas_processo` | 12 tabelas de referência (siglas, assuntos, classes, tipos-*) via `tabela` enum |
503
+
504
+ ### Grupo D — Votações (3 ferramentas)
505
+
506
+ | Ferramenta | Descrição |
507
+ |------|-------------|
508
+ | `senado_obter_votacao` | Detalhes de uma votação com votos nominais. Aceita `codigoVotacao` (codigoSessao da sessão plenária). |
509
+ | `senado_votos_materia` | Votações de uma matéria (via v3 `/votacao?codigoMateria`), com votos nominais opcionais |
510
+ | `senado_search_votacoes` | Busca/listagem flexível de votações do plenário por `dias`, período, processo, matéria ou senador |
511
+
512
+ ### Grupo E — Comissões (7 ferramentas)
513
+
514
+ | Ferramenta | Descrição |
515
+ |------|-------------|
516
+ | `senado_listar_comissoes` | Lista comissões (colegiados) ativas, filtráveis por tipo |
517
+ | `senado_obter_comissao` | Dados de uma comissão via `secao` enum: resumo (mesa/totais) ou membros (composição). Resolve sigla para código internamente. |
518
+ | `senado_reunioes_comissao` | Reuniões de uma comissão num período (lida com intervalos entre anos) |
519
+ | `senado_agenda_comissoes` | Agenda de reuniões de todas as comissões numa data |
520
+ | `senado_reuniao_comissao` | Detalhe completo de uma reunião: partes, itens, convidados, resultados, links pauta/ata |
521
+ | `senado_requerimentos_cpi` | Requerimentos protocolados numa CPI em atividade, paginados |
522
+ | `senado_distribuicao_materias` | Estatísticas de carga por senador numa comissão: autoria ou relatoria |
523
+
524
+ ### Grupo F — Plenário (7 ferramentas)
525
+
526
+ | Ferramenta | Descrição |
527
+ |------|-------------|
528
+ | `senado_agenda_plenario` | Agenda do plenário — por dia, mês ou Congresso (escopo dia/mes/cn) |
529
+ | `senado_resultado_plenario` | Resultados de sessão: itens deliberados, pareceres, desfechos (SF/CN/mês) |
530
+ | `senado_orientacao_bancada` | Orientações de voto das lideranças por votação, com placar |
531
+ | `senado_vetos` | Vetos presidenciais por ano ou situação de tramitação |
532
+ | `senado_resultado_veto` | Resultados nominais de votação de veto (por veto, matéria vetada ou dispositivo) |
533
+ | `senado_encontro_plenario` | Detalhe de sessão legislativa, itens de pauta, resultados ou resumo |
534
+ | `senado_tabelas_plenario` | Tipos de sessão, tipos de comparecimento, lista de legislaturas |
535
+
536
+ ### Grupo G — e-Cidadania (9 ferramentas)
537
+
538
+ | Ferramenta | Descrição |
539
+ |------|-------------|
540
+ | `senado_ecidadania_listar_consultas` | Consultas públicas (conjunto completo das **abertas** — matérias em tramitação) com votação sim/não; filtro `status` (padrão `aberta`) |
541
+ | `senado_ecidadania_obter_consulta` | Detalhe de uma consulta: votos, autor, relator, comentários |
542
+ | `senado_ecidadania_consultas_analise` | Analisa o conjunto completo de consultas **abertas** via `modo` (consenso/polarizada); `status` padrão `aberta` |
543
+ | `senado_ecidadania_listar_ideias` | Ideias legislativas de cidadãos; ranking das mais apoiadas via `ordenarPor: apoios` |
544
+ | `senado_ecidadania_obter_ideia` | Detalhe de uma ideia: texto, apoios, status de conversão em projeto |
545
+ | `senado_ecidadania_listar_eventos` | Eventos interativos (audiências, sabatinas, lives); ranking dos mais comentados via `ordenarPor` |
546
+ | `senado_ecidadania_obter_evento` | Detalhe de um evento: pauta, convidados, link de vídeo |
547
+ | `senado_ecidadania_sugerir_tema_enquete` | Sugere temas para enquete mensal a partir de critérios configuráveis |
548
+ | `senado_ecidadania_consultas_votos` | Acervo **histórico** de votos das consultas com quebra **por UF** (CSV Arquimedes); ranking por `total`/`sim`/`nao`, filtro `uf`/`materia` |
549
+
550
+ ### Grupo I — Discursos (3 ferramentas)
551
+
552
+ | Ferramenta | Descrição |
553
+ |------|-------------|
554
+ | `senado_discursos_senador` | Pronunciamentos de um senador via `tipo` enum: discursos (próprios) ou apartes (intervenções) |
555
+ | `senado_discursos_plenario` | Todos os discursos em plenário num intervalo de datas |
556
+ | `senado_discurso_texto` | Texto integral de um pronunciamento/discurso específico |
557
+
558
+ ### Grupo J — Blocos e Lideranças (4 ferramentas)
559
+
560
+ | Ferramenta | Descrição |
561
+ |------|-------------|
562
+ | `senado_listar_blocos` | Blocos parlamentares do Senado e seus partidos membros |
563
+ | `senado_obter_bloco` | Detalhes de um bloco parlamentar específico |
564
+ | `senado_liderancas` | Lideranças do Senado/Congresso (líderes, vice-líderes), filtráveis |
565
+ | `senado_mesa` | Membros da Mesa Diretora via `casa` enum: senado (Mesa do SF) ou congresso (Mesa do CN) |
566
+
567
+ ### Grupo K — Orçamento (1 ferramenta)
568
+
569
+ | Ferramenta | Descrição |
570
+ |------|-------------|
571
+ | `senado_orcamento_parlamentar` | Dados de emendas orçamentárias via `tipo` enum: emendas (lotes) ou oficios (ofícios de apoio) |
572
+
573
+ ### Grupo L — Legislação Federal (2 ferramentas)
574
+
575
+ | Ferramenta | Descrição |
576
+ |------|-------------|
577
+ | `senado_buscar_legislacao` | Busca normas jurídicas federais por tipo, número, ano ou data (ao menos um obrigatório) |
578
+ | `senado_obter_legislacao` | Detalhes de uma norma jurídica federal específica |
579
+
580
+ ### Grupo M — Votação em Comissão (1 ferramenta)
581
+
582
+ | Ferramenta | Descrição |
583
+ |------|-------------|
584
+ | `senado_votacao_comissao` | Votações em comissões via `por` enum: comissao, senador ou materia; período opcional |
585
+
586
+ ### Grupo N — Taquigrafia (2 ferramentas)
587
+
588
+ | Ferramenta | Descrição |
589
+ |------|-------------|
590
+ | `senado_notas_taquigraficas` | Notas taquigráficas oficiais de sessões plenárias ou reuniões de comissão — modo resumo com trechos, modo texto integral paginado em blocos, filtro por orador |
591
+ | `senado_videos_taquigrafia` | Unidades de vídeo/áudio por sessão ou reunião, com orador e links de mídia |
592
+
593
+ ### Grupo O — Senadores/Administrativo (2 ferramentas)
594
+
595
+ | Ferramenta | Descrição |
596
+ |------|-------------|
597
+ | `senado_ceaps` | Despesas da cota parlamentar (CEAPS) por ano — agregadas por senador, tipo de despesa, mês ou fornecedor, ou detalhe item a item; filtros por senador/mês/tipo/fornecedor |
598
+ | `senado_senadores_admin` | Dados administrativos dos senadores via `tipo` enum: auxilio-moradia, escritorios-apoio ou aposentados |
599
+
600
+ ### Grupo P — Servidores / Gestão de Pessoas (4 ferramentas)
601
+
602
+ | Ferramenta | Descrição |
603
+ |------|-------------|
604
+ | `senado_servidores` | Servidores por situação (ativos/efetivos/comissionados/inativos), filtráveis por nome, unidade, cargo |
605
+ | `senado_remuneracoes_servidores` | Folha mensal — resumo por tipo de folha ou composição por pessoa com bruto calculado |
606
+ | `senado_horas_extras` | Pagamentos de horas extras por mês, com totais |
607
+ | `senado_pessoal_tabelas` | Tabelas de pessoal via `tabela` enum: quantitativos (pessoal, cargos-funcoes, previsao-aposentadoria, senadores) e listas (estagiarios, pensionistas, lotacoes, cargos) |
608
+
609
+ ### Grupo Q — Contratações (6 ferramentas)
610
+
611
+ | Ferramenta | Descrição |
612
+ |------|-------------|
613
+ | `senado_contratos` | Contratos com filtros no servidor: fornecedor, CNPJ, ano, número, objeto, mão de obra |
614
+ | `senado_contratacao_detalhe` | Itens, pagamentos, garantias, aditivos ou ativações de um contrato/ata/empenho |
615
+ | `senado_licitacoes` | Licitações por número ou texto do objeto |
616
+ | `senado_terceirizados` | Colaboradores terceirizados por nome, empresa ou unidade |
617
+ | `senado_empresas_contratadas` | Empresas que contratam com o Senado (exige filtro por nome/CNPJ) |
618
+ | `senado_contratacoes_lista` | Atas de registro de preço, notas de empenho, menores aprendizes |
619
+
620
+ ### Grupo R — Suprimento de Fundos (1 ferramenta)
621
+
622
+ | Ferramenta | Descrição |
623
+ |------|-------------|
624
+ | `senado_suprimento_fundos` | Adiantamentos de suprimento de fundos por ano: beneficiários, atos de concessão, empenhos, movimentações, transações de cartão |
625
+
626
+ ### Grupo S — Orçamento do Senado (1 ferramenta)
627
+
628
+ | Ferramenta | Descrição |
629
+ |------|-------------|
630
+ | `senado_execucao_orcamentaria` | Execução orçamentária desde 2013 (dotação, empenhado/liquidado/pago) e receitas próprias desde 2012 (previsto vs. arrecadado) — agregadas por ano, ação, grupo de despesa, fonte ou origem de receita |
631
+
632
+ **Total: 66 ferramentas**
633
+
634
+ ### Prompts (4)
635
+
636
+ Templates de workflow reutilizáveis em pt-BR (capacidade MCP `prompts`), definidos em `src/prompts.ts`:
637
+
638
+ | Prompt | Args | O que orienta |
639
+ | --- | --- | --- |
640
+ | `senado_gastos_senador` | `senador`, `ano` | Resolve o senador e agrega/detalha despesas CEAPS. |
641
+ | `senado_tramitacao_materia` | `sigla`, `numero`, `ano` | Obtém situação atual + histórico de tramitação da matéria. |
642
+ | `senado_votos_senador` | `senador`, `periodo?` | Lista os votos nominais do senador no período. |
643
+ | `senado_panorama_ecidadania` | — | Consolida consultas (consenso/polarização), ideias e eventos populares. |
644
+
645
+ ### Recursos (5)
646
+
647
+ Documentos/tabelas de contexto estáticos (capacidade MCP `resources`), definidos em `src/resources.ts`:
648
+
649
+ | URI | Tipo | Conteúdo |
650
+ | --- | --- | --- |
651
+ | `senado://guia` | markdown | Visão geral e qual ferramenta usar por objetivo. |
652
+ | `senado://catalogo` | markdown | As 66 ferramentas agrupadas por domínio. |
653
+ | `senado://glossario` | markdown | Siglas e termos do Senado (PEC, CEAPS, CCJ, RCN…). |
654
+ | `senado://tabelas/tipos-materia` | json | Tipos de proposição (sigla/nome/descrição). |
655
+ | `senado://tabelas/ufs` | json | As 27 unidades federativas. |
656
+
657
+ ## Estrutura do projeto
658
+
659
+ ```
660
+ src/
661
+ ├── index.ts # Entrypoint do Worker (handler de fetch + handler scheduled/Cron)
662
+ ├── server.ts # Fábrica do McpServer (cria instância por requisição)
663
+ ├── auth.ts # Auth Bearer token opcional (comparação em tempo constante)
664
+ ├── metrics.ts # Contadores em memória servidos em /metrics
665
+ ├── types.ts # Env, categorias de cache, constantes de salvaguarda
666
+ ├── cache/
667
+ │ ├── l0-memory.ts # Cache Map em memória com TTL + evicção LRU
668
+ │ ├── l1-cache-api.ts # Wrapper da Cloudflare Cache API (chaves GET sintéticas)
669
+ │ └── manager.ts # Orquestrador de cache (L0 → L1 → upstream)
670
+ ├── throttle/
671
+ │ ├── token-bucket.ts # Rate limiter token bucket (global + por cliente)
672
+ │ └── upstream.ts # Fetch upstream com limite de concorrência, retry, timeout
673
+ ├── scraper/
674
+ │ ├── ecidadania.ts # Scraper isolado do e-Cidadania (listas REST + detalhe HTML por regex; buildConsultaResumo)
675
+ │ ├── pipeline.ts # Cron de 2h: splice de métrica direcionado (consultas/eventos/ideias); corpora são dos jobs semanais
676
+ │ ├── anomaly.ts # Classificação de execução (execução anômala nunca sobrescreve current)
677
+ │ └── store.ts # Leituras D1 (resolveList + staleness por entidade, lastGoodRunAt) + write-through de detalhe
678
+ ├── instrument.ts # Telemetria de chamadas por ferramenta (memória + Analytics Engine)
679
+ ├── utils/
680
+ │ ├── logger.ts # Logging estruturado em JSON
681
+ │ └── validation.ts # helpers toolResult, toolError, errorFrom, buildParams, ensureArray
682
+ └── tools/
683
+ ├── referencia.ts # Grupo H — 1 ferramenta de referência/metadados
684
+ ├── senadores.ts # Grupo A — 5 ferramentas de senadores
685
+ ├── materias.ts # Grupo B — 2 ferramentas de matérias (backend v3)
686
+ ├── processos.ts # Grupo C — 5 ferramentas de processos
687
+ ├── votacoes.ts # Grupo D — 3 ferramentas de votações
688
+ ├── comissoes.ts # Grupo E — 7 ferramentas de comissões
689
+ ├── plenario.ts # Grupo F — 7 ferramentas de plenário
690
+ ├── ecidadania.ts # Grupo G — 9 ferramentas do e-Cidadania (leem do D1; veja scraper/)
691
+ ├── discursos.ts # Grupo I — 3 ferramentas de discursos
692
+ ├── composicao.ts # Grupo J — 4 ferramentas de blocos/lideranças
693
+ ├── orcamento.ts # Grupo K — 1 ferramenta de orçamento
694
+ ├── legislacao.ts # Grupo L — 2 ferramentas de legislação federal
695
+ ├── votacao-comissao.ts # Grupo M — 1 ferramenta de votação em comissão
696
+ ├── taquigrafia.ts # Grupo N — 2 ferramentas de notas taquigráficas
697
+ ├── senadores-admin.ts # Grupo O — 2 ferramentas administrativas de senadores (CEAPS, moradia)
698
+ ├── servidores.ts # Grupo P — 4 ferramentas de pessoal
699
+ ├── contratacoes.ts # Grupo Q — 6 ferramentas de contratações
700
+ ├── supridos.ts # Grupo R — 1 ferramenta de suprimento de fundos
701
+ └── orcamento-senado.ts # Grupo S — 1 ferramenta de execução orçamentária
702
+ scripts/
703
+ └── ingest-ecidadania/ # Ingestão semanal do corpus completo de consultas, fora do Worker (via `npm run ingest:ecidadania`)
704
+ ├── index.ts # Orquestrador: crawl → status (/processo) → normaliza → guards → out.sql
705
+ ├── listing.ts # Parser puro da listagem (parseConsultaListingPage, findLastPage)
706
+ ├── status.ts # conjunto tramitando=S de /processo → aberta/encerrada (deriveStatus)
707
+ ├── restatus.ts # Correção de linger: re-status das linhas armazenadas por presença em /processo (fecha zumbis)
708
+ ├── http.ts # Fetch educado (retry/backoff) para o crawl não supervisionado
709
+ ├── d1.ts # Pré-leituras do D1 (meta existente, payloads, últimas boas linhas) via wrangler
710
+ └── sql.ts # Geração do out.sql (espelha SQL.upsert/SQL.history; reusa SyncRecord)
711
+ .github/workflows/ # publish-mcp.yml (registry) + ingest-ecidadania.yml (carga semanal do corpus no D1)
712
+ migrations/ # Schema D1 (0001 tabelas, 0002 índices) para o pipeline do e-Cidadania
713
+ tests/ # Testes unitários Vitest espelhando src/ (parsers, cache, throttle, auth, scraper,
714
+ # pipeline/anomaly/store, listing/sql/highlights, além de testes de contrato do e-Cidadania)
715
+ ```
716
+
717
+ ## Variáveis de ambiente
718
+
719
+ | Variável | Obrigatória | Padrão | Descrição |
720
+ |----------|----------|---------|-------------|
721
+ | `SENADO_BASE_URL` | Não | `https://legis.senado.leg.br/dadosabertos` | URL base da API legislativa |
722
+ | `SENADO_ADM_BASE_URL` | Não | `https://adm.senado.gov.br/adm-dadosabertos` | URL base da API administrativa |
723
+ | `ALLOWED_ORIGIN` | Não | `*` | Origem permitida no CORS |
724
+ | `API_KEY` | Não (secret) | — | Quando definido, exige `Authorization: Bearer <key>` em todas as requisições exceto `/health`, `/metrics` e preflight CORS |
725
+ | `CACHE_KV` | Sim (binding) | — | Namespace KV para o cache L2 |
726
+ | `ECIDADANIA_DB` | Sim (binding) | — | Banco D1 para o pipeline do e-Cidadania (persistência de listas + histórico) |
727
+ | `ECIDADANIA_CORPUS_STALE_MAX_MIN` | Não | `14400` | Janela de desatualização (minutos, ~10d) para os corpora semanais completos (todas as entidades do e-Cidadania) — servido com flag, nunca colapsado para destaques |
728
+ | `ECIDADANIA_CORPUS_MIN_PCT` | Não | `80` | Piso catastrófico para os jobs de corpus fora do Worker: um crawl/parse completo abaixo desse % do último bom corpus é rejeitado |
729
+ | `CLOUDFLARE_API_TOKEN` | Não (secret) | — | Secret do GitHub Actions (escopo de edição D1) para o job semanal de ingestão do corpus; não usado pelo Worker |
730
+ | `CLOUDFLARE_ACCOUNT_ID` | Não (var do Actions) | — | Variável de repositório do GitHub Actions para o wrangler pular o auto-discovery de conta via `/memberships` (um token com escopo só de D1 não consegue lê-lo); obrigatória junto com `CLOUDFLARE_API_TOKEN` no job de ingestão |
731
+ | `SENADO_ANALYTICS` | Não (binding) | — | Dataset do Analytics Engine para telemetria de chamadas por ferramenta |
732
+
733
+ ## Conectando clientes MCP
734
+
735
+ Este é um servidor **remoto** (Streamable HTTP, sem instalação, acesso aberto) — aponte qualquer cliente MCP para
736
+ `https://senado.sidneybissoli.com/mcp`. Além das 66 ferramentas, ele expõe **prompts** (workflows prontos em pt-BR:
737
+ `senado_gastos_senador`, `senado_tramitacao_materia`, `senado_votos_senador`,
738
+ `senado_panorama_ecidadania`) e **recursos** (`senado://guia`, `senado://catalogo`,
739
+ `senado://glossario`, `senado://tabelas/tipos-materia`, `senado://tabelas/ufs`).
740
+
741
+ ### Um clique (LobeHub)
742
+
743
+ Instale pelo marketplace do LobeHub — abra a
744
+ [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**
745
+ (ele pré-preenche o endpoint remoto, sem config necessária).
746
+
747
+ ### Claude Desktop / Claude Code
748
+
749
+ Adicione à sua configuração MCP:
750
+
751
+ ```json
752
+ {
753
+ "mcpServers": {
754
+ "senado-br": {
755
+ "url": "https://senado.sidneybissoli.com/mcp"
756
+ }
757
+ }
758
+ }
759
+ ```
760
+
761
+ Para clientes baseados em comando (ou qualquer cliente sem suporte remoto nativo), use a ponte `mcp-remote`:
762
+
763
+ ```json
764
+ {
765
+ "mcpServers": {
766
+ "senado-br": {
767
+ "command": "npx",
768
+ "args": ["-y", "mcp-remote", "https://senado.sidneybissoli.com/mcp"]
769
+ }
770
+ }
771
+ }
772
+ ```
773
+
774
+ ### MCP Inspector
775
+
776
+ ```bash
777
+ npx @modelcontextprotocol/inspector https://senado.sidneybissoli.com/mcp
778
+ ```
779
+
780
+ ## Licença
781
+
782
+ MIT
783
+
784
+ ## Créditos
785
+
786
+ Ícone: *"Amanhecer no Congresso Nacional"* — fotografia do Congresso Nacional
787
+ brasileiro, usada sob licença Creative Commons. (Se você é o autor, abra uma
788
+ issue para adicionarmos a atribuição completa / o link da licença.)