senado-br-mcp 3.3.1 → 3.4.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 (44) hide show
  1. package/README.md +891 -822
  2. package/README.pt-BR.md +829 -801
  3. package/dist/app-surface.js +122 -0
  4. package/dist/dataset/dictionary.js +94 -0
  5. package/dist/dataset/harmonize.js +32 -0
  6. package/dist/dataset/provenance.js +56 -0
  7. package/dist/dataset/release.js +164 -0
  8. package/dist/dataset/schema.js +572 -0
  9. package/dist/legal.js +114 -0
  10. package/dist/observability/origin.js +36 -0
  11. package/dist/openai-app-widget.js +455 -0
  12. package/dist/openai-domain-verification.js +10 -0
  13. package/dist/scraper/ecidadania.js +207 -33
  14. package/dist/scraper/pipeline.js +24 -4
  15. package/dist/server.js +22 -9
  16. package/dist/status.js +7 -0
  17. package/dist/throttle/upstream.js +2 -1
  18. package/dist/tools/comissoes.js +82 -31
  19. package/dist/tools/composicao.js +76 -33
  20. package/dist/tools/contratacoes.js +69 -26
  21. package/dist/tools/discursos.js +48 -15
  22. package/dist/tools/ecidadania.js +71 -23
  23. package/dist/tools/legislacao.js +46 -36
  24. package/dist/tools/materias.js +65 -16
  25. package/dist/tools/orcamento-senado.js +130 -10
  26. package/dist/tools/orcamento.js +82 -36
  27. package/dist/tools/plenario.js +61 -34
  28. package/dist/tools/processos.js +107 -19
  29. package/dist/tools/referencia.js +3 -4
  30. package/dist/tools/senadores-admin.js +109 -20
  31. package/dist/tools/senadores.js +58 -12
  32. package/dist/tools/servidores.js +254 -18
  33. package/dist/tools/supridos.js +150 -1
  34. package/dist/tools/taquigrafia.js +32 -9
  35. package/dist/tools/votacao-comissao.js +52 -29
  36. package/dist/tools/votacoes.js +42 -7
  37. package/dist/utils/estatisticas.js +134 -0
  38. package/dist/utils/placar.js +34 -0
  39. package/dist/utils/provenance.js +67 -23
  40. package/dist/utils/untrusted.js +0 -0
  41. package/dist/utils/upstream-parse.js +103 -0
  42. package/dist/utils/validation.js +53 -0
  43. package/dist/version.js +2 -1
  44. package/package.json +29 -6
