senado-br-mcp 3.18.4 → 3.18.5

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
@@ -553,18 +553,24 @@ Coverage spans all four upstream sources, each with its own `source`/`citation`/
553
553
  - **Senado Federal — Execução Orçamentária e Financeira** — Arquimedes/Financeiro feed at `senado.gov.br`
554
554
  - **Senado Federal — Portal e-Cidadania** — `www12.senado.leg.br/ecidadania`
555
555
 
556
- Fields of the `concise` block (per response — one tool, one source; keys in this fixed order, `null` when the source does not expose the value):
556
+ Fields of the `concise` block (contract v1.3 since 3.18.5; per response — one tool, one source; keys in this fixed order; the first seven are always present, with `null` when the source does not expose the value; the optional ones are **absent**, never empty, when they do not apply):
557
557
 
558
558
  | Field | Meaning |
559
559
  |-------|---------|
560
560
  | `source` | Official source name (e.g. *Senado Federal — Dados Abertos (Legislativo)*) |
561
561
  | `source_url` | Canonical endpoint/item URL consulted (e.g. `…/processo/{id}`) |
562
562
  | `data_vintage` | Vintage/competência of the data (e.g. `2024-03-15`, `2019`) — named `reference_period` before v3.5.0 |
563
- | `retrieved_at` | ISO-8601 of the **upstream extraction** — carried through the cache, so it reflects when the data was actually fetched, not the build or the cache-hit time |
563
+ | `retrieved_at` | ISO-8601 of the **upstream extraction** — carried through the cache, so it reflects when the data was actually fetched, not the build or the cache-hit time; on merged responses, the oldest of the parts |
564
+ | `retrieval` | Measured diagnostics of the trip to the source (attempts, outcome), or `null` when nothing was fetched in the call (pure cache, local data) — since 3.11.0 (v1.1) |
564
565
  | `citation` | Ready-to-use citation string (human-readable) |
565
566
  | `license` | Source terms (Dados Abertos do Senado Federal) |
567
+ | `field_sources` | *Optional.* Per-field sub-sources, each with its own extraction instant — only on responses that merge reads (v1.2, since 3.17.0; see below) |
568
+ | `derived` / `derivation_note` | *Optional.* `true` + a fixed note when the server computed the values — the `estatisticas` modes (distribution, aggregates, rankings) of `senado_remuneracoes_servidores`, `senado_horas_extras`, `senado_ceaps`, `senado_execucao_orcamentaria` and `senado_suprimento_fundos`; the individual values they cite remain the Senate's own |
569
+ | `revision` | Whether the figure may still change at the source: `status` is `current` for every Senate source (the version in force at extraction; none is claimed `final`), and `note` says, for the administrative and budget sources, that the Senate may correct published data later |
566
570
 
567
- The canonical model behind the block also carries `dataset.id` (item/series identifier, e.g. `codigoMateria=137808`) and `api_version`; those are validated on every build and inform `attribution` (below), but are not part of the `concise` projection. Per-field `field_sources` are (contract v1.2, since 3.17.0), on the responses that merge reads.
571
+ No Senate source publishes notices alongside the data, so `notices` (also part of v1.3) does not appear. The text footer gains a line only for exceptions — here, the computed-values line on the `estatisticas` modes.
572
+
573
+ The canonical model behind the block also carries `dataset.id` (item/series identifier, e.g. `codigoMateria=137808`) and `api_version`; those are validated on every build and inform `attribution` (below), but are not part of the `concise` projection.
568
574
 
