senado-br-mcp 3.12.0 → 3.13.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.
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  [![License: MIT](https://img.shields.io/github/license/SidneyBissoli/senado-br-mcp-cloudflare)](LICENSE)
15
15
  [![Status](https://img.shields.io/website?url=https%3A%2F%2Fsenado.sidneybissoli.com%2Fhealth&up_message=online&down_message=offline&label=status)](https://senado.sidneybissoli.com/status)
16
16
 
17
- 🇧🇷 [Leia em Português](README.pt-BR.md)
17
+ 🇧🇷 [Leia em Português](LEIA-ME.md)
18
18
 
19
19
  A **public, hosted** MCP server that gives AI assistants live, structured access to **Brazilian Senate open data** — **no installation, no account, no API key**. Point your MCP client at the hosted endpoint and start asking about senators, bills, votes, expenses, and more. It runs on Cloudflare Workers over Streamable HTTP.
20
20
 
@@ -752,7 +752,7 @@ Reads a bundled snapshot of the Senate's organizational tree (crawled from the i
752
752
 
753
753
  ### Group U — Deep Research (2 tools)
754
754
 
755
- The [OpenAI Deep Research contract](#chatgpt-deep-research): the only two tools without the `senado_` prefix, because the names are fixed by the contract. Registered through the same shim as the others (read-only annotations, permissive `outputSchema`, per-tool telemetry) and served on `/mcp` only — the curated ChatGPT app profile does not include them. The index (senators in office + active committees, ~300 documents) is built on first use from the same two list endpoints the `senado_listar_*` tools read, and kept for 24 h.
755
+ The [OpenAI Deep Research contract](#chatgpt-deep-research): the only two tools without the `senado_` prefix, because the names are fixed by the contract. Registered through the same shim as the others (read-only annotations, the shared output envelope — open data plus required `provenance` + `attribution` —, per-tool telemetry) and served on `/mcp` only — the curated ChatGPT app profile does not include them. The index (senators in office + active committees, ~300 documents) is built on first use from the same two list endpoints the `senado_listar_*` tools read, and kept for 24 h.
756
756
 
757
757
  | Tool | Description |
758
758
  |------|-------------|
package/dist/server.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { McpServer } from "@modelcontextprotocol/server";
6
6
  import { z } from "zod";
7
+ import { ConciseBlockSchema } from "@sbissoli/mcp-provenance";
7
8
  import { registerReferenciaTools } from "./tools/referencia.js";
8
9
  import { registerSenadoresTools } from "./tools/senadores.js";
9
10
  import { registerMateriasTools } from "./tools/materias.js";
@@ -83,10 +84,23 @@ export function createServer(env, ctx, options = {}) {
83
84
  // reaches external systems (Senate APIs / e-Cidadania) whose data is an open, changing
84
85
  // set; and every tool returns a JSON object via toolResult(). Rather than repeat that
85
86
  // metadata at every call site, wrap the group modules' `server.tool(name, desc, shape, cb)`
86
- // calls and route them through registerTool() with shared annotations and a permissive
87
- // object outputSchema. toolResult() supplies the matching structuredContent. The callback
88
- // is also wrapped with instrumentTool() so every invocation is counted per tool.
89
- const outputSchema = z.object({}).passthrough();
87
+ // calls and route them through registerTool() with shared annotations and ONE shared
88
+ // outputSchema. The callback is also wrapped with instrumentTool() so every invocation
89
+ // is counted per tool.
90
+ //
91
+ // O schema de saída é o ENVELOPE COMUM (decisão do dono, 04/10/2026): aberto — a forma
92
+ // dos dados de cada tool segue sem contrato, como decidido em
93
+ // docs/_local/_checklist-melhorias-arquiteturais.pt-BR.md ("passthrough foi decisão
94
+ // deliberada") —, mas com o que TODA resposta de sucesso das 69 carrega obrigatório:
95
+ // `provenance` + `attribution`, que `resultWithProvenance`/`provenanceExtras` sempre
96
+ // montam. O bloco é o schema IMPORTADO do @sbissoli/mcp-provenance, nunca transcrito:
97
+ // a cópia à mão de um bloco selado derrubou quatro irmãos quando o contrato ganhou
98
+ // `retrieval`. `provenance` é objeto com uma fonte e LISTA quando a chamada passa
99
+ // várias (o índice do Deep Research), então os dois.
100
+ const outputSchema = z.looseObject({
101
+ provenance: z.union([ConciseBlockSchema, z.array(ConciseBlockSchema).min(1)]),
102
+ attribution: z.array(z.string()),
103
+ });
90
104
  const registerTool = server.registerTool.bind(server);
91
105
  const analytics = env.SENADO_ANALYTICS;
92
106
  // O shim é instalado sobre a instância e o resultado é NOMEADO: os módulos de
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Single source of truth for the server version (kept in sync with package.json). */
2
- export const VERSION = "3.12.0";
2
+ export const VERSION = "3.13.0";
3
3
  export const USER_AGENT = `senado-br-mcp/${VERSION} (+https://senado.sidneybissoli.com; sbissoli76@gmail.com)`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "senado-br-mcp",
3
- "version": "3.12.0",
3
+ "version": "3.13.0",
4
4
  "description": "MCP server for Brazilian Senate open data — runs hosted on Cloudflare Workers or locally via npx (stdio)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -62,7 +62,7 @@
62
62
  "@modelcontextprotocol/client": "^2.0.0",
63
63
  "@modelcontextprotocol/sdk": "^1.30.0",
64
64
  "@sbissoli/mcp-evals": "^0.1.0",
65
- "@sbissoli/mcp-surface": "^0.1.1",
65
+ "@sbissoli/mcp-surface": "^0.2.0",
66
66
  "@types/node": "^26.5.1",
67
67
  "agents": "^0.24.0",
68
68
  "exceljs": "^4.4.0",
package/README.pt-BR.md DELETED
@@ -1,887 +0,0 @@
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-69-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 **69 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 27
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 27 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
- ### ChatGPT (Deep Research)
72
-
73
- O deep research do ChatGPT (e o company knowledge, e os workflows de pesquisa da API Responses) só usa um servidor MCP que exponha exatamente `search` e `fetch` — este servidor expõe, além das ferramentas `senado_*`, na superfície completa `/mcp` (não no perfil curado do app). Aponte o conector para o endpoint hospedado, sem chave:
74
-
75
- ```
76
- https://senado.sidneybissoli.com/mcp
77
- ```
78
-
79
- `search` ranqueia a consulta contra os senadores em exercício e as comissões ativas do Senado e do Congresso Nacional e devolve `{ id, title, url }` (`sen:<código>` / `com:<código>`); `fetch` devolve o documento em Markdown legível — a biografia e os mandatos do senador, ou o resumo e a mesa da comissão — com a página pública canônica (o perfil do senador em www25.senado.leg.br ou a página da comissão em legis.senado.leg.br), que é o que o ChatGPT cita. As duas carregam o mesmo bloco de proveniência das outras ferramentas, em `structuredContent` e `_meta` (o canal de texto é o JSON do contrato). No modo desenvolvedor do ChatGPT (Settings → Security and login → Developer mode) qualquer ferramenta é chamável — as `senado_*` continuam sendo as ferramentas para dados.
80
-
81
- ### Instalação (qualquer cliente)
82
-
83
- Para clientes que iniciam servidores MCP como um comando — e para uma configuração de um único comando — use a
84
- ponte [`mcp-remote`](https://www.npmjs.com/package/mcp-remote). **Sem build, sem config, sem chave:**
85
-
86
- ```bash
87
- npx -y mcp-remote https://senado.sidneybissoli.com/mcp
88
- ```
89
-
90
- - **Um clique (LobeHub):** abra a [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**.
91
- - **URL remota nativa** (Claude Desktop/Code e outros clientes Streamable HTTP): veja [Conectando clientes MCP](#conectando-clientes-mcp).
92
-
93
- Tudo abaixo de *Arquitetura* (Pré-requisitos, Configuração, Deploy) é **apenas para opcionalmente auto-hospedar a sua
94
- própria instância** — **não** é necessário para usar este servidor público.
95
-
96
- ## Rodar localmente (npx · stdio)
97
-
98
- Prefere não rotear suas consultas por um servidor de terceiros (ex.: política de uma redação)? O **mesmo
99
- servidor** também roda como um **processo local stdio** que bate **direto nas APIs oficiais do governo** —
100
- as mesmas 69 ferramentas, o mesmo envelope de proveniência, sem Cloudflare no caminho. É o canal npm/stdio,
101
- publicado como [`senado-br-mcp`](https://www.npmjs.com/package/senado-br-mcp).
102
-
103
- Aponte um cliente baseado em comando (Claude Desktop/Code, etc.) para o pacote — o npm baixa e executa,
104
- sem clone nem build:
105
-
106
- ```json
107
- {
108
- "mcpServers": {
109
- "senado-br": {
110
- "command": "npx",
111
- "args": ["-y", "senado-br-mcp"]
112
- }
113
- }
114
- }
115
- ```
116
-
117
- Para rodar direto ou mexer no código, use o checkout do fonte:
118
-
119
- ```bash
120
- git clone https://github.com/SidneyBissoli/senado-br-mcp-cloudflare
121
- cd senado-br-mcp-cloudflare
122
- npm install
123
- npm run build
124
- node dist/cli.js # serve o MCP por stdio (Ctrl+C para parar)
125
- ```
126
-
127
- **Paridade com o servidor hospedado:** as ferramentas legislativas e administrativas são **idênticas**
128
- (mesmas APIs de origem, mesmo throttle/cache/proveniência) — localmente o cache L1 do Cloudflare vira
129
- no-op, mas o L0 em memória continua funcionando, então o resultado é o mesmo. A **única** diferença são
130
- as ferramentas de lista/corpus do e-Cidadania: sem D1, elas caem no scraping ao vivo dos ~5 destaques
131
- REST, sinalizado por `meta.fonte` / `possivelDesatualizacao`; as de detalhe (`obter_*`) são idênticas.
132
- Os logs vão para o **stderr** — o stdout carrega apenas o fluxo do protocolo JSON-RPC.
133
-
134
- ## Agent Skill (opcional)
135
-
136
- Este repositório inclui uma [Agent Skill](https://platform.claude.com/docs/en/docs/agents-and-tools/agent-skills/overview)
137
- do Claude em [`.claude/skills/senado-br/`](.claude/skills/senado-br/SKILL.md) que ensina o Claude **quando**
138
- recorrer a este servidor e **como** usar bem as 69 ferramentas — um mapa de ferramentas por tema, playbooks de
139
- pergunta→ferramenta, o contrato de proveniência e os gotchas (datas, a ponte `codigoMateria`, a listagem
140
- só-abertas do e-Cidadania, paginação). Ela aponta para os recursos `senado://catalogo` / `senado://guia` do
141
- próprio servidor em vez de duplicá-los.
142
-
143
- O Claude Code a descobre automaticamente ao trabalhar neste repositório. Para usá-la em outro lugar, copie
144
- `.claude/skills/senado-br/` para o seu `~/.claude/skills/`, ou compacte a pasta e faça upload no claude.ai
145
- (Configurações → Recursos). A skill pressupõe o servidor MCP `senado-br` conectado (hospedado ou via npx).
146
-
147
- ## Arquitetura
148
-
149
- - **Runtime:** Cloudflare Workers (ESM)
150
- - **Transporte:** Streamable HTTP (spec MCP 2025-03-26) via `createMcpHandler` de `agents/mcp`
151
- - **Protocolo:** MCP sobre JSON-RPC — `/mcp` serve o catalogo publico completo; `/mcp/openai-app-v2` expoe um perfil curado de 27 ferramentas mais um widget MCP Apps compartilhado para revisao/submissao como app OpenAI (`/mcp/openai-app` permanece como alias legado)
152
- - **SDK:** `@modelcontextprotocol/server` 2.x (instâncias de McpServer por requisição; o `@modelcontextprotocol/sdk` v1 fica só como peer do `agents`, em tempo de dev)
153
- - **Validação:** schemas Zod para todas as entradas das ferramentas
154
- - **Cache:** 2 camadas (L0 memória + L1 Cache API) com chaveamento SHA-256
155
- - **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))
156
- - **Rate limiting:** Token bucket — global (8 req/s) + por cliente (2 req/s)
157
- - **Throttle de upstream:** Máx. 6 requisições simultâneas, timeout de 10s, retry com backoff exponencial
158
- - **Auth:** Bearer token opcional (defina o secret `API_KEY`; acesso aberto quando ausente). Comparação em tempo constante.
159
- - **Observabilidade:** Logging estruturado em JSON + contadores em memória expostos em `/metrics`
160
- - **Testes:** testes unitários Vitest para parsers, helpers, cache, throttle e auth
161
-
162
- ## Auto-hospedagem (opcional)
163
-
164
- > **Não é necessário para usar o servidor** — ele já está hospedado em `https://senado.sidneybissoli.com/mcp`
165
- > (acesso aberto). Siga esta seção apenas se quiser rodar a sua **própria** instância privada.
166
-
167
- ### Pré-requisitos
168
-
169
- - Node.js 22+ (`engines.node`)
170
- - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) v4+
171
- - Conta Cloudflare
172
-
173
- ### Configuração
174
-
175
- #### 1. Instalar dependências
176
-
177
- ```bash
178
- npm install
179
- ```
180
-
181
- #### 2. Criar o namespace KV
182
-
183
- ```bash
184
- # Cria o namespace KV
185
- wrangler kv namespace create CACHE_KV
186
-
187
- # Anote o ID da saída, ex.:
188
- # { binding = "CACHE_KV", id = "abc123..." }
189
- ```
190
-
191
- #### 3. Configurar o wrangler.toml
192
-
193
- Substitua o ID placeholder do namespace KV:
194
-
195
- ```toml
196
- [[kv_namespaces]]
197
- binding = "CACHE_KV"
198
- id = "YOUR_KV_NAMESPACE_ID_HERE"
199
- ```
200
-
201
- Opcionalmente, defina `ALLOWED_ORIGIN` para restringir o CORS:
202
-
203
- ```toml
204
- [vars]
205
- ALLOWED_ORIGIN = "https://your-app.example.com"
206
- ```
207
-
208
- 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):
209
-
210
- ```toml
211
- [[d1_databases]]
212
- binding = "ECIDADANIA_DB"
213
- database_name = "senado-ecidadania"
214
- database_id = "YOUR_D1_DATABASE_ID_HERE"
215
-
216
- [triggers]
217
- crons = ["0 */2 * * *"]
218
- ```
219
-
220
- Crie o banco (cole o ID retornado acima) e aplique o schema:
221
-
222
- ```bash
223
- npx wrangler d1 create senado-ecidadania
224
- npx wrangler d1 migrations apply senado-ecidadania --remote
225
- ```
226
-
227
- 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.
228
-
229
- #### 4. (Opcional) Habilitar autenticação
230
-
231
- ```bash
232
- wrangler secret put API_KEY
233
- # Os clientes passam a enviar: Authorization: Bearer <key>
234
- # Quando API_KEY não está definido, o servidor é de acesso aberto.
235
- ```
236
-
237
- #### 5. Desenvolvimento local
238
-
239
- ```bash
240
- npm run dev
241
- # O servidor de dev roda localmente na porta 8787 (apenas local).
242
- # O endpoint MCP público é https://senado.sidneybissoli.com/mcp
243
- ```
244
-
245
- #### 6. Testes e typecheck
246
-
247
- ```bash
248
- npm test # roda todos os testes uma vez
249
- npm run test:watch # modo watch
250
- npm run typecheck # tsc --noEmit
251
- ```
252
-
253
- #### 7. Deploy
254
-
255
- ```bash
256
- npm run deploy
257
- # Servido em https://senado.sidneybissoli.com (domínio próprio) e
258
- # https://senado-br-mcp.sidneybissoli.workers.dev (fallback workers.dev)
259
- ```
260
-
261
- ## Endpoints
262
-
263
- | Caminho | Métodos | Descrição |
264
- |------|---------|-------------|
265
- | `/mcp` | POST, GET, DELETE, OPTIONS | Endpoint MCP Streamable HTTP (gerenciado por `createMcpHandler`) |
266
- | `/health` | GET | Health check — retorna `ok` (sempre público) |
267
- | `/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) |
268
-
269
- ## Exemplos de requisição MCP
270
-
271
- Todas as requisições vão para `POST /mcp` no formato JSON-RPC 2.0.
272
-
273
- ### Listar as ferramentas disponíveis
274
-
275
- ```json
276
- {
277
- "jsonrpc": "2.0",
278
- "id": 1,
279
- "method": "tools/list"
280
- }
281
- ```
282
-
283
- ### Chamar uma ferramenta — Listar senadores de SP
284
-
285
- ```json
286
- {
287
- "jsonrpc": "2.0",
288
- "id": 2,
289
- "method": "tools/call",
290
- "params": {
291
- "name": "senado_listar_senadores",
292
- "arguments": {
293
- "uf": "SP",
294
- "emExercicio": true
295
- }
296
- }
297
- }
298
- ```
299
-
300
- ### Chamar uma ferramenta — Buscar matérias por palavra-chave
301
-
302
- ```json
303
- {
304
- "jsonrpc": "2.0",
305
- "id": 3,
306
- "method": "tools/call",
307
- "params": {
308
- "name": "senado_buscar_materias",
309
- "arguments": {
310
- "palavraChave": "inteligência artificial",
311
- "tramitando": true
312
- }
313
- }
314
- }
315
- ```
316
-
317
- ### Chamar uma ferramenta — Votações recentes do plenário
318
-
319
- ```json
320
- {
321
- "jsonrpc": "2.0",
322
- "id": 4,
323
- "method": "tools/call",
324
- "params": {
325
- "name": "senado_search_votacoes",
326
- "arguments": {
327
- "dias": 7
328
- }
329
- }
330
- }
331
- ```
332
-
333
- ### Chamar uma ferramenta — Ideias de cidadãos mais populares
334
-
335
- ```json
336
- {
337
- "jsonrpc": "2.0",
338
- "id": 5,
339
- "method": "tools/call",
340
- "params": {
341
- "name": "senado_ecidadania_listar_ideias",
342
- "arguments": {
343
- "ordenarPor": "apoios",
344
- "ordem": "desc",
345
- "status": "aberta"
346
- }
347
- }
348
- }
349
- ```
350
-
351
- ## Endpoints da API de origem (upstream)
352
-
353
- O servidor consome duas classes de endpoints upstream da API do Senado:
354
-
355
- ### Endpoints legados (sufixo `.json`, respostas em PascalCase)
356
-
357
- 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.
358
-
359
- | Caminho upstream | Usado por |
360
- |---------------|---------|
361
- | `/senador/lista/atual` | `senado_listar_senadores` |
362
- | `/senador/lista/legislatura/{legislatura}` | `senado_listar_senadores` (param `legislatura`) |
363
- | `/senador/{codigo}` (+ `/mandatos`) | `senado_obter_senador` (biografia + mandatos via chamada extra) |
364
- | `/senador/{codigo}/licencas`, `/comissoes`, `/cargos`, `/historicoAcademico`, `/filiacoes`, `/profissao` | `senado_senador_historico` (`tipo` enum) |
365
- | `/senador/afastados` | `senado_senadores_afastados` |
366
- | `/senador/{codigo}/apartes` | `senado_discursos_senador` (`tipo=apartes`) |
367
- | `/comissao/lista/colegiados` | `senado_listar_comissoes` (+ resolução sigla→código) |
368
- | `/comissao/{codigo}` | `senado_obter_comissao` (`secao=resumo`; código numérico, não sigla) |
369
- | `/composicao/comissao/{codigo}` (+ `?ativas=S`) | `senado_obter_comissao` (`secao=membros`) |
370
- | `/comissao/agenda/{data}` | `senado_agenda_comissoes` |
371
- | `/comissao/agenda/{dataInicio}/{dataFim}` | `senado_reunioes_comissao` |
372
- | `/comissao/reuniao/{codigoReuniao}` | `senado_reuniao_comissao` |
373
- | `/comissao/cpi/{sigla}/requerimentos` | `senado_requerimentos_cpi` (upstream costuma vir vazio mesmo para CPIs ativas — retorno vazio traz `aviso`) |
374
- | `/materia/distribuicao/autoria`, `/distribuicao/relatoria/{sigla}` | `senado_distribuicao_materias` |
375
- | `/plenario/agenda/dia/{data}`, `/agenda/mes/{data}`, `/agenda/cn/...` | `senado_agenda_plenario` |
376
- | `/plenario/resultado/{data}`, `/resultado/cn/{data}`, `/resultado/mes/{data}` | `senado_resultado_plenario` |
377
- | `/plenario/resultado/veto/{codigo}` (+ `/materia/`, `/dispositivo/`) | `senado_resultado_veto` |
378
- | `/plenario/votacao/orientacaoBancada/{data}` (+ período) | `senado_orientacao_bancada` |
379
- | `/plenario/encontro/{codigo}` (+ `/pauta`, `/resultado`, `/resumo`) | `senado_encontro_plenario` |
380
- | `/plenario/tiposSessao`, `/lista/tiposComparecimento`, `/lista/legislaturas` | `senado_tabelas_plenario` |
381
- | `/materia/vetos/{ano}`, `/vetos/aposrcn`, `/vetos/antesrcn`, `/vetos/encerrados` | `senado_vetos` |
382
- | `/taquigrafia/notas/{sessao\|reuniao}/{id}` | `senado_notas_taquigraficas` |
383
- | `/taquigrafia/videos/{sessao\|reuniao}/{id}` | `senado_videos_taquigrafia` |
384
- | `/senador/{codigo}/discursos` | `senado_discursos_senador` |
385
- | `/plenario/lista/discursos/{dataInicio}/{dataFim}` | `senado_discursos_plenario` |
386
- | `/discurso/texto-integral/{codigo}` | `senado_discurso_texto` (texto puro, buscado diretamente) |
387
- | `/senador/lista/tiposUsoPalavra` | `senado_tabelas_referencia` (`tabela=tipos-uso-palavra`) |
388
- | `/composicao/lista/blocos` | `senado_listar_blocos` |
389
- | `/composicao/bloco/{codigo}` | `senado_obter_bloco` |
390
- | `/composicao/lideranca` | `senado_liderancas` |
391
- | `/composicao/mesaSF` | `senado_mesa` (`casa=senado`) |
392
- | `/composicao/mesaCN` | `senado_mesa` (`casa=congresso`) |
393
- | `/orcamento/lista` | `senado_orcamento_parlamentar` (`tipo=emendas`) |
394
- | `/orcamento/oficios` | `senado_orcamento_parlamentar` (`tipo=oficios`) |
395
- | `/legislacao/lista` | `senado_buscar_legislacao` |
396
- | `/legislacao/{codigo}` | `senado_obter_legislacao` |
397
- | `/legislacao/tiposNorma` | `senado_tabelas_referencia` (`tabela=tipos-norma`) |
398
- | `/votacaoComissao/comissao/{sigla}` | `senado_votacao_comissao` (`por=comissao`) |
399
- | `/votacaoComissao/parlamentar/{codigo}` | `senado_votacao_comissao` (`por=senador`) |
400
- | `/votacaoComissao/materia/{sigla}/{numero}/{ano}` | `senado_votacao_comissao` (`por=materia`) |
401
- | `/autor/lista/atual` | `senado_autores_atuais` |
402
-
403
- ### Endpoints v3 (arrays/objetos JSON planos, camelCase)
404
-
405
- 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.
406
-
407
- | Caminho upstream | Usado por |
408
- |---------------|---------|
409
- | `/votacao` | `senado_obter_votacao`, `senado_search_votacoes`, `senado_votos_materia`, `senado_votacoes_senador` |
410
- | `/processo` | `senado_search_processos`, `senado_buscar_materias` |
411
- | `/processo/{id}` | `senado_obter_processo`, `senado_obter_materia` (`secao=detalhe`/`tramitacao`) |
412
- | `/processo/documento` | `senado_obter_materia` (`secao=textos`) |
413
- | `/processo/emenda` | `senado_processo_detalhe` (`secao=emendas`) |
414
- | `/processo/relatoria` | `senado_processo_detalhe` (`secao=relatorias`), `senado_obter_materia` (relator) |
415
- | `/processo/prazo` | `senado_processo_detalhe` (`secao=prazos`) |
416
- | `/processo/{siglas,assuntos,classes,destinos,entes,tipos-*}` | `senado_tabelas_processo` (12 tabelas de referência) |
417
-
418
- ### API administrativa (adm.senado.gov.br/adm-dadosabertos, JSON plano em snake_case)
419
-
420
- 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`.
421
-
422
- | Caminho upstream | Usado por |
423
- |---------------|---------|
424
- | `/api/v1/senadores/despesas_ceaps/{ano}` | `senado_ceaps` (~10 MB/ano, cacheado + agregado no Worker) |
425
- | `/api/v1/senadores/{auxilio-moradia,escritorios,aposentados}` | `senado_senadores_admin` (`tipo` enum) |
426
- | `/api/v1/servidores/servidores/{ativos,efetivos,comissionados,inativos}` | `senado_servidores` |
427
- | `/api/v1/servidores/remuneracoes/{ano}/{mes}` | `senado_remuneracoes_servidores` (~5.5 MB/mês) |
428
- | `/api/v1/servidores/horas-extras/{ano}/{mes}` | `senado_horas_extras` |
429
- | `/api/v1/servidores/quantitativos/*`, `/previsao-aposentadoria`, `/api/v1/senadores/quantitativos/senadores` | `senado_pessoal_tabelas` (quantitativos) |
430
- | `/api/v1/servidores/{estagiarios,pensionistas,lotacoes,cargos}` | `senado_pessoal_tabelas` (listas nominais) |
431
- | `/api/v1/contratacoes/contratos` (+ `/{id}/aditivos`) | `senado_contratos`, `senado_contratacao_detalhe` |
432
- | `/api/v1/contratacoes/{tipo}/{id}/{itens,pagamentos,garantias}` | `senado_contratacao_detalhe` |
433
- | `/api/v1/contratacoes/licitacoes` | `senado_licitacoes` |
434
- | `/api/v1/contratacoes/terceirizados` | `senado_terceirizados` |
435
- | `/api/v1/contratacoes/empresas` | `senado_empresas_contratadas` (~13 MB, exige filtro) |
436
- | `/api/v1/contratacoes/{atas_registro_preco,notas_empenho,menores_aprendizes}` | `senado_contratacoes_lista` |
437
- | `/api/v1/supridos/{ano}` (+ atosConcessao, empenhos, movimentacoes, transacoes) | `senado_suprimento_fundos` |
438
- | `senado.gov.br/bi-arqs/Arquimedes/Financeiro/{Despesa,Receitas}SenadoDadosAbertos.json` | `senado_execucao_orcamentaria` (feeds JSON diários, strings decimais brasileiras normalizadas) |
439
-
440
- ### e-Cidadania (em D1, atualizado por Cron)
441
-
442
- 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:
443
-
444
- - uma **GitHub Action semanal fora do Worker** é dona do **corpus completo** de cada entidade (veja abaixo) — a fonte da verdade;
445
- - 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.
446
-
447
- Ambos os escritores constroem os payloads pelos builders canônicos `buildXResumo` + `contentHash` compartilhado, então suas linhas são byte-idênticas. Cada escrita:
448
-
449
- - faz **upsert** em `ecidadania_current` (uma linha por item — o que as ferramentas leem),
450
- - **anexa** em `ecidadania_history` apenas quando o `content_hash` de um item muda (pronto para série temporal),
451
- - registra cada execução em `ecidadania_scrape_runs`.
452
-
453
- 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.
454
-
455
- 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.
456
-
457
- 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.
458
-
459
- #### Ingestão do corpus completo (fora do Worker, semanal)
460
-
461
- 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:
462
-
463
- - **`consultas`** — consultas abertas (detalhado abaixo).
464
- - **`eventos`** — audiências/eventos da listagem HTML `principalaudiencia?p=N`; o status vem direto do bloco da listagem (sem ponte por `/processo`).
465
- - **`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.
466
- - **`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 `data_vintage` da proveniência; fica **fora** do hash da linha (`consultaVotoCore`) para que a reingestão semanal com votos inalterados não suje o `_history` (o Senado republica o CSV periodicamente — confirmado em 20/07/2026 —, então o job semanal reingere o vintage corrente sob os mesmos guards de anomalia dos demais corpora). `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`).
467
-
468
- O job de `consultas` é a implementação de referência:
469
-
470
- `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:
471
-
472
- 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.
473
- 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.
474
- 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.
475
-
476
- 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:
477
-
478
- ```bash
479
- CLOUDFLARE_API_TOKEN=… npm run ingest:ecidadania # escreve scripts/ingest-ecidadania/out.sql
480
- npx wrangler d1 execute senado-ecidadania --remote --file=scripts/ingest-ecidadania/out.sql
481
- ```
482
-
483
- ## Cache
484
-
485
- ### Arquitetura de camadas
486
-
487
- | Camada | Armazenamento | Escopo | Faixa de TTL | Finalidade |
488
- |-------|---------|-------|-----------|---------|
489
- | **L0** | `Map` em memória | Por isolate | 30-300s | Ultrarrápido, elimina requisições redundantes dentro de um isolate do Worker |
490
- | **L1** | Cloudflare Cache API (`caches.default`) | Por colo (PoP) | 60-600s | Compartilhado entre requisições no mesmo edge |
491
- | **L2** | KV (opcional) | Global | Variável | Reservado para dados raros e de baixa escrita |
492
-
493
- ### Categorias de cache
494
-
495
- | Categoria | L0 TTL | L1 TTL | Usado para |
496
- |----------|--------|--------|----------|
497
- | **STATIC** | 300s | 600s | Tipos de legislação, referência estática |
498
- | **SEMI_STATIC** | 120s | 300s | Lista de partidos, lista de UFs, detalhes de comissão |
499
- | **DYNAMIC** | 30s | 60s | Agendas, votações recentes, listas de reuniões |
500
- | **ON_DEMAND** | 30s | 120s | Consultas específicas de matéria/senador/votação |
501
-
502
- ### Abordagem de cache de POST
503
-
504
- 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:
505
-
506
- 1. **Hash dos parâmetros** — Nome da ferramenta + parâmetros ordenados são hasheados com SHA-256
507
- 2. **Chave GET sintética** — Uma URL sintética `https://senado-br-mcp.internal/__cache/{tool}/{hash}` é construída
508
- 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
509
-
510
- Esse cache acontece no **nível da ferramenta** (dentro do callback de cada ferramenta), não no nível do transporte MCP.
511
-
512
- ## Proveniência
513
-
514
- **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). Desde a **v3.5.0** o envelope implementa o **contrato de proveniência v1.0** do portfólio ([`@sbissoli/mcp-provenance`](https://www.npmjs.com/package/@sbissoli/mcp-provenance)): o servidor monta e valida um modelo canônico completo por resposta e emite a projeção **`concise`** — bloco de 6 chaves em ordem fixa, com `null` explícito quando a fonte não expõe o valor. O bloco fica em `structuredContent.provenance` e é espelhado como um rodapé compacto de fonte no texto (linha de fonte, linha de licença e o aviso de que a referência completa pode ser solicitada na própria conversa) — o JSON dos dados **não** é duplicado com o envelope, mantendo o custo de tokens por resposta baixo.
515
-
516
- Campos do bloco `concise` (por resposta — uma ferramenta, uma fonte): `source`, `source_url` (URL canônica consultada), `data_vintage` (competência/vintage do dado; chamava-se `reference_period` antes da v3.5.0), `retrieved_at` (ISO-8601 da extração no upstream — preservado mesmo em cache-hit, o diferenciador nível-1), `citation` (citação pronta) e `license`. O modelo canônico por trás do bloco também carrega `dataset.id`, `api_version` e `field_sources` por campo — validados a cada build e refletidos na lista `attribution` (todas as `source_url` distintas da resposta), que acompanha o bloco no `structuredContent`.
517
-
518
- 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.
519
-
520
- ## Conjunto de dados citável (participação no e-Cidadania)
521
-
522
- Além do servidor ao vivo, este projeto publica um **conjunto de dados congelado, versionado e citável** da camada de participação do e-Cidadania (consultas públicas, ideias legislativas, eventos interativos + seus comentários, votos históricos por estado) — a camada que o pacote R `congressbr` nunca cobriu. Cada valor carrega um envelope de procedência por campo (`{ value, sourceEndpoint, sourceField, retrievedAt, license, schemaVersion }`); a licença dos dados (Dados Abertos do Senado Federal) é mantida **separada** da licença do código (MIT).
523
-
524
- - **Como citar** — [`CITATION.cff`](CITATION.cff) (conjunto de dados; cite o DOI da versão do snapshot que você usou, e o DOI de conceito para o conjunto através das versões).
525
- - **O que vai em cada release** — [`CHANGELOG-dataset.md`](CHANGELOG-dataset.md) (cumulativo, só acrescenta; amarra cada release ao seu `schemaVersion`).
526
- - **Dicionário de variáveis e procedência de campo** — [`docs/dataset-dictionary.md`](docs/dataset-dictionary.md) (gerado de `src/dataset/schema.ts`, a fonte única de verdade).
527
- - **Licença dos dados** — [`LICENSE-DATA.md`](LICENSE-DATA.md).
528
- - **Como cortar uma release** (congelar → checksums → GitHub Release → DOI no Zenodo) — [`docs/release-runbook.md`](docs/release-runbook.md); a maquinaria está em `src/dataset/`, `scripts/build-dataset/` e `.github/workflows/release-dataset.yml`.
529
-
530
- ### Inventário — schema v2 (`schemaVersion` `2.0.0`)
531
-
532
- Cada release entrega um recurso NDJSON por entidade (um `HarmonizedRecord` por linha: identidade + um envelope de procedência por campo), mais um manifesto `datapackage.json` e uma cópia do dicionário. Cinco recursos:
533
-
534
- | Recurso (`*.ndjson`) | Grão | Variáveis principais | Fonte(s) |
535
- |---|---|---|---|
536
- | `consultas` | 1 consulta pública (matéria) | `materia`, `ementa`, `votosSim`/`votosNao`/`totalVotos`, `percentual*`, **`autoria`ⁿ**, **`relator`ⁿ**, `status`, `url`, `firstSeenAt` | listagem `pesquisamateria` + **detalhe** (`visualizacaomateria`)ⁿ + `/processo?tramitando=S` para o status |
537
- | `ideias` | 1 ideia legislativa (~113,7 mil) | `titulo`, `apoios`, `status`, **`dataPublicacao`ⁿ**, **`autorUf`ⁿ**, **`descricao`ⁿ**, **`plConvertido`ⁿ**, `url`, `firstSeenAt` | listagem `pesquisaideia` + **detalhe** (`visualizacaoideia`) por um backfill retomávelⁿ |
538
- | `eventos` | 1 evento interativo (audiência) | `titulo`, **`data`ᶜ**, **`hora`ᶜ**, `comissao`, **`comissaoNomeCompleto`ⁿ**, **`local`ⁿ**, **`descricao`ⁿ**, **`pauta`ⁿ**, **`convidados`ⁿ**, **`videoUrl`ⁿ**, **`comentarios`ᶜ**, `status`, `url`, `firstSeenAt` | listagem `principalaudiencia` + **detalhe** (`visualizacaoaudiencia`)ⁿ + **fragmento AJAX de comentários**ᶜ |
539
- | **`eventos_comentarios`ⁿ** | 1 comentário (nível de comentário) | `eventoId`, `comentarioId`, `uf`, `texto`, `data`, `hora`, `momentoVideoUrl`, `convidadoAssociado` | fragmento AJAX `ajaxcolecaocomentarioaudiencia?audienciaId=` |
540
- | `consultas_votos` | 1 matéria (acervo histórico) | `materia`, `ementa`, `autoria`, `votosSim`/`votosNao`/`totalVotos`, `votosPorUf`, `status`, `url`, `referencePeriod` | CSV do Arquimedes `Proposições-com-votos.csv` (reingerido semanalmente) |
541
-
542
- **ⁿ = novo ou reaberto na v2 · ᶜ = fonte corrigida para a canônica na v2.** O que a v2 (`2.0.0`) mudou — a ingestão saiu de **só listagem** para **listagem + detalhe (+ comentários por AJAX nos eventos)**:
543
-
544
- - **Eventos corrigidos e enriquecidos.** `data`/`hora` agora vêm da página de detalhe (a canônica — o [estudo A3](docs/estudo-a3-reconciliacao-eventos.md) achou a listagem divergente em 57% dos casos no `hora`), mais seis campos novos de detalhe (`comissaoNomeCompleto`, `local`, `descricao`, `pauta`, `convidados`, `videoUrl`). `comentarios` passou a ser a **contagem canônica do AJAX** (a contagem da listagem era `0` espúrio em 82% dos eventos, capturando só ~6,7% do engajamento).
545
- - **Recurso novo em nível de comentário**, `eventos_comentarios` — uma linha por comentário de audiência, o sinal de participação que ninguém mais publica versionado.
546
- - **Campos que só existem no detalhe foram reabertos** para `ideias` (`dataPublicacao`, `autorUf`, `descricao`, `plConvertido`) e `consultas` (`autoria`, `relator`) — antes sempre `null` por decisão de projeto.
547
- - **Postura de privacidade pela origem do dado.** Conteúdo de cidadão (comentários de audiência, autores de ideia) guarda **apenas a UF — nunca o nome**, descartado já no parser; agente público (autoria/relatoria de consulta, convidados de evento) guarda o nome (público pela função). O racional campo a campo está em `docs/schema-v2-inventario.md` (alvo aprovado).
548
-
549
- O NDJSON congelado **não** é commitado (é construído sob demanda a partir do corpus soberano no D1); uma release marcada `dataset-v*` anexa o tarball + `SHA256SUMS` + `release.json` e os arquiva no Zenodo.
550
-
551
- ## Inventário de ferramentas
552
-
553
- ### Grupo H — Referência/Metadados (1 ferramenta)
554
-
555
- | Ferramenta | Descrição |
556
- |------|-------------|
557
- | `senado_tabelas_referencia` | Tabelas de referência via `tabela` enum: tipos-materia, partidos, ufs, legislatura-atual, tipos-norma, tipos-uso-palavra |
558
-
559
- ### Grupo A — Senadores (5 ferramentas)
560
-
561
- | Ferramenta | Descrição |
562
- |------|-------------|
563
- | `senado_listar_senadores` | Lista senadores em exercício/por legislatura, com filtros `nome` (busca parcial sem acento), `uf` e `partido` |
564
- | `senado_obter_senador` | Detalhe biográfico de um senador: bio, mandatos, partido, contato |
565
- | `senado_votacoes_senador` | Como um senador votou em cada matéria (via v3 `/votacao`) |
566
- | `senado_senador_historico` | Histórico funcional via `tipo` enum: licencas, comissoes, cargos, historico-academico, filiacoes, profissoes |
567
- | `senado_senadores_afastados` | Senadores atualmente afastados (fora de exercício) |
568
-
569
- ### Grupo B — Matérias (2 ferramentas, backend v3)
570
-
571
- | Ferramenta | Descrição |
572
- |------|-------------|
573
- | `senado_buscar_materias` | Busca matérias por tipo, número, ano, palavra-chave, autor ou tramitação (via v3 `/processo`) |
574
- | `senado_obter_materia` | Dados de uma matéria via `secao` enum: detalhe (situação/relator), tramitacao (histórico) ou textos (documentos) |
575
-
576
- ### Grupo C — Processos (5 ferramentas)
577
-
578
- | Ferramenta | Descrição |
579
- |------|-------------|
580
- | `senado_search_processos` | Busca processos legislativos (complementar à busca de matérias) |
581
- | `senado_obter_processo` | Detalhes completos de um processo legislativo específico |
582
- | `senado_processo_detalhe` | Aspecto de um processo via `secao` enum: emendas, relatorias ou prazos |
583
- | `senado_autores_atuais` | Parlamentares autores de processos em tramitação, ordenados por produção |
584
- | `senado_tabelas_processo` | 12 tabelas de referência (siglas, assuntos, classes, tipos-*) via `tabela` enum |
585
-
586
- ### Grupo D — Votações (3 ferramentas)
587
-
588
- | Ferramenta | Descrição |
589
- |------|-------------|
590
- | `senado_obter_votacao` | Detalhes de uma votação com votos nominais. Aceita `codigoVotacao` (codigoSessao da sessão plenária). |
591
- | `senado_votos_materia` | Votações de uma matéria (via v3 `/votacao?codigoMateria`), com votos nominais opcionais |
592
- | `senado_search_votacoes` | Busca/listagem flexível de votações do plenário por `dias`, período, processo, matéria ou senador |
593
-
594
- ### Grupo E — Comissões (7 ferramentas)
595
-
596
- | Ferramenta | Descrição |
597
- |------|-------------|
598
- | `senado_listar_comissoes` | Lista comissões (colegiados) ativas, filtráveis por tipo |
599
- | `senado_obter_comissao` | Dados de uma comissão via `secao` enum: resumo (mesa/totais) ou membros (composição). Resolve sigla para código internamente. |
600
- | `senado_reunioes_comissao` | Reuniões de uma comissão num período (lida com intervalos entre anos) |
601
- | `senado_agenda_comissoes` | Agenda de reuniões de todas as comissões numa data |
602
- | `senado_reuniao_comissao` | Detalhe completo de uma reunião: partes, itens, convidados, resultados, links pauta/ata |
603
- | `senado_requerimentos_cpi` | Requerimentos protocolados numa CPI em atividade, paginados (upstream costuma vir vazio mesmo para CPIs ativas; retorno vazio traz `aviso`) |
604
- | `senado_distribuicao_materias` | Estatísticas de carga por senador numa comissão: autoria ou relatoria |
605
-
606
- ### Grupo F — Plenário (7 ferramentas)
607
-
608
- | Ferramenta | Descrição |
609
- |------|-------------|
610
- | `senado_agenda_plenario` | Agenda do plenário — por dia, mês ou Congresso (escopo dia/mes/cn) |
611
- | `senado_resultado_plenario` | Resultados de sessão: itens deliberados, pareceres, desfechos (SF/CN/mês) |
612
- | `senado_orientacao_bancada` | Orientações de voto das lideranças por votação, com placar |
613
- | `senado_vetos` | Vetos presidenciais por ano ou situação de tramitação |
614
- | `senado_resultado_veto` | Resultados nominais de votação de veto (por veto, matéria vetada ou dispositivo) |
615
- | `senado_encontro_plenario` | Detalhe de sessão legislativa, itens de pauta, resultados ou resumo |
616
- | `senado_tabelas_plenario` | Tipos de sessão, tipos de comparecimento, lista de legislaturas |
617
-
618
- ### Grupo G — e-Cidadania (9 ferramentas)
619
-
620
- | Ferramenta | Descrição |
621
- |------|-------------|
622
- | `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`) |
623
- | `senado_ecidadania_obter_consulta` | Detalhe de uma consulta: votos, autor, relator, comentários |
624
- | `senado_ecidadania_consultas_analise` | Analisa o conjunto completo de consultas **abertas** via `modo` (consenso/polarizada); `status` padrão `aberta` |
625
- | `senado_ecidadania_listar_ideias` | Ideias legislativas de cidadãos; ranking das mais apoiadas via `ordenarPor: apoios` |
626
- | `senado_ecidadania_obter_ideia` | Detalhe de uma ideia: texto, apoios, status de conversão em projeto |
627
- | `senado_ecidadania_listar_eventos` | Eventos interativos (audiências, sabatinas, lives); ranking dos mais comentados via `ordenarPor` |
628
- | `senado_ecidadania_obter_evento` | Detalhe de um evento: pauta, convidados, link de vídeo |
629
- | `senado_ecidadania_sugerir_tema_enquete` | Sugere temas para enquete mensal a partir de critérios configuráveis |
630
- | `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` |
631
-
632
- ### Grupo I — Discursos (3 ferramentas)
633
-
634
- | Ferramenta | Descrição |
635
- |------|-------------|
636
- | `senado_discursos_senador` | Pronunciamentos de um senador via `tipo` enum: discursos (próprios) ou apartes (intervenções) |
637
- | `senado_discursos_plenario` | Todos os discursos em plenário num intervalo de datas |
638
- | `senado_discurso_texto` | Texto integral de um pronunciamento/discurso específico |
639
-
640
- ### Grupo J — Blocos e Lideranças (4 ferramentas)
641
-
642
- | Ferramenta | Descrição |
643
- |------|-------------|
644
- | `senado_listar_blocos` | Blocos parlamentares do Senado e seus partidos membros |
645
- | `senado_obter_bloco` | Detalhes de um bloco parlamentar específico |
646
- | `senado_liderancas` | Lideranças do Senado/Congresso (líderes, vice-líderes), filtráveis |
647
- | `senado_mesa` | Membros da Mesa Diretora via `casa` enum: senado (Mesa do SF) ou congresso (Mesa do CN) |
648
-
649
- ### Grupo K — Orçamento (1 ferramenta)
650
-
651
- | Ferramenta | Descrição |
652
- |------|-------------|
653
- | `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) |
654
-
655
- ### Grupo L — Legislação Federal (2 ferramentas)
656
-
657
- | Ferramenta | Descrição |
658
- |------|-------------|
659
- | `senado_buscar_legislacao` | Busca normas jurídicas federais por tipo, número, ano ou data (ao menos um obrigatório) |
660
- | `senado_obter_legislacao` | Detalhes de uma norma jurídica federal específica |
661
-
662
- ### Grupo M — Votação em Comissão (1 ferramenta)
663
-
664
- | Ferramenta | Descrição |
665
- |------|-------------|
666
- | `senado_votacao_comissao` | Votações em comissões via `por` enum: comissao, senador ou materia; período opcional |
667
-
668
- ### Grupo N — Taquigrafia (2 ferramentas)
669
-
670
- | Ferramenta | Descrição |
671
- |------|-------------|
672
- | `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 |
673
- | `senado_videos_taquigrafia` | Unidades de vídeo/áudio por sessão ou reunião, com orador e links de mídia |
674
-
675
- ### Grupo O — Senadores/Administrativo (2 ferramentas)
676
-
677
- | Ferramenta | Descrição |
678
- |------|-------------|
679
- | `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 |
680
- | `senado_senadores_admin` | Dados administrativos dos senadores via `tipo` enum: auxilio-moradia, escritorios-apoio ou aposentados |
681
-
682
- ### Grupo P — Servidores / Gestão de Pessoas (4 ferramentas)
683
-
684
- | Ferramenta | Descrição |
685
- |------|-------------|
686
- | `senado_servidores` | Servidores por situação (ativos/efetivos/comissionados/inativos), filtráveis por nome, unidade, cargo |
687
- | `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` |
688
- | `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` |
689
- | `senado_pessoal_tabelas` | Tabelas de pessoal via `tabela` enum: quantitativos (pessoal, cargos-funcoes, previsao-aposentadoria, senadores) e listas (estagiarios, pensionistas, lotacoes, cargos) |
690
-
691
- ### Grupo Q — Contratações (6 ferramentas)
692
-
693
- | Ferramenta | Descrição |
694
- |------|-------------|
695
- | `senado_contratos` | Contratos filtrados no Worker sobre a base completa (sem acento): fornecedor, CNPJ, ano, número, objeto, mão de obra |
696
- | `senado_contratacao_detalhe` | Itens, pagamentos, garantias, aditivos ou ativações de um contrato/ata/empenho |
697
- | `senado_licitacoes` | Licitações por número ou texto do objeto |
698
- | `senado_terceirizados` | Colaboradores terceirizados por nome, empresa ou unidade |
699
- | `senado_empresas_contratadas` | Empresas que contratam com o Senado (exige filtro por nome/CNPJ) |
700
- | `senado_contratacoes_lista` | Atas de registro de preço, notas de empenho, menores aprendizes |
701
-
702
- ### Grupo R — Suprimento de Fundos (1 ferramenta)
703
-
704
- | Ferramenta | Descrição |
705
- |------|-------------|
706
- | `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` |
707
-
708
- ### Grupo S — Orçamento do Senado (1 ferramenta)
709
-
710
- | Ferramenta | Descrição |
711
- |------|-------------|
712
- | `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` |
713
-
714
- ### Grupo T — Estrutura Organizacional (1 ferramenta)
715
-
716
- Lê um retrato embutido da árvore organizacional do Senado (varrida do portal institucional até o nível de serviço por `npm run ingest:estrutura`), porque a API de dados abertos só publica unidades até Secretaria e nunca liga uma unidade-folha ao pai dela. Unidades que o portal lista apenas por nome, sem página própria (os núcleos da CONLEG/CONORF), são capturadas como nós sintéticos a partir da listagem indentada da página. Órgãos do Congresso onde o cadastro de servidores registra lotações (CMO, CPCMS, CMMC) vêm de um complemento curado (`src/estrutura/complemento-cn.ts`, fonte pública: congressonacional.leg.br) sob uma raiz **Congresso Nacional** (`CN`) separada — nunca sob a árvore do Senado, de modo que `subordinadasA: "DGER"` os exclui e `subordinadasA: "CN"` os conta. Servidores registrados sob as pseudo-unidades situacionais "Servidores Afastados/em Trânsito - SF" são reportados à parte, como `afastadosOuEmTransito`, por `senado_servidores`.
717
-
718
- | Ferramenta | Descrição |
719
- |------|-------------|
720
- | `senado_estrutura_organizacional` | Organograma resolvido para uma `unidade` (sigla como `DGER` ou nome): devolve o `caminho` (ancestrais) e todas as unidades subordinadas (`subordinadas[]` — secretarias, coordenações, serviços, núcleos — com `nivel`). Faz par com o filtro `subordinadasA` de `senado_servidores`, que conta/lista todos os servidores sob uma diretoria inteira (o servidor fica num serviço-folha, então filtrar `lotacao` pela sigla do pai devolve 0). |
721
-
722
- ### Grupo U — Deep Research (2 ferramentas)
723
-
724
- O [contrato Deep Research da OpenAI](#chatgpt-deep-research): as únicas duas ferramentas sem o prefixo `senado_`, porque os nomes são fixados pelo contrato. Registradas pelo mesmo shim das outras (annotations somente-leitura, `outputSchema` permissivo, telemetria por ferramenta) e servidas só em `/mcp` — o perfil curado do app do ChatGPT não as inclui. O índice (senadores em exercício + comissões ativas, ~300 documentos) é construído no primeiro uso a partir dos mesmos dois endpoints de lista que as ferramentas `senado_listar_*` leem, e mantido por 24 h.
725
-
726
- | Ferramenta | Descrição |
727
- |------|-------------|
728
- | `search` | Ranqueia a consulta (linguagem natural ou palavras-chave, pt/en, sem distinguir acentos) contra senadores em exercício e comissões ativas; devolve até 10 `{ id, title, url }` — `sen:<código>` com a URL do perfil público, `com:<código>` com a página pública da comissão. Proveniência das duas listas em `structuredContent`/`_meta`. |
729
- | `fetch` | Devolve o documento de um id vindo de `search` como `{ id, title, text, url, metadata }`: a biografia e os mandatos do senador (a mesma leitura de `senado_obter_senador`) ou o resumo e a mesa da comissão (a mesma leitura de `senado_obter_comissao`), em Markdown, com a proveniência dessa leitura. Id desconhecido → erro. |
730
-
731
- **Total: 69 ferramentas**
732
-
733
- ### Prompts (4)
734
-
735
- Templates de workflow reutilizáveis em pt-BR (capacidade MCP `prompts`), definidos em `src/prompts.ts`:
736
-
737
- | Prompt | Args | O que orienta |
738
- | --- | --- | --- |
739
- | `senado_gastos_senador` | `senador`, `ano` | Resolve o senador e agrega/detalha despesas CEAPS. |
740
- | `senado_tramitacao_materia` | `sigla`, `numero`, `ano` | Obtém situação atual + histórico de tramitação da matéria. |
741
- | `senado_votos_senador` | `senador`, `periodo?` | Lista os votos nominais do senador no período. |
742
- | `senado_panorama_ecidadania` | — | Consolida consultas (consenso/polarização), ideias e eventos populares. |
743
-
744
- ### Recursos (5)
745
-
746
- Documentos/tabelas de contexto estáticos (capacidade MCP `resources`), definidos em `src/resources.ts`:
747
-
748
- | URI | Tipo | Conteúdo |
749
- | --- | --- | --- |
750
- | `senado://guia` | markdown | Visão geral e qual ferramenta usar por objetivo. |
751
- | `senado://catalogo` | markdown | As 69 ferramentas agrupadas por domínio. |
752
- | `senado://glossario` | markdown | Siglas e termos do Senado (PEC, CEAPS, CCJ, RCN…). |
753
- | `senado://tabelas/tipos-materia` | json | Tipos de proposição (sigla/nome/descrição). |
754
- | `senado://tabelas/ufs` | json | As 27 unidades federativas. |
755
-
756
- ## Estrutura do projeto
757
-
758
- ```
759
- src/
760
- ├── index.ts # Entrypoint do Worker (handler de fetch + handler scheduled/Cron)
761
- ├── server.ts # Fábrica do McpServer (cria instância por requisição)
762
- ├── auth.ts # Auth Bearer token opcional (comparação em tempo constante)
763
- ├── metrics.ts # Contadores em memória servidos em /metrics
764
- ├── types.ts # Env, categorias de cache, constantes de salvaguarda
765
- ├── cache/
766
- │ ├── l0-memory.ts # Cache Map em memória com TTL + evicção LRU
767
- │ ├── l1-cache-api.ts # Wrapper da Cloudflare Cache API (chaves GET sintéticas)
768
- │ └── manager.ts # Orquestrador de cache (L0 → L1 → upstream)
769
- ├── throttle/
770
- │ ├── token-bucket.ts # Rate limiter token bucket (global + por cliente)
771
- │ └── upstream.ts # Fetch upstream com limite de concorrência, retry, timeout
772
- ├── scraper/
773
- │ ├── ecidadania.ts # Scraper isolado do e-Cidadania (listas REST + detalhe HTML por regex; buildConsultaResumo)
774
- │ ├── pipeline.ts # Cron de 2h: splice de métrica direcionado (consultas/eventos/ideias); corpora são dos jobs semanais
775
- │ ├── anomaly.ts # Classificação de execução (execução anômala nunca sobrescreve current)
776
- │ └── store.ts # Leituras D1 (resolveList + staleness por entidade, lastGoodRunAt) + write-through de detalhe
777
- ├── instrument.ts # Telemetria de chamadas por ferramenta (memória + Analytics Engine)
778
- ├── utils/
779
- │ ├── logger.ts # Logging estruturado em JSON
780
- │ └── validation.ts # helpers toolResult, toolError, errorFrom, buildParams, ensureArray
781
- └── tools/
782
- ├── referencia.ts # Grupo H — 1 ferramenta de referência/metadados
783
- ├── senadores.ts # Grupo A — 5 ferramentas de senadores
784
- ├── materias.ts # Grupo B — 2 ferramentas de matérias (backend v3)
785
- ├── processos.ts # Grupo C — 5 ferramentas de processos
786
- ├── votacoes.ts # Grupo D — 3 ferramentas de votações
787
- ├── comissoes.ts # Grupo E — 7 ferramentas de comissões
788
- ├── plenario.ts # Grupo F — 7 ferramentas de plenário
789
- ├── ecidadania.ts # Grupo G — 9 ferramentas do e-Cidadania (leem do D1; veja scraper/)
790
- ├── discursos.ts # Grupo I — 3 ferramentas de discursos
791
- ├── composicao.ts # Grupo J — 4 ferramentas de blocos/lideranças
792
- ├── orcamento.ts # Grupo K — 1 ferramenta de orçamento
793
- ├── legislacao.ts # Grupo L — 2 ferramentas de legislação federal
794
- ├── votacao-comissao.ts # Grupo M — 1 ferramenta de votação em comissão
795
- ├── taquigrafia.ts # Grupo N — 2 ferramentas de notas taquigráficas
796
- ├── senadores-admin.ts # Grupo O — 2 ferramentas administrativas de senadores (CEAPS, moradia)
797
- ├── servidores.ts # Grupo P — 4 ferramentas de pessoal
798
- ├── contratacoes.ts # Grupo Q — 6 ferramentas de contratações
799
- ├── supridos.ts # Grupo R — 1 ferramenta de suprimento de fundos
800
- └── orcamento-senado.ts # Grupo S — 1 ferramenta de execução orçamentária
801
- scripts/
802
- └── ingest-ecidadania/ # Ingestão semanal do corpus completo de consultas, fora do Worker (via `npm run ingest:ecidadania`)
803
- ├── index.ts # Orquestrador: crawl → status (/processo) → normaliza → guards → out.sql
804
- ├── listing.ts # Parser puro da listagem (parseConsultaListingPage, findLastPage)
805
- ├── status.ts # conjunto tramitando=S de /processo → aberta/encerrada (deriveStatus)
806
- ├── restatus.ts # Correção de linger: re-status das linhas armazenadas por presença em /processo (fecha zumbis)
807
- ├── http.ts # Fetch educado (retry/backoff) para o crawl não supervisionado
808
- ├── d1.ts # Pré-leituras do D1 (meta existente, payloads, últimas boas linhas) via wrangler
809
- └── sql.ts # Geração do out.sql (espelha SQL.upsert/SQL.history; reusa SyncRecord)
810
- .github/workflows/ # publish-mcp.yml (registry) + ingest-ecidadania.yml (carga semanal do corpus no D1)
811
- migrations/ # Schema D1 (0001 tabelas, 0002 índices) para o pipeline do e-Cidadania
812
- tests/ # Testes unitários Vitest espelhando src/ (parsers, cache, throttle, auth, scraper,
813
- # pipeline/anomaly/store, listing/sql/highlights, além de testes de contrato do e-Cidadania)
814
- ```
815
-
816
- ## Variáveis de ambiente
817
-
818
- | Variável | Obrigatória | Padrão | Descrição |
819
- |----------|----------|---------|-------------|
820
- | `SENADO_BASE_URL` | Não | `https://legis.senado.leg.br/dadosabertos` | URL base da API legislativa |
821
- | `SENADO_ADM_BASE_URL` | Não | `https://adm.senado.gov.br/adm-dadosabertos` | URL base da API administrativa |
822
- | `ALLOWED_ORIGIN` | Não | `*` | Origem permitida no CORS |
823
- | `API_KEY` | Não (secret) | — | Quando definido, exige `Authorization: Bearer <key>` em todas as requisições exceto `/health`, `/metrics` e preflight CORS |
824
- | `CACHE_KV` | Sim (binding) | — | Namespace KV para o cache L2 |
825
- | `ECIDADANIA_DB` | Sim (binding) | — | Banco D1 para o pipeline do e-Cidadania (persistência de listas + histórico) |
826
- | `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 |
827
- | `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 |
828
- | `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 |
829
- | `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 |
830
- | `SENADO_ANALYTICS` | Não (binding) | — | Dataset do Analytics Engine para telemetria de chamadas por ferramenta |
831
-
832
- ## Conectando clientes MCP
833
-
834
- Este é um servidor **remoto** (Streamable HTTP, sem instalação, acesso aberto) — aponte qualquer cliente MCP para
835
- `https://senado.sidneybissoli.com/mcp`. Além das 69 ferramentas, ele expõe **prompts** (workflows prontos em pt-BR:
836
- `senado_gastos_senador`, `senado_tramitacao_materia`, `senado_votos_senador`,
837
- `senado_panorama_ecidadania`) e **recursos** (`senado://guia`, `senado://catalogo`,
838
- `senado://glossario`, `senado://tabelas/tipos-materia`, `senado://tabelas/ufs`).
839
-
840
- ### Um clique (LobeHub)
841
-
842
- Instale pelo marketplace do LobeHub — abra a
843
- [página do servidor](https://lobehub.com/mcp/sidneybissoli-senado-br-mcp-cloudflare) e clique em **Install**
844
- (ele pré-preenche o endpoint remoto, sem config necessária).
845
-
846
- ### Claude Desktop / Claude Code
847
-
848
- Adicione à sua configuração MCP:
849
-
850
- ```json
851
- {
852
- "mcpServers": {
853
- "senado-br": {
854
- "url": "https://senado.sidneybissoli.com/mcp"
855
- }
856
- }
857
- }
858
- ```
859
-
860
- Para clientes baseados em comando (ou qualquer cliente sem suporte remoto nativo), use a ponte `mcp-remote`:
861
-
862
- ```json
863
- {
864
- "mcpServers": {
865
- "senado-br": {
866
- "command": "npx",
867
- "args": ["-y", "mcp-remote", "https://senado.sidneybissoli.com/mcp"]
868
- }
869
- }
870
- }
871
- ```
872
-
873
- ### MCP Inspector
874
-
875
- ```bash
876
- npx @modelcontextprotocol/inspector https://senado.sidneybissoli.com/mcp
877
- ```
878
-
879
- ## Licença
880
-
881
- MIT
882
-
883
- ## Créditos
884
-
885
- Ícone: *"Amanhecer no Congresso Nacional"* — fotografia do Congresso Nacional
886
- brasileiro, usada sob licença Creative Commons. (Se você é o autor, abra uma
887
- issue para adicionarmos a atribuição completa / o link da licença.)