package/README.pt-BR.md CHANGED
@@ -1,801 +1,829 @@
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
- ## Agent Skill (opcional)
97
-
98
- Este repositório inclui uma [Agent Skill](https://platform.claude.com/docs/en/docs/agents-and-tools/agent-skills/overview)
99
- do Claude em [`.claude/skills/senado-br/`](.claude/skills/senado-br/SKILL.md) que ensina o Claude **quando**
100
- recorrer a este servidor e **como** usar bem as 66 ferramentas — um mapa de ferramentas por tema, playbooks de
101
- pergunta→ferramenta, o contrato de proveniência e os gotchas (datas, a ponte `codigoMateria`, a listagem
102
- só-abertas do e-Cidadania, paginação). Ela aponta para os recursos `senado://catalogo` / `senado://guia` do
103
- próprio servidor em vez de duplicá-los.
104
-
105
- O Claude Code a descobre automaticamente ao trabalhar neste repositório. Para usá-la em outro lugar, copie
106
- `.claude/skills/senado-br/` para o seu `~/.claude/skills/`, ou compacte a pasta e faça upload no claude.ai
107
- (Configurações → Recursos). A skill pressupõe o servidor MCP `senado-br` conectado (hospedado ou via npx).
108
-
109
- ## Arquitetura
110
-
111
- - **Runtime:** Cloudflare Workers (ESM)
112
- - **Transporte:** Streamable HTTP (spec MCP 2025-03-26) via `createMcpHandler` de `agents/mcp`
113
- - **Protocolo:** MCP sobre JSON-RPC — um único endpoint `/mcp` trata POST, GET, DELETE
114
- - **SDK:** `@modelcontextprotocol/sdk` 1.26.0+ (instâncias de McpServer por requisição)
115
- - **Validação:** schemas Zod para todas as entradas das ferramentas
116
- - **Cache:** 2 camadas (L0 memória + L1 Cache API) com chaveamento SHA-256
117
- - **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))
118
- - **Rate limiting:** Token bucket — global (8 req/s) + por cliente (2 req/s)
119
- - **Throttle de upstream:** Máx. 6 requisições simultâneas, timeout de 10s, retry com backoff exponencial
120
- - **Auth:** Bearer token opcional (defina o secret `API_KEY`; acesso aberto quando ausente). Comparação em tempo constante.
121
- - **Observabilidade:** Logging estruturado em JSON + contadores em memória expostos em `/metrics`
122
- - **Testes:** testes unitários Vitest para parsers, helpers, cache, throttle e auth
123
-
124
- ## Auto-hospedagem (opcional)
125
-
126
- > **Não é necessário para usar o servidor** — ele já está hospedado em `https://senado.sidneybissoli.com/mcp`
127
- > (acesso aberto). Siga esta seção apenas se quiser rodar a sua **própria** instância privada.
128
-
129
- ### Pré-requisitos
130
-
131
- - Node.js 18+
132
- - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) v4+
133
- - Conta Cloudflare
134
-
135
- ### Configuração
136
-
137
- #### 1. Instalar dependências
138
-
139
- ```bash
140
- npm install
141
- ```
142
-
143
- #### 2. Criar o namespace KV
144
-
145
- ```bash
146
- # Cria o namespace KV
147
- wrangler kv namespace create CACHE_KV
148
-
149
- # Anote o ID da saída, ex.:
150
- # { binding = "CACHE_KV", id = "abc123..." }
151
- ```
152
-
153
- #### 3. Configurar o wrangler.toml
154
-
155
- Substitua o ID placeholder do namespace KV:
156
-
157
- ```toml
158
- [[kv_namespaces]]
159
- binding = "CACHE_KV"
160
- id = "YOUR_KV_NAMESPACE_ID_HERE"
161
- ```
162
-
163
- Opcionalmente, defina `ALLOWED_ORIGIN` para restringir o CORS:
164
-
165
- ```toml
166
- [vars]
167
- ALLOWED_ORIGIN = "https://your-app.example.com"
168
- ```
169
-
170
- 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):
171
-
172
- ```toml
173
- [[d1_databases]]
174
- binding = "ECIDADANIA_DB"
175
- database_name = "senado-ecidadania"
176
- database_id = "YOUR_D1_DATABASE_ID_HERE"
177
-
178
- [triggers]
179
- crons = ["0 */2 * * *"]
180
- ```
181
-
182
- Crie o banco (cole o ID retornado acima) e aplique o schema:
183
-
184
- ```bash
185
- npx wrangler d1 create senado-ecidadania
186
- npx wrangler d1 migrations apply senado-ecidadania --remote
187
- ```
188
-
189
- 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.
190
-
191
- #### 4. (Opcional) Habilitar autenticação
192
-
193
- ```bash
194
- wrangler secret put API_KEY
195
- # Os clientes passam a enviar: Authorization: Bearer <key>
196
- # Quando API_KEY não está definido, o servidor é de acesso aberto.
197
- ```
198
-
199
- #### 5. Desenvolvimento local
200
-
201
- ```bash
202
- npm run dev
203
- # O servidor de dev roda localmente na porta 8787 (apenas local).
204
- # O endpoint MCP público é https://senado.sidneybissoli.com/mcp
205
- ```
206
-
207
- #### 6. Testes e typecheck
208
-
209
- ```bash
210
- npm test # roda todos os testes uma vez
211
- npm run test:watch # modo watch
212
- npm run typecheck # tsc --noEmit
213
- ```
214
-
215
- #### 7. Deploy
216
-
217
- ```bash
218
- npm run deploy
219
- # Servido em https://senado.sidneybissoli.com (domínio próprio) e
220
- # https://senado-br-mcp.sidneybissoli.workers.dev (fallback workers.dev)
221
- ```
222
-
223
- ## Endpoints
224
-
225
- | Caminho | Métodos | Descrição |
226
- |------|---------|-------------|
227
- | `/mcp` | POST, GET, DELETE, OPTIONS | Endpoint MCP Streamable HTTP (gerenciado por `createMcpHandler`) |
228
- | `/health` | GET | Health check — retorna `ok` (sempre público) |
229
- | `/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) |
230
-
231
- ## Exemplos de requisição MCP
232
-
233
- Todas as requisições vão para `POST /mcp` no formato JSON-RPC 2.0.
234
-
235
- ### Listar as ferramentas disponíveis
236
-
237
- ```json
238
- {
239
- "jsonrpc": "2.0",
240
- "id": 1,
241
- "method": "tools/list"
242
- }
243
- ```
244
-
245
- ### Chamar uma ferramenta — Listar senadores de SP
246
-
247
- ```json
248
- {
249
- "jsonrpc": "2.0",
250
- "id": 2,
251
- "method": "tools/call",
252
- "params": {
253
- "name": "senado_listar_senadores",
254
- "arguments": {
255
- "uf": "SP",
256
- "emExercicio": true
257
- }
258
- }
259
- }
260
- ```
261
-
262
- ### Chamar uma ferramenta — Buscar matérias por palavra-chave
263
-
264
- ```json
265
- {
266
- "jsonrpc": "2.0",
267
- "id": 3,
268
- "method": "tools/call",
269
- "params": {
270
- "name": "senado_buscar_materias",
271
- "arguments": {
272
- "palavraChave": "inteligência artificial",
273
- "tramitando": true
274
- }
275
- }
276
- }
277
- ```
278
-
279
- ### Chamar uma ferramenta — Votações recentes do plenário
280
-
281
- ```json
282
- {
283
- "jsonrpc": "2.0",
284
- "id": 4,
285
- "method": "tools/call",
286
- "params": {
287
- "name": "senado_search_votacoes",
288
- "arguments": {
289
- "dias": 7
290
- }
291
- }
292
- }
293
- ```
294
-
295
- ### Chamar uma ferramenta — Ideias de cidadãos mais populares
296
-
297
- ```json
298
- {
299
- "jsonrpc": "2.0",
300
- "id": 5,
301
- "method": "tools/call",
302
- "params": {
303
- "name": "senado_ecidadania_listar_ideias",
304
- "arguments": {
305
- "ordenarPor": "apoios",
306
- "ordem": "desc",
307
- "status": "aberta"
308
- }
309
- }
310
- }
311
- ```
312
-
313
- ## Endpoints da API de origem (upstream)
314
-
315
- O servidor consome duas classes de endpoints upstream da API do Senado:
316
-
317
- ### Endpoints legados (sufixo `.json`, respostas em PascalCase)
318
-
319
- 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.
320
-
321
- | Caminho upstream | Usado por |
322
- |---------------|---------|
323
- | `/senador/lista/atual` | `senado_listar_senadores` |
324
- | `/senador/lista/legislatura/{legislatura}` | `senado_listar_senadores` (param `legislatura`) |
325
- | `/senador/{codigo}` | `senado_obter_senador` |
326
- | `/senador/{codigo}/licencas`, `/comissoes`, `/cargos`, `/historicoAcademico`, `/filiacoes`, `/profissao` | `senado_senador_historico` (`tipo` enum) |
327
- | `/senador/afastados` | `senado_senadores_afastados` |
328
- | `/senador/{codigo}/apartes` | `senado_discursos_senador` (`tipo=apartes`) |
329
- | `/comissao/lista/colegiados` | `senado_listar_comissoes` (+ resolução sigla→código) |
330
- | `/comissao/{codigo}` | `senado_obter_comissao` (`secao=resumo`; código numérico, não sigla) |
331
- | `/composicao/comissao/{codigo}` | `senado_obter_comissao` (`secao=membros`) |
332
- | `/comissao/agenda/{data}` | `senado_agenda_comissoes` |
333
- | `/comissao/agenda/{dataInicio}/{dataFim}` | `senado_reunioes_comissao` |
334
- | `/comissao/reuniao/{codigoReuniao}` | `senado_reuniao_comissao` |
335
- | `/comissao/cpi/{sigla}/requerimentos` | `senado_requerimentos_cpi` (corpo vazio = sem requerimentos) |
336
- | `/materia/distribuicao/autoria`, `/distribuicao/relatoria/{sigla}` | `senado_distribuicao_materias` |
337
- | `/plenario/agenda/dia/{data}`, `/agenda/mes/{data}`, `/agenda/cn/...` | `senado_agenda_plenario` |
338
- | `/plenario/resultado/{data}`, `/resultado/cn/{data}`, `/resultado/mes/{data}` | `senado_resultado_plenario` |
339
- | `/plenario/resultado/veto/{codigo}` (+ `/materia/`, `/dispositivo/`) | `senado_resultado_veto` |
340
- | `/plenario/votacao/orientacaoBancada/{data}` (+ período) | `senado_orientacao_bancada` |
341
- | `/plenario/encontro/{codigo}` (+ `/pauta`, `/resultado`, `/resumo`) | `senado_encontro_plenario` |
342
- | `/plenario/tiposSessao`, `/lista/tiposComparecimento`, `/lista/legislaturas` | `senado_tabelas_plenario` |
343
- | `/materia/vetos/{ano}`, `/vetos/aposrcn`, `/vetos/antesrcn`, `/vetos/encerrados` | `senado_vetos` |
344
- | `/taquigrafia/notas/{sessao\|reuniao}/{id}` | `senado_notas_taquigraficas` |
345
- | `/taquigrafia/videos/{sessao\|reuniao}/{id}` | `senado_videos_taquigrafia` |
346
- | `/senador/{codigo}/discursos` | `senado_discursos_senador` |
347
- | `/plenario/lista/discursos/{dataInicio}/{dataFim}` | `senado_discursos_plenario` |
348
- | `/discurso/texto-integral/{codigo}` | `senado_discurso_texto` (texto puro, buscado diretamente) |
349
- | `/senador/lista/tiposUsoPalavra` | `senado_tabelas_referencia` (`tabela=tipos-uso-palavra`) |
350
- | `/composicao/lista/blocos` | `senado_listar_blocos` |
351
- | `/composicao/bloco/{codigo}` | `senado_obter_bloco` |
352
- | `/composicao/lideranca` | `senado_liderancas` |
353
- | `/composicao/mesaSF` | `senado_mesa` (`casa=senado`) |
354
- | `/composicao/mesaCN` | `senado_mesa` (`casa=congresso`) |
355
- | `/orcamento/lista` | `senado_orcamento_parlamentar` (`tipo=emendas`) |
356
- | `/orcamento/oficios` | `senado_orcamento_parlamentar` (`tipo=oficios`) |
357
- | `/legislacao/lista` | `senado_buscar_legislacao` |
358
- | `/legislacao/{codigo}` | `senado_obter_legislacao` |
359
- | `/legislacao/tiposNorma` | `senado_tabelas_referencia` (`tabela=tipos-norma`) |
360
- | `/votacaoComissao/comissao/{sigla}` | `senado_votacao_comissao` (`por=comissao`) |
361
- | `/votacaoComissao/parlamentar/{codigo}` | `senado_votacao_comissao` (`por=senador`) |
362
- | `/votacaoComissao/materia/{sigla}/{numero}/{ano}` | `senado_votacao_comissao` (`por=materia`) |
363
- | `/autor/lista/atual` | `senado_autores_atuais` |
364
-
365
- ### Endpoints v3 (arrays/objetos JSON planos, camelCase)
366
-
367
- 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.
368
-
369
- | Caminho upstream | Usado por |
370
- |---------------|---------|
371
- | `/votacao` | `senado_obter_votacao`, `senado_search_votacoes`, `senado_votos_materia`, `senado_votacoes_senador` |
372
- | `/processo` | `senado_search_processos`, `senado_buscar_materias` |
373
- | `/processo/{id}` | `senado_obter_processo`, `senado_obter_materia` (`secao=detalhe`/`tramitacao`) |
374
- | `/processo/documento` | `senado_obter_materia` (`secao=textos`) |
375
- | `/processo/emenda` | `senado_processo_detalhe` (`secao=emendas`) |
376
- | `/processo/relatoria` | `senado_processo_detalhe` (`secao=relatorias`), `senado_obter_materia` (relator) |
377
- | `/processo/prazo` | `senado_processo_detalhe` (`secao=prazos`) |
378
- | `/processo/{siglas,assuntos,classes,destinos,entes,tipos-*}` | `senado_tabelas_processo` (12 tabelas de referência) |
379
-
380
- ### API administrativa (adm.senado.gov.br/adm-dadosabertos, JSON plano em snake_case)
381
-
382
- 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`.
383
-
384
- | Caminho upstream | Usado por |
385
- |---------------|---------|
386
- | `/api/v1/senadores/despesas_ceaps/{ano}` | `senado_ceaps` (~10 MB/ano, cacheado + agregado no Worker) |
387
- | `/api/v1/senadores/{auxilio-moradia,escritorios,aposentados}` | `senado_senadores_admin` (`tipo` enum) |
388
- | `/api/v1/servidores/servidores/{ativos,efetivos,comissionados,inativos}` | `senado_servidores` |
389
- | `/api/v1/servidores/remuneracoes/{ano}/{mes}` | `senado_remuneracoes_servidores` (~5.5 MB/mês) |
390
- | `/api/v1/servidores/horas-extras/{ano}/{mes}` | `senado_horas_extras` |
391
- | `/api/v1/servidores/quantitativos/*`, `/previsao-aposentadoria`, `/api/v1/senadores/quantitativos/senadores` | `senado_pessoal_tabelas` (quantitativos) |
392
- | `/api/v1/servidores/{estagiarios,pensionistas,lotacoes,cargos}` | `senado_pessoal_tabelas` (listas nominais) |
393
- | `/api/v1/contratacoes/contratos` (+ `/{id}/aditivos`) | `senado_contratos`, `senado_contratacao_detalhe` |
394
- | `/api/v1/contratacoes/{tipo}/{id}/{itens,pagamentos,garantias}` | `senado_contratacao_detalhe` |
395
- | `/api/v1/contratacoes/licitacoes` | `senado_licitacoes` |
396
- | `/api/v1/contratacoes/terceirizados` | `senado_terceirizados` |
397
- | `/api/v1/contratacoes/empresas` | `senado_empresas_contratadas` (~13 MB, exige filtro) |
398
- | `/api/v1/contratacoes/{atas_registro_preco,notas_empenho,menores_aprendizes}` | `senado_contratacoes_lista` |
399
- | `/api/v1/supridos/{ano}` (+ atosConcessao, empenhos, movimentacoes, transacoes) | `senado_suprimento_fundos` |
400
- | `senado.gov.br/bi-arqs/Arquimedes/Financeiro/{Despesa,Receitas}SenadoDadosAbertos.json` | `senado_execucao_orcamentaria` (feeds JSON diários, strings decimais brasileiras normalizadas) |
401
-
402
- ### e-Cidadania (em D1, atualizado por Cron)
403
-
404
- 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:
405
-
406
- - uma **GitHub Action semanal fora do Worker** é dona do **corpus completo** de cada entidade (veja abaixo) — a fonte da verdade;
407
- - 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.
408
-
409
- Ambos os escritores constroem os payloads pelos builders canônicos `buildXResumo` + `contentHash` compartilhado, então suas linhas são byte-idênticas. Cada escrita:
410
-
411
- - faz **upsert** em `ecidadania_current` (uma linha por item — o que as ferramentas leem),
412
- - **anexa** em `ecidadania_history` apenas quando o `content_hash` de um item muda (pronto para série temporal),
413
- - registra cada execução em `ecidadania_scrape_runs`.
414
-
415
- 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.
416
-
417
- 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.
418
-
419
- 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.
420
-
421
- #### Ingestão do corpus completo (fora do Worker, semanal)
422
-
423
- 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:
424
-
425
- - **`consultas`** — consultas abertas (detalhado abaixo).
426
- - **`eventos`** — audiências/eventos da listagem HTML `principalaudiencia?p=N`; o status vem direto do bloco da listagem (sem ponte por `/processo`).
427
- - **`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.
428
- - **`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`).
429
-
430
- O job de `consultas` é a implementação de referência:
431
-
432
- `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:
433
-
434
- 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.
435
- 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.
436
- 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.
437
-
438
- 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:
439
-
440
- ```bash
441
- CLOUDFLARE_API_TOKEN=… npm run ingest:ecidadania # escreve scripts/ingest-ecidadania/out.sql
442
- npx wrangler d1 execute senado-ecidadania --remote --file=scripts/ingest-ecidadania/out.sql
443
- ```
444
-
445
- ## Cache
446
-
447
- ### Arquitetura de camadas
448
-
449
- | Camada | Armazenamento | Escopo | Faixa de TTL | Finalidade |
450
- |-------|---------|-------|-----------|---------|
451
- | **L0** | `Map` em memória | Por isolate | 30-300s | Ultrarrápido, elimina requisições redundantes dentro de um isolate do Worker |
452
- | **L1** | Cloudflare Cache API (`caches.default`) | Por colo (PoP) | 60-600s | Compartilhado entre requisições no mesmo edge |
453
- | **L2** | KV (opcional) | Global | Variável | Reservado para dados raros e de baixa escrita |
454
-
455
- ### Categorias de cache
456
-
457
- | Categoria | L0 TTL | L1 TTL | Usado para |
458
- |----------|--------|--------|----------|
459
- | **STATIC** | 300s | 600s | Tipos de legislação, referência estática |
460
- | **SEMI_STATIC** | 120s | 300s | Lista de partidos, lista de UFs, detalhes de comissão |
461
- | **DYNAMIC** | 30s | 60s | Agendas, votações recentes, listas de reuniões |
462
- | **ON_DEMAND** | 30s | 120s | Consultas específicas de matéria/senador/votação |
463
-
464
- ### Abordagem de cache de POST
465
-
466
- 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:
467
-
468
- 1. **Hash dos parâmetros** — Nome da ferramenta + parâmetros ordenados são hasheados com SHA-256
469
- 2. **Chave GET sintética** — Uma URL sintética `https://senado-br-mcp.internal/__cache/{tool}/{hash}` é construída
470
- 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
471
-
472
- Esse cache acontece no **nível da ferramenta** (dentro do callback de cada ferramenta), não no nível do transporte MCP.
473
-
474
- ## Proveniência
475
-
476
- **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).
477
-
478
- 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`.
479
-
480
- 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.
481
-
482
- ## Inventário de ferramentas
483
-
484
- ### Grupo H — Referência/Metadados (1 ferramenta)
485
-
486
- | Ferramenta | Descrição |
487
- |------|-------------|
488
- | `senado_tabelas_referencia` | Tabelas de referência via `tabela` enum: tipos-materia, partidos, ufs, legislatura-atual, tipos-norma, tipos-uso-palavra |
489
-
490
- ### Grupo A — Senadores (5 ferramentas)
491
-
492
- | Ferramenta | Descrição |
493
- |------|-------------|
494
- | `senado_listar_senadores` | Lista senadores em exercício/por legislatura, com filtros `nome` (busca parcial sem acento), `uf` e `partido` |
495
- | `senado_obter_senador` | Detalhe biográfico de um senador: bio, mandatos, partido, contato |
496
- | `senado_votacoes_senador` | Como um senador votou em cada matéria (via v3 `/votacao`) |
497
- | `senado_senador_historico` | Histórico funcional via `tipo` enum: licencas, comissoes, cargos, historico-academico, filiacoes, profissoes |
498
- | `senado_senadores_afastados` | Senadores atualmente afastados (fora de exercício) |
499
-
500
- ### Grupo B — Matérias (2 ferramentas, backend v3)
501
-
502
- | Ferramenta | Descrição |
503
- |------|-------------|
504
- | `senado_buscar_materias` | Busca matérias por tipo, número, ano, palavra-chave, autor ou tramitação (via v3 `/processo`) |
505
- | `senado_obter_materia` | Dados de uma matéria via `secao` enum: detalhe (situação/relator), tramitacao (histórico) ou textos (documentos) |
506
-
507
- ### Grupo C — Processos (5 ferramentas)
508
-
509
- | Ferramenta | Descrição |
510
- |------|-------------|
511
- | `senado_search_processos` | Busca processos legislativos (complementar à busca de matérias) |
512
- | `senado_obter_processo` | Detalhes completos de um processo legislativo específico |
513
- | `senado_processo_detalhe` | Aspecto de um processo via `secao` enum: emendas, relatorias ou prazos |
514
- | `senado_autores_atuais` | Parlamentares autores de processos em tramitação, ordenados por produção |
515
- | `senado_tabelas_processo` | 12 tabelas de referência (siglas, assuntos, classes, tipos-*) via `tabela` enum |
516
-
517
- ### Grupo D — Votações (3 ferramentas)
518
-
519
- | Ferramenta | Descrição |
520
- |------|-------------|
521
- | `senado_obter_votacao` | Detalhes de uma votação com votos nominais. Aceita `codigoVotacao` (codigoSessao da sessão plenária). |
522
- | `senado_votos_materia` | Votações de uma matéria (via v3 `/votacao?codigoMateria`), com votos nominais opcionais |
523
- | `senado_search_votacoes` | Busca/listagem flexível de votações do plenário por `dias`, período, processo, matéria ou senador |
524
-
525
- ### Grupo E — Comissões (7 ferramentas)
526
-
527
- | Ferramenta | Descrição |
528
- |------|-------------|
529
- | `senado_listar_comissoes` | Lista comissões (colegiados) ativas, filtráveis por tipo |
530
- | `senado_obter_comissao` | Dados de uma comissão via `secao` enum: resumo (mesa/totais) ou membros (composição). Resolve sigla para código internamente. |
531
- | `senado_reunioes_comissao` | Reuniões de uma comissão num período (lida com intervalos entre anos) |
532
- | `senado_agenda_comissoes` | Agenda de reuniões de todas as comissões numa data |
533
- | `senado_reuniao_comissao` | Detalhe completo de uma reunião: partes, itens, convidados, resultados, links pauta/ata |
534
- | `senado_requerimentos_cpi` | Requerimentos protocolados numa CPI em atividade, paginados |
535
- | `senado_distribuicao_materias` | Estatísticas de carga por senador numa comissão: autoria ou relatoria |
536
-
537
- ### Grupo F — Plenário (7 ferramentas)
538
-
539
- | Ferramenta | Descrição |
540
- |------|-------------|
541
- | `senado_agenda_plenario` | Agenda do plenário — por dia, mês ou Congresso (escopo dia/mes/cn) |
542
- | `senado_resultado_plenario` | Resultados de sessão: itens deliberados, pareceres, desfechos (SF/CN/mês) |
543
- | `senado_orientacao_bancada` | Orientações de voto das lideranças por votação, com placar |
544
- | `senado_vetos` | Vetos presidenciais por ano ou situação de tramitação |
545
- | `senado_resultado_veto` | Resultados nominais de votação de veto (por veto, matéria vetada ou dispositivo) |
546
- | `senado_encontro_plenario` | Detalhe de sessão legislativa, itens de pauta, resultados ou resumo |
547
- | `senado_tabelas_plenario` | Tipos de sessão, tipos de comparecimento, lista de legislaturas |
548
-
549
- ### Grupo G — e-Cidadania (9 ferramentas)
550
-
551
- | Ferramenta | Descrição |
552
- |------|-------------|
553
- | `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`) |
554
- | `senado_ecidadania_obter_consulta` | Detalhe de uma consulta: votos, autor, relator, comentários |
555
- | `senado_ecidadania_consultas_analise` | Analisa o conjunto completo de consultas **abertas** via `modo` (consenso/polarizada); `status` padrão `aberta` |
556
- | `senado_ecidadania_listar_ideias` | Ideias legislativas de cidadãos; ranking das mais apoiadas via `ordenarPor: apoios` |
557
- | `senado_ecidadania_obter_ideia` | Detalhe de uma ideia: texto, apoios, status de conversão em projeto |
558
- | `senado_ecidadania_listar_eventos` | Eventos interativos (audiências, sabatinas, lives); ranking dos mais comentados via `ordenarPor` |
559
- | `senado_ecidadania_obter_evento` | Detalhe de um evento: pauta, convidados, link de vídeo |
560
- | `senado_ecidadania_sugerir_tema_enquete` | Sugere temas para enquete mensal a partir de critérios configuráveis |
561
- | `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` |
562
-
563
- ### Grupo I — Discursos (3 ferramentas)
564
-
565
- | Ferramenta | Descrição |
566
- |------|-------------|
567
- | `senado_discursos_senador` | Pronunciamentos de um senador via `tipo` enum: discursos (próprios) ou apartes (intervenções) |
568
- | `senado_discursos_plenario` | Todos os discursos em plenário num intervalo de datas |
569
- | `senado_discurso_texto` | Texto integral de um pronunciamento/discurso específico |
570
-
571
- ### Grupo J — Blocos e Lideranças (4 ferramentas)
572
-
573
- | Ferramenta | Descrição |
574
- |------|-------------|
575
- | `senado_listar_blocos` | Blocos parlamentares do Senado e seus partidos membros |
576
- | `senado_obter_bloco` | Detalhes de um bloco parlamentar específico |
577
- | `senado_liderancas` | Lideranças do Senado/Congresso (líderes, vice-líderes), filtráveis |
578
- | `senado_mesa` | Membros da Mesa Diretora via `casa` enum: senado (Mesa do SF) ou congresso (Mesa do CN) |
579
-
580
- ### Grupo K — Orçamento (1 ferramenta)
581
-
582
- | Ferramenta | Descrição |
583
- |------|-------------|
584
- | `senado_orcamento_parlamentar` | Dados de emendas orçamentárias via `tipo` enum: emendas (lotes) ou oficios (ofícios de apoio) |
585
-
586
- ### Grupo L — Legislação Federal (2 ferramentas)
587
-
588
- | Ferramenta | Descrição |
589
- |------|-------------|
590
- | `senado_buscar_legislacao` | Busca normas jurídicas federais por tipo, número, ano ou data (ao menos um obrigatório) |
591
- | `senado_obter_legislacao` | Detalhes de uma norma jurídica federal específica |
592
-
593
- ### Grupo M — Votação em Comissão (1 ferramenta)
594
-
595
- | Ferramenta | Descrição |
596
- |------|-------------|
597
- | `senado_votacao_comissao` | Votações em comissões via `por` enum: comissao, senador ou materia; período opcional |
598
-
599
- ### Grupo N — Taquigrafia (2 ferramentas)
600
-
601
- | Ferramenta | Descrição |
602
- |------|-------------|
603
- | `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 |
604
- | `senado_videos_taquigrafia` | Unidades de vídeo/áudio por sessão ou reunião, com orador e links de mídia |
605
-
606
- ### Grupo O — Senadores/Administrativo (2 ferramentas)
607
-
608
- | Ferramenta | Descrição |
609
- |------|-------------|
610
- | `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 |
611
- | `senado_senadores_admin` | Dados administrativos dos senadores via `tipo` enum: auxilio-moradia, escritorios-apoio ou aposentados |
612
-
613
- ### Grupo P — Servidores / Gestão de Pessoas (4 ferramentas)
614
-
615
- | Ferramenta | Descrição |
616
- |------|-------------|
617
- | `senado_servidores` | Servidores por situação (ativos/efetivos/comissionados/inativos), filtráveis por nome, unidade, cargo |
618
- | `senado_remuneracoes_servidores` | Folha mensal — resumo por tipo de folha ou composição por pessoa com bruto calculado |
619
- | `senado_horas_extras` | Pagamentos de horas extras por mês, com totais |
620
- | `senado_pessoal_tabelas` | Tabelas de pessoal via `tabela` enum: quantitativos (pessoal, cargos-funcoes, previsao-aposentadoria, senadores) e listas (estagiarios, pensionistas, lotacoes, cargos) |
621
-
622
- ### Grupo Q — Contratações (6 ferramentas)
623
-
624
- | Ferramenta | Descrição |
625
- |------|-------------|
626
- | `senado_contratos` | Contratos com filtros no servidor: fornecedor, CNPJ, ano, número, objeto, mão de obra |
627
- | `senado_contratacao_detalhe` | Itens, pagamentos, garantias, aditivos ou ativações de um contrato/ata/empenho |
628
- | `senado_licitacoes` | Licitações por número ou texto do objeto |
629
- | `senado_terceirizados` | Colaboradores terceirizados por nome, empresa ou unidade |
630
- | `senado_empresas_contratadas` | Empresas que contratam com o Senado (exige filtro por nome/CNPJ) |
631
- | `senado_contratacoes_lista` | Atas de registro de preço, notas de empenho, menores aprendizes |
632
-
633
- ### Grupo R — Suprimento de Fundos (1 ferramenta)
634
-
635
- | Ferramenta | Descrição |
636
- |------|-------------|
637
- | `senado_suprimento_fundos` | Adiantamentos de suprimento de fundos por ano: beneficiários, atos de concessão, empenhos, movimentações, transações de cartão |
638
-
639
- ### Grupo S — Orçamento do Senado (1 ferramenta)
640
-
641
- | Ferramenta | Descrição |
642
- |------|-------------|
643
- | `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 |
644
-
645
- **Total: 66 ferramentas**
646
-
647
- ### Prompts (4)
648
-
649
- Templates de workflow reutilizáveis em pt-BR (capacidade MCP `prompts`), definidos em `src/prompts.ts`:
650
-
651
- | Prompt | Args | O que orienta |
652
- | --- | --- | --- |
653
- | `senado_gastos_senador` | `senador`, `ano` | Resolve o senador e agrega/detalha despesas CEAPS. |
654
- | `senado_tramitacao_materia` | `sigla`, `numero`, `ano` | Obtém situação atual + histórico de tramitação da matéria. |
655
- | `senado_votos_senador` | `senador`, `periodo?` | Lista os votos nominais do senador no período. |
656
- | `senado_panorama_ecidadania` | — | Consolida consultas (consenso/polarização), ideias e eventos populares. |
657
-
658
- ### Recursos (5)
659
-
660
- Documentos/tabelas de contexto estáticos (capacidade MCP `resources`), definidos em `src/resources.ts`:
661
-
662
- | URI | Tipo | Conteúdo |
663
- | --- | --- | --- |
664
- | `senado://guia` | markdown | Visão geral e qual ferramenta usar por objetivo. |
665
- | `senado://catalogo` | markdown | As 66 ferramentas agrupadas por domínio. |
666
- | `senado://glossario` | markdown | Siglas e termos do Senado (PEC, CEAPS, CCJ, RCN…). |
667
- | `senado://tabelas/tipos-materia` | json | Tipos de proposição (sigla/nome/descrição). |
668
- | `senado://tabelas/ufs` | json | As 27 unidades federativas. |
669
-
670
- ## Estrutura do projeto
671
-
672
- ```
673
- src/
674
- ├── index.ts # Entrypoint do Worker (handler de fetch + handler scheduled/Cron)
675
- ├── server.ts # Fábrica do McpServer (cria instância por requisição)
676
- ├── auth.ts # Auth Bearer token opcional (comparação em tempo constante)
677
- ├── metrics.ts # Contadores em memória servidos em /metrics
678
- ├── types.ts # Env, categorias de cache, constantes de salvaguarda
679
- ├── cache/
680
- │ ├── l0-memory.ts # Cache Map em memória com TTL + evicção LRU
681
- │ ├── l1-cache-api.ts # Wrapper da Cloudflare Cache API (chaves GET sintéticas)
682
- │ └── manager.ts # Orquestrador de cache (L0 → L1 → upstream)
683
- ├── throttle/
684
- │ ├── token-bucket.ts # Rate limiter token bucket (global + por cliente)
685
- │ └── upstream.ts # Fetch upstream com limite de concorrência, retry, timeout
686
- ├── scraper/
687
- │ ├── ecidadania.ts # Scraper isolado do e-Cidadania (listas REST + detalhe HTML por regex; buildConsultaResumo)
688
- │ ├── pipeline.ts # Cron de 2h: splice de métrica direcionado (consultas/eventos/ideias); corpora são dos jobs semanais
689
- │ ├── anomaly.ts # Classificação de execução (execução anômala nunca sobrescreve current)
690
- │ └── store.ts # Leituras D1 (resolveList + staleness por entidade, lastGoodRunAt) + write-through de detalhe
691
- ├── instrument.ts # Telemetria de chamadas por ferramenta (memória + Analytics Engine)
692
- ├── utils/
693
- │ ├── logger.ts # Logging estruturado em JSON
694
- │ └── validation.ts # helpers toolResult, toolError, errorFrom, buildParams, ensureArray
695
- └── tools/
696
- ├── referencia.ts # Grupo H — 1 ferramenta de referência/metadados
697
- ├── senadores.ts # Grupo A — 5 ferramentas de senadores
698
- ├── materias.ts # Grupo B — 2 ferramentas de matérias (backend v3)
699
- ├── processos.ts # Grupo C — 5 ferramentas de processos
700
- ├── votacoes.ts # Grupo D — 3 ferramentas de votações
701
- ├── comissoes.ts # Grupo E — 7 ferramentas de comissões
702
- ├── plenario.ts # Grupo F — 7 ferramentas de plenário
703
- ├── ecidadania.ts # Grupo G — 9 ferramentas do e-Cidadania (leem do D1; veja scraper/)
704
- ├── discursos.ts # Grupo I — 3 ferramentas de discursos
705
- ├── composicao.ts # Grupo J — 4 ferramentas de blocos/lideranças
706
- ├── orcamento.ts # Grupo K — 1 ferramenta de orçamento
707
- ├── legislacao.ts # Grupo L — 2 ferramentas de legislação federal
708
- ├── votacao-comissao.ts # Grupo M — 1 ferramenta de votação em comissão
709
- ├── taquigrafia.ts # Grupo N — 2 ferramentas de notas taquigráficas
710
- ├── senadores-admin.ts # Grupo O — 2 ferramentas administrativas de senadores (CEAPS, moradia)
711
- ├── servidores.ts # Grupo P — 4 ferramentas de pessoal
712
- ├── contratacoes.ts # Grupo Q — 6 ferramentas de contratações
713
- ├── supridos.ts # Grupo R — 1 ferramenta de suprimento de fundos
714
- └── orcamento-senado.ts # Grupo S — 1 ferramenta de execução orçamentária
715
- scripts/
716
- └── ingest-ecidadania/ # Ingestão semanal do corpus completo de consultas, fora do Worker (via `npm run ingest:ecidadania`)
717
- ├── index.ts # Orquestrador: crawl → status (/processo) → normaliza → guards → out.sql
718
- ├── listing.ts # Parser puro da listagem (parseConsultaListingPage, findLastPage)
719
- ├── status.ts # conjunto tramitando=S de /processo → aberta/encerrada (deriveStatus)
720
- ├── restatus.ts # Correção de linger: re-status das linhas armazenadas por presença em /processo (fecha zumbis)
721
- ├── http.ts # Fetch educado (retry/backoff) para o crawl não supervisionado
722
- ├── d1.ts # Pré-leituras do D1 (meta existente, payloads, últimas boas linhas) via wrangler
723
- └── sql.ts # Geração do out.sql (espelha SQL.upsert/SQL.history; reusa SyncRecord)
724
- .github/workflows/ # publish-mcp.yml (registry) + ingest-ecidadania.yml (carga semanal do corpus no D1)
725
- migrations/ # Schema D1 (0001 tabelas, 0002 índices) para o pipeline do e-Cidadania
726
- tests/ # Testes unitários Vitest espelhando src/ (parsers, cache, throttle, auth, scraper,
727
- # pipeline/anomaly/store, listing/sql/highlights, além de testes de contrato do e-Cidadania)
728
- ```
729
-
730
- ## Variáveis de ambiente
731
-
732
- | Variável | Obrigatória | Padrão | Descrição |
733
- |----------|----------|---------|-------------|
734
- | `SENADO_BASE_URL` | Não | `https://legis.senado.leg.br/dadosabertos` | URL base da API legislativa |
735
- | `SENADO_ADM_BASE_URL` | Não | `https://adm.senado.gov.br/adm-dadosabertos` | URL base da API administrativa |
736
- | `ALLOWED_ORIGIN` | Não | `*` | Origem permitida no CORS |
737
- | `API_KEY` | Não (secret) | — | Quando definido, exige `Authorization: Bearer <key>` em todas as requisições exceto `/health`, `/metrics` e preflight CORS |
738
- | `CACHE_KV` | Sim (binding) | — | Namespace KV para o cache L2 |
739
- | `ECIDADANIA_DB` | Sim (binding) | — | Banco D1 para o pipeline do e-Cidadania (persistência de listas + histórico) |
740
- | `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 |
741
- | `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 |
742
- | `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 |
743
- | `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 |
744
- | `SENADO_ANALYTICS` | Não (binding) | — | Dataset do Analytics Engine para telemetria de chamadas por ferramenta |
745
-
746
- ## Conectando clientes MCP
747
-
748
- Este é um servidor **remoto** (Streamable HTTP, sem instalação, acesso aberto) — aponte qualquer cliente MCP para
749
- `https://senado.sidneybissoli.com/mcp`. Além das 66 ferramentas, ele expõe **prompts** (workflows prontos em pt-BR:
750
- `senado_gastos_senador`, `senado_tramitacao_materia`, `senado_votos_senador`,
751
- `senado_panorama_ecidadania`) e **recursos** (`senado://guia`, `senado://catalogo`,
752
- `senado://glossario`, `senado://tabelas/tipos-materia`, `senado://tabelas/ufs`).
753
-
754
- ### Um clique (LobeHub)
755
-
756
- Instale pelo marketplace do LobeHub — abra a
757
- [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**
758
- (ele pré-preenche o endpoint remoto, sem config necessária).
759
-
760
- ### Claude Desktop / Claude Code
761
-
762
- Adicione à sua configuração MCP:
763
-
764
- ```json
765
- {
766
- "mcpServers": {
767
- "senado-br": {
768
- "url": "https://senado.sidneybissoli.com/mcp"
769
- }
770
- }
771
- }
772
- ```
773
-
774
- Para clientes baseados em comando (ou qualquer cliente sem suporte remoto nativo), use a ponte `mcp-remote`:
775
-
776
- ```json
777
- {
778
- "mcpServers": {
779
- "senado-br": {
780
- "command": "npx",
781
- "args": ["-y", "mcp-remote", "https://senado.sidneybissoli.com/mcp"]
782
- }
783
- }
784
- }
785
- ```
786
-
787
- ### MCP Inspector
788
-
789
- ```bash
790
- npx @modelcontextprotocol/inspector https://senado.sidneybissoli.com/mcp
791
- ```
792
-
793
- ## Licença
794
-
795
- MIT
796
-
797
- ## Créditos
798
-
799
- Ícone: *"Amanhecer no Congresso Nacional"* — fotografia do Congresso Nacional
800
- brasileiro, usada sob licença Creative Commons. (Se você é o autor, abra uma
801
- issue para adicionarmos a atribuição completa / o link da licença.)
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
+ [![CI](https://github.com/SidneyBissoli/senado-br-mcp-cloudflare/actions/workflows/ci.yml/badge.svg)](https://github.com/SidneyBissoli/senado-br-mcp-cloudflare/actions/workflows/ci.yml)
7
+ [![MCP Registry](https://img.shields.io/badge/MCP-Registry-blue)](https://registry.modelcontextprotocol.io)
8
+ [![LobeHub](https://lobehub.com/badge/mcp/sidneybissoli-senado-br-mcp-cloudflare)](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare)
9
+ [![smithery badge](https://smithery.ai/badge/sidneybissoli/senado-br-mcp-cloudflare)](https://smithery.ai/servers/sidneybissoli/senado-br-mcp-cloudflare)
10
+ [![senado-br-mcp-cloudflare MCP server](https://glama.ai/mcp/servers/SidneyBissoli/senado-br-mcp-cloudflare/badges/score.svg)](https://glama.ai/mcp/servers/SidneyBissoli/senado-br-mcp-cloudflare)
11
+ [![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)
12
+ [![GitHub Sponsors](https://img.shields.io/github/sponsors/SidneyBissoli?logo=githubsponsors&label=Sponsor&color=db61a2)](https://github.com/sponsors/SidneyBissoli)
13
+ [![License: MIT](https://img.shields.io/github/license/SidneyBissoli/senado-br-mcp-cloudflare)](LICENSE)
14
+
15
+ 🇺🇸 [Read in English](README.md)
16
+
17
+ 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.
18
+
19
+ Expõe **66 ferramentas**, **4 prompts** e **5 recursos** em dois domínios:
20
+
21
+ - **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.
22
+ - **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.
23
+
24
+ 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.
25
+
26
+ ## Veja na prática
27
+
28
+ Aponte um cliente para o endpoint e pergunte, em português:
29
+
30
+ - *"Como os senadores de São Paulo votaram nas últimas votações do plenário?"* → `senado_search_votacoes`
31
+ - *"Mostre a tramitação da PEC 45/2019."* → `senado_buscar_materias` + `senado_obter_materia`
32
+ - *"Quanto foi gasto com a cota parlamentar (CEAPS) em 2024, por tipo de despesa?"* → `senado_ceaps`
33
+
34
+ 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.
35
+
36
+ ## Como usar (hospedado — sem configuração)
37
+
38
+ Este é um servidor **remoto, hospedado e de acesso aberto**. Para usá-lo, aponte qualquer cliente MCP para o endpoint
39
+ Streamable HTTP — **sem instalação, sem conta, sem chave de API, sem configuração**:
40
+
41
+ ```
42
+ https://senado.sidneybissoli.com/mcp
43
+ ```
44
+
45
+ ### Superficie para app OpenAI / ChatGPT
46
+
47
+ Para submissao e revisao pelo OpenAI Apps SDK, o Worker tambem expoe uma superficie MCP curada:
48
+
49
+ ```
50
+ https://senado.sidneybissoli.com/mcp/openai-app-v2
51
+ ```
52
+
53
+ Esse endpoint preserva o servidor MCP publico completo em `/mcp`, mas limita a descoberta a 25
54
+ ferramentas de alto sinal, organizadas por intencao de usuario, para uso como app do ChatGPT.
55
+ `/mcp/openai-app` continua disponivel como alias legado, mas novas configuracoes do app no ChatGPT
56
+ devem usar `/mcp/openai-app-v2` para forcar a leitura do schema atual das ferramentas. As ferramentas
57
+ continuam chamando os mesmos handlers e retornando o mesmo envelope de proveniencia; apenas a superficie
58
+ anunciada fica mais estreita. Qualquer listagem de ChatGPT App deve apresentar isto como um app
59
+ independente de pesquisa em dados abertos, nao como conector oficial do Senado, da OpenAI ou do ChatGPT.
60
+
61
+ Para ChatGPT Apps, essas 25 ferramentas tambem anunciam um template UI compartilhado do MCP Apps em
62
+ `ui://senado-br-mcp/openai-app-dashboard-v2.html`. O widget e autocontido e renderiza o
63
+ `structuredContent` retornado como painel compacto com metricas, registros principais e fonte/proveniencia,
64
+ sem adicionar outra ferramenta de dados visivel ao modelo.
65
+
66
+ URLs publicas legais para revisao do app:
67
+
68
+ - Politica de privacidade: `https://senado.sidneybissoli.com/privacy`
69
+ - Termos de uso: `https://senado.sidneybissoli.com/terms`
70
+
71
+ ### Instalação (qualquer cliente)
72
+
73
+ Para clientes que iniciam servidores MCP como um comando — e para uma configuração de um único comando — use a
74
+ ponte [`mcp-remote`](https://www.npmjs.com/package/mcp-remote). **Sem build, sem config, sem chave:**
75
+
76
+ ```bash
77
+ npx -y mcp-remote https://senado.sidneybissoli.com/mcp
78
+ ```
79
+
80
+ - **Um clique (LobeHub):** abra a [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**.
81
+ - **URL remota nativa** (Claude Desktop/Code e outros clientes Streamable HTTP): veja [Conectando clientes MCP](#conectando-clientes-mcp).
82
+
83
+ Tudo abaixo de *Arquitetura* (Pré-requisitos, Configuração, Deploy) é **apenas para opcionalmente auto-hospedar a sua
84
+ própria instância** — **não** é necessário para usar este servidor público.
85
+
86
+ ## Rodar localmente (npx · stdio)
87
+
88
+ Prefere não rotear suas consultas por um servidor de terceiros (ex.: política de uma redação)? O **mesmo
89
+ servidor** também roda como um **processo local stdio** que bate **direto nas APIs oficiais do governo** —
90
+ as mesmas 66 ferramentas, o mesmo envelope de proveniência, sem Cloudflare no caminho. É o canal npm/stdio,
91
+ publicado como [`senado-br-mcp`](https://www.npmjs.com/package/senado-br-mcp).
92
+
93
+ Aponte um cliente baseado em comando (Claude Desktop/Code, etc.) para o pacote — o npm baixa e executa,
94
+ sem clone nem build:
95
+
96
+ ```json
97
+ {
98
+ "mcpServers": {
99
+ "senado-br": {
100
+ "command": "npx",
101
+ "args": ["-y", "senado-br-mcp"]
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ Para rodar direto ou mexer no código, use o checkout do fonte:
108
+
109
+ ```bash
110
+ git clone https://github.com/SidneyBissoli/senado-br-mcp-cloudflare
111
+ cd senado-br-mcp-cloudflare
112
+ npm install
113
+ npm run build
114
+ node dist/cli.js # serve o MCP por stdio (Ctrl+C para parar)
115
+ ```
116
+
117
+ **Paridade com o servidor hospedado:** as ferramentas legislativas e administrativas são **idênticas**
118
+ (mesmas APIs de origem, mesmo throttle/cache/proveniência) — localmente o cache L1 do Cloudflare vira
119
+ no-op, mas o L0 em memória continua funcionando, então o resultado é o mesmo. A **única** diferença são
120
+ as ferramentas de lista/corpus do e-Cidadania: sem D1, elas caem no scraping ao vivo dos ~5 destaques
121
+ REST, sinalizado por `meta.fonte` / `possivelDesatualizacao`; as de detalhe (`obter_*`) são idênticas.
122
+ Os logs vão para o **stderr** — o stdout carrega apenas o fluxo do protocolo JSON-RPC.
123
+
124
+ ## Agent Skill (opcional)
125
+
126
+ Este repositório inclui uma [Agent Skill](https://platform.claude.com/docs/en/docs/agents-and-tools/agent-skills/overview)
127
+ do Claude em [`.claude/skills/senado-br/`](.claude/skills/senado-br/SKILL.md) que ensina o Claude **quando**
128
+ recorrer a este servidor e **como** usar bem as 66 ferramentas — um mapa de ferramentas por tema, playbooks de
129
+ pergunta→ferramenta, o contrato de proveniência e os gotchas (datas, a ponte `codigoMateria`, a listagem
130
+ só-abertas do e-Cidadania, paginação). Ela aponta para os recursos `senado://catalogo` / `senado://guia` do
131
+ próprio servidor em vez de duplicá-los.
132
+
133
+ O Claude Code a descobre automaticamente ao trabalhar neste repositório. Para usá-la em outro lugar, copie
134
+ `.claude/skills/senado-br/` para o seu `~/.claude/skills/`, ou compacte a pasta e faça upload no claude.ai
135
+ (Configurações → Recursos). A skill pressupõe o servidor MCP `senado-br` conectado (hospedado ou via npx).
136
+
137
+ ## Arquitetura
138
+
139
+ - **Runtime:** Cloudflare Workers (ESM)
140
+ - **Transporte:** Streamable HTTP (spec MCP 2025-03-26) via `createMcpHandler` de `agents/mcp`
141
+ - **Protocolo:** MCP sobre JSON-RPC — `/mcp` serve o catalogo publico completo; `/mcp/openai-app-v2` expoe um perfil curado de 25 ferramentas mais um widget MCP Apps compartilhado para revisao/submissao como app OpenAI (`/mcp/openai-app` permanece como alias legado)
142
+ - **SDK:** `@modelcontextprotocol/sdk` 1.26.0+ (instâncias de McpServer por requisição)
143
+ - **Validação:** schemas Zod para todas as entradas das ferramentas
144
+ - **Cache:** 2 camadas (L0 memória + L1 Cache API) com chaveamento SHA-256
145
+ - **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))
146
+ - **Rate limiting:** Token bucket — global (8 req/s) + por cliente (2 req/s)
147
+ - **Throttle de upstream:** Máx. 6 requisições simultâneas, timeout de 10s, retry com backoff exponencial
148
+ - **Auth:** Bearer token opcional (defina o secret `API_KEY`; acesso aberto quando ausente). Comparação em tempo constante.
149
+ - **Observabilidade:** Logging estruturado em JSON + contadores em memória expostos em `/metrics`
150
+ - **Testes:** testes unitários Vitest para parsers, helpers, cache, throttle e auth
151
+
152
+ ## Auto-hospedagem (opcional)
153
+
154
+ > **Não é necessário para usar o servidor** — ele já está hospedado em `https://senado.sidneybissoli.com/mcp`
155
+ > (acesso aberto). Siga esta seção apenas se quiser rodar a sua **própria** instância privada.
156
+
157
+ ### Pré-requisitos
158
+
159
+ - Node.js 20+
160
+ - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) v4+
161
+ - Conta Cloudflare
162
+
163
+ ### Configuração
164
+
165
+ #### 1. Instalar dependências
166
+
167
+ ```bash
168
+ npm install
169
+ ```
170
+
171
+ #### 2. Criar o namespace KV
172
+
173
+ ```bash
174
+ # Cria o namespace KV
175
+ wrangler kv namespace create CACHE_KV
176
+
177
+ # Anote o ID da saída, ex.:
178
+ # { binding = "CACHE_KV", id = "abc123..." }
179
+ ```
180
+
181
+ #### 3. Configurar o wrangler.toml
182
+
183
+ Substitua o ID placeholder do namespace KV:
184
+
185
+ ```toml
186
+ [[kv_namespaces]]
187
+ binding = "CACHE_KV"
188
+ id = "YOUR_KV_NAMESPACE_ID_HERE"
189
+ ```
190
+
191
+ Opcionalmente, defina `ALLOWED_ORIGIN` para restringir o CORS:
192
+
193
+ ```toml
194
+ [vars]
195
+ ALLOWED_ORIGIN = "https://your-app.example.com"
196
+ ```
197
+
198
+ 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):
199
+
200
+ ```toml
201
+ [[d1_databases]]
202
+ binding = "ECIDADANIA_DB"
203
+ database_name = "senado-ecidadania"
204
+ database_id = "YOUR_D1_DATABASE_ID_HERE"
205
+
206
+ [triggers]
207
+ crons = ["0 */2 * * *"]
208
+ ```
209
+
210
+ Crie o banco (cole o ID retornado acima) e aplique o schema:
211
+
212
+ ```bash
213
+ npx wrangler d1 create senado-ecidadania
214
+ npx wrangler d1 migrations apply senado-ecidadania --remote
215
+ ```
216
+
217
+ 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.
218
+
219
+ #### 4. (Opcional) Habilitar autenticação
220
+
221
+ ```bash
222
+ wrangler secret put API_KEY
223
+ # Os clientes passam a enviar: Authorization: Bearer <key>
224
+ # Quando API_KEY não está definido, o servidor é de acesso aberto.
225
+ ```
226
+
227
+ #### 5. Desenvolvimento local
228
+
229
+ ```bash
230
+ npm run dev
231
+ # O servidor de dev roda localmente na porta 8787 (apenas local).
232
+ # O endpoint MCP público é https://senado.sidneybissoli.com/mcp
233
+ ```
234
+
235
+ #### 6. Testes e typecheck
236
+
237
+ ```bash
238
+ npm test # roda todos os testes uma vez
239
+ npm run test:watch # modo watch
240
+ npm run typecheck # tsc --noEmit
241
+ ```
242
+
243
+ #### 7. Deploy
244
+
245
+ ```bash
246
+ npm run deploy
247
+ # Servido em https://senado.sidneybissoli.com (domínio próprio) e
248
+ # https://senado-br-mcp.sidneybissoli.workers.dev (fallback workers.dev)
249
+ ```
250
+
251
+ ## Endpoints
252
+
253
+ | Caminho | Métodos | Descrição |
254
+ |------|---------|-------------|
255
+ | `/mcp` | POST, GET, DELETE, OPTIONS | Endpoint MCP Streamable HTTP (gerenciado por `createMcpHandler`) |
256
+ | `/health` | GET | Health check — retorna `ok` (sempre público) |
257
+ | `/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) |
258
+
259
+ ## Exemplos de requisição MCP
260
+
261
+ Todas as requisições vão para `POST /mcp` no formato JSON-RPC 2.0.
262
+
263
+ ### Listar as ferramentas disponíveis
264
+
265
+ ```json
266
+ {
267
+ "jsonrpc": "2.0",
268
+ "id": 1,
269
+ "method": "tools/list"
270
+ }
271
+ ```
272
+
273
+ ### Chamar uma ferramenta — Listar senadores de SP
274
+
275
+ ```json
276
+ {
277
+ "jsonrpc": "2.0",
278
+ "id": 2,
279
+ "method": "tools/call",
280
+ "params": {
281
+ "name": "senado_listar_senadores",
282
+ "arguments": {
283
+ "uf": "SP",
284
+ "emExercicio": true
285
+ }
286
+ }
287
+ }
288
+ ```
289
+
290
+ ### Chamar uma ferramenta — Buscar matérias por palavra-chave
291
+
292
+ ```json
293
+ {
294
+ "jsonrpc": "2.0",
295
+ "id": 3,
296
+ "method": "tools/call",
297
+ "params": {
298
+ "name": "senado_buscar_materias",
299
+ "arguments": {
300
+ "palavraChave": "inteligência artificial",
301
+ "tramitando": true
302
+ }
303
+ }
304
+ }
305
+ ```
306
+
307
+ ### Chamar uma ferramenta — Votações recentes do plenário
308
+
309
+ ```json
310
+ {
311
+ "jsonrpc": "2.0",
312
+ "id": 4,
313
+ "method": "tools/call",
314
+ "params": {
315
+ "name": "senado_search_votacoes",
316
+ "arguments": {
317
+ "dias": 7
318
+ }
319
+ }
320
+ }
321
+ ```
322
+
323
+ ### Chamar uma ferramenta — Ideias de cidadãos mais populares
324
+
325
+ ```json
326
+ {
327
+ "jsonrpc": "2.0",
328
+ "id": 5,
329
+ "method": "tools/call",
330
+ "params": {
331
+ "name": "senado_ecidadania_listar_ideias",
332
+ "arguments": {
333
+ "ordenarPor": "apoios",
334
+ "ordem": "desc",
335
+ "status": "aberta"
336
+ }
337
+ }
338
+ }
339
+ ```
340
+
341
+ ## Endpoints da API de origem (upstream)
342
+
343
+ O servidor consome duas classes de endpoints upstream da API do Senado:
344
+
345
+ ### Endpoints legados (sufixo `.json`, respostas em PascalCase)
346
+
347
+ 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.
348
+
349
+ | Caminho upstream | Usado por |
350
+ |---------------|---------|
351
+ | `/senador/lista/atual` | `senado_listar_senadores` |
352
+ | `/senador/lista/legislatura/{legislatura}` | `senado_listar_senadores` (param `legislatura`) |
353
+ | `/senador/{codigo}` (+ `/mandatos`) | `senado_obter_senador` (biografia + mandatos via chamada extra) |
354
+ | `/senador/{codigo}/licencas`, `/comissoes`, `/cargos`, `/historicoAcademico`, `/filiacoes`, `/profissao` | `senado_senador_historico` (`tipo` enum) |
355
+ | `/senador/afastados` | `senado_senadores_afastados` |
356
+ | `/senador/{codigo}/apartes` | `senado_discursos_senador` (`tipo=apartes`) |
357
+ | `/comissao/lista/colegiados` | `senado_listar_comissoes` (+ resolução sigla→código) |
358
+ | `/comissao/{codigo}` | `senado_obter_comissao` (`secao=resumo`; código numérico, não sigla) |
359
+ | `/composicao/comissao/{codigo}` (+ `?ativas=S`) | `senado_obter_comissao` (`secao=membros`) |
360
+ | `/comissao/agenda/{data}` | `senado_agenda_comissoes` |
361
+ | `/comissao/agenda/{dataInicio}/{dataFim}` | `senado_reunioes_comissao` |
362
+ | `/comissao/reuniao/{codigoReuniao}` | `senado_reuniao_comissao` |
363
+ | `/comissao/cpi/{sigla}/requerimentos` | `senado_requerimentos_cpi` (upstream costuma vir vazio mesmo para CPIs ativas — retorno vazio traz `aviso`) |
364
+ | `/materia/distribuicao/autoria`, `/distribuicao/relatoria/{sigla}` | `senado_distribuicao_materias` |
365
+ | `/plenario/agenda/dia/{data}`, `/agenda/mes/{data}`, `/agenda/cn/...` | `senado_agenda_plenario` |
366
+ | `/plenario/resultado/{data}`, `/resultado/cn/{data}`, `/resultado/mes/{data}` | `senado_resultado_plenario` |
367
+ | `/plenario/resultado/veto/{codigo}` (+ `/materia/`, `/dispositivo/`) | `senado_resultado_veto` |
368
+ | `/plenario/votacao/orientacaoBancada/{data}` (+ período) | `senado_orientacao_bancada` |
369
+ | `/plenario/encontro/{codigo}` (+ `/pauta`, `/resultado`, `/resumo`) | `senado_encontro_plenario` |
370
+ | `/plenario/tiposSessao`, `/lista/tiposComparecimento`, `/lista/legislaturas` | `senado_tabelas_plenario` |
371
+ | `/materia/vetos/{ano}`, `/vetos/aposrcn`, `/vetos/antesrcn`, `/vetos/encerrados` | `senado_vetos` |
372
+ | `/taquigrafia/notas/{sessao\|reuniao}/{id}` | `senado_notas_taquigraficas` |
373
+ | `/taquigrafia/videos/{sessao\|reuniao}/{id}` | `senado_videos_taquigrafia` |
374
+ | `/senador/{codigo}/discursos` | `senado_discursos_senador` |
375
+ | `/plenario/lista/discursos/{dataInicio}/{dataFim}` | `senado_discursos_plenario` |
376
+ | `/discurso/texto-integral/{codigo}` | `senado_discurso_texto` (texto puro, buscado diretamente) |
377
+ | `/senador/lista/tiposUsoPalavra` | `senado_tabelas_referencia` (`tabela=tipos-uso-palavra`) |
378
+ | `/composicao/lista/blocos` | `senado_listar_blocos` |
379
+ | `/composicao/bloco/{codigo}` | `senado_obter_bloco` |
380
+ | `/composicao/lideranca` | `senado_liderancas` |
381
+ | `/composicao/mesaSF` | `senado_mesa` (`casa=senado`) |
382
+ | `/composicao/mesaCN` | `senado_mesa` (`casa=congresso`) |
383
+ | `/orcamento/lista` | `senado_orcamento_parlamentar` (`tipo=emendas`) |
384
+ | `/orcamento/oficios` | `senado_orcamento_parlamentar` (`tipo=oficios`) |
385
+ | `/legislacao/lista` | `senado_buscar_legislacao` |
386
+ | `/legislacao/{codigo}` | `senado_obter_legislacao` |
387
+ | `/legislacao/tiposNorma` | `senado_tabelas_referencia` (`tabela=tipos-norma`) |
388
+ | `/votacaoComissao/comissao/{sigla}` | `senado_votacao_comissao` (`por=comissao`) |
389
+ | `/votacaoComissao/parlamentar/{codigo}` | `senado_votacao_comissao` (`por=senador`) |
390
+ | `/votacaoComissao/materia/{sigla}/{numero}/{ano}` | `senado_votacao_comissao` (`por=materia`) |
391
+ | `/autor/lista/atual` | `senado_autores_atuais` |
392
+
393
+ ### Endpoints v3 (arrays/objetos JSON planos, camelCase)
394
+
395
+ 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.
396
+
397
+ | Caminho upstream | Usado por |
398
+ |---------------|---------|
399
+ | `/votacao` | `senado_obter_votacao`, `senado_search_votacoes`, `senado_votos_materia`, `senado_votacoes_senador` |
400
+ | `/processo` | `senado_search_processos`, `senado_buscar_materias` |
401
+ | `/processo/{id}` | `senado_obter_processo`, `senado_obter_materia` (`secao=detalhe`/`tramitacao`) |
402
+ | `/processo/documento` | `senado_obter_materia` (`secao=textos`) |
403
+ | `/processo/emenda` | `senado_processo_detalhe` (`secao=emendas`) |
404
+ | `/processo/relatoria` | `senado_processo_detalhe` (`secao=relatorias`), `senado_obter_materia` (relator) |
405
+ | `/processo/prazo` | `senado_processo_detalhe` (`secao=prazos`) |
406
+ | `/processo/{siglas,assuntos,classes,destinos,entes,tipos-*}` | `senado_tabelas_processo` (12 tabelas de referência) |
407
+
408
+ ### API administrativa (adm.senado.gov.br/adm-dadosabertos, JSON plano em snake_case)
409
+
410
+ 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`.
411
+
412
+ | Caminho upstream | Usado por |
413
+ |---------------|---------|
414
+ | `/api/v1/senadores/despesas_ceaps/{ano}` | `senado_ceaps` (~10 MB/ano, cacheado + agregado no Worker) |
415
+ | `/api/v1/senadores/{auxilio-moradia,escritorios,aposentados}` | `senado_senadores_admin` (`tipo` enum) |
416
+ | `/api/v1/servidores/servidores/{ativos,efetivos,comissionados,inativos}` | `senado_servidores` |
417
+ | `/api/v1/servidores/remuneracoes/{ano}/{mes}` | `senado_remuneracoes_servidores` (~5.5 MB/mês) |
418
+ | `/api/v1/servidores/horas-extras/{ano}/{mes}` | `senado_horas_extras` |
419
+ | `/api/v1/servidores/quantitativos/*`, `/previsao-aposentadoria`, `/api/v1/senadores/quantitativos/senadores` | `senado_pessoal_tabelas` (quantitativos) |
420
+ | `/api/v1/servidores/{estagiarios,pensionistas,lotacoes,cargos}` | `senado_pessoal_tabelas` (listas nominais) |
421
+ | `/api/v1/contratacoes/contratos` (+ `/{id}/aditivos`) | `senado_contratos`, `senado_contratacao_detalhe` |
422
+ | `/api/v1/contratacoes/{tipo}/{id}/{itens,pagamentos,garantias}` | `senado_contratacao_detalhe` |
423
+ | `/api/v1/contratacoes/licitacoes` | `senado_licitacoes` |
424
+ | `/api/v1/contratacoes/terceirizados` | `senado_terceirizados` |
425
+ | `/api/v1/contratacoes/empresas` | `senado_empresas_contratadas` (~13 MB, exige filtro) |
426
+ | `/api/v1/contratacoes/{atas_registro_preco,notas_empenho,menores_aprendizes}` | `senado_contratacoes_lista` |
427
+ | `/api/v1/supridos/{ano}` (+ atosConcessao, empenhos, movimentacoes, transacoes) | `senado_suprimento_fundos` |
428
+ | `senado.gov.br/bi-arqs/Arquimedes/Financeiro/{Despesa,Receitas}SenadoDadosAbertos.json` | `senado_execucao_orcamentaria` (feeds JSON diários, strings decimais brasileiras normalizadas) |
429
+
430
+ ### e-Cidadania (em D1, atualizado por Cron)
431
+
432
+ 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:
433
+
434
+ - uma **GitHub Action semanal fora do Worker** é dona do **corpus completo** de cada entidade (veja abaixo) — a fonte da verdade;
435
+ - 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.
436
+
437
+ Ambos os escritores constroem os payloads pelos builders canônicos `buildXResumo` + `contentHash` compartilhado, então suas linhas são byte-idênticas. Cada escrita:
438
+
439
+ - faz **upsert** em `ecidadania_current` (uma linha por item — o que as ferramentas leem),
440
+ - **anexa** em `ecidadania_history` apenas quando o `content_hash` de um item muda (pronto para série temporal),
441
+ - registra cada execução em `ecidadania_scrape_runs`.
442
+
443
+ 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.
444
+
445
+ 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.
446
+
447
+ 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.
448
+
449
+ #### Ingestão do corpus completo (fora do Worker, semanal)
450
+
451
+ 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:
452
+
453
+ - **`consultas`** — consultas abertas (detalhado abaixo).
454
+ - **`eventos`** — audiências/eventos da listagem HTML `principalaudiencia?p=N`; o status vem direto do bloco da listagem (sem ponte por `/processo`).
455
+ - **`ideias`** — ideias legislativas (~113,7 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.
456
+ - **`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`).
457
+
458
+ O job de `consultas` é a implementação de referência:
459
+
460
+ `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:
461
+
462
+ 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.
463
+ 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.
464
+ 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.
465
+
466
+ 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:
467
+
468
+ ```bash
469
+ CLOUDFLARE_API_TOKEN=… npm run ingest:ecidadania # escreve scripts/ingest-ecidadania/out.sql
470
+ npx wrangler d1 execute senado-ecidadania --remote --file=scripts/ingest-ecidadania/out.sql
471
+ ```
472
+
473
+ ## Cache
474
+
475
+ ### Arquitetura de camadas
476
+
477
+ | Camada | Armazenamento | Escopo | Faixa de TTL | Finalidade |
478
+ |-------|---------|-------|-----------|---------|
479
+ | **L0** | `Map` em memória | Por isolate | 30-300s | Ultrarrápido, elimina requisições redundantes dentro de um isolate do Worker |
480
+ | **L1** | Cloudflare Cache API (`caches.default`) | Por colo (PoP) | 60-600s | Compartilhado entre requisições no mesmo edge |
481
+ | **L2** | KV (opcional) | Global | Variável | Reservado para dados raros e de baixa escrita |
482
+
483
+ ### Categorias de cache
484
+
485
+ | Categoria | L0 TTL | L1 TTL | Usado para |
486
+ |----------|--------|--------|----------|
487
+ | **STATIC** | 300s | 600s | Tipos de legislação, referência estática |
488
+ | **SEMI_STATIC** | 120s | 300s | Lista de partidos, lista de UFs, detalhes de comissão |
489
+ | **DYNAMIC** | 30s | 60s | Agendas, votações recentes, listas de reuniões |
490
+ | **ON_DEMAND** | 30s | 120s | Consultas específicas de matéria/senador/votação |
491
+
492
+ ### Abordagem de cache de POST
493
+
494
+ 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:
495
+
496
+ 1. **Hash dos parâmetros** — Nome da ferramenta + parâmetros ordenados são hasheados com SHA-256
497
+ 2. **Chave GET sintética** — Uma URL sintética `https://senado-br-mcp.internal/__cache/{tool}/{hash}` é construída
498
+ 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
499
+
500
+ Esse cache acontece no **nível da ferramenta** (dentro do callback de cada ferramenta), não no nível do transporte MCP.
501
+
502
+ ## Proveniência
503
+
504
+ **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).
505
+
506
+ 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`.
507
+
508
+ 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.
509
+
510
+ ## Inventário de ferramentas
511
+
512
+ ### Grupo H — Referência/Metadados (1 ferramenta)
513
+
514
+ | Ferramenta | Descrição |
515
+ |------|-------------|
516
+ | `senado_tabelas_referencia` | Tabelas de referência via `tabela` enum: tipos-materia, partidos, ufs, legislatura-atual, tipos-norma, tipos-uso-palavra |
517
+
518
+ ### Grupo A — Senadores (5 ferramentas)
519
+
520
+ | Ferramenta | Descrição |
521
+ |------|-------------|
522
+ | `senado_listar_senadores` | Lista senadores em exercício/por legislatura, com filtros `nome` (busca parcial sem acento), `uf` e `partido` |
523
+ | `senado_obter_senador` | Detalhe biográfico de um senador: bio, mandatos, partido, contato |
524
+ | `senado_votacoes_senador` | Como um senador votou em cada matéria (via v3 `/votacao`) |
525
+ | `senado_senador_historico` | Histórico funcional via `tipo` enum: licencas, comissoes, cargos, historico-academico, filiacoes, profissoes |
526
+ | `senado_senadores_afastados` | Senadores atualmente afastados (fora de exercício) |
527
+
528
+ ### Grupo B — Matérias (2 ferramentas, backend v3)
529
+
530
+ | Ferramenta | Descrição |
531
+ |------|-------------|
532
+ | `senado_buscar_materias` | Busca matérias por tipo, número, ano, palavra-chave, autor ou tramitação (via v3 `/processo`) |
533
+ | `senado_obter_materia` | Dados de uma matéria via `secao` enum: detalhe (situação/relator), tramitacao (histórico) ou textos (documentos) |
534
+
535
+ ### Grupo C — Processos (5 ferramentas)
536
+
537
+ | Ferramenta | Descrição |
538
+ |------|-------------|
539
+ | `senado_search_processos` | Busca processos legislativos (complementar à busca de matérias) |
540
+ | `senado_obter_processo` | Detalhes completos de um processo legislativo específico |
541
+ | `senado_processo_detalhe` | Aspecto de um processo via `secao` enum: emendas, relatorias ou prazos |
542
+ | `senado_autores_atuais` | Parlamentares autores de processos em tramitação, ordenados por produção |
543
+ | `senado_tabelas_processo` | 12 tabelas de referência (siglas, assuntos, classes, tipos-*) via `tabela` enum |
544
+
545
+ ### Grupo D — Votações (3 ferramentas)
546
+
547
+ | Ferramenta | Descrição |
548
+ |------|-------------|
549
+ | `senado_obter_votacao` | Detalhes de uma votação com votos nominais. Aceita `codigoVotacao` (codigoSessao da sessão plenária). |
550
+ | `senado_votos_materia` | Votações de uma matéria (via v3 `/votacao?codigoMateria`), com votos nominais opcionais |
551
+ | `senado_search_votacoes` | Busca/listagem flexível de votações do plenário por `dias`, período, processo, matéria ou senador |
552
+
553
+ ### Grupo E — Comissões (7 ferramentas)
554
+
555
+ | Ferramenta | Descrição |
556
+ |------|-------------|
557
+ | `senado_listar_comissoes` | Lista comissões (colegiados) ativas, filtráveis por tipo |
558
+ | `senado_obter_comissao` | Dados de uma comissão via `secao` enum: resumo (mesa/totais) ou membros (composição). Resolve sigla para código internamente. |
559
+ | `senado_reunioes_comissao` | Reuniões de uma comissão num período (lida com intervalos entre anos) |
560
+ | `senado_agenda_comissoes` | Agenda de reuniões de todas as comissões numa data |
561
+ | `senado_reuniao_comissao` | Detalhe completo de uma reunião: partes, itens, convidados, resultados, links pauta/ata |
562
+ | `senado_requerimentos_cpi` | Requerimentos protocolados numa CPI em atividade, paginados (upstream costuma vir vazio mesmo para CPIs ativas; retorno vazio traz `aviso`) |
563
+ | `senado_distribuicao_materias` | Estatísticas de carga por senador numa comissão: autoria ou relatoria |
564
+
565
+ ### Grupo F — Plenário (7 ferramentas)
566
+
567
+ | Ferramenta | Descrição |
568
+ |------|-------------|
569
+ | `senado_agenda_plenario` | Agenda do plenário — por dia, mês ou Congresso (escopo dia/mes/cn) |
570
+ | `senado_resultado_plenario` | Resultados de sessão: itens deliberados, pareceres, desfechos (SF/CN/mês) |
571
+ | `senado_orientacao_bancada` | Orientações de voto das lideranças por votação, com placar |
572
+ | `senado_vetos` | Vetos presidenciais por ano ou situação de tramitação |
573
+ | `senado_resultado_veto` | Resultados nominais de votação de veto (por veto, matéria vetada ou dispositivo) |
574
+ | `senado_encontro_plenario` | Detalhe de sessão legislativa, itens de pauta, resultados ou resumo |
575
+ | `senado_tabelas_plenario` | Tipos de sessão, tipos de comparecimento, lista de legislaturas |
576
+
577
+ ### Grupo G — e-Cidadania (9 ferramentas)
578
+
579
+ | Ferramenta | Descrição |
580
+ |------|-------------|
581
+ | `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`) |
582
+ | `senado_ecidadania_obter_consulta` | Detalhe de uma consulta: votos, autor, relator, comentários |
583
+ | `senado_ecidadania_consultas_analise` | Analisa o conjunto completo de consultas **abertas** via `modo` (consenso/polarizada); `status` padrão `aberta` |
584
+ | `senado_ecidadania_listar_ideias` | Ideias legislativas de cidadãos; ranking das mais apoiadas via `ordenarPor: apoios` |
585
+ | `senado_ecidadania_obter_ideia` | Detalhe de uma ideia: texto, apoios, status de conversão em projeto |
586
+ | `senado_ecidadania_listar_eventos` | Eventos interativos (audiências, sabatinas, lives); ranking dos mais comentados via `ordenarPor` |
587
+ | `senado_ecidadania_obter_evento` | Detalhe de um evento: pauta, convidados, link de vídeo |
588
+ | `senado_ecidadania_sugerir_tema_enquete` | Sugere temas para enquete mensal a partir de critérios configuráveis |
589
+ | `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` |
590
+
591
+ ### Grupo I — Discursos (3 ferramentas)
592
+
593
+ | Ferramenta | Descrição |
594
+ |------|-------------|
595
+ | `senado_discursos_senador` | Pronunciamentos de um senador via `tipo` enum: discursos (próprios) ou apartes (intervenções) |
596
+ | `senado_discursos_plenario` | Todos os discursos em plenário num intervalo de datas |
597
+ | `senado_discurso_texto` | Texto integral de um pronunciamento/discurso específico |
598
+
599
+ ### Grupo J — Blocos e Lideranças (4 ferramentas)
600
+
601
+ | Ferramenta | Descrição |
602
+ |------|-------------|
603
+ | `senado_listar_blocos` | Blocos parlamentares do Senado e seus partidos membros |
604
+ | `senado_obter_bloco` | Detalhes de um bloco parlamentar específico |
605
+ | `senado_liderancas` | Lideranças do Senado/Congresso (líderes, vice-líderes), filtráveis |
606
+ | `senado_mesa` | Membros da Mesa Diretora via `casa` enum: senado (Mesa do SF) ou congresso (Mesa do CN) |
607
+
608
+ ### Grupo K — Orçamento (1 ferramenta)
609
+
610
+ | Ferramenta | Descrição |
611
+ |------|-------------|
612
+ | `senado_orcamento_parlamentar` | Emendas parlamentares ao orçamento via `tipo` enum: emendas (lotes por autor) ou oficios (indicação de destino — filtrável por `ano` da emenda, paginado, `incluirEmendas` opcional) |
613
+
614
+ ### Grupo L — Legislação Federal (2 ferramentas)
615
+
616
+ | Ferramenta | Descrição |
617
+ |------|-------------|
618
+ | `senado_buscar_legislacao` | Busca normas jurídicas federais por tipo, número, ano ou data (ao menos um obrigatório) |
619
+ | `senado_obter_legislacao` | Detalhes de uma norma jurídica federal específica |
620
+
621
+ ### Grupo M — Votação em Comissão (1 ferramenta)
622
+
623
+ | Ferramenta | Descrição |
624
+ |------|-------------|
625
+ | `senado_votacao_comissao` | Votações em comissões via `por` enum: comissao, senador ou materia; período opcional |
626
+
627
+ ### Grupo N — Taquigrafia (2 ferramentas)
628
+
629
+ | Ferramenta | Descrição |
630
+ |------|-------------|
631
+ | `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 |
632
+ | `senado_videos_taquigrafia` | Unidades de vídeo/áudio por sessão ou reunião, com orador e links de mídia |
633
+
634
+ ### Grupo O — Senadores/Administrativo (2 ferramentas)
635
+
636
+ | Ferramenta | Descrição |
637
+ |------|-------------|
638
+ | `senado_ceaps` | Despesas da cota parlamentar (CEAPS) por ano — agregadas por senador, tipo de despesa, mês ou fornecedor, ou detalhe item a item; `estatisticas=true` devolve a distribuição do conjunto (mín/máx/média/mediana/percentis) + ranking top/bottom, ou um ranking de grupos por gasto total via `agruparPor` (senador/tipo/mês/fornecedor) com `topN`; filtros por senador/mês/tipo/fornecedor |
639
+ | `senado_senadores_admin` | Dados administrativos dos senadores via `tipo` enum: auxilio-moradia, escritorios-apoio ou aposentados |
640
+
641
+ ### Grupo P — Servidores / Gestão de Pessoas (4 ferramentas)
642
+
643
+ | Ferramenta | Descrição |
644
+ |------|-------------|
645
+ | `senado_servidores` | Servidores por situação (ativos/efetivos/comissionados/inativos), filtráveis por nome, unidade, cargo |
646
+ | `senado_remuneracoes_servidores` | Folha mensal — resumo por tipo de folha ou composição por pessoa com bruto calculado; `estatisticas=true` devolve estatísticas da folha inteira (mín/máx/média/mediana/percentis) + ranking top/bottom, com `campo`, `consolidarPorServidor`, `agruparPor` e `topN` |
647
+ | `senado_horas_extras` | Pagamentos de horas extras por mês, com totais; `estatisticas=true` devolve a distribuição do conjunto (mín/máx/média/mediana/percentis) + ranking top/bottom, ou um ranking por servidor via `agruparPor` (nome/competência), com `topN` |
648
+ | `senado_pessoal_tabelas` | Tabelas de pessoal via `tabela` enum: quantitativos (pessoal, cargos-funcoes, previsao-aposentadoria, senadores) e listas (estagiarios, pensionistas, lotacoes, cargos) |
649
+
650
+ ### Grupo Q — Contratações (6 ferramentas)
651
+
652
+ | Ferramenta | Descrição |
653
+ |------|-------------|
654
+ | `senado_contratos` | Contratos filtrados no Worker sobre a base completa (sem acento): fornecedor, CNPJ, ano, número, objeto, mão de obra |
655
+ | `senado_contratacao_detalhe` | Itens, pagamentos, garantias, aditivos ou ativações de um contrato/ata/empenho |
656
+ | `senado_licitacoes` | Licitações por número ou texto do objeto |
657
+ | `senado_terceirizados` | Colaboradores terceirizados por nome, empresa ou unidade |
658
+ | `senado_empresas_contratadas` | Empresas que contratam com o Senado (exige filtro por nome/CNPJ) |
659
+ | `senado_contratacoes_lista` | Atas de registro de preço, notas de empenho, menores aprendizes |
660
+
661
+ ### Grupo R — Suprimento de Fundos (1 ferramenta)
662
+
663
+ | Ferramenta | Descrição |
664
+ |------|-------------|
665
+ | `senado_suprimento_fundos` | Adiantamentos de suprimento de fundos por ano: beneficiários, atos de concessão, empenhos, movimentações, transações de cartão; `estatisticas=true` (tipo transacoes/empenhos/atos-concessao) devolve a distribuição do conjunto (mín/máx/média/mediana/percentis) + ranking top/bottom, ou um ranking por soma do valor via `agruparPor` (ex.: fornecedor), com `campo` contextual e `topN` |
666
+
667
+ ### Grupo S — Orçamento do Senado (1 ferramenta)
668
+
669
+ | Ferramenta | Descrição |
670
+ |------|-------------|
671
+ | `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; `estatisticas=true` devolve a distribuição do conjunto (min/máx/média/mediana/percentis) + ranking top/bottom, ou um ranking de grupos por soma do `campo` via `agruparPor`, com `campo` (padrão pago / arrecadada) e `topN` |
672
+
673
+ **Total: 66 ferramentas**
674
+
675
+ ### Prompts (4)
676
+
677
+ Templates de workflow reutilizáveis em pt-BR (capacidade MCP `prompts`), definidos em `src/prompts.ts`:
678
+
679
+ | Prompt | Args | O que orienta |
680
+ | --- | --- | --- |
681
+ | `senado_gastos_senador` | `senador`, `ano` | Resolve o senador e agrega/detalha despesas CEAPS. |
682
+ | `senado_tramitacao_materia` | `sigla`, `numero`, `ano` | Obtém situação atual + histórico de tramitação da matéria. |
683
+ | `senado_votos_senador` | `senador`, `periodo?` | Lista os votos nominais do senador no período. |
684
+ | `senado_panorama_ecidadania` | — | Consolida consultas (consenso/polarização), ideias e eventos populares. |
685
+
686
+ ### Recursos (5)
687
+
688
+ Documentos/tabelas de contexto estáticos (capacidade MCP `resources`), definidos em `src/resources.ts`:
689
+
690
+ | URI | Tipo | Conteúdo |
691
+ | --- | --- | --- |
692
+ | `senado://guia` | markdown | Visão geral e qual ferramenta usar por objetivo. |
693
+ | `senado://catalogo` | markdown | As 66 ferramentas agrupadas por domínio. |
694
+ | `senado://glossario` | markdown | Siglas e termos do Senado (PEC, CEAPS, CCJ, RCN…). |
695
+ | `senado://tabelas/tipos-materia` | json | Tipos de proposição (sigla/nome/descrição). |
696
+ | `senado://tabelas/ufs` | json | As 27 unidades federativas. |
697
+
698
+ ## Estrutura do projeto
699
+
700
+ ```
701
+ src/
702
+ ├── index.ts # Entrypoint do Worker (handler de fetch + handler scheduled/Cron)
703
+ ├── server.ts # Fábrica do McpServer (cria instância por requisição)
704
+ ├── auth.ts # Auth Bearer token opcional (comparação em tempo constante)
705
+ ├── metrics.ts # Contadores em memória servidos em /metrics
706
+ ├── types.ts # Env, categorias de cache, constantes de salvaguarda
707
+ ├── cache/
708
+ │ ├── l0-memory.ts # Cache Map em memória com TTL + evicção LRU
709
+ │ ├── l1-cache-api.ts # Wrapper da Cloudflare Cache API (chaves GET sintéticas)
710
+ │ └── manager.ts # Orquestrador de cache (L0 → L1 → upstream)
711
+ ├── throttle/
712
+ │ ├── token-bucket.ts # Rate limiter token bucket (global + por cliente)
713
+ │ └── upstream.ts # Fetch upstream com limite de concorrência, retry, timeout
714
+ ├── scraper/
715
+ │ ├── ecidadania.ts # Scraper isolado do e-Cidadania (listas REST + detalhe HTML por regex; buildConsultaResumo)
716
+ │ ├── pipeline.ts # Cron de 2h: splice de métrica direcionado (consultas/eventos/ideias); corpora são dos jobs semanais
717
+ │ ├── anomaly.ts # Classificação de execução (execução anômala nunca sobrescreve current)
718
+ │ └── store.ts # Leituras D1 (resolveList + staleness por entidade, lastGoodRunAt) + write-through de detalhe
719
+ ├── instrument.ts # Telemetria de chamadas por ferramenta (memória + Analytics Engine)
720
+ ├── utils/
721
+ │ ├── logger.ts # Logging estruturado em JSON
722
+ │ └── validation.ts # helpers toolResult, toolError, errorFrom, buildParams, ensureArray
723
+ └── tools/
724
+ ├── referencia.ts # Grupo H — 1 ferramenta de referência/metadados
725
+ ├── senadores.ts # Grupo A — 5 ferramentas de senadores
726
+ ├── materias.ts # Grupo B — 2 ferramentas de matérias (backend v3)
727
+ ├── processos.ts # Grupo C — 5 ferramentas de processos
728
+ ├── votacoes.ts # Grupo D — 3 ferramentas de votações
729
+ ├── comissoes.ts # Grupo E — 7 ferramentas de comissões
730
+ ├── plenario.ts # Grupo F — 7 ferramentas de plenário
731
+ ├── ecidadania.ts # Grupo G — 9 ferramentas do e-Cidadania (leem do D1; veja scraper/)
732
+ ├── discursos.ts # Grupo I — 3 ferramentas de discursos
733
+ ├── composicao.ts # Grupo J — 4 ferramentas de blocos/lideranças
734
+ ├── orcamento.ts # Grupo K — 1 ferramenta de orçamento
735
+ ├── legislacao.ts # Grupo L — 2 ferramentas de legislação federal
736
+ ├── votacao-comissao.ts # Grupo M — 1 ferramenta de votação em comissão
737
+ ├── taquigrafia.ts # Grupo N — 2 ferramentas de notas taquigráficas
738
+ ├── senadores-admin.ts # Grupo O — 2 ferramentas administrativas de senadores (CEAPS, moradia)
739
+ ├── servidores.ts # Grupo P — 4 ferramentas de pessoal
740
+ ├── contratacoes.ts # Grupo Q — 6 ferramentas de contratações
741
+ ├── supridos.ts # Grupo R — 1 ferramenta de suprimento de fundos
742
+ └── orcamento-senado.ts # Grupo S — 1 ferramenta de execução orçamentária
743
+ scripts/
744
+ └── ingest-ecidadania/ # Ingestão semanal do corpus completo de consultas, fora do Worker (via `npm run ingest:ecidadania`)
745
+ ├── index.ts # Orquestrador: crawl → status (/processo) → normaliza → guards → out.sql
746
+ ├── listing.ts # Parser puro da listagem (parseConsultaListingPage, findLastPage)
747
+ ├── status.ts # conjunto tramitando=S de /processo → aberta/encerrada (deriveStatus)
748
+ ├── restatus.ts # Correção de linger: re-status das linhas armazenadas por presença em /processo (fecha zumbis)
749
+ ├── http.ts # Fetch educado (retry/backoff) para o crawl não supervisionado
750
+ ├── d1.ts # Pré-leituras do D1 (meta existente, payloads, últimas boas linhas) via wrangler
751
+ └── sql.ts # Geração do out.sql (espelha SQL.upsert/SQL.history; reusa SyncRecord)
752
+ .github/workflows/ # publish-mcp.yml (registry) + ingest-ecidadania.yml (carga semanal do corpus no D1)
753
+ migrations/ # Schema D1 (0001 tabelas, 0002 índices) para o pipeline do e-Cidadania
754
+ tests/ # Testes unitários Vitest espelhando src/ (parsers, cache, throttle, auth, scraper,
755
+ # pipeline/anomaly/store, listing/sql/highlights, além de testes de contrato do e-Cidadania)
756
+ ```
757
+
758
+ ## Variáveis de ambiente
759
+
760
+ | Variável | Obrigatória | Padrão | Descrição |
761
+ |----------|----------|---------|-------------|
762
+ | `SENADO_BASE_URL` | Não | `https://legis.senado.leg.br/dadosabertos` | URL base da API legislativa |
763
+ | `SENADO_ADM_BASE_URL` | Não | `https://adm.senado.gov.br/adm-dadosabertos` | URL base da API administrativa |
764
+ | `ALLOWED_ORIGIN` | Não | `*` | Origem permitida no CORS |
765
+ | `API_KEY` | Não (secret) | — | Quando definido, exige `Authorization: Bearer <key>` em todas as requisições exceto `/health`, `/metrics` e preflight CORS |
766
+ | `CACHE_KV` | Sim (binding) | — | Namespace KV para o cache L2 |
767
+ | `ECIDADANIA_DB` | Sim (binding) | — | Banco D1 para o pipeline do e-Cidadania (persistência de listas + histórico) |
768
+ | `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 |
769
+ | `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 |
770
+ | `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 |
771
+ | `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 |
772
+ | `SENADO_ANALYTICS` | Não (binding) | — | Dataset do Analytics Engine para telemetria de chamadas por ferramenta |
773
+
774
+ ## Conectando clientes MCP
775
+
776
+ Este é um servidor **remoto** (Streamable HTTP, sem instalação, acesso aberto) — aponte qualquer cliente MCP para
777
+ `https://senado.sidneybissoli.com/mcp`. Além das 66 ferramentas, ele expõe **prompts** (workflows prontos em pt-BR:
778
+ `senado_gastos_senador`, `senado_tramitacao_materia`, `senado_votos_senador`,
779
+ `senado_panorama_ecidadania`) e **recursos** (`senado://guia`, `senado://catalogo`,
780
+ `senado://glossario`, `senado://tabelas/tipos-materia`, `senado://tabelas/ufs`).
781
+
782
+ ### Um clique (LobeHub)
783
+
784
+ Instale pelo marketplace do LobeHub — abra a
785
+ [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**
786
+ (ele pré-preenche o endpoint remoto, sem config necessária).
787
+
788
+ ### Claude Desktop / Claude Code
789
+
790
+ Adicione à sua configuração MCP:
791
+
792
+ ```json
793
+ {
794
+ "mcpServers": {
795
+ "senado-br": {
796
+ "url": "https://senado.sidneybissoli.com/mcp"
797
+ }
798
+ }
799
+ }
800
+ ```
801
+
802
+ Para clientes baseados em comando (ou qualquer cliente sem suporte remoto nativo), use a ponte `mcp-remote`:
803
+
804
+ ```json
805
+ {
806
+ "mcpServers": {
807
+ "senado-br": {
808
+ "command": "npx",
809
+ "args": ["-y", "mcp-remote", "https://senado.sidneybissoli.com/mcp"]
810
+ }
811
+ }
812
+ }
813
+ ```
814
+
815
+ ### MCP Inspector
816
+
817
+ ```bash
818
+ npx @modelcontextprotocol/inspector https://senado.sidneybissoli.com/mcp
819
+ ```
820
+
821
+ ## Licença
822
+
823
+ MIT
824
+
825
+ ## Créditos
826
+
827
+ Ícone: *"Amanhecer no Congresso Nacional"* — fotografia do Congresso Nacional
828
+ brasileiro, usada sob licença Creative Commons. (Se você é o autor, abra uma
829
+ issue para adicionarmos a atribuição completa / o link da licença.)