@mcpassure/mcp-anvisa-bulario 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +196 -0
  3. package/README.md +192 -5
  4. package/dist/cache/sqlite-cache.d.ts +13 -0
  5. package/dist/cache/sqlite-cache.d.ts.map +1 -0
  6. package/dist/cache/sqlite-cache.js +58 -0
  7. package/dist/cache/sqlite-cache.js.map +1 -0
  8. package/dist/cache/types.d.ts +17 -0
  9. package/dist/cache/types.d.ts.map +1 -0
  10. package/dist/cache/types.js +7 -0
  11. package/dist/cache/types.js.map +1 -0
  12. package/dist/config.d.ts +12 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +17 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/domain/repository.d.ts +47 -0
  17. package/dist/domain/repository.d.ts.map +1 -0
  18. package/dist/domain/repository.js +88 -0
  19. package/dist/domain/repository.js.map +1 -0
  20. package/dist/domain/types.d.ts +2 -0
  21. package/dist/domain/types.d.ts.map +1 -0
  22. package/dist/domain/types.js +2 -0
  23. package/dist/domain/types.js.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +37 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/prompts/handlers.d.ts +24 -0
  29. package/dist/prompts/handlers.d.ts.map +1 -0
  30. package/dist/prompts/handlers.js +267 -0
  31. package/dist/prompts/handlers.js.map +1 -0
  32. package/dist/prompts/index.d.ts +4 -0
  33. package/dist/prompts/index.d.ts.map +1 -0
  34. package/dist/prompts/index.js +35 -0
  35. package/dist/prompts/index.js.map +1 -0
  36. package/dist/prompts/schemas.d.ts +22 -0
  37. package/dist/prompts/schemas.d.ts.map +1 -0
  38. package/dist/prompts/schemas.js +15 -0
  39. package/dist/prompts/schemas.js.map +1 -0
  40. package/dist/resources/handlers.d.ts +5 -0
  41. package/dist/resources/handlers.d.ts.map +1 -0
  42. package/dist/resources/handlers.js +145 -0
  43. package/dist/resources/handlers.js.map +1 -0
  44. package/dist/resources/index.d.ts +4 -0
  45. package/dist/resources/index.d.ts.map +1 -0
  46. package/dist/resources/index.js +48 -0
  47. package/dist/resources/index.js.map +1 -0
  48. package/dist/schemas/tools.d.ts +134 -0
  49. package/dist/schemas/tools.d.ts.map +1 -0
  50. package/dist/schemas/tools.js +106 -0
  51. package/dist/schemas/tools.js.map +1 -0
  52. package/dist/server.d.ts +4 -0
  53. package/dist/server.d.ts.map +1 -0
  54. package/dist/server.js +25 -0
  55. package/dist/server.js.map +1 -0
  56. package/dist/sources/anvisa-api.d.ts +25 -0
  57. package/dist/sources/anvisa-api.d.ts.map +1 -0
  58. package/dist/sources/anvisa-api.js +153 -0
  59. package/dist/sources/anvisa-api.js.map +1 -0
  60. package/dist/sources/anvisa-dados-abertos.d.ts +12 -0
  61. package/dist/sources/anvisa-dados-abertos.d.ts.map +1 -0
  62. package/dist/sources/anvisa-dados-abertos.js +27 -0
  63. package/dist/sources/anvisa-dados-abertos.js.map +1 -0
  64. package/dist/sources/anvisa-portal.d.ts +12 -0
  65. package/dist/sources/anvisa-portal.d.ts.map +1 -0
  66. package/dist/sources/anvisa-portal.js +27 -0
  67. package/dist/sources/anvisa-portal.js.map +1 -0
  68. package/dist/sources/types.d.ts +56 -0
  69. package/dist/sources/types.d.ts.map +1 -0
  70. package/dist/sources/types.js +2 -0
  71. package/dist/sources/types.js.map +1 -0
  72. package/dist/tools/buscar-por-classe-terapeutica.d.ts +4 -0
  73. package/dist/tools/buscar-por-classe-terapeutica.d.ts.map +1 -0
  74. package/dist/tools/buscar-por-classe-terapeutica.js +30 -0
  75. package/dist/tools/buscar-por-classe-terapeutica.js.map +1 -0
  76. package/dist/tools/buscar-por-nome.d.ts +4 -0
  77. package/dist/tools/buscar-por-nome.d.ts.map +1 -0
  78. package/dist/tools/buscar-por-nome.js +25 -0
  79. package/dist/tools/buscar-por-nome.js.map +1 -0
  80. package/dist/tools/buscar-por-principio-ativo.d.ts +4 -0
  81. package/dist/tools/buscar-por-principio-ativo.d.ts.map +1 -0
  82. package/dist/tools/buscar-por-principio-ativo.js +25 -0
  83. package/dist/tools/buscar-por-principio-ativo.js.map +1 -0
  84. package/dist/tools/consultar-bula.d.ts +4 -0
  85. package/dist/tools/consultar-bula.d.ts.map +1 -0
  86. package/dist/tools/consultar-bula.js +42 -0
  87. package/dist/tools/consultar-bula.js.map +1 -0
  88. package/dist/tools/filtrar-por-tarja.d.ts +4 -0
  89. package/dist/tools/filtrar-por-tarja.d.ts.map +1 -0
  90. package/dist/tools/filtrar-por-tarja.js +29 -0
  91. package/dist/tools/filtrar-por-tarja.js.map +1 -0
  92. package/dist/tools/listar-apresentacoes.d.ts +4 -0
  93. package/dist/tools/listar-apresentacoes.d.ts.map +1 -0
  94. package/dist/tools/listar-apresentacoes.js +34 -0
  95. package/dist/tools/listar-apresentacoes.js.map +1 -0
  96. package/dist/tools/shared.d.ts +97 -0
  97. package/dist/tools/shared.d.ts.map +1 -0
  98. package/dist/tools/shared.js +34 -0
  99. package/dist/tools/shared.js.map +1 -0
  100. package/dist/utils/backoff.d.ts +8 -0
  101. package/dist/utils/backoff.d.ts.map +1 -0
  102. package/dist/utils/backoff.js +37 -0
  103. package/dist/utils/backoff.js.map +1 -0
  104. package/dist/utils/http.d.ts +45 -0
  105. package/dist/utils/http.d.ts.map +1 -0
  106. package/dist/utils/http.js +175 -0
  107. package/dist/utils/http.js.map +1 -0
  108. package/dist/utils/meta.d.ts +8 -0
  109. package/dist/utils/meta.d.ts.map +1 -0
  110. package/dist/utils/meta.js +13 -0
  111. package/dist/utils/meta.js.map +1 -0
  112. package/dist/utils/playwright-http.d.ts +2 -0
  113. package/dist/utils/playwright-http.d.ts.map +1 -0
  114. package/dist/utils/playwright-http.js +4 -0
  115. package/dist/utils/playwright-http.js.map +1 -0
  116. package/package.json +68 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MCPAssure Brasil
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,196 @@
1
+ **[🇧🇷 Português (BR)](./README.md) · 🇺🇸 English**
2
+
3
+ ---
4
+
5
+ # @mcpassure/mcp-anvisa-bulario
6
+
7
+ **MCPAssure Catalog — Wave 1** — MCP server for querying the ANVISA Electronic Drug Information Database (Bulário Eletrônico).
8
+
9
+ Enables AI agents (Claude, GPT, Copilot) to query drug leaflets (bulas), active ingredients, therapeutic classes, and other metadata for medications registered in Brazil, with structured responses and efficient caching.
10
+
11
+ [![CI](https://github.com/mcpassure/mcp-anvisa-bulario/actions/workflows/ci.yml/badge.svg)](https://github.com/mcpassure/mcp-anvisa-bulario/actions)
12
+ [![npm](https://img.shields.io/npm/v/@mcpassure/mcp-anvisa-bulario)](https://www.npmjs.com/package/@mcpassure/mcp-anvisa-bulario)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
14
+
15
+ ---
16
+
17
+ ## Quick install
18
+
19
+ ```bash
20
+ npx -y @mcpassure/mcp-anvisa-bulario
21
+ ```
22
+
23
+ On first install, `postinstall` downloads the Playwright Chromium browser (~150MB). This is required by the HTTP transport (see [Requirements](#requirements)).
24
+
25
+ ### Claude Desktop
26
+
27
+ Add to `claude_desktop_config.json`:
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "anvisa-bulario": {
33
+ "command": "npx",
34
+ "args": ["-y", "@mcpassure/mcp-anvisa-bulario"]
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ### VS Code / Claude Code
41
+
42
+ ```json
43
+ {
44
+ "mcp": {
45
+ "servers": {
46
+ "anvisa-bulario": {
47
+ "command": "npx",
48
+ "args": ["-y", "@mcpassure/mcp-anvisa-bulario"]
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Available Tools
58
+
59
+ | Tool | Description |
60
+ |---|---|
61
+ | `buscar_por_nome` | Search by trade name (nome comercial) |
62
+ | `buscar_por_principio_ativo` | Search by INN/DCB active ingredient (princípio ativo) |
63
+ | `buscar_por_classe_terapeutica` | Search by therapeutic class |
64
+ | `filtrar_por_tarja` | Filter by controlled-substance tier (LIVRE/OTC, VERMELHA/Rx, PRETA/special-control) |
65
+ | `consultar_bula` | Retrieve full drug data + leaflet PDF links (bula) |
66
+ | `listar_apresentacoes` | List commercial presentations/packaging of a medication |
67
+
68
+ ---
69
+
70
+ ## Available Prompts
71
+
72
+ | Prompt | Description |
73
+ |---|---|
74
+ | `verificar_medicamento_completo` | Consolidates trade name, active ingredient, class, controlled-substance tier, presentations, and (optionally) leaflet for a search term |
75
+ | `comparar_tarjas_por_classe` | Groups medications of a therapeutic class by controlled-substance tier |
76
+ | `analisar_apresentacoes` | Groups a medication's presentations by dosage strength, pharmaceutical form, or manufacturer |
77
+
78
+ ---
79
+
80
+ ## Available Resources
81
+
82
+ | URI | Type | Description |
83
+ |---|---|---|
84
+ | `bulario://tarjas` | `application/json` | Regulatory taxonomy of controlled-substance tiers (RDC 357/2020, Ordinance 344/98) |
85
+ | `bulario://classes_terapeuticas` | `application/json` | List of main indexed therapeutic classes |
86
+ | `bulario://scope` | `text/markdown` | MCP scope (PT/EN): what it does/doesn't do, regulatory disclaimer |
87
+
88
+ ---
89
+
90
+ ## Demo
91
+
92
+ ![Demo](./.github/assets/demo.gif)
93
+
94
+ To run locally:
95
+
96
+ ```bash
97
+ npm run demo
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Understanding Brazilian drug tiers (Tarja)
103
+
104
+ Brazil uses a **tarja** (literally "stripe/band") system to classify medication control requirements — there is no direct English equivalent:
105
+
106
+ | Tarja | English equivalent | Control level |
107
+ |---|---|---|
108
+ | **Sem Tarja** | OTC / Over-the-counter | No prescription required |
109
+ | **Tarja Amarela** (Yellow-banded) | Prescription-only (mild control) | Antibiotics and similar — prescription required, receipt not retained |
110
+ | **Tarja Vermelha** (Red-banded) | Prescription-only (standard) | Receipt retained by pharmacy |
111
+ | **Tarja Preta** (Black-banded) | **Controlled substance** — Brazilian Ordinance SVS/MS 344/1998 | Special-control prescription; covers psychotropics, narcotics, precursors |
112
+
113
+ > ⚠️ **Tarja Preta** is the strictest tier. Medications in this category include benzodiazepines, opioids, barbiturates, and other substances under Brazil's controlled substance ordinance (Portaria 344/98). Misuse is a criminal offense under Brazilian law.
114
+
115
+ ---
116
+
117
+ ## Environment variables
118
+
119
+ | Variable | Default | Description |
120
+ |---|---|---|
121
+ | `MCPASSURE_CACHE_PATH` | `~/.cache/mcpassure-anvisa/cache.db` | SQLite cache file path |
122
+ | `MCPASSURE_MAX_RETRIES` | `3` | Retry attempts on API failure |
123
+ | `MCPASSURE_BASE_DELAY_MS` | `1000` | Base delay for exponential backoff (ms) |
124
+ | `MCPASSURE_REQUEST_TIMEOUT_MS` | `10000` | HTTP request timeout (ms) |
125
+ | `MCPASSURE_ANVISA_BASE_URL` | `https://consultas.anvisa.gov.br` | ANVISA API base URL |
126
+ | `MCPASSURE_DEGRADED_THRESHOLD_DAYS` | `30` | Days after which cached data is flagged as degraded |
127
+ | `MCPASSURE_STATUS_HEARTBEAT` | `false` | Enable heartbeat for status page |
128
+ | `MCPASSURE_STATUS_PAGE_URL` | `https://status.mcpassure.com.br/api/v1/heartbeat/anvisa-bulario` | Heartbeat endpoint URL |
129
+
130
+ ---
131
+
132
+ ## Requirements
133
+
134
+ - **Node.js >= 22.0.0**
135
+ - **Playwright Chromium** (~150MB) — installed automatically by `postinstall`. Required because the ANVISA API is behind Cloudflare since 2026, blocking Node's native fetch.
136
+ - **+150-250MB RAM** at runtime (Chromium in background). First call has ~2-3s overhead (Chromium boot + warm-up). Subsequent calls: ~100-300ms.
137
+
138
+ If the Chromium postinstall fails (firewall, corporate policy, etc.), install manually:
139
+
140
+ ```bash
141
+ npx playwright install chromium
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Development
147
+
148
+ ```bash
149
+ nvm use # uses Node 22 as per .nvmrc
150
+ npm install # installs deps and downloads Playwright Chromium
151
+
152
+ # Run in dev mode (stdio)
153
+ npm run dev
154
+
155
+ # Validate
156
+ npm run typecheck
157
+ npm run lint
158
+ npm run test
159
+ npm run test:integration:offline
160
+ npm run canary
161
+ ```
162
+
163
+ ## Architecture
164
+
165
+ - **Local SQLite** (`better-sqlite3`) as primary cache with 24h TTL
166
+ - **Source pattern** with cascading sources: `anvisa-api` → `anvisa-dados-abertos` (v1.1+) → `anvisa-portal` (v1.2+)
167
+ - **Repository pattern** decoupling domain from sources
168
+ - **HTTP transport via Playwright** — real headless Chromium with clean UA and webdriver masking. Lazy-initialized browser singleton, page reused between requests. Required to bypass ANVISA's Cloudflare barrier.
169
+ - **Optional status page hook** via `MCPASSURE_STATUS_HEARTBEAT`
170
+ - **Daily canary** validates source accessibility and data patterns
171
+
172
+ ---
173
+
174
+ ## ⚠️ Medical disclaimer
175
+
176
+ This MCP server is a **pharmaceutical reference tool** based on public ANVISA data. **It does not replace evaluation, diagnosis, or prescription by a licensed healthcare professional.** Drug information should always be used under professional supervision.
177
+
178
+ Data comes from the ANVISA Electronic Drug Information Database (`consultas.anvisa.gov.br`), an official public source. This server does not store personal data and never processes PHI/PII.
179
+
180
+ ---
181
+
182
+ ## Dependencies
183
+
184
+ This release uses current versions (audited 2026-05-13). For history or exceptions, see `DEPS.md`.
185
+
186
+ Automated audit runs every Monday at 09:00 UTC (`deps-audit` workflow).
187
+
188
+ ## License
189
+
190
+ MIT — see [LICENSE](LICENSE)
191
+
192
+ Maintained by [MCPAssure Brasil](https://github.com/mcpassure). See [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md), and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
193
+
194
+ ---
195
+
196
+ Part of the [MCPAssure](https://github.com/mcpassure) catalog — curated MCP examples for Brazilian healthcare.
package/README.md CHANGED
@@ -1,5 +1,192 @@
1
- # @mcpassure/mcp-anvisa-bulario
2
-
3
- Reserved namespace. MCP server for ANVISA Bulario Eletronico, coming soon as part of the MCPAssure catalog.
4
-
5
- See https://mcpassure.com.br
1
+ **🇧🇷 Português (BR) · [🇺🇸 English](./README.en.md)**
2
+
3
+ ---
4
+
5
+ # @mcpassure/mcp-anvisa-bulario
6
+
7
+ **Catálogo MCPAssure — Onda 1** — MCP server para consulta ao Bulário Eletrônico da ANVISA.
8
+
9
+ Permite que agentes de IA (Claude, GPT, Copilot) consultem bulas, princípios ativos, classes terapêuticas e demais metadados de medicamentos registrados no Brasil com resposta estruturada e cache eficiente.
10
+
11
+ [![CI](https://github.com/mcpassure/mcp-anvisa-bulario/actions/workflows/ci.yml/badge.svg)](https://github.com/mcpassure/mcp-anvisa-bulario/actions)
12
+ [![npm](https://img.shields.io/npm/v/@mcpassure/mcp-anvisa-bulario)](https://www.npmjs.com/package/@mcpassure/mcp-anvisa-bulario)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
14
+
15
+ ---
16
+
17
+ ## Instalação rápida
18
+
19
+ ```bash
20
+ npx -y @mcpassure/mcp-anvisa-bulario
21
+ ```
22
+
23
+ Na primeira instalação, o `postinstall` baixa o Chromium do Playwright
24
+ (~150MB). Isso é requerido pelo transport HTTP (ver [Requisitos](#requisitos)).
25
+
26
+ ### Claude Desktop
27
+
28
+ Adicione ao `claude_desktop_config.json`:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "anvisa-bulario": {
34
+ "command": "npx",
35
+ "args": ["-y", "@mcpassure/mcp-anvisa-bulario"]
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### VS Code / Claude Code
42
+
43
+ ```json
44
+ {
45
+ "mcp": {
46
+ "servers": {
47
+ "anvisa-bulario": {
48
+ "command": "npx",
49
+ "args": ["-y", "@mcpassure/mcp-anvisa-bulario"]
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Tools disponíveis
59
+
60
+ | Tool | Descrição |
61
+ |---|---|
62
+ | `buscar_por_nome` | Busca por nome comercial do medicamento |
63
+ | `buscar_por_principio_ativo` | Busca por DCB/DCI (princípio ativo) |
64
+ | `buscar_por_classe_terapeutica` | Busca por classe terapêutica |
65
+ | `filtrar_por_tarja` | Lista medicamentos por tipo de tarja (LIVRE, VERMELHA, PRETA) |
66
+ | `consultar_bula` | Retorna dados completos + links da bula (PDF) |
67
+ | `listar_apresentacoes` | Lista apresentações/embalagens de um medicamento |
68
+
69
+ ---
70
+
71
+ ## Prompts disponíveis
72
+
73
+ | Prompt | Descrição |
74
+ |---|---|
75
+ | `verificar_medicamento_completo` | Consolida nome, princípio ativo, classe, tarja, apresentações e (opcional) bula para um termo de busca |
76
+ | `comparar_tarjas_por_classe` | Agrupa medicamentos de uma classe terapêutica por tarja regulatória |
77
+ | `analisar_apresentacoes` | Agrupa apresentações de um medicamento por concentração, forma farmacêutica ou fabricante |
78
+
79
+ ---
80
+
81
+ ## Resources disponíveis
82
+
83
+ | URI | Tipo | Descrição |
84
+ |---|---|---|
85
+ | `bulario://tarjas` | `application/json` | Taxonomia regulatória de tarjas (RDC 357/2020, Portaria 344/98) |
86
+ | `bulario://classes_terapeuticas` | `application/json` | Lista das principais classes terapêuticas indexadas |
87
+ | `bulario://scope` | `text/markdown` | Escopo do MCP (PT/EN), o que faz/não faz, disclaimer regulatório |
88
+
89
+ ---
90
+
91
+ ## Demo
92
+
93
+ ![Demo](./.github/assets/demo.gif)
94
+
95
+ Para rodar localmente:
96
+
97
+ ```bash
98
+ npm run demo
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Variáveis de ambiente
104
+
105
+ | Variável | Padrão | Descrição |
106
+ |---|---|---|
107
+ | `MCPASSURE_CACHE_PATH` | `~/.cache/mcpassure-anvisa/cache.db` | Caminho do banco SQLite de cache |
108
+ | `MCPASSURE_MAX_RETRIES` | `3` | Tentativas em caso de falha da API |
109
+ | `MCPASSURE_BASE_DELAY_MS` | `1000` | Delay base para backoff exponencial (ms) |
110
+ | `MCPASSURE_REQUEST_TIMEOUT_MS` | `10000` | Timeout de requisição HTTP (ms) |
111
+ | `MCPASSURE_ANVISA_BASE_URL` | `https://consultas.anvisa.gov.br` | Base URL da API ANVISA |
112
+ | `MCPASSURE_DEGRADED_THRESHOLD_DAYS` | `30` | Dias após os quais dados são considerados degradados |
113
+ | `MCPASSURE_STATUS_HEARTBEAT` | `false` | Habilita heartbeat para status page |
114
+ | `MCPASSURE_STATUS_PAGE_URL` | `https://status.mcpassure.com.br/api/v1/heartbeat/anvisa-bulario` | URL do heartbeat |
115
+
116
+ ---
117
+
118
+ ## Requisitos
119
+
120
+ - **Node.js >= 22.0.0**
121
+ - **Chromium do Playwright** (~150MB) — instalado automaticamente pelo
122
+ `postinstall`. Requerido porque a API ANVISA está atrás de Cloudflare desde
123
+ 2026, bloqueando fetch nativo do Node. Ver
124
+ [`DIAGNOSTICO_ANVISA_CLOUDFLARE_2026-05-13.md`](DIAGNOSTICO_ANVISA_CLOUDFLARE_2026-05-13.md)
125
+ para detalhes técnicos.
126
+ - **+150-250MB de RAM** em runtime (Chromium em background quando o MCP
127
+ estiver ativo). Primeira chamada tem ~2-3s de overhead (boot do Chromium
128
+ + warm-up). Chamadas subsequentes: ~100-300ms.
129
+
130
+ Se o postinstall do Chromium falhar (firewall, política corporativa, etc.),
131
+ rode manualmente:
132
+
133
+ ```bash
134
+ npx playwright install chromium
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Desenvolvimento
140
+
141
+ ```bash
142
+ nvm use # usa Node 22 conforme .nvmrc
143
+ npm install # instala deps e baixa Chromium do Playwright
144
+
145
+ # Rodar em modo dev (stdio)
146
+ npm run dev
147
+
148
+ # Validar
149
+ npm run typecheck
150
+ npm run lint
151
+ npm run test
152
+ npm run test:integration:offline
153
+ npm run canary
154
+ ```
155
+
156
+ ## Arquitetura
157
+
158
+ - **SQLite local** (`better-sqlite3`) como cache primário com TTL 24h
159
+ - **Source pattern** com cascata de fontes: `anvisa-api` → `anvisa-dados-abertos` (v1.1+) → `anvisa-portal` (v1.2+)
160
+ - **Repository pattern** desacoplando domínio das fontes
161
+ - **HTTP transport via Playwright** — Chromium real (headless) com UA limpo
162
+ e mascaramento de webdriver. Browser singleton lazy-initialized, page
163
+ reutilizada entre requests. Necessário para contornar a barreira Cloudflare
164
+ da ANVISA (ver diagnóstico).
165
+ - **Status page hook** opcional via `MCPASSURE_STATUS_HEARTBEAT`
166
+ - **Canário diário** valida acessibilidade e padrões da fonte oficial
167
+
168
+ ---
169
+
170
+ ## ⚠️ Disclaimer médico
171
+
172
+ Este servidor MCP é uma **fonte de consulta farmacêutica** baseada em dados públicos da ANVISA. **Não substitui avaliação, diagnóstico ou prescrição por profissional de saúde habilitado.** Informações sobre medicamentos devem ser utilizadas com acompanhamento profissional.
173
+
174
+ Os dados são provenientes do Bulário Eletrônico da ANVISA (`consultas.anvisa.gov.br`), que é fonte pública oficial. Este servidor não armazena dados pessoais e não processa PHI/PII em nenhum momento.
175
+
176
+ ---
177
+
178
+ ## Dependências
179
+
180
+ Esta versão usa versões correntes (auditadas em 2026-05-13). Para histórico ou exceções, ver `DEPS.md`.
181
+
182
+ Auditoria automática roda toda segunda às 09:00 UTC (`deps-audit` workflow).
183
+
184
+ ## Licença
185
+
186
+ MIT — veja [LICENSE](LICENSE)
187
+
188
+ Mantido pela [MCPAssure Brasil](https://github.com/mcpassure). Consulte [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md) e [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
189
+
190
+ ---
191
+
192
+ Parte do catálogo [MCPAssure](https://github.com/mcpassure) — exemplos de curadoria de MCPs para saúde brasileira.
@@ -0,0 +1,13 @@
1
+ import type { CacheStore } from "./types.js";
2
+ export declare class SqliteCache implements CacheStore {
3
+ private readonly db;
4
+ constructor(dbPath: string);
5
+ get<T>(key: string): {
6
+ value: T;
7
+ data_da_base: string;
8
+ } | null;
9
+ set<T>(key: string, value: T, ttlSeconds: number, data_da_base?: string): void;
10
+ invalidate(key: string): void;
11
+ close(): void;
12
+ }
13
+ //# sourceMappingURL=sqlite-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-cache.d.ts","sourceRoot":"","sources":["../../src/cache/sqlite-cache.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,qBAAa,WAAY,YAAW,UAAU;IAC5C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAE3B,MAAM,EAAE,MAAM;IA0B1B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAmB9D,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAU9E,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAK7B,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,58 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import Database from "better-sqlite3";
4
+ export class SqliteCache {
5
+ db;
6
+ constructor(dbPath) {
7
+ const dir = path.dirname(dbPath);
8
+ fs.mkdirSync(dir, { recursive: true });
9
+ this.db = new Database(dbPath);
10
+ this.db.exec(`
11
+ PRAGMA journal_mode=WAL;
12
+ CREATE TABLE IF NOT EXISTS cache (
13
+ key TEXT PRIMARY KEY,
14
+ value TEXT NOT NULL,
15
+ expires_at INTEGER NOT NULL,
16
+ data_da_base TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
17
+ );
18
+ `);
19
+ // Migration: add data_da_base column to existing databases that don't have it
20
+ try {
21
+ this.db.exec(`ALTER TABLE cache ADD COLUMN data_da_base TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))`);
22
+ }
23
+ catch {
24
+ // Column already exists — expected on fresh databases or after first migration
25
+ }
26
+ }
27
+ get(key) {
28
+ const now = Math.floor(Date.now() / 1000);
29
+ const stmt = this.db.prepare("SELECT value, expires_at, data_da_base FROM cache WHERE key = ? AND expires_at > ?");
30
+ const row = stmt.get(key, now);
31
+ if (!row)
32
+ return null;
33
+ try {
34
+ return {
35
+ value: JSON.parse(row.value),
36
+ data_da_base: row.data_da_base,
37
+ };
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ set(key, value, ttlSeconds, data_da_base) {
44
+ const expiresAt = Math.floor(Date.now() / 1000) + ttlSeconds;
45
+ const serialized = JSON.stringify(value);
46
+ const dataBase = data_da_base ?? new Date().toISOString();
47
+ const stmt = this.db.prepare("INSERT OR REPLACE INTO cache (key, value, expires_at, data_da_base) VALUES (?, ?, ?, ?)");
48
+ stmt.run(key, serialized, expiresAt, dataBase);
49
+ }
50
+ invalidate(key) {
51
+ const stmt = this.db.prepare("DELETE FROM cache WHERE key = ?");
52
+ stmt.run(key);
53
+ }
54
+ close() {
55
+ this.db.close();
56
+ }
57
+ }
58
+ //# sourceMappingURL=sqlite-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-cache.js","sourceRoot":"","sources":["../../src/cache/sqlite-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAKtC,MAAM,OAAO,WAAW;IACL,EAAE,CAAoB;IAEvC,YAAY,MAAc;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACjC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvC,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAE/B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;KAQZ,CAAC,CAAC;QAEH,8EAA8E;QAC9E,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,IAAI,CACV,yGAAyG,CAC1G,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,+EAA+E;QACjF,CAAC;IACH,CAAC;IAED,GAAG,CAAI,GAAW;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAC1B,oFAAoF,CACrF,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAA0B,CAAC;QAExD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QAEtB,IAAI,CAAC;YACH,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAM;gBACjC,YAAY,EAAE,GAAG,CAAC,YAAY;aAC/B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,GAAG,CAAI,GAAW,EAAE,KAAQ,EAAE,UAAkB,EAAE,YAAqB;QACrE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC;QAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,YAAY,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAC1B,yFAAyF,CAC1F,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,UAAU,CAAC,GAAW;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QAChE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ export interface CacheStore {
2
+ get<T>(key: string): {
3
+ value: T;
4
+ data_da_base: string;
5
+ } | null;
6
+ set<T>(key: string, value: T, ttlSeconds: number, data_da_base?: string): void;
7
+ invalidate(key: string): void;
8
+ close(): void;
9
+ }
10
+ export declare const DEFAULT_TTLS: {
11
+ readonly searchResults: 3600;
12
+ readonly medicamentoDetalhes: 86400;
13
+ readonly categorias: 604800;
14
+ readonly bulaLink: 86400;
15
+ };
16
+ export type TtlConfig = typeof DEFAULT_TTLS;
17
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/D,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/E,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,OAAO,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ export const DEFAULT_TTLS = {
2
+ searchResults: 3_600,
3
+ medicamentoDetalhes: 86_400,
4
+ categorias: 604_800,
5
+ bulaLink: 86_400,
6
+ };
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,aAAa,EAAE,KAAK;IACpB,mBAAmB,EAAE,MAAM;IAC3B,UAAU,EAAE,OAAO;IACnB,QAAQ,EAAE,MAAM;CACR,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type Config = {
2
+ cachePath: string;
3
+ maxRetries: number;
4
+ baseDelayMs: number;
5
+ requestTimeoutMs: number;
6
+ anvisaBaseUrl: string;
7
+ degradedThresholdDays: number;
8
+ statusPageEnabled: boolean;
9
+ statusPageUrl: string;
10
+ };
11
+ export declare function loadConfig(): Config;
12
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,MAAM,GAAG;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,UAAU,IAAI,MAAM,CAkBnC"}
package/dist/config.js ADDED
@@ -0,0 +1,17 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ export function loadConfig() {
4
+ return {
5
+ cachePath: process.env.MCPASSURE_CACHE_PATH ??
6
+ path.join(os.homedir(), ".cache", "mcpassure-anvisa", "cache.db"),
7
+ maxRetries: Number.parseInt(process.env.MCPASSURE_MAX_RETRIES ?? "3", 10),
8
+ baseDelayMs: Number.parseInt(process.env.MCPASSURE_BASE_DELAY_MS ?? "1000", 10),
9
+ requestTimeoutMs: Number.parseInt(process.env.MCPASSURE_REQUEST_TIMEOUT_MS ?? "10000", 10),
10
+ anvisaBaseUrl: process.env.MCPASSURE_ANVISA_BASE_URL ?? "https://consultas.anvisa.gov.br",
11
+ degradedThresholdDays: Number.parseInt(process.env.MCPASSURE_DEGRADED_THRESHOLD_DAYS ?? "30", 10),
12
+ statusPageEnabled: process.env.MCPASSURE_STATUS_HEARTBEAT === "true",
13
+ statusPageUrl: process.env.MCPASSURE_STATUS_PAGE_URL ??
14
+ "https://status.mcpassure.com.br/api/v1/heartbeat/anvisa-bulario",
15
+ };
16
+ }
17
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAa7B,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,SAAS,EACP,OAAO,CAAC,GAAG,CAAC,oBAAoB;YAChC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE,UAAU,CAAC;QACnE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,GAAG,EAAE,EAAE,CAAC;QACzE,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,MAAM,EAAE,EAAE,CAAC;QAC/E,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,OAAO,EAAE,EAAE,CAAC;QAC1F,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,iCAAiC;QACzF,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CACpC,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,IAAI,EACrD,EAAE,CACH;QACD,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,MAAM;QACpE,aAAa,EACX,OAAO,CAAC,GAAG,CAAC,yBAAyB;YACrC,iEAAiE;KACpE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { CacheStore } from "../cache/types.js";
2
+ import type { Apresentacao, BulaLink, BularioSource, MedicamentoDetalhes, MedicamentoResumo, SearchByClasseTerapeuticaParams, SearchByNameParams, SearchByPrincipalAtivoParams, SearchByTarjaParams } from "../sources/types.js";
3
+ export type Meta = {
4
+ data_da_base: string;
5
+ fonte: string;
6
+ defasagem_dias: number;
7
+ modo: "cache_local" | "online";
8
+ status?: "ok" | "stale";
9
+ };
10
+ export type ResponseWithMeta<T> = {
11
+ data: T;
12
+ _meta: Meta;
13
+ };
14
+ export declare class AllSourcesFailedError extends Error {
15
+ readonly failures: Array<{
16
+ source: string;
17
+ error: Error;
18
+ }>;
19
+ constructor(failures: Array<{
20
+ source: string;
21
+ error: Error;
22
+ }>);
23
+ }
24
+ export interface IBularioRepository {
25
+ searchByName(params: SearchByNameParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
26
+ searchByPrincipalAtivo(params: SearchByPrincipalAtivoParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
27
+ searchByClasseTerapeutica(params: SearchByClasseTerapeuticaParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
28
+ searchByTarja(params: SearchByTarjaParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
29
+ getDetalhes(numProcesso: string): Promise<ResponseWithMeta<MedicamentoDetalhes>>;
30
+ getApresentacoes(numProcesso: string): Promise<ResponseWithMeta<Apresentacao[]>>;
31
+ getBulaLink(idBulaProtegido: string): Promise<ResponseWithMeta<BulaLink>>;
32
+ }
33
+ export declare class BularioRepository implements IBularioRepository {
34
+ private readonly cache;
35
+ private readonly sources;
36
+ private readonly degradedThresholdDays;
37
+ constructor(cache: CacheStore, sources: BularioSource[], degradedThresholdDays?: number);
38
+ searchByName(params: SearchByNameParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
39
+ searchByPrincipalAtivo(params: SearchByPrincipalAtivoParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
40
+ searchByClasseTerapeutica(params: SearchByClasseTerapeuticaParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
41
+ searchByTarja(params: SearchByTarjaParams): Promise<ResponseWithMeta<MedicamentoResumo[]>>;
42
+ getDetalhes(numProcesso: string): Promise<ResponseWithMeta<MedicamentoDetalhes>>;
43
+ getApresentacoes(numProcesso: string): Promise<ResponseWithMeta<Apresentacao[]>>;
44
+ getBulaLink(idBulaProtegido: string): Promise<ResponseWithMeta<BulaLink>>;
45
+ private _withCache;
46
+ }
47
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/domain/repository.ts"],"names":[],"mappings":"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"}