bcb-br-mcp 1.3.4 → 1.4.1

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
@@ -18,7 +18,7 @@ Query economic and financial indicators such as **Selic** (interest rate), **IPC
18
18
 
19
19
  > If you find this project useful, please consider giving it a [star on GitHub](https://github.com/SidneyBissoli/bcb-br-mcp). It helps others discover the project!
20
20
 
21
- **Capabilities:** 8 tools (skills) · 3 resources · 3 prompts — everything an MCP client needs to query the Brazilian Central Bank (SGS/BCB) time-series API.
21
+ **Capabilities:** 13 tools (skills) · 3 resources · 3 prompts — everything an MCP client needs to query the Brazilian Central Bank: SGS/BCB time series, the **Focus** market-expectations survey and **PTAX** exchange rates.
22
22
 
23
23
  ## See it in action
24
24
 
@@ -27,6 +27,9 @@ Ask your assistant, in plain Portuguese:
27
27
  - *"Qual a taxa Selic atual?"* → `bcb_indicadores_atuais`
28
28
  - *"Mostre o IPCA mês a mês em 2024."* → `bcb_serie_valores`
29
29
  - *"Qual foi a variação do dólar nos últimos 12 meses?"* → `bcb_variacao`
30
+ - *"O que o mercado espera do IPCA em 2027?"* → `bcb_focus_expectativas`
31
+ - *"Qual a Selic esperada na próxima reunião do Copom?"* → `bcb_focus_selic`
32
+ - *"Qual foi a PTAX de fechamento do euro na sexta?"* → `bcb_cambio_cotacao`
30
33
 
31
34
  The answers come live from the Brazilian Central Bank's SGS API — exact figures with provenance, not numbers guessed from training data.
32
35
 
@@ -40,6 +43,8 @@ The answers come live from the Brazilian Central Bank's SGS API — exact figure
40
43
  - **Current indicators** - Latest values for key economic indicators
41
44
  - **Variation calculation** - Percentage change between periods with statistics
42
45
  - **Series comparison** - Compare multiple series over the same period
46
+ - **Focus survey** - Market expectations (mean, median, std. deviation, min, max, respondents) for IPCA, GDP, FX and more, by monthly/quarterly/annual horizon or rolling 12/24-month inflation, plus Selic by Copom meeting
47
+ - **PTAX exchange rates** - Official closing quotes for any currency the BCB publishes, single day or date range
43
48
 
44
49
  ## Available Tools
45
50
 
@@ -53,6 +58,11 @@ The answers come live from the Brazilian Central Bank's SGS API — exact figure
53
58
  | `bcb_indicadores_atuais` | Latest values: Selic, IPCA, USD/BRL, IBC-Br |
54
59
  | `bcb_variacao` | Calculate percentage variation between dates or last N periods |
55
60
  | `bcb_comparar` | Compare 2 to 5 series over the same period with ranking |
61
+ | `bcb_focus_expectativas` | Focus survey expectations for one indicator, horizon as a parameter (monthly, quarterly, annual, rolling 12m/24m inflation); `top5` flag |
62
+ | `bcb_focus_selic` | Focus expectations for the Selic rate, by Copom meeting (R1/2026 form) |
63
+ | `bcb_focus_referencias` | Which indicators and reference dates the Focus survey actually publishes, **broken down per scope** (the five horizons plus `selic`, whose axis is the Copom meeting) — the indicator set differs by scope (9 monthly vs 26 annual) |
64
+ | `bcb_cambio_cotacao` | PTAX quote for a currency (USD by default), single day or date range |
65
+ | `bcb_cambio_moedas` | Currencies with quotes published by the BCB |
56
66
 
57
67
  ## Resources
58
68
 
@@ -85,9 +95,14 @@ Visit [bcb-br-mcp on Smithery](https://smithery.ai/servers/sidneybissoli/bcb-br-
85
95
  Use the HTTP endpoint directly, no installation required:
86
96
 
87
97
  ```
88
- https://bcb.sidneybissoli.workers.dev
98
+ https://bcb.sidneybissoli.com/mcp
89
99
  ```
90
100
 
101
+ The legacy hostname `https://bcb.sidneybissoli.workers.dev` keeps working, and so
102
+ does the older `POST /` route — clients configured before the endpoint moved to
103
+ `/mcp` are rewritten transparently, so nothing that used to work stopped working.
104
+ New setups should use the URL above.
105
+
91
106
  ### Via npx (Claude Desktop)
92
107
 
93
108
  Add to your Claude Desktop configuration file:
@@ -324,11 +339,26 @@ The SGS database contains over 18,000 time series. To find codes for other serie
324
339
 
325
340
  ### Smart Search
326
341
 
327
- The `bcb_buscar_serie` tool normalizes search terms, allowing you to find series even without Portuguese accents:
342
+ `bcb_buscar_serie` searches two layers: the curated catalog of 150+ series (which ranks first, with reviewed
343
+ names) and the index of the BCB Open Data Portal, with thousands of series identified by code. Terms are
344
+ accent- and case-insensitive, and several terms are combined with AND:
328
345
 
329
346
  - `"inflacao"` → finds "Inflação"
330
347
  - `"cambio"` → finds "Câmbio"
331
- - `"credito"` → finds "Crédito"
348
+ - `"ipca servicos"` → both terms must match
349
+
350
+ The portal index is served from a 24-hour cache, renewed by the first search after it expires (one request to
351
+ the portal, only metadata — series codes and names, never observations). Every answer carries
352
+ `catalogo.cobertura`: the index is **not** the whole SGS, so not finding a series here is not proof it does not
353
+ exist.
354
+
355
+ ### Data source and licence
356
+
357
+ Data obtained from the Banco Central do Brasil (SGS / Olinda-Expectativas / PTAX), published under the
358
+ **Open Data Commons Open Database License (ODbL) v1.0** — https://opendatacommons.org/licenses/odbl/.
359
+ Exchange-rate answers pass through the BCB's own liability disclaimer verbatim; cross-currency parities are
360
+ **not** compiled by the BCB — they come from an information agency (Refinitiv) and are redistributed by the
361
+ BCB, and the tools say so.
332
362
 
333
363
  ## Development
334
364
 
@@ -379,6 +409,32 @@ This server uses the Brazilian Central Bank's public API:
379
409
 
380
410
  ## Changelog
381
411
 
412
+ ### v1.4.1
413
+
414
+ - `bcb_focus_referencias`: the parameter is now `escopo`, not `horizonte`, and the
415
+ response array is `escopos`. The scopes are the five horizons of
416
+ `bcb_focus_expectativas` **plus `selic`** — and `selic` is not a horizon: its
417
+ axis is the Copom meeting. Each block names the `tool` that consumes it. The
418
+ previous name implied `selic` was a queryable horizon of
419
+ `bcb_focus_expectativas`, which it is not. Never published to npm under the old
420
+ name.
421
+
422
+ ### v1.4.0
423
+
424
+ - **Three APIs under one contract, 8 tools → 13.** Focus market-expectations
425
+ survey (`bcb_focus_expectativas`, `bcb_focus_selic`, `bcb_focus_referencias`)
426
+ and PTAX exchange rates (`bcb_cambio_cotacao`, `bcb_cambio_moedas`), consolidated
427
+ by parameter rather than mirroring the source's ~18 OData resources.
428
+ - **Real search.** `bcb_buscar_serie` now queries the Open Data Portal index
429
+ (3,500+ series, 24-hour cache, metadata only) on top of the curated catalog, and
430
+ states the index's coverage instead of claiming a series does not exist.
431
+ - Every Focus and PTAX field name verified against the live API, including the
432
+ Top 5 Selic resource, which publishes its fields in a different case from the
433
+ other twelve.
434
+ - ODbL obligations shipped with the exchange-rate tools: the BCB disclaimer is
435
+ passed through verbatim, and non-USD parities are qualified as third-party
436
+ (Refinitiv) data redistributed by the BCB.
437
+
382
438
  ### v1.2.0
383
439
 
384
440
  - HTTP endpoint via Cloudflare Workers (`https://bcb.sidneybissoli.workers.dev`)
@@ -0,0 +1,72 @@
1
+ /**
2
+ * PTAX — cotações de câmbio e lista de moedas.
3
+ *
4
+ * Desenho aprovado (fronteira concreta da sessão de D3): os quatro recursos de
5
+ * cotação da fonte (dólar-dia, dólar-período, moeda-dia, moeda-período) viram
6
+ * UMA tool, `bcb_cambio_cotacao`, com `moeda` (padrão USD) e data única ou
7
+ * intervalo. Mais `bcb_cambio_moedas` para a lista de moedas, porque descobrir o
8
+ * símbolo é pergunta própria.
9
+ *
10
+ * Duas obrigações legais do `bcb/docs/01` nascem implementadas aqui, não no D4:
11
+ *
12
+ * 1. **O disclaimer do BCB é repassado literalmente** em toda resposta de
13
+ * cotação — é o único texto tipo-ToS que a fonte publica.
14
+ * 2. **Paridades de moedas não-dólar são QUALIFICADAS**: elas não são dado do
15
+ * BCB, vêm de agência de informação (Refinitiv) e são redistribuídas pelo BCB.
16
+ * Anunciá-las como dado do BCB sem qualificar seria incorreto.
17
+ *
18
+ * Pegadinha da API que mora em `olinda.ts`: os parâmetros de data da PTAX são
19
+ * **MM-DD-YYYY**, não ISO nem dd/MM/yyyy.
20
+ */
21
+ import { type ToolDefinition, type ToolResult } from "./shared.js";
22
+ /** Repassado literalmente, como o `docs/01` exige. */
23
+ export declare const DISCLAIMER_PTAX: string;
24
+ export declare const QUALIFICACAO_PARIDADE: string;
25
+ export interface CotacaoNormalizada {
26
+ /** Data e hora da cotação como a fonte publica. */
27
+ dataHora: string | null;
28
+ cotacaoCompra: number | null;
29
+ cotacaoVenda: number | null;
30
+ /** Só para moedas não-dólar: paridade contra o USD (origem: agência de informação). */
31
+ paridadeCompra?: number | null;
32
+ paridadeVenda?: number | null;
33
+ /** Nulo em USD: verificado contra a origem, os recursos de dólar não publicam este campo. */
34
+ tipoBoletim: string | null;
35
+ }
36
+ export declare function normalizarCotacao(linha: Record<string, unknown>, dolar: boolean): CotacaoNormalizada;
37
+ interface UrlCotacao {
38
+ url: string;
39
+ dolar: boolean;
40
+ dataInicial: string;
41
+ dataFinal: string;
42
+ janelaPadrao: boolean;
43
+ }
44
+ /**
45
+ * Monta a URL da cotação escolhendo entre os quatro recursos da fonte. É o único
46
+ * lugar que sabe que existem quatro: para fora há uma tool só.
47
+ */
48
+ export declare function montarUrlCotacao(args: {
49
+ moeda?: string;
50
+ data?: string;
51
+ dataInicial?: string;
52
+ dataFinal?: string;
53
+ }): UrlCotacao | {
54
+ erro: string;
55
+ };
56
+ export interface ArgsCotacao {
57
+ moeda?: string;
58
+ data?: string;
59
+ dataInicial?: string;
60
+ dataFinal?: string;
61
+ limite?: number;
62
+ }
63
+ export declare function handleCambioCotacao(args: ArgsCotacao, timeoutMs?: number, maxRetries?: number): Promise<ToolResult>;
64
+ export interface ArgsMoedas {
65
+ termo?: string;
66
+ }
67
+ export declare function handleCambioMoedas(args: ArgsMoedas, timeoutMs?: number, maxRetries?: number): Promise<ToolResult>;
68
+ export declare const CAMBIO_TOOL_DEFINITIONS: ToolDefinition[];
69
+ /** Retorna null quando a tool não é deste módulo (o dispatcher central segue). */
70
+ export declare function dispatchCambioTool(toolName: string, args: Record<string, unknown>, timeoutMs?: number, maxRetries?: number): Promise<ToolResult> | null;
71
+ export {};
72
+ //# sourceMappingURL=cambio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cambio.d.ts","sourceRoot":"","sources":["../src/cambio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAaH,OAAO,EAA+D,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAKhI,sDAAsD;AACtD,eAAO,MAAM,eAAe,QAIO,CAAC;AAEpC,eAAO,MAAM,qBAAqB,QAGT,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6FAA6F;IAC7F,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAcpG;AAED,UAAU,UAAU;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CA4ChC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,WAAW,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,CA0CrB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,CA8BrB;AASD,eAAO,MAAM,uBAAuB,EAAE,cAAc,EA6GnD,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAS5B"}
package/dist/cambio.js ADDED
@@ -0,0 +1,284 @@
1
+ /**
2
+ * PTAX — cotações de câmbio e lista de moedas.
3
+ *
4
+ * Desenho aprovado (fronteira concreta da sessão de D3): os quatro recursos de
5
+ * cotação da fonte (dólar-dia, dólar-período, moeda-dia, moeda-período) viram
6
+ * UMA tool, `bcb_cambio_cotacao`, com `moeda` (padrão USD) e data única ou
7
+ * intervalo. Mais `bcb_cambio_moedas` para a lista de moedas, porque descobrir o
8
+ * símbolo é pergunta própria.
9
+ *
10
+ * Duas obrigações legais do `bcb/docs/01` nascem implementadas aqui, não no D4:
11
+ *
12
+ * 1. **O disclaimer do BCB é repassado literalmente** em toda resposta de
13
+ * cotação — é o único texto tipo-ToS que a fonte publica.
14
+ * 2. **Paridades de moedas não-dólar são QUALIFICADAS**: elas não são dado do
15
+ * BCB, vêm de agência de informação (Refinitiv) e são redistribuídas pelo BCB.
16
+ * Anunciá-las como dado do BCB sem qualificar seria incorreto.
17
+ *
18
+ * Pegadinha da API que mora em `olinda.ts`: os parâmetros de data da PTAX são
19
+ * **MM-DD-YYYY**, não ISO nem dd/MM/yyyy.
20
+ */
21
+ import { PTAX_ODATA, consultarOData, hojeIso, montarUrlOData, numeroOuNulo, paraDataPtax, paraIso, somarDiasIso, textoOuNulo } from "./olinda.js";
22
+ import { erroResult, leituraRemota, mensagemDeErro, structuredResult } from "./shared.js";
23
+ /** Janela padrão quando não se informa data nenhuma: cobre feriados e fins de semana. */
24
+ const JANELA_PADRAO_DIAS = 7;
25
+ /** Repassado literalmente, como o `docs/01` exige. */
26
+ export const DISCLAIMER_PTAX = "O Banco Central não assume qualquer responsabilidade pela não simultaneidade ou falta das informações " +
27
+ "prestadas, assim como por eventuais erros de paridades das moedas. Não assume, também, responsabilidade " +
28
+ "por qualquer perda ou dano oriundo de tais interrupções, atrasos, falhas ou imperfeições, bem como pelo " +
29
+ "uso inadequado das informações.";
30
+ export const QUALIFICACAO_PARIDADE = "As paridades das moedas contra o dólar americano NÃO são apuradas pelo Banco Central: são obtidas junto a " +
31
+ "agências de informação (Refinitiv) e redistribuídas pelo BCB. Trate-as como dado de terceiro qualificado, " +
32
+ "não como dado do BCB.";
33
+ export function normalizarCotacao(linha, dolar) {
34
+ const normalizada = {
35
+ dataHora: textoOuNulo(linha.dataHoraCotacao),
36
+ cotacaoCompra: numeroOuNulo(linha.cotacaoCompra),
37
+ cotacaoVenda: numeroOuNulo(linha.cotacaoVenda),
38
+ tipoBoletim: textoOuNulo(linha.tipoBoletim)
39
+ };
40
+ if (!dolar) {
41
+ normalizada.paridadeCompra = numeroOuNulo(linha.paridadeCompra);
42
+ normalizada.paridadeVenda = numeroOuNulo(linha.paridadeVenda);
43
+ }
44
+ return normalizada;
45
+ }
46
+ /**
47
+ * Monta a URL da cotação escolhendo entre os quatro recursos da fonte. É o único
48
+ * lugar que sabe que existem quatro: para fora há uma tool só.
49
+ */
50
+ export function montarUrlCotacao(args) {
51
+ const moeda = (args.moeda ?? "USD").toUpperCase();
52
+ const dolar = moeda === "USD";
53
+ let inicio;
54
+ let fim;
55
+ let janelaPadrao = false;
56
+ if (args.data !== undefined) {
57
+ if (args.dataInicial !== undefined || args.dataFinal !== undefined) {
58
+ return { erro: "Use `data` para um dia específico OU `dataInicial`/`dataFinal` para um intervalo, não os dois." };
59
+ }
60
+ inicio = paraIso(args.data);
61
+ if (!inicio)
62
+ return { erro: `data inválida: "${args.data}". Use yyyy-MM-dd ou dd/MM/yyyy.` };
63
+ fim = inicio;
64
+ }
65
+ else {
66
+ fim = args.dataFinal ? paraIso(args.dataFinal) : hojeIso();
67
+ if (!fim)
68
+ return { erro: `dataFinal inválida: "${args.dataFinal}". Use yyyy-MM-dd ou dd/MM/yyyy.` };
69
+ inicio = args.dataInicial ? paraIso(args.dataInicial) : somarDiasIso(fim, -JANELA_PADRAO_DIAS);
70
+ if (!inicio)
71
+ return { erro: `dataInicial inválida: "${args.dataInicial}". Use yyyy-MM-dd ou dd/MM/yyyy.` };
72
+ janelaPadrao = args.dataInicial === undefined && args.dataFinal === undefined;
73
+ }
74
+ if (inicio > fim) {
75
+ return { erro: `A janela está invertida: dataInicial (${inicio}) é posterior a dataFinal (${fim}).` };
76
+ }
77
+ const diaUnico = inicio === fim && args.data !== undefined;
78
+ const pInicio = paraDataPtax(inicio);
79
+ const pFim = paraDataPtax(fim);
80
+ // Recursos parametrizados do OData: os argumentos vão como @parâmetros.
81
+ const recurso = diaUnico
82
+ ? dolar
83
+ ? `CotacaoDolarDia(dataCotacao=@dataCotacao)?@dataCotacao='${pInicio}'`
84
+ : `CotacaoMoedaDia(moeda=@moeda,dataCotacao=@dataCotacao)?@moeda='${moeda}'&@dataCotacao='${pInicio}'`
85
+ : dolar
86
+ ? `CotacaoDolarPeriodo(dataInicial=@dataInicial,dataFinalCotacao=@dataFinalCotacao)?@dataInicial='${pInicio}'&@dataFinalCotacao='${pFim}'`
87
+ : `CotacaoMoedaPeriodo(moeda=@moeda,dataInicial=@dataInicial,dataFinalCotacao=@dataFinalCotacao)?@moeda='${moeda}'&@dataInicial='${pInicio}'&@dataFinalCotacao='${pFim}'`;
88
+ // O recurso já carrega query string, então o formato entra com `&`.
89
+ const url = `${PTAX_ODATA}/${recurso}&$format=json`;
90
+ return { url, dolar, dataInicial: inicio, dataFinal: fim, janelaPadrao };
91
+ }
92
+ export async function handleCambioCotacao(args, timeoutMs, maxRetries) {
93
+ const montada = montarUrlCotacao(args);
94
+ if ("erro" in montada)
95
+ return erroResult(montada.erro);
96
+ try {
97
+ const linhas = await consultarOData(montada.url, timeoutMs, maxRetries);
98
+ const limite = args.limite ?? 100;
99
+ const todas = linhas
100
+ .map(l => normalizarCotacao(l, montada.dolar))
101
+ .sort((a, b) => (b.dataHora ?? "").localeCompare(a.dataHora ?? ""));
102
+ const cotacoes = todas.slice(0, limite);
103
+ const payload = {
104
+ moeda: (args.moeda ?? "USD").toUpperCase(),
105
+ periodo: {
106
+ dataInicial: montada.dataInicial,
107
+ dataFinal: montada.dataFinal,
108
+ janelaPadrao: montada.janelaPadrao
109
+ },
110
+ totalRegistros: todas.length,
111
+ cotacoes,
112
+ disclaimer: DISCLAIMER_PTAX,
113
+ urlConsulta: montada.url,
114
+ consultadoEm: new Date().toISOString()
115
+ };
116
+ if (!montada.dolar)
117
+ payload.qualificacaoParidade = QUALIFICACAO_PARIDADE;
118
+ if (cotacoes.length < todas.length) {
119
+ payload.observacao = `Exibindo ${cotacoes.length} de ${todas.length} boletins; aumente 'limite' ou estreite o período.`;
120
+ }
121
+ if (todas.length === 0) {
122
+ payload.observacao =
123
+ "Nenhuma cotação no período. A PTAX só existe em dia útil com fechamento de câmbio — fim de semana, " +
124
+ "feriado e o próprio dia antes do fechamento voltam vazios. Confirme também o símbolo da moeda com " +
125
+ "bcb_cambio_moedas.";
126
+ }
127
+ return structuredResult(payload);
128
+ }
129
+ catch (error) {
130
+ return erroResult(`Erro ao consultar cotação de câmbio: ${mensagemDeErro(error)}`);
131
+ }
132
+ }
133
+ export async function handleCambioMoedas(args, timeoutMs, maxRetries) {
134
+ const url = montarUrlOData(PTAX_ODATA, { recurso: "Moedas" });
135
+ try {
136
+ const linhas = await consultarOData(url, timeoutMs, maxRetries);
137
+ let moedas = linhas.map(l => ({
138
+ simbolo: textoOuNulo(l.simbolo),
139
+ nome: textoOuNulo(l.nomeFormatado),
140
+ tipo: textoOuNulo(l.tipoMoeda)
141
+ }));
142
+ if (args.termo !== undefined) {
143
+ const termo = args.termo.toUpperCase();
144
+ moedas = moedas.filter(m => (m.simbolo ?? "").includes(termo) || (m.nome ?? "").toUpperCase().includes(termo));
145
+ }
146
+ return structuredResult({
147
+ termo: args.termo ?? null,
148
+ totalMoedas: moedas.length,
149
+ moedas,
150
+ disclaimer: DISCLAIMER_PTAX,
151
+ qualificacaoParidade: QUALIFICACAO_PARIDADE,
152
+ urlConsulta: url,
153
+ consultadoEm: new Date().toISOString(),
154
+ observacao: "Use o `simbolo` em bcb_cambio_cotacao. O dólar americano (USD) é o padrão da tool de cotação."
155
+ });
156
+ }
157
+ catch (error) {
158
+ return erroResult(`Erro ao listar moedas: ${mensagemDeErro(error)}`);
159
+ }
160
+ }
161
+ // ==================== SCHEMAS ====================
162
+ const NOTA_PTAX = "Fonte: PTAX / Cotações e boletins de câmbio do Banco Central do Brasil, via Olinda OData. A resposta repassa " +
163
+ "literalmente o disclaimer de responsabilidade do BCB, em `disclaimer`. Cotações existem só em dia útil com " +
164
+ "fechamento de câmbio.";
165
+ export const CAMBIO_TOOL_DEFINITIONS = [
166
+ {
167
+ name: "bcb_cambio_cotacao",
168
+ description: "Consulta a cotação PTAX de uma moeda contra o real, em um dia específico ou num intervalo de datas. " +
169
+ "Padrão: dólar americano (USD). Devolve compra, venda, data/hora e tipo de boletim; para moedas " +
170
+ "não-dólar devolve também a paridade contra o USD, com a origem qualificada. " +
171
+ "Quando usar: para a cotação oficial de fechamento de um dia ou a série de um período curto. " +
172
+ "Quando NÃO usar: para a série histórica longa do dólar como série temporal do SGS use bcb_serie_valores " +
173
+ "(códigos 1 = livre venda, 3698 = PTAX venda, 3697 = PTAX compra, 3695 = PTAX média) — esta tool é a " +
174
+ "fonte primária do boletim, com compra e venda no mesmo registro; para descobrir o símbolo da moeda use " +
175
+ "bcb_cambio_moedas. " +
176
+ "Retorna: `moeda`, `periodo` (dataInicial, dataFinal, janelaPadrao), `totalRegistros`, `cotacoes`, " +
177
+ "`disclaimer`, `qualificacaoParidade` (só para moedas não-dólar), `urlConsulta`, `consultadoEm` e, quando " +
178
+ "aplicável, `observacao`. Sem datas, cobre os últimos 7 dias (para atravessar fim de semana e feriado). " +
179
+ NOTA_PTAX +
180
+ " As paridades de moedas não-dólar vêm de agência de informação (Refinitiv), redistribuídas pelo BCB — não " +
181
+ "são apuradas pelo Banco Central.",
182
+ annotations: leituraRemota("Cotação de câmbio (PTAX)"),
183
+ inputSchema: {
184
+ type: "object",
185
+ properties: {
186
+ moeda: { type: "string", description: "Símbolo da moeda (ex.: USD, EUR, GBP, JPY). Padrão: USD.", default: "USD" },
187
+ data: { type: "string", description: "Dia específico (yyyy-MM-dd ou dd/MM/yyyy). Não combine com dataInicial/dataFinal." },
188
+ dataInicial: { type: "string", description: "Início do intervalo (yyyy-MM-dd ou dd/MM/yyyy). Padrão: 7 dias antes do fim." },
189
+ dataFinal: { type: "string", description: "Fim do intervalo (yyyy-MM-dd ou dd/MM/yyyy). Padrão: hoje." },
190
+ limite: { type: "number", description: "Máximo de boletins a devolver (1-1000, padrão 100)", default: 100, minimum: 1, maximum: 1000 }
191
+ }
192
+ },
193
+ outputSchema: {
194
+ type: "object",
195
+ properties: {
196
+ moeda: { type: "string" },
197
+ periodo: {
198
+ type: "object",
199
+ properties: {
200
+ dataInicial: { type: "string" },
201
+ dataFinal: { type: "string" },
202
+ janelaPadrao: { type: "boolean", description: "true quando a janela de 7 dias foi assumida" }
203
+ },
204
+ required: ["dataInicial", "dataFinal", "janelaPadrao"]
205
+ },
206
+ totalRegistros: { type: "number" },
207
+ cotacoes: {
208
+ type: "array",
209
+ items: {
210
+ type: "object",
211
+ properties: {
212
+ dataHora: { type: ["string", "null"], description: "Data e hora da cotação" },
213
+ cotacaoCompra: { type: ["number", "null"] },
214
+ cotacaoVenda: { type: ["number", "null"] },
215
+ paridadeCompra: { type: ["number", "null"], description: "Paridade de compra contra o USD (moedas não-dólar; origem: agência de informação)" },
216
+ paridadeVenda: { type: ["number", "null"], description: "Paridade de venda contra o USD (moedas não-dólar; origem: agência de informação)" },
217
+ tipoBoletim: { type: ["string", "null"], description: "Tipo de boletim (ex.: Fechamento, Abertura, Intermediário). Nulo em USD: a fonte não publica este campo nos recursos de dólar, só nos de moeda." }
218
+ },
219
+ required: ["dataHora"]
220
+ }
221
+ },
222
+ disclaimer: { type: "string", description: "Disclaimer de responsabilidade do BCB, repassado literalmente" },
223
+ qualificacaoParidade: { type: "string", description: "Qualificação da origem das paridades não-dólar" },
224
+ urlConsulta: { type: "string" },
225
+ consultadoEm: { type: "string" },
226
+ observacao: { type: "string" }
227
+ },
228
+ required: ["moeda", "periodo", "totalRegistros", "cotacoes", "disclaimer", "urlConsulta", "consultadoEm"]
229
+ }
230
+ },
231
+ {
232
+ name: "bcb_cambio_moedas",
233
+ description: "Lista as moedas com cotação publicada pelo Banco Central, com símbolo, nome e tipo, e aceita um termo " +
234
+ "para filtrar. " +
235
+ "Quando usar: para descobrir o símbolo correto antes de chamar bcb_cambio_cotacao (é a causa mais comum " +
236
+ "de cotação vazia). Quando NÃO usar: para valores de cotação. " +
237
+ "Retorna: `termo`, `totalMoedas`, `moedas` (simbolo, nome, tipo), `disclaimer`, `qualificacaoParidade`, " +
238
+ "`urlConsulta` e `consultadoEm`. " + NOTA_PTAX,
239
+ annotations: leituraRemota("Moedas com cotação no BCB"),
240
+ inputSchema: {
241
+ type: "object",
242
+ properties: {
243
+ termo: { type: "string", description: "Filtro por símbolo ou nome (ex.: 'EUR', 'libra'). Opcional." }
244
+ }
245
+ },
246
+ outputSchema: {
247
+ type: "object",
248
+ properties: {
249
+ termo: { type: ["string", "null"], description: "Termo aplicado no filtro; nulo quando não foi informado" },
250
+ totalMoedas: { type: "number" },
251
+ moedas: {
252
+ type: "array",
253
+ items: {
254
+ type: "object",
255
+ properties: {
256
+ simbolo: { type: ["string", "null"], description: "Símbolo a usar em bcb_cambio_cotacao" },
257
+ nome: { type: ["string", "null"] },
258
+ tipo: { type: ["string", "null"], description: "Tipo da moeda conforme a fonte (A ou B)" }
259
+ },
260
+ required: ["simbolo"]
261
+ }
262
+ },
263
+ disclaimer: { type: "string" },
264
+ qualificacaoParidade: { type: "string" },
265
+ urlConsulta: { type: "string" },
266
+ consultadoEm: { type: "string" },
267
+ observacao: { type: "string" }
268
+ },
269
+ required: ["totalMoedas", "moedas", "disclaimer", "urlConsulta", "consultadoEm"]
270
+ }
271
+ }
272
+ ];
273
+ /** Retorna null quando a tool não é deste módulo (o dispatcher central segue). */
274
+ export function dispatchCambioTool(toolName, args, timeoutMs, maxRetries) {
275
+ switch (toolName) {
276
+ case "bcb_cambio_cotacao":
277
+ return handleCambioCotacao(args, timeoutMs, maxRetries);
278
+ case "bcb_cambio_moedas":
279
+ return handleCambioMoedas(args, timeoutMs, maxRetries);
280
+ default:
281
+ return null;
282
+ }
283
+ }
284
+ //# sourceMappingURL=cambio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cambio.js","sourceRoot":"","sources":["../src/cambio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Índice de séries do Portal de Dados Abertos do BCB (CKAN) — busca real.
3
+ *
4
+ * Desenho fechado pelo decisor na fase bcb (arbitragem 5), e as restrições
5
+ * importam mais que o código:
6
+ *
7
+ * - Fonte é `package_list` do CKAN: UMA requisição (~310 KB) devolve o nome de
8
+ * todos os datasets do portal, e 3.555 deles são nomeados pelo próprio código
9
+ * da série (`{codigo}-{slug}`) — ~24× a cobertura do catálogo curado local.
10
+ * Nada de raspar o localizador JSP do SGS.
11
+ * - O catálogo é servido de cache com validade de 24 h e a renovação é
12
+ * BLOQUEANTE: quem faz a primeira busca depois do vencimento paga o ~0,8 s.
13
+ * Sem tarefa agendada e sem seed manual — se ninguém buscar, a origem não
14
+ * recebe requisição nenhuma. Descartado de propósito o
15
+ * stale-while-revalidate: com tráfego baixo ele entregaria retrato de semanas
16
+ * ao primeiro usuário para poupar 0,8 s de um único usuário por dia.
17
+ * - O cache guarda **só metadados** (código e slug), NUNCA observações. É por
18
+ * isso que ele não é a "base derivada" que a arbitragem 2 evitou: o servidor
19
+ * segue sendo *Produced Work* sob a ODbL, e valores de série continuam
20
+ * buscados ao vivo a cada pergunta.
21
+ * - `Disallow: /api/` + `Crawl-Delay: 10` no robots do portal do catálogo é o
22
+ * motivo de existir cache: ≤1 requisição por dia por instância, não uma por
23
+ * chamada.
24
+ *
25
+ * O cache é módulo-level, ou seja, por processo (stdio) e por isolate
26
+ * (Cloudflare). Isolate reciclado = catálogo buscado de novo; com o tráfego
27
+ * atual isso mantém a ordem de grandeza prometida (unidades de requisição por
28
+ * dia), e é a única forma de cache que não introduz armazenamento persistente.
29
+ */
30
+ import { type SeriePopular } from "./shared.js";
31
+ export declare const CKAN_PACKAGE_LIST = "https://dadosabertos.bcb.gov.br/api/3/action/package_list";
32
+ export declare const CKAN_DATASET_BASE = "https://dadosabertos.bcb.gov.br/dataset";
33
+ /** Validade do catálogo em cache: 24 h (decisão do decisor). */
34
+ export declare const CATALOGO_TTL_MS: number;
35
+ /** Uma entrada do índice: código da série + slug do dataset. Só metadados. */
36
+ export interface EntradaCatalogo {
37
+ codigo: number;
38
+ slug: string;
39
+ }
40
+ export interface SnapshotCatalogo {
41
+ entradas: EntradaCatalogo[];
42
+ /** ISO 8601 do momento em que o índice foi obtido da origem. */
43
+ obtidoEm: string;
44
+ /** Total de datasets devolvidos pelo portal (inclui os sem código). */
45
+ totalDatasets: number;
46
+ expiraEm: number;
47
+ }
48
+ export interface ResultadoCatalogo {
49
+ snapshot: SnapshotCatalogo | null;
50
+ /** Preenchido quando o índice servido não é o ideal (vencido, ou ausente). */
51
+ aviso?: string;
52
+ }
53
+ /** Só para os testes: zera o cache do módulo. */
54
+ export declare function _resetCatalogo(): void;
55
+ /** Só para os testes: injeta um snapshot como se tivesse vindo da origem. */
56
+ export declare function _seedCatalogo(snapshot: SnapshotCatalogo): void;
57
+ /**
58
+ * Conserta mojibake de ISO-8859-1 servido como UTF-8 ("Câmbio" -> "Câmbio").
59
+ * Os slugs do `package_list` são ASCII, então isto é defesa para os campos de
60
+ * texto do CKAN que já apareceram corrompidos na verificação de abertura.
61
+ */
62
+ export declare function normalizarMojibake(texto: string): string;
63
+ /**
64
+ * Nome legível a partir do slug do dataset. O `package_list` devolve slug, não
65
+ * título: `---` é separador de campos e `-` separa palavras, e os acentos foram
66
+ * perdidos na origem — daí o nome reconstruído ser aproximado de propósito. Para
67
+ * as séries do catálogo curado o nome bom (com acento) prevalece; para as
68
+ * demais, quem quiser o nome oficial usa `bcb_serie_metadados`.
69
+ */
70
+ export declare function nomeDoSlug(slug: string): string;
71
+ /** `1-taxa-de-cambio---livre---dolar-americano-venda---diario` -> {1, slug}. */
72
+ export declare function parsePackageList(nomes: unknown): {
73
+ entradas: EntradaCatalogo[];
74
+ totalDatasets: number;
75
+ };
76
+ /**
77
+ * Devolve o índice do portal, renovando de forma bloqueante quando vencido.
78
+ *
79
+ * Degradação: se a renovação falhar e houver retrato anterior, ele é servido
80
+ * COM aviso e com a data de obtenção visível — a API do BCB cai de verdade
81
+ * (ocorreu durante esta fase), e nesse caso é melhor um índice velho declarado
82
+ * do que busca nenhuma. Sem retrato anterior, devolve `snapshot: null` e quem
83
+ * chamou cai no catálogo curado.
84
+ */
85
+ export declare function obterCatalogo(timeoutMs?: number, maxRetries?: number): Promise<ResultadoCatalogo>;
86
+ export type OrigemSerie = "curado" | "indice";
87
+ export interface SerieEncontrada {
88
+ codigo: number;
89
+ nome: string;
90
+ categoria?: string;
91
+ periodicidade?: string;
92
+ /** `curado` = catálogo local com nome/categoria revisados; `indice` = portal. */
93
+ origem: OrigemSerie;
94
+ /** Página do dataset no portal (só para achados do índice). */
95
+ dataset?: string;
96
+ }
97
+ /**
98
+ * Ranqueia os achados. O catálogo curado é a CAMADA DE DESTAQUE: quando uma
99
+ * série está nele, ela vem primeiro e com o nome bom, porque foi revisada à
100
+ * mão; o índice do portal entra depois, ordenado do slug mais curto (mais
101
+ * específico) para o mais longo, com desempate estável pelo código.
102
+ */
103
+ export declare function buscarSeries(termo: string, curadoria: SeriePopular[], entradas: EntradaCatalogo[] | null, limite: number): {
104
+ total: number;
105
+ series: SerieEncontrada[];
106
+ };
107
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAE9E,eAAO,MAAM,iBAAiB,8DAA8D,CAAC;AAC7F,eAAO,MAAM,iBAAiB,4CAA4C,CAAC;AAE3E,gEAAgE;AAChE,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAkBvG;AAwBD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA+BvG;AAID,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,MAAM,EAAE,WAAW,CAAC;IACpB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,YAAY,EAAE,EACzB,QAAQ,EAAE,eAAe,EAAE,GAAG,IAAI,EAClC,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CA6B9C"}