569
575
  In addition to the `provenance` envelope, `structuredContent` carries a top-level **`attribution`** list — the distinct source URLs behind the response. This mirrors the naming proposed in [modelcontextprotocol#711](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/711) (where `attribution` is a list of source references at the response level), so the server stays forward-compatible if that RFC lands; the richer `provenance` object remains this server's own extension.
570
576
 
@@ -134,7 +134,7 @@ export function parseDocumentoProcesso(d) {
134
134
  * também entra como sub-fonte: o `retrieved_at` do topo é derivado pelo adaptador como o
135
135
  * MAIS ANTIGO das três (contrato §3) e, sem este item, o instante do detalhe sumiria do
136
136
  * bloco quando o resumo fosse mais velho. Antes da 3.17.0 o topo era o fetch do detalhe,
137
- * feito DEPOIS das sub-fontes — com a v1.2 ligada, a lib lançaria e a tool cairia.
137
+ * feito DEPOIS das sub-fontes — com a regra da v1.2 (que a 1.3 mantém), a lib lançaria e a tool cairia.
138
138
  */
139
139
  export function provenanceMateriaDetalhe(baseUrl, a) {
140
140
  const base = baseUrl.replace(/\/$/, "");
@@ -13,7 +13,7 @@ import { z } from "zod";
13
13
  import { cachedFetchWithMeta } from "../cache/manager.js";
14
14
  import { upstreamFetch } from "../throttle/upstream.js";
15
15
  import { errorFrom, ensureArray, safeInt, parseBRL } from "../utils/validation.js";
16
- import { provenanceFor, resultWithProvenance } from "../utils/provenance.js";
16
+ import { derivadoDeEstatisticas, provenanceFor, resultWithProvenance } from "../utils/provenance.js";
17
17
  import { computarEstatisticas, arredondarEstatisticas, arredondarEntradas, } from "../utils/estatisticas.js";
18
18
  import { CACHE_STATIC } from "../types.js";
19
19
  const FINANCEIRO_BASE = "https://www.senado.gov.br";
@@ -249,7 +249,7 @@ export function registerOrcamentoSenadoTools(server) {
249
249
  ano: params.ano ?? null,
250
250
  totalLinhas: itens.length,
251
251
  ...estatisticasExecucao(itens, { tipo, campo: params.campo, agruparPor: params.agruparPor, topN: params.topN ?? 10 }),
252
- }, prov);
252
+ }, derivadoDeEstatisticas(prov));
253
253
  }
254
254
  if (tipo === "despesas") {
255
255
  let itens = ensureArray(bruto?.despesas).map(parseDespesa);
@@ -12,7 +12,7 @@ import { cachedFetchWithMeta } from "../cache/manager.js";
12
12
  import { admFetch, admFetchLarge } from "../throttle/adm.js";
13
13
  import { errorFrom, ensureArray, normalizeText, parseBRL } from "../utils/validation.js";
14
14
  import { unwrapAdmEnvelope } from "../utils/upstream-parse.js";
15
- import { provenanceFor, resultWithProvenance } from "../utils/provenance.js";
15
+ import { derivadoDeEstatisticas, provenanceFor, resultWithProvenance } from "../utils/provenance.js";
16
16
  import { computarEstatisticas, arredondarEstatisticas, arredondarEntradas, } from "../utils/estatisticas.js";
17
17
  import { CACHE_SEMI_STATIC, CACHE_STATIC } from "../types.js";
18
18
  const norm = normalizeText;
@@ -157,7 +157,7 @@ export function registerSenadoresAdminTools(server, admBaseUrl) {
157
157
  totalDespesas: filtrado.length,
158
158
  valorTotal: totalGeral,
159
159
  ...estatisticasCeaps(filtrado, { agruparPor: params.agruparPor, topN: params.topN ?? 10 }),
160
- }, prov);
160
+ }, derivadoDeEstatisticas(prov));
161
161
  }
162
162
  const limite = params.limite ?? 100;
163
163
  const modo = params.modo ?? "por-senador";
@@ -12,7 +12,7 @@ import { cachedFetchWithMeta } from "../cache/manager.js";
12
12
  import { admFetch, admFetchLarge } from "../throttle/adm.js";
13
13
  import { errorFrom, ensureArray, parseBRL } from "../utils/validation.js";
14
14
  import { unwrapAdmEnvelope } from "../utils/upstream-parse.js";
15
- import { provenanceFor, resultWithProvenance } from "../utils/provenance.js";
15
+ import { derivadoDeEstatisticas, provenanceFor, resultWithProvenance } from "../utils/provenance.js";
16
16
  import { computarEstatisticas, arredondarEstatisticas, arredondarEntradas, } from "../utils/estatisticas.js";
17
17
  import { CACHE_SEMI_STATIC, CACHE_STATIC } from "../types.js";
18
18
  import { matchesFiltro, matchesFiltroCampo } from "./contratacoes.js";
@@ -342,7 +342,7 @@ export function particionarPorUnidade(lista, indice, codUnidade) {
342
342
  * organograma foi lido agora, o que também é. Com ele, o topo passa a ser o mais antigo
343
343
  * das duas (derivado pelo adaptador, contrato §3), e a folha entra como sub-fonte própria
344
344
  * para que o seu instante não suma do bloco. Antes da 3.17.0 o topo era o da folha, mais
345
- * novo que o snapshot — com a v1.2 ligada, a lib lançaria e a tool cairia.
345
+ * novo que o snapshot — com a regra da v1.2 (que a 1.3 mantém), a lib lançaria e a tool cairia.
346
346
  *
347
347
  * `folhaDoCache` é o `fromCache` da leitura da folha; o snapshot embutido não é cache nem
348
348
  * busca, então a sub-fonte dele não diz (`served_from_cache: null`).
@@ -473,7 +473,7 @@ export function registerServidoresTools(server, admBaseUrl) {
473
473
  agruparPor: params.agruparPor,
474
474
  topN: params.topN ?? 10,
475
475
  }),
476
- }, prov);
476
+ }, derivadoDeEstatisticas(prov));
477
477
  }
478
478
  if ((params.modo ?? "resumo") === "detalhe") {
479
479
  const limite = params.limite ?? 50;
@@ -539,7 +539,7 @@ export function registerServidoresTools(server, admBaseUrl) {
539
539
  total: itens.length,
540
540
  valorTotal,
541
541
  ...estatisticasHorasExtras(itens, { agruparPor: params.agruparPor, topN: params.topN ?? 10 }),
542
- }, prov);
542
+ }, derivadoDeEstatisticas(prov));
543
543
  }
544
544
  return resultWithProvenance({
545
545
  ano: params.ano,
@@ -9,7 +9,7 @@ import { z } from "zod";
9
9
  import { cachedFetchWithMeta } from "../cache/manager.js";
10
10
  import { admFetch } from "../throttle/adm.js";
11
11
  import { errorFrom, ensureArray } from "../utils/validation.js";
12
- import { leituraDoCache, provenanceFor, resultWithProvenance, withFieldSources } from "../utils/provenance.js";
12
+ import { derivadoDeEstatisticas, leituraDoCache, provenanceFor, resultWithProvenance, withFieldSources } from "../utils/provenance.js";
13
13
  import { computarEstatisticas, arredondarEstatisticas, arredondarEntradas, } from "../utils/estatisticas.js";
14
14
  import { CACHE_STATIC } from "../types.js";
15
15
  import { matchesFiltro } from "./contratacoes.js";
@@ -285,7 +285,7 @@ export function registerSupridosTools(server, admBaseUrl) {
285
285
  modo: "estatisticas",
286
286
  total: lista.length,
287
287
  ...estatisticasSuprimento(lista, { tipo, campo: params.campo, agruparPor: params.agruparPor, topN: params.topN ?? 10, nomePorCodigo: nomes?.nomes }),
288
- }, nomes ? provenanceSuprimentoComNomes(prov, { fromCache }, params.ano, admBaseUrl, nomes, params.agruparPor) : prov);
288
+ }, derivadoDeEstatisticas(nomes ? provenanceSuprimentoComNomes(prov, { fromCache }, params.ano, admBaseUrl, nomes, params.agruparPor) : prov));
289
289
  }
290
290
  return resultWithProvenance({
291
291
  ano: params.ano,
@@ -17,14 +17,16 @@
17
17
  * - v1.1 (release 3.11.0): o concise tem 7 chaves fixas — `source`, `source_url`,
18
18
  * `data_vintage` (ex-`reference_period`), `retrieved_at`, `citation`, `license` e
19
19
  * `retrieval` (diagnóstico medido da ida à origem, ou `null`).
20
- * - v1.2 (EMITIDA desde a release 3.17.0): acrescenta ao concise a chave opcional
21
- * `field_sources` (sub-fontes por campo), só nas respostas que fundem recortes. Com
22
- * ela a lib COBRA que o `retrieved_at` do topo seja o mais antigo entre as sub-fontes
23
- * (lança `ProvenanceContractError`, o que derrubaria a tool) — por isso o adaptador
24
- * o deriva por construção (`oldestRetrievedAt`), nunca a tool à mão.
25
- * - v1.3 (declarada pelo `outputSchema` desde a 3.17.0, ainda NÃO emitida): `notices`,
26
- * `derived`/`derivation_note` e `revision`. A `revision` já é informada aqui, por
27
- * fonte (`SOURCES`), e a lib a descarta enquanto o servidor emitir 1.2.
20
+ * - v1.2 (release 3.17.0): acrescenta ao concise a chave opcional `field_sources`
21
+ * (sub-fontes por campo), só nas respostas que fundem recortes. Com ela a lib COBRA
22
+ * que o `retrieved_at` do topo seja o mais antigo entre as sub-fontes (lança
23
+ * `ProvenanceContractError`, o que derrubaria a tool) — por isso o adaptador o deriva
24
+ * por construção (`oldestRetrievedAt`), nunca a tool à mão.
25
+ * - v1.3 (EMITIDA desde a release 3.18.5; o `outputSchema` a aceitava desde a 3.17.0):
26
+ * o concise leva `revision` SEMPRE (por fonte, em `SOURCES`) e `derived` +
27
+ * `derivation_note` nos modos `estatisticas` (`derivadoDeEstatisticas`). `notices`
28
+ * não sai: nenhuma fonte do senado publica aviso junto com o dado. Sem cálculo, as
29
+ * chaves opcionais ficam AUSENTES, não vazias.
28
30
  * - O rodapé de texto segue a redação fixada do contrato: linha de fonte
29
31
  * ("Fonte: … · url · dados de … · extraído em …"), linha de licença e o aviso ao
30
32
  * leitor de que a referência completa pode ser solicitada na própria conversa.
@@ -57,7 +59,7 @@ export const provenanceContext = createProvenanceContext({
57
59
  locale: "pt-BR",
58
60
  timezone: { offset: "-03:00", label: "horário de Brasília" },
59
61
  defaultMode: "concise",
60
- contractVersion: "1.2",
62
+ contractVersion: "1.3",
61
63
  });
62
64
  const BRASILIA = provenanceContext.timezone;
63
65
  /**
@@ -134,7 +136,7 @@ const extraToCanonical = (extra = {}) => {
134
136
  * `current` em todas as fontes do senado, `final` em nenhuma — só com prova da fonte).
135
137
  * A `note` só repete o que o servidor JÁ diz nas instructions (`src/app-surface.ts`) sobre
136
138
  * os dados administrativos; nas demais fontes não há texto publicado, então `null`.
137
- * Enquanto o servidor emitir a v1.2 a lib descarta o campo do fio — fica no canônico.
139
+ * Sai no concise de toda resposta (v1.3).
138
140
  */
139
141
  const REVISAO_VIGENTE = { status: "current", note: null };
140
142
  const REVISAO_ADMINISTRATIVA = {
@@ -268,6 +270,24 @@ export function withFieldSources(prov, fieldSources) {
268
270
  field_sources: fieldSources.map(toCanonicalFieldSource),
269
271
  });
270
272
  }
273
+ /**
274
+ * Nota fixa dos modos `estatisticas` (mesma redação do ibge-br-mcp, adaptada à fonte):
275
+ * a distribuição, os agregados e o ranking são cálculo deste servidor; cada valor
276
+ * individual citado é o que o Senado publica.
277
+ */
278
+ export const NOTA_DERIVACAO_ESTATISTICAS = "Estatísticas (distribuição, agregados e rankings) computadas pelo servidor a partir dos registros brutos retornados pela fonte; os valores individuais permanecem os originais do Senado Federal.";
279
+ /**
280
+ * Marca o bloco como derivado (contrato v1.3): `derived: true` + a nota fixa dos modos
281
+ * `estatisticas`. Aplique por último, sobre o bloco já completo (inclusive o de
282
+ * `withFieldSources`); o envelope é re-validado inteiro no contrato (build).
283
+ */
284
+ export function derivadoDeEstatisticas(prov) {
285
+ return provenanceContext.build({
286
+ ...prov,
287
+ derived: true,
288
+ derivation_note: NOTA_DERIVACAO_ESTATISTICAS,
289
+ });
290
+ }
271
291
  /** Rodapé de texto do contrato: fonte · url · vintage · extração, licença e aviso ao leitor. */
272
292
  export const provenanceFooter = (p) => provenanceContext.footer(p);
273
293
  /**
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.18.4";
2
+ export const VERSION = "3.18.5";
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.18.4",
3
+ "version": "3.18.5",
4
4
  "description": "MCP server for Brazilian Senate open data — runs hosted on Cloudflare Workers or locally via npx (stdio)",
5
5
  "keywords": [
6
6
  "mcp",