{
  "markdown": "# vaers\n\nVAERS (Vaccine Adverse Event Reporting System) report counts — by vaccine,\nmanufacturer, symptom, year and severity. Fleet #1294.\n\nPart of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1558+ live data sources.\n\n## A VAERS report is not a confirmed adverse event — read this first\n\nAnyone can file a VAERS report — a patient, a parent, a clinician, a\nmanufacturer — and VAERS does not verify what's in it. A rise in report counts\nfor a vaccine can reflect more doses given, more media attention, or a\nreporting-requirement change just as easily as a real safety signal. CDC and\nFDA say this about their own data:\n\n> The number of reports alone cannot be interpreted as evidence of a causal\n> association between a vaccine and an adverse event, or as evidence about\n> the existence, severity, frequency, or rates of problems associated with\n> vaccines. Reports may include incomplete, inaccurate, coincidental, and\n> unverified information.\n> — <https://wonder.cdc.gov/wonder/help/vaers.html>\n\nEvery tool response below carries that disclaimer **and** a literal\n`is_causal: false` field, so a model reading the payload cannot round a report\ncount up into a causal claim. No tool here returns a single report's free\ntext (`SYMPTOM_TEXT`, `HISTORY`, `LAB_DATA`, `OTHER_MEDS`, `CUR_ILL`,\n`ALLERGIES` are not even stored — see the migration comment) — everything is\na count, by design.\n\n## Tools\n\n| Tool | Answers |\n|---|---|\n| `vaers_events_by_vaccine` | Report counts + severity breakdown by vaccine (and optionally manufacturer), for a year range. Omit `vaccine` to browse the top vaccines by report volume — this doubles as vax_type-code discovery. |\n| `vaers_events_by_symptom` | Report-mention counts by symptom (MedDRA preferred term), optionally narrowed to one vaccine/year range. Omit `symptom` to see the most-reported symptoms. |\n| `vaers_coverage` | Total unique reports, year range, distinct vaccine/manufacturer counts, when the seed was last loaded, and the top 5 vaccines by volume. |\n\n## Counting convention — read before comparing numbers across tools\n\nA report that names more than one vaccine is counted **once per vaccine** —\nthe same convention CDC WONDER itself uses for VAERS. So summing\n`report_count` across every vaccine for a year can exceed that year's\n**unique** report total (`vaers_coverage.total_unique_reports`). Symptom\ncounts are **mentions**: a report naming several symptoms and/or several\nvaccines contributes to each combination.\n\n## Auth\n\nNone — no key, no account. This pack answers from pre-aggregated report\ncounts built from the seed described below.\n\n## Data source and how it got here\n\n**VAERS**, co-run by CDC and FDA — public data files at\n<https://vaers.hhs.gov/data/datasets.html>. US federal public-domain data.\n\nEvery automated surface CDC exposes for VAERS is closed to a script:\n\n- The bulk-download page is CAPTCHA-gated (image word-verification).\n- CDC WONDER's own XML API documents VAERS (database `D8`) as a live\n  dataset but the endpoint returns `HTTP 500` with **no error message** for\n  every request shape tried — recognized but not enabled, undocumented.\n- `data.cdc.gov`'s two VAERS listings are `href` pointers back to WONDER, not\n  queryable Socrata datasets.\n\nFull write-up: `docs/vaers-access-finding.md`.\n\nSo Bruce's ruling (task #1294, 2026-09-07) is **seed-plus-manual-refresh**:\nhe downloads `AllVAERSDataCSVS.zip` (the single archive covering every year,\n1990-2026, plus non-domestic reports) by hand from the datasets page above,\nand this pack's loader ingests it. He explicitly did **not** authorize the\noutward-facing option (emailing CDC to ask for the API to be enabled) — that\nstill needs his own OK if it's ever pursued.\n\n## Storage — why aggregates, not raw rows\n\nThe seed is 2.8M report rows / 3.4M vaccine rows / 3.77M symptom rows (2.75GB\nuncompressed CSV, 589MB zip). Postgres here is small and has crashed on an\nunbatched load before (`docs/medical-data-ingest-plan.md` §3), and this\npack's tools only ever answer count questions — never a raw-row dump — so the\nloader (`scripts/ingest-vaers.mjs`) aggregates entirely in memory and writes\nonly the aggregates, in committed batches:\n\n| Table | Grain | Measured rows (1990-2026 + non-domestic seed) |\n|---|---|---|\n| `vaers_yearly_totals` | year | 37 |\n| `vaers_severity_by_vaccine` | year × vax_type × manufacturer | 4,975 |\n| `vaers_symptom_counts` | year × vax_type × symptom | 961,457 |\n\nTotal Postgres footprint: tens of MB, not gigabytes. Three RPCs\n(`vaers_vaccine_stats`, `vaers_symptom_stats`, `vaers_coverage_stats`, see\n`supabase/migrations/165_vaers_aggregates.sql`) do the filtering/summing in\nSQL since the tables are small enough that a plain `GROUP BY` is fast.\n\n**Compression note**, since this class of bug has bitten a sibling ingest\nbefore (NCHS natality was Deflate64, unreadable by Node's zlib): checked\nfirst — every entry in `AllVAERSDataCSVS.zip` is method 8 (plain Deflate),\nwhich `node:zlib.inflateRawSync` reads natively. No Deflate64 trap here.\n\n## Refreshing (manual, by design)\n\nVAERS updates weekly. There is no automated path around the CAPTCHA, so\nrefresh is:\n\n1. A human downloads a fresh `AllVAERSDataCSVS.zip` from\n   <https://vaers.hhs.gov/data/datasets.html>.\n2. `node scripts/ingest-vaers.mjs /path/to/AllVAERSDataCSVS.zip`\n\nThe loader is idempotent (`ON CONFLICT ... DO UPDATE`) and re-runnable — a\nrerun with the same or a newer file simply updates the aggregates in place.\nIt refuses to load a result that looks truncated (fewer than 20 years, 1,000\nseverity keys, or 100,000 symptom keys) rather than quietly shrinking the\ndataset.\n\n**Proposed cadence: weekly**, matching VAERS' own release rhythm — one\nre-download + rerun per week keeps `vaers_coverage.data_last_loaded` inside\na week of the live data. This is a recurring cost of Bruce's time by design\n(his ruling); if an automated path ever opens up (CDC enabling the WONDER\nAPI for D8, or a future scrape-friendly surface), this is the loader to\nreplace, not the schema.\n\n### Two write paths, chosen automatically\n\n`ingest-vaers.mjs` looks for the platform's database credentials in `.env`\nfirst (fast REST batched upsert). If they aren't available in the\nenvironment it's run from, it falls back to writing chunked, idempotent SQL\nfiles to `/tmp/vaers-sql/` and printing the `supabase db query --file ...\n--linked` commands to apply them — the same Management-API path used to\napply `supabase/migrations/165_vaers_aggregates.sql`. Either path produces\nthe same tables.\n\n## What this does not cover\n\n- Individual report narratives (`SYMPTOM_TEXT`, `HISTORY`, etc.) — not\n  stored, not returned, by design (see above).\n- Anything past the loaded seed's vintage — check `vaers_coverage` before\n  relying on recency.\n- FAERS (drug adverse events) — that's `openfda`. VAERS is vaccines only.\n\n## Quick Start\n\nAdd to your MCP client (Claude Desktop, Cursor, Windsurf, etc.):\n\n```json\n{\n  \"mcpServers\": {\n    \"vaers\": {\n      \"url\": \"https://gateway.pipeworx.io/vaers/mcp\"\n    }\n  }\n}\n```\n\n### What this endpoint actually serves\n\n`tools/list` at `https://gateway.pipeworx.io/vaers/mcp` returns the tools in the table\nabove **plus the shared Pipeworx meta-tools** — `ask_pipeworx`,\n`discover_tools`, `search_within`, `remember`/`recall` and the rest of the\ngateway-wide set. So the tool count you see is larger than this table: a\nsingle-pack endpoint currently lists roughly 30 shared tools alongside the\npack's own. The connection's `initialize` response states its exact scope, and\nis the authoritative answer for a given day.\n\nThis is deliberate, not multiplexing by accident. The meta-tools are what let a\nscoped connection answer a question this pack does not cover — via\n`ask_pipeworx`, which routes across the whole catalog — without you adding a\nsecond MCP server. There is currently no way to mount a pack endpoint without\nthem; if the extra schemas cost you more context than the routing is worth,\nconnect to the full gateway once rather than to several pack endpoints.\n\nOr connect to the full Pipeworx gateway to get every pack's tools listed\ndirectly, instead of just this one's:\n\n```json\n{\n  \"mcpServers\": {\n    \"pipeworx\": {\n      \"url\": \"https://gateway.pipeworx.io/mcp\"\n    }\n  }\n}\n```\n\nBoth URLs reach the same gateway and the same 1558+ data sources. The\nonly difference is which pack's tools are listed **directly**; `ask_pipeworx`\nreaches all of them from either one.\n\n## Standalone (no gateway account)\n\nThis package also runs as a local stdio MCP server — no Pipeworx account, no\ngateway round-trip:\n\n```json\n{\n  \"mcpServers\": {\n    \"vaers\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@pipeworx/mcp-vaers\"]\n    }\n  }\n}\n```\n\nOr run it directly to confirm it starts:\n\n```bash\nnpx -y @pipeworx/mcp-vaers\n```\n\nIt speaks MCP over stdin/stdout and answers `initialize`/`tools/list`/`tools/call`\nfor **only** this pack's tools — none of the shared meta-tools the gateway\nconnection above adds. Same source, same tools, no ask_pipeworx routing.\n\n## Using with ask_pipeworx\n\nInstead of calling tools directly, you can ask questions in plain English —\nthis works on the pack endpoint above as well as on the full gateway:\n\n```\nask_pipeworx({ question: \"your question about Vaers data\" })\n```\n\nThe gateway picks the right tool and fills the arguments automatically.\n\n## More\n\n- [Docs and guides](https://pipeworx.io/docs)\n- [pipeworx.io](https://pipeworx.io)\n\n## License\n\nMIT\n",
  "bytes": 9453,
  "sha": "36f2c9c801302428f49a6a411d7a606425a9dcbf4373ed4874ee7c7bf55d91cd",
  "repo_slug": "pipeworx-io/mcp-vaers",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_pipeworx_io_vaers_347aad35/readme"
}