brasil-data-mcp 0.2.0 → 0.3.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
@@ -7,9 +7,9 @@
7
7
  [![node](https://img.shields.io/node/v/brasil-data-mcp.svg)](https://nodejs.org)
8
8
  [![Glama MCP server](https://glama.ai/mcp/servers/alanpcf/brasil-data-mcp/badges/score.svg)](https://glama.ai/mcp/servers/alanpcf/brasil-data-mcp)
9
9
 
10
- > MCP server que expõe dados públicos brasileiros (CNPJ, CEP, bancos, feriados, DDD, ISBN, taxas econômicas, corretoras CVM) como tools pra Claude Desktop, Claude Code, Cursor, Windsurf e qualquer cliente compatível com [Model Context Protocol](https://modelcontextprotocol.io). Inclui também **prompts MCP** (workflows guiados).
10
+ > MCP server que expõe dados públicos brasileiros (CNPJ, CEP, bancos, feriados, DDD, ISBN, taxas econômicas, câmbio, corretoras CVM, estados e municípios IBGE, domínios .br) como tools pra Claude Desktop, Claude Code, Cursor, Windsurf e qualquer cliente compatível com [Model Context Protocol](https://modelcontextprotocol.io). Inclui também **prompts MCP** (workflows guiados).
11
11
  >
12
- > _MCP server exposing Brazilian public data (CNPJ, CEP, banks, holidays, area codes, ISBN, economic rates, CVM brokers) as tools for Claude Desktop, Claude Code, Cursor, Windsurf and any MCP-compatible client. Ships with MCP prompts for guided workflows._
12
+ > _MCP server exposing Brazilian public data (CNPJ, CEP, banks, holidays, area codes, ISBN, economic rates, exchange rates, CVM brokers, IBGE states/municipalities, .br domains) as tools for Claude Desktop, Claude Code, Cursor, Windsurf and any MCP-compatible client. Ships with MCP prompts for guided workflows._
13
13
 
14
14
  Powered by [BrasilAPI](https://brasilapi.com.br) — sem chave, sem auth, dados oficiais.
15
15
 
@@ -27,10 +27,13 @@ Conecte seu cliente de IA aos dados públicos brasileiros sem escrever uma linha
27
27
  - _"Me dá o livro do ISBN 9788532530802."_
28
28
  - _"Qual a SELIC hoje?"_
29
29
  - _"A corretora de CNPJ 02.332.886/0011-78 ainda tá ativa?"_
30
+ - _"Quanto fechou o dólar sexta-feira?"_
31
+ - _"Quais os municípios do Acre?"_
32
+ - _"meuprojeto.com.br tá disponível?"_
30
33
 
31
34
  O Claude (ou outro cliente MCP) chama a tool, retorna o JSON estruturado, e você lê a resposta em português direto na conversa.
32
35
 
33
- ### Tools disponíveis (10)
36
+ ### Tools disponíveis (15)
34
37
 
35
38
  | Tool | O que faz |
36
39
  | ---------------------- | ---------------------------------------------------------------------------------- |
@@ -44,6 +47,11 @@ O Claude (ou outro cliente MCP) chama a tool, retorna o JSON estruturado, e voc
44
47
  | `consultar_taxa` | Valor atual de taxa econômica (SELIC, CDI, IPCA) em % ao ano |
45
48
  | `listar_taxas` | Panorama com todas as taxas econômicas vigentes |
46
49
  | `consultar_corretora` | Dados cadastrais de corretora de valores autorizada pela CVM (status, endereço) |
50
+ | `consultar_cambio` | Cotação de câmbio (USD, EUR, +8 moedas) em BRL por data — boletins PTAX/BACEN |
51
+ | `listar_moedas` | Moedas estrangeiras com cotação disponível (símbolo, nome, tipo) |
52
+ | `listar_estados` | As 27 UFs com código IBGE, nome, região e capital |
53
+ | `consultar_municipios` | Municípios de uma UF com nome e código IBGE de 7 dígitos |
54
+ | `consultar_dominio_br` | Disponibilidade/status de domínio .br no registro.br (DNS, expiração, sugestões) |
47
55
 
48
56
  ### Prompts disponíveis (2)
49
57
 
@@ -60,7 +68,7 @@ Prompts MCP são **workflows guiados** que aparecem como atalho no Claude Deskto
60
68
 
61
69
  Plug your AI client into Brazilian public data with zero code. Ask in natural language and the LLM picks the right tool, calls it, and answers you with structured data from official sources (Receita Federal, ViaCEP, BACEN, CVM, BrasilAPI).
62
70
 
63
- 10 tools covering CNPJ, CEP, banks, holidays, area codes (DDD), ISBN, economic rates (SELIC/CDI/IPCA) and CVM brokers — plus 2 MCP prompts (`analise-cnpj`, `panorama-economico`) for guided workflows.
71
+ 15 tools covering CNPJ, CEP, banks, holidays, area codes (DDD), ISBN, economic rates (SELIC/CDI/IPCA), exchange rates (PTAX/BACEN), CVM brokers, IBGE states and municipalities, and .br domain availability — plus 2 MCP prompts (`analise-cnpj`, `panorama-economico`) for guided workflows.
64
72
 
65
73
  ---
66
74
 
@@ -145,6 +153,7 @@ Pra apontar seu cliente MCP pro build local em vez do pacote do npm:
145
153
  - [x] **Fase 2** — `consultar_cep`, `consultar_banco`, `listar_bancos`, `consultar_feriados` + testes Vitest
146
154
  - [x] **Fase 3** — CI (GitHub Actions), `CONTRIBUTING.md`, cobertura 94%/85%, publicação no [npm](https://www.npmjs.com/package/brasil-data-mcp), listagem no [Glama](https://glama.ai/mcp/servers/alanpcf/brasil-data-mcp)
147
155
  - [x] **Fase 4 (v0.2.0)** — `consultar_ddd`, `consultar_isbn`, `consultar_taxa` + `listar_taxas`, `consultar_corretora` (CVM) + MCP prompts (`analise-cnpj`, `panorama-economico`)
156
+ - [x] **Fase 5 (v0.3.0)** — `consultar_cambio` + `listar_moedas` (PTAX/BACEN), `listar_estados` + `consultar_municipios` (IBGE), `consultar_dominio_br` (registro.br); versão single-source; registry declarativo de tools; testes do caminho de retry
148
157
  - [ ] **Próximo** — FIPE (aguardando upstream estabilizar, [BrasilAPI#805](https://github.com/BrasilAPI/BrasilAPI/issues/805)); Trusted Publishing (npm OIDC); mais prompts conforme demanda
149
158
 
150
159
  ---
@@ -163,7 +172,7 @@ Se você é dev brasileiro e usa LLM no dia a dia, esse server é pra você.
163
172
 
164
173
  Issues e PRs muito bem-vindos. Pra adicionar uma tool nova, siga o padrão de `src/tools/cnpj.ts` (schema Zod + descrição + handler) e registre em `src/index.ts`.
165
174
 
166
- Guia detalhado em `CONTRIBUTING.md` _(em breve)_.
175
+ Guia detalhado em [CONTRIBUTING.md](./CONTRIBUTING.md).
167
176
 
168
177
  ---
169
178
 
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
6
  *
7
7
  * Boot:
8
8
  * 1. Cria um McpServer (high-level API do SDK 1.x).
9
- * 2. Registra cada tool via registerTool — o SDK deriva o JSON Schema do
9
+ * 2. Registra cada tool do array TOOLS — o SDK deriva o JSON Schema do
10
10
  * schema Zod, então atendemos "validação dupla" (Zod runtime + JSON
11
11
  * Schema na definição) com uma única declaração por tool.
12
12
  * 3. Registra prompts (workflows) via registerPrompt.
@@ -15,9 +15,9 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
15
  * REGRA CRÍTICA: nunca escrever em stdout fora do protocolo. Logs em stderr
16
16
  * via console.error. console.log corrompe o canal MCP.
17
17
  *
18
- * REGISTRY: adicionar tool nova = uma chamada de registerTool. O helper
19
- * wrapHandler aplica o try/catch defensivo padronizado (bug numa tool não
20
- * derruba o server).
18
+ * REGISTRY: adicionar tool nova = uma entrada no array TOOLS. O loop de
19
+ * registro aplica o wrapHandler (try/catch defensivo padronizado bug numa
20
+ * tool não derruba o server) uniformemente, sem risco de esquecer.
21
21
  */
22
22
 
23
23
  declare function createServer(): McpServer;
package/dist/index.js CHANGED
@@ -85,12 +85,27 @@ function panoramaEconomicoHandler() {
85
85
  // src/tools/banco.ts
86
86
  import { z as z2 } from "zod";
87
87
 
88
+ // src/version.ts
89
+ import { readFileSync } from "fs";
90
+ function lerVersao() {
91
+ try {
92
+ const raw = readFileSync(
93
+ new URL("../package.json", import.meta.url),
94
+ "utf-8"
95
+ );
96
+ return JSON.parse(raw).version ?? "0.0.0";
97
+ } catch {
98
+ return "0.0.0";
99
+ }
100
+ }
101
+ var VERSION = lerVersao();
102
+
88
103
  // src/clients/brasilapi.ts
89
104
  var BASE_URL = "https://brasilapi.com.br/api";
90
105
  var DEFAULT_TIMEOUT_MS = 1e4;
91
106
  var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
92
107
  var MAX_RETRIES = 3;
93
- var USER_AGENT = "brasil-data-mcp/0.2.0 (+https://github.com/alanpcf/brasil-data-mcp)";
108
+ var USER_AGENT = `brasil-data-mcp/${VERSION} (+https://github.com/alanpcf/brasil-data-mcp)`;
94
109
  var BrasilApiError = class extends Error {
95
110
  constructor(message, status, path, body) {
96
111
  super(message);
@@ -308,10 +323,174 @@ async function listarBancosHandler(_input) {
308
323
  }
309
324
  }
310
325
 
311
- // src/tools/cep.ts
326
+ // src/tools/cambio.ts
312
327
  import { z as z3 } from "zod";
313
- var consultarCepSchema = z3.object({
314
- cep: z3.string().describe(
328
+ var MOEDAS_VALIDAS = /* @__PURE__ */ new Set([
329
+ "AUD",
330
+ "CAD",
331
+ "CHF",
332
+ "DKK",
333
+ "EUR",
334
+ "GBP",
335
+ "JPY",
336
+ "NOK",
337
+ "SEK",
338
+ "USD"
339
+ ]);
340
+ function hojeSaoPaulo() {
341
+ return new Intl.DateTimeFormat("en-CA", {
342
+ timeZone: "America/Sao_Paulo"
343
+ }).format(/* @__PURE__ */ new Date());
344
+ }
345
+ function diaAnterior(iso) {
346
+ const d = /* @__PURE__ */ new Date(`${iso}T12:00:00Z`);
347
+ d.setUTCDate(d.getUTCDate() - 1);
348
+ return d.toISOString().slice(0, 10);
349
+ }
350
+ function normalizarData(entrada) {
351
+ const s = entrada.trim();
352
+ let iso;
353
+ const brasileira = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(s);
354
+ if (brasileira) {
355
+ iso = `${brasileira[3]}-${brasileira[2]}-${brasileira[1]}`;
356
+ } else if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
357
+ iso = s;
358
+ } else {
359
+ return null;
360
+ }
361
+ const d = /* @__PURE__ */ new Date(`${iso}T12:00:00Z`);
362
+ if (Number.isNaN(d.getTime()) || d.toISOString().slice(0, 10) !== iso) {
363
+ return null;
364
+ }
365
+ return iso;
366
+ }
367
+ var consultarCambioSchema = z3.object({
368
+ moeda: z3.string().describe(
369
+ "C\xF3digo da moeda (ISO 4217), case-insensitive. Aceitas: USD, EUR, GBP, JPY, CHF, CAD, AUD, DKK, NOK, SEK. Ex: 'USD'."
370
+ ),
371
+ data: z3.string().optional().describe(
372
+ "Data da cota\xE7\xE3o no formato YYYY-MM-DD (aceita tamb\xE9m DD/MM/YYYY). Se omitida, usa ontem (fuso de Bras\xEDlia) \u2014 a fonte n\xE3o exp\xF5e o dia corrente. Em data sem preg\xE3o (fim de semana, feriado) a API retorna as cota\xE7\xF5es do \xFAltimo dia \xFAtil anterior."
373
+ )
374
+ });
375
+ var consultarCambioTool = {
376
+ name: "consultar_cambio",
377
+ description: [
378
+ "Consulta a cota\xE7\xE3o de c\xE2mbio oficial de uma moeda estrangeira em rela\xE7\xE3o ao Real (BRL) numa data, via boletins PTAX do Banco Central (BrasilAPI).",
379
+ "",
380
+ "Retorna em JSON os boletins do dia (ABERTURA, INTERMEDI\xC1RIO, FECHAMENTO) com cota\xE7\xE3o de compra e venda em BRL, paridade e data_hora_cotacao. A fonte N\xC3O exp\xF5e o dia corrente: com data omitida a tool consulta ontem (a cota\xE7\xE3o mais recente dispon\xEDvel), e em data sem preg\xE3o a API retorna os boletins do \xFAltimo dia \xFAtil anterior.",
381
+ "",
382
+ "Use quando o usu\xE1rio perguntar 'quanto t\xE1 o d\xF3lar?' (retorna a cota\xE7\xE3o mais recente, do dia \xFAtil anterior), 'cota\xE7\xE3o do euro em 26/06', 'quanto fechou a libra sexta-feira' \u2014 qualquer pergunta sobre valor de moeda estrangeira em reais.",
383
+ "",
384
+ "N\xC3O use para: criptomoedas (n\xE3o est\xE1 nesta API), BRL (\xE9 a moeda base), s\xE9rie hist\xF3rica (uma data por chamada), ou moedas fora das 10 suportadas \u2014 pra descobrir as moedas dispon\xEDveis use listar_moedas."
385
+ ].join(" "),
386
+ inputSchema: consultarCambioSchema
387
+ };
388
+ async function consultarCambioHandler(input) {
389
+ const moeda = input.moeda.trim().toUpperCase();
390
+ if (!MOEDAS_VALIDAS.has(moeda)) {
391
+ return {
392
+ content: [
393
+ {
394
+ type: "text",
395
+ text: `Moeda n\xE3o suportada: '${input.moeda}'. Use uma de: ${[...MOEDAS_VALIDAS].join(", ")}.`
396
+ }
397
+ ],
398
+ isError: true
399
+ };
400
+ }
401
+ const hoje = hojeSaoPaulo();
402
+ const ontem = diaAnterior(hoje);
403
+ let data;
404
+ if (input.data === void 0) {
405
+ data = ontem;
406
+ } else {
407
+ const normalizada = normalizarData(input.data);
408
+ if (normalizada === null) {
409
+ return {
410
+ content: [
411
+ {
412
+ type: "text",
413
+ text: `Data inv\xE1lida: '${input.data}'. Use o formato YYYY-MM-DD (ex: ${ontem}) ou DD/MM/YYYY.`
414
+ }
415
+ ],
416
+ isError: true
417
+ };
418
+ }
419
+ data = normalizada;
420
+ }
421
+ if (data >= hoje) {
422
+ return {
423
+ content: [
424
+ {
425
+ type: "text",
426
+ text: `A fonte n\xE3o fornece cota\xE7\xE3o do dia corrente nem de datas futuras ('${data}'). A cota\xE7\xE3o mais recente dispon\xEDvel \xE9 a de ${ontem} \u2014 omita 'data' pra us\xE1-la.`
427
+ }
428
+ ],
429
+ isError: true
430
+ };
431
+ }
432
+ try {
433
+ const dados = await brasilApi.get(
434
+ `/cambio/v1/cotacao/${moeda}/${data}`
435
+ );
436
+ return {
437
+ content: [{ type: "text", text: JSON.stringify(dados, null, 2) }]
438
+ };
439
+ } catch (err) {
440
+ return {
441
+ content: [
442
+ {
443
+ type: "text",
444
+ text: traduzirErroBrasilApi(err, {
445
+ notFound: `Cota\xE7\xE3o de ${moeda} n\xE3o encontrada para ${data}.`,
446
+ contextoErro: "Erro ao consultar c\xE2mbio"
447
+ })
448
+ }
449
+ ],
450
+ isError: true
451
+ };
452
+ }
453
+ }
454
+ var listarMoedasSchema = z3.object({});
455
+ var listarMoedasTool = {
456
+ name: "listar_moedas",
457
+ description: [
458
+ "Lista as moedas estrangeiras com cota\xE7\xE3o dispon\xEDvel na BrasilAPI (boletins PTAX/BACEN).",
459
+ "",
460
+ "Retorna em JSON um array com s\xEDmbolo (ISO 4217), nome e tipo de cada moeda \u2014 10 moedas: USD, EUR, GBP, JPY, CHF, CAD, AUD, DKK, NOK, SEK.",
461
+ "",
462
+ "Use quando o usu\xE1rio quiser saber quais moedas t\xEAm cota\xE7\xE3o dispon\xEDvel ou n\xE3o souber o c\xF3digo da moeda.",
463
+ "",
464
+ "N\xC3O use para obter a cota\xE7\xE3o em si \u2014 use consultar_cambio."
465
+ ].join(" "),
466
+ inputSchema: listarMoedasSchema
467
+ };
468
+ async function listarMoedasHandler(_input) {
469
+ try {
470
+ const dados = await brasilApi.get("/cambio/v1/moedas");
471
+ return {
472
+ content: [{ type: "text", text: JSON.stringify(dados, null, 2) }]
473
+ };
474
+ } catch (err) {
475
+ return {
476
+ content: [
477
+ {
478
+ type: "text",
479
+ text: traduzirErroBrasilApi(err, {
480
+ notFound: "Lista de moedas n\xE3o dispon\xEDvel no momento.",
481
+ contextoErro: "Erro ao listar moedas"
482
+ })
483
+ }
484
+ ],
485
+ isError: true
486
+ };
487
+ }
488
+ }
489
+
490
+ // src/tools/cep.ts
491
+ import { z as z4 } from "zod";
492
+ var consultarCepSchema = z4.object({
493
+ cep: z4.string().describe(
315
494
  "CEP brasileiro com ou sem h\xEDfen. Aceita '01310-100' ou '01310100'. Deve ter 8 d\xEDgitos."
316
495
  )
317
496
  });
@@ -371,7 +550,7 @@ async function consultarCepHandler(input) {
371
550
  }
372
551
 
373
552
  // src/tools/cnpj.ts
374
- import { z as z4 } from "zod";
553
+ import { z as z5 } from "zod";
375
554
 
376
555
  // src/utils/cnpj.ts
377
556
  function limparCnpj(s) {
@@ -384,8 +563,8 @@ function validarCnpj(s) {
384
563
  }
385
564
 
386
565
  // src/tools/cnpj.ts
387
- var consultarCnpjSchema = z4.object({
388
- cnpj: z4.string().describe(
566
+ var consultarCnpjSchema = z5.object({
567
+ cnpj: z5.string().describe(
389
568
  "CNPJ da empresa, com ou sem m\xE1scara. Aceita '12.345.678/0001-90' ou '12345678000190'. Deve ter 14 d\xEDgitos."
390
569
  )
391
570
  });
@@ -449,9 +628,9 @@ async function consultarCnpjHandler(input) {
449
628
  }
450
629
 
451
630
  // src/tools/corretoras.ts
452
- import { z as z5 } from "zod";
453
- var consultarCorretoraSchema = z5.object({
454
- cnpj: z5.string().describe(
631
+ import { z as z6 } from "zod";
632
+ var consultarCorretoraSchema = z6.object({
633
+ cnpj: z6.string().describe(
455
634
  "CNPJ da corretora, com ou sem m\xE1scara. 14 d\xEDgitos. Ex: '02.332.886/0011-78' (XP Investimentos)."
456
635
  )
457
636
  });
@@ -505,9 +684,9 @@ async function consultarCorretoraHandler(input) {
505
684
  }
506
685
 
507
686
  // src/tools/ddd.ts
508
- import { z as z6 } from "zod";
509
- var consultarDddSchema = z6.object({
510
- ddd: z6.union([z6.string(), z6.number()]).describe(
687
+ import { z as z7 } from "zod";
688
+ var consultarDddSchema = z7.object({
689
+ ddd: z7.union([z7.string(), z7.number()]).describe(
511
690
  "C\xF3digo DDD brasileiro (2 d\xEDgitos). Aceita string ou n\xFAmero. Ex: 11 (S\xE3o Paulo capital), 21 (Rio), 41 (Curitiba), 71 (Salvador)."
512
691
  )
513
692
  });
@@ -563,10 +742,76 @@ async function consultarDddHandler(input) {
563
742
  }
564
743
  }
565
744
 
745
+ // src/tools/dominio.ts
746
+ import { z as z8 } from "zod";
747
+ function normalizarDominio(entrada) {
748
+ const semProtocolo = entrada.trim().toLowerCase().replace(/^https?:\/\//, "");
749
+ const semPath = semProtocolo.split("/")[0] ?? "";
750
+ return semPath.replace(/^www\./, "");
751
+ }
752
+ function validarDominioBr(dominio) {
753
+ return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*\.br$/.test(
754
+ dominio
755
+ );
756
+ }
757
+ var consultarDominioBrSchema = z8.object({
758
+ dominio: z8.string().describe(
759
+ "Dom\xEDnio .br a verificar. Aceita URL completa ou dom\xEDnio puro \u2014 ser\xE1 normalizado (remove http(s)://, www. e caminho). Ex: 'exemplo.com.br' ou 'https://www.exemplo.com.br/pagina'."
760
+ )
761
+ });
762
+ var consultarDominioBrTool = {
763
+ name: "consultar_dominio_br",
764
+ description: [
765
+ "Consulta o status de registro de um dom\xEDnio .br direto na base do registro.br (via BrasilAPI).",
766
+ "",
767
+ "Retorna em JSON: status (AVAILABLE = dispon\xEDvel pra registro, REGISTERED = j\xE1 registrado), fqdn, hosts (servidores DNS) e expires-at quando registrado, e suggestions de extens\xF5es quando dispon\xEDvel. O resultado nunca \xE9 cacheado \u2014 \xE9 sempre o status atual.",
768
+ "",
769
+ "Use quando o usu\xE1rio perguntar 'o dom\xEDnio X.com.br t\xE1 livre?', 'quando expira Y.org.br?', 'quem responde pelo DNS de Z.br?'.",
770
+ "",
771
+ "N\xC3O use para: dom\xEDnios internacionais .com/.net/gTLDs (a base \xE9 s\xF3 .br), dados de titular/whois completo (a API n\xE3o exp\xF5e), ou hospedagem/conte\xFAdo do site."
772
+ ].join(" "),
773
+ inputSchema: consultarDominioBrSchema
774
+ };
775
+ async function consultarDominioBrHandler(input) {
776
+ const dominio = normalizarDominio(input.dominio);
777
+ if (!validarDominioBr(dominio)) {
778
+ return {
779
+ content: [
780
+ {
781
+ type: "text",
782
+ text: `Dom\xEDnio inv\xE1lido: '${input.dominio}'. Esta tool s\xF3 consulta dom\xEDnios .br (registro.br). Ex: 'exemplo.com.br'.`
783
+ }
784
+ ],
785
+ isError: true
786
+ };
787
+ }
788
+ try {
789
+ const dados = await brasilApi.get(`/registrobr/v1/${dominio}`, {
790
+ ttlMs: 0
791
+ });
792
+ return {
793
+ content: [{ type: "text", text: JSON.stringify(dados, null, 2) }]
794
+ };
795
+ } catch (err) {
796
+ return {
797
+ content: [
798
+ {
799
+ type: "text",
800
+ text: traduzirErroBrasilApi(err, {
801
+ notFound: `Dom\xEDnio ${dominio} n\xE3o encontrado na base do registro.br.`,
802
+ contextoErro: "Erro ao consultar dom\xEDnio"
803
+ })
804
+ }
805
+ ],
806
+ isError: true
807
+ };
808
+ }
809
+ }
810
+
566
811
  // src/tools/feriados.ts
567
- import { z as z7 } from "zod";
568
- var consultarFeriadosSchema = z7.object({
569
- ano: z7.number().int().describe(
812
+ import { z as z9 } from "zod";
813
+ var consultarFeriadosSchema = z9.object({
814
+ ano: z9.number().int().describe(
570
815
  "Ano dos feriados, 4 d\xEDgitos. Faixa aceita: 1900 a 2199. Ex: 2026."
571
816
  )
572
817
  });
@@ -619,10 +864,128 @@ async function consultarFeriadosHandler(input) {
619
864
  }
620
865
  }
621
866
 
867
+ // src/tools/ibge.ts
868
+ import { z as z10 } from "zod";
869
+ var UFS_VALIDAS = /* @__PURE__ */ new Set([
870
+ "AC",
871
+ "AL",
872
+ "AP",
873
+ "AM",
874
+ "BA",
875
+ "CE",
876
+ "DF",
877
+ "ES",
878
+ "GO",
879
+ "MA",
880
+ "MT",
881
+ "MS",
882
+ "MG",
883
+ "PA",
884
+ "PB",
885
+ "PR",
886
+ "PE",
887
+ "PI",
888
+ "RJ",
889
+ "RN",
890
+ "RS",
891
+ "RO",
892
+ "RR",
893
+ "SC",
894
+ "SP",
895
+ "SE",
896
+ "TO"
897
+ ]);
898
+ var listarEstadosSchema = z10.object({});
899
+ var listarEstadosTool = {
900
+ name: "listar_estados",
901
+ description: [
902
+ "Lista as 27 unidades federativas do Brasil (26 estados + DF) com dados do IBGE, via BrasilAPI.",
903
+ "",
904
+ "Retorna em JSON um array com id (c\xF3digo IBGE), sigla, nome, regi\xE3o (Norte/Nordeste/Centro-Oeste/Sudeste/Sul) e capital de cada UF.",
905
+ "",
906
+ "Use quando o usu\xE1rio precisar do c\xF3digo IBGE de um estado, agrupar estados por regi\xE3o, validar siglas de UF ou saber a capital.",
907
+ "",
908
+ "N\xC3O use para: munic\xEDpios (use consultar_municipios), dados demogr\xE1ficos ou populacionais (n\xE3o est\xE3o nesta API)."
909
+ ].join(" "),
910
+ inputSchema: listarEstadosSchema
911
+ };
912
+ async function listarEstadosHandler(_input) {
913
+ try {
914
+ const dados = await brasilApi.get("/ibge/uf/v1");
915
+ return {
916
+ content: [{ type: "text", text: JSON.stringify(dados, null, 2) }]
917
+ };
918
+ } catch (err) {
919
+ return {
920
+ content: [
921
+ {
922
+ type: "text",
923
+ text: traduzirErroBrasilApi(err, {
924
+ notFound: "Lista de estados n\xE3o dispon\xEDvel no momento.",
925
+ contextoErro: "Erro ao listar estados"
926
+ })
927
+ }
928
+ ],
929
+ isError: true
930
+ };
931
+ }
932
+ }
933
+ var consultarMunicipiosSchema = z10.object({
934
+ uf: z10.string().describe(
935
+ "Sigla da unidade federativa, 2 letras, case-insensitive. Ex: 'SP', 'rj', 'DF'."
936
+ )
937
+ });
938
+ var consultarMunicipiosTool = {
939
+ name: "consultar_municipios",
940
+ description: [
941
+ "Lista todos os munic\xEDpios de uma UF brasileira com nome e c\xF3digo IBGE de 7 d\xEDgitos, via BrasilAPI.",
942
+ "",
943
+ "Retorna em JSON um array de {nome, codigo_ibge}. Aten\xE7\xE3o: estados grandes retornam listas longas (SP tem 645 munic\xEDpios, ~30KB) \u2014 prefira usar s\xF3 quando precisar da lista ou do c\xF3digo de um munic\xEDpio.",
944
+ "",
945
+ "Use quando o usu\xE1rio precisar do c\xF3digo IBGE de um munic\xEDpio ou listar as cidades de um estado.",
946
+ "",
947
+ "N\xC3O use para: buscar um munic\xEDpio por nome no pa\xEDs inteiro (a API s\xF3 filtra por UF \u2014 se souber o estado, consulte-o), endere\xE7os/CEP (use consultar_cep), ou dados populacionais."
948
+ ].join(" "),
949
+ inputSchema: consultarMunicipiosSchema
950
+ };
951
+ async function consultarMunicipiosHandler(input) {
952
+ const uf = input.uf.trim().toUpperCase();
953
+ if (!UFS_VALIDAS.has(uf)) {
954
+ return {
955
+ content: [
956
+ {
957
+ type: "text",
958
+ text: `UF inv\xE1lida: '${input.uf}'. Use uma sigla de estado brasileiro, ex: SP, RJ, MG.`
959
+ }
960
+ ],
961
+ isError: true
962
+ };
963
+ }
964
+ try {
965
+ const dados = await brasilApi.get(`/ibge/municipios/v1/${uf}`);
966
+ return {
967
+ content: [{ type: "text", text: JSON.stringify(dados, null, 2) }]
968
+ };
969
+ } catch (err) {
970
+ return {
971
+ content: [
972
+ {
973
+ type: "text",
974
+ text: traduzirErroBrasilApi(err, {
975
+ notFound: `Munic\xEDpios da UF ${uf} n\xE3o encontrados.`,
976
+ contextoErro: "Erro ao consultar munic\xEDpios"
977
+ })
978
+ }
979
+ ],
980
+ isError: true
981
+ };
982
+ }
983
+ }
984
+
622
985
  // src/tools/isbn.ts
623
- import { z as z8 } from "zod";
624
- var consultarIsbnSchema = z8.object({
625
- codigo: z8.string().describe(
986
+ import { z as z11 } from "zod";
987
+ var consultarIsbnSchema = z11.object({
988
+ codigo: z11.string().describe(
626
989
  "ISBN do livro, 10 ou 13 d\xEDgitos. Aceita com ou sem h\xEDfens. Ex: '978-85-325-3080-2' ou '9788532530802'."
627
990
  )
628
991
  });
@@ -682,10 +1045,10 @@ async function consultarIsbnHandler(input) {
682
1045
  }
683
1046
 
684
1047
  // src/tools/taxas.ts
685
- import { z as z9 } from "zod";
1048
+ import { z as z12 } from "zod";
686
1049
  var TTL_TAXAS_MS = 60 * 60 * 1e3;
687
- var consultarTaxaSchema = z9.object({
688
- sigla: z9.string().describe(
1050
+ var consultarTaxaSchema = z12.object({
1051
+ sigla: z12.string().describe(
689
1052
  "Sigla da taxa, case-insensitive. Aceita: 'Selic' (taxa b\xE1sica de juros), 'CDI' (Certificado de Dep\xF3sito Interbanc\xE1rio), 'IPCA' (infla\xE7\xE3o oficial)."
690
1053
  )
691
1054
  });
@@ -741,7 +1104,7 @@ async function consultarTaxaHandler(input) {
741
1104
  };
742
1105
  }
743
1106
  }
744
- var listarTaxasSchema = z9.object({});
1107
+ var listarTaxasSchema = z12.object({});
745
1108
  var listarTaxasTool = {
746
1109
  name: "listar_taxas",
747
1110
  description: [
@@ -780,7 +1143,6 @@ async function listarTaxasHandler(_input) {
780
1143
  }
781
1144
 
782
1145
  // src/index.ts
783
- var VERSION = "0.2.0";
784
1146
  function wrapHandler(toolName, handler) {
785
1147
  return async (input) => {
786
1148
  try {
@@ -799,91 +1161,39 @@ function wrapHandler(toolName, handler) {
799
1161
  }
800
1162
  };
801
1163
  }
1164
+ var TOOLS = [
1165
+ { tool: consultarCnpjTool, handler: consultarCnpjHandler },
1166
+ { tool: consultarCepTool, handler: consultarCepHandler },
1167
+ { tool: consultarBancoTool, handler: consultarBancoHandler },
1168
+ { tool: listarBancosTool, handler: listarBancosHandler },
1169
+ { tool: consultarFeriadosTool, handler: consultarFeriadosHandler },
1170
+ { tool: consultarDddTool, handler: consultarDddHandler },
1171
+ { tool: consultarIsbnTool, handler: consultarIsbnHandler },
1172
+ { tool: consultarTaxaTool, handler: consultarTaxaHandler },
1173
+ { tool: listarTaxasTool, handler: listarTaxasHandler },
1174
+ { tool: consultarCorretoraTool, handler: consultarCorretoraHandler },
1175
+ // Fase 5 (v0.3.0):
1176
+ { tool: consultarCambioTool, handler: consultarCambioHandler },
1177
+ { tool: listarMoedasTool, handler: listarMoedasHandler },
1178
+ { tool: listarEstadosTool, handler: listarEstadosHandler },
1179
+ { tool: consultarMunicipiosTool, handler: consultarMunicipiosHandler },
1180
+ { tool: consultarDominioBrTool, handler: consultarDominioBrHandler }
1181
+ ];
802
1182
  function createServer() {
803
1183
  const server = new McpServer({
804
1184
  name: "brasil-data-mcp",
805
1185
  version: VERSION
806
1186
  });
807
- server.registerTool(
808
- consultarCnpjTool.name,
809
- {
810
- description: consultarCnpjTool.description,
811
- inputSchema: consultarCnpjSchema.shape
812
- },
813
- wrapHandler(consultarCnpjTool.name, consultarCnpjHandler)
814
- );
815
- server.registerTool(
816
- consultarCepTool.name,
817
- {
818
- description: consultarCepTool.description,
819
- inputSchema: consultarCepSchema.shape
820
- },
821
- wrapHandler(consultarCepTool.name, consultarCepHandler)
822
- );
823
- server.registerTool(
824
- consultarBancoTool.name,
825
- {
826
- description: consultarBancoTool.description,
827
- inputSchema: consultarBancoSchema.shape
828
- },
829
- wrapHandler(consultarBancoTool.name, consultarBancoHandler)
830
- );
831
- server.registerTool(
832
- listarBancosTool.name,
833
- {
834
- description: listarBancosTool.description,
835
- inputSchema: listarBancosSchema.shape
836
- },
837
- wrapHandler(listarBancosTool.name, listarBancosHandler)
838
- );
839
- server.registerTool(
840
- consultarFeriadosTool.name,
841
- {
842
- description: consultarFeriadosTool.description,
843
- inputSchema: consultarFeriadosSchema.shape
844
- },
845
- wrapHandler(consultarFeriadosTool.name, consultarFeriadosHandler)
846
- );
847
- server.registerTool(
848
- consultarDddTool.name,
849
- {
850
- description: consultarDddTool.description,
851
- inputSchema: consultarDddSchema.shape
852
- },
853
- wrapHandler(consultarDddTool.name, consultarDddHandler)
854
- );
855
- server.registerTool(
856
- consultarIsbnTool.name,
857
- {
858
- description: consultarIsbnTool.description,
859
- inputSchema: consultarIsbnSchema.shape
860
- },
861
- wrapHandler(consultarIsbnTool.name, consultarIsbnHandler)
862
- );
863
- server.registerTool(
864
- consultarTaxaTool.name,
865
- {
866
- description: consultarTaxaTool.description,
867
- inputSchema: consultarTaxaSchema.shape
868
- },
869
- wrapHandler(consultarTaxaTool.name, consultarTaxaHandler)
870
- );
871
- server.registerTool(
872
- listarTaxasTool.name,
873
- {
874
- description: listarTaxasTool.description,
875
- inputSchema: listarTaxasSchema.shape
876
- },
877
- wrapHandler(listarTaxasTool.name, listarTaxasHandler)
878
- );
879
- server.registerTool(
880
- consultarCorretoraTool.name,
881
- {
882
- description: consultarCorretoraTool.description,
883
- inputSchema: consultarCorretoraSchema.shape
884
- },
885
- wrapHandler(consultarCorretoraTool.name, consultarCorretoraHandler)
886
- );
1187
+ for (const { tool, handler } of TOOLS) {
1188
+ server.registerTool(
1189
+ tool.name,
1190
+ {
1191
+ description: tool.description,
1192
+ inputSchema: tool.inputSchema.shape
1193
+ },
1194
+ wrapHandler(tool.name, handler)
1195
+ );
1196
+ }
887
1197
  server.registerPrompt(
888
1198
  analiseCnpjPrompt.name,
889
1199
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "brasil-data-mcp",
3
- "version": "0.2.0",
4
- "description": "MCP server providing access to Brazilian public data (CNPJ, CEP, banks, holidays, DDD, ISBN, economic rates, CVM brokers) via BrasilAPI. Ships with MCP prompts for guided workflows. For use with Claude Desktop, Claude Code, Cursor, and other MCP-compatible clients.",
3
+ "version": "0.3.0",
4
+ "description": "MCP server providing access to Brazilian public data (CNPJ, CEP, banks, holidays, DDD, ISBN, economic rates, exchange rates, CVM brokers, IBGE states/municipalities, .br domains) via BrasilAPI. Ships with MCP prompts for guided workflows. For use with Claude Desktop, Claude Code, Cursor, and other MCP-compatible clients.",
5
5
  "keywords": [
6
6
  "mcp",
7
7
  "model-context-protocol",
@@ -15,6 +15,9 @@
15
15
  "selic",
16
16
  "cdi",
17
17
  "ipca",
18
+ "cambio",
19
+ "ibge",
20
+ "registro-br",
18
21
  "cvm",
19
22
  "brasilapi",
20
23
  "ai-tools"