
Connects Claude to the CDC's Socrata SODA API across 1,487+ public health datasets covering mortality, vaccinations, NNDSS surveillance, and behavioral risk factors. Three tools handle the full workflow: discover datasets by keyword or category, fetch column schemas with row counts and types, then execute SoQL queries with filtering, aggregation, and full-text search. All responses return as strings per SODA v2.1 spec, so you'll need the schema metadata to parse correctly. Ships with a guided five-step prompt for trend analysis and two resources for quick dataset orientation. No auth required for basic use, optional app token bumps rate limits. Available as a public hosted instance or self-hosted via stdio, Docker, or Streamable HTTP.
claude mcp add --transport http cdc-health https://cdc.caseyjhand.com/mcpRun in your terminal. Add --scope user to make it available in every project.
Review the command, arguments, and environment values before installing — MCP servers run with your local permissions.
Verified live against the running server on Jun 10, 2026.
cdc_discover_datasetsSearch the CDC dataset catalog by keyword, category, or tag. Returns dataset IDs, names, descriptions, column lists, and update timestamps.5 paramsSearch the CDC dataset catalog by keyword, category, or tag. Returns dataset IDs, names, descriptions, column lists, and update timestamps.
categorystringlimitintegeroffsetintegerquerystringtagsarraycdc_get_dataset_schemaFetch the full column schema for a CDC dataset — names, data types, descriptions, row count, and last-updated timestamp. Get dataset IDs from cdc_discover_datasets.1 paramsFetch the full column schema for a CDC dataset — names, data types, descriptions, row count, and last-updated timestamp. Get dataset IDs from cdc_discover_datasets.
datasetId*stringcdc_query_datasetExecute a SoQL query against any CDC dataset. Supports filtering, aggregation, sorting, full-text search, and field selection. Use cdc_discover_datasets to find dataset IDs and cdc_get_dataset_schema to inspect columns before querying.9 paramsExecute a SoQL query against any CDC dataset. Supports filtering, aggregation, sorting, full-text search, and field selection. Use cdc_discover_datasets to find dataset IDs and cdc_get_dataset_schema to inspect columns before querying.
datasetId*stringgroupstringhavingstringlimitintegeroffsetintegerorderstringsearchstringselectstringwherestringSearch and query CDC public health data — mortality, vaccinations, surveillance, behavioral risk (Socrata SODA API) via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://cdc.caseyjhand.com/mcp
Four tools for discovering and querying CDC public health data. Three query the CDC Open Data portal (Socrata); one queries CDC WONDER mortality statistics:
| Tool | Description |
|---|---|
cdc_discover_datasets | Search the catalog by keyword, category, or tag. Entry point for all queries. |
cdc_get_dataset_schema | Fetch column schema, row count, and metadata for a dataset. Essential before writing SoQL queries. Returns a bounded column window with a continuation offset for wide schemas. |
cdc_query_dataset | Execute SoQL queries — filter, aggregate, sort, full-text search, and field selection. |
cdc_query_wonder | Query CDC WONDER for national mortality statistics (deaths, population, crude/age-adjusted rates) by year, age, sex, and race, filtered by ICD-10 cause. Covers five CDC mortality databases — final and provisional, underlying-cause and multiple-cause. Large tables page with a continuation offset. |
cdc_discover_datasetsSearch the CDC dataset catalog to find relevant datasets.
["covid19", "surveillance"]) — a dataset matches on any one tag, so each tag added widens the result set; narrow with query or category, which intersect with the tag setcdc_get_dataset_schema for the full column listassetType (dataset, filter, chart, map, story, file, href); a columnCount of 0 marks an entry that is not tabular and yields no data from the other toolsoffset plus limit must not exceed 10,000, the ceiling the catalog enforcesdomain selects the host contacted, data.cdc.gov (default) or chronicdata.cdc.gov — both front the same catalog and return the same entries, so switching hosts neither widens nor narrows a searchcdc_get_dataset_schemaFetch the column schema for a specific dataset.
$where clausesbi63-dtpu)totalCount, truncated, and a nextOffset to pass back as column_offset. Raise column_limit (max 500) to pull a wide schema in one callcolumn_offset at or past the column count returns an empty window rather than an errornot_queryable when the ID names a non-tabular catalog asset, rather than returning an empty column listdomain selects the host contacted, data.cdc.gov (default) or chronicdata.cdc.gov — a four-by-four ID resolves on eithercdc_query_datasetExecute SoQL queries against any CDC dataset.
$select, $where, $group, $having, $order$qtruncated is measured, not guessed: the request fetches one row past the limit and drops it, so a page that fills the limit exactly is reported as complete instead of sending you paginating an aggregatenextOffset names where to resume whenever rows remain. Pair it with an order clause — SODA does not order results implicitly, and order=":id" works on any datasetlimit: 5000 returns a usable page with a nextOffset rather than several megabyteseffectiveQuery, values in their original text rather than URL-encoded, so a clause can be copied back into the parameter it came fromdomain selects the host contacted, data.cdc.gov (default) or chronicdata.cdc.gov — a four-by-four ID returns the same rows from eithercdc_query_wonderQuery CDC WONDER for national US mortality statistics — a separate CDC system from the Socrata datasets the other tools query.
database picks which of CDC's five mortality databases answers the query:
| Value | CDC database | Years | Race groups | mcd_icd10 |
|---|---|---|---|---|
underlying_1999_2020 (default) | D76 — Underlying Cause of Death | 1999–2020 | 4 bridged | — |
provisional | D176 — Provisional Mortality Statistics | 2018 → current year | 6 single-race | yes |
underlying_2018_2024 | D158 — Underlying Cause of Death, Single Race | 2018–2024 | 6 single-race | — |
multiple_1999_2020 | D77 — Multiple Cause of Death | 1999–2020 | 4 bridged | yes |
multiple_2018_2024 | D157 — Multiple Cause of Death, Single Race | 2018–2024 | 6 single-race | yes |
year, age_group, sex, race (1–4 dimensions)age_groups carries the whole list CDC offers: the eleven ten-year groups plus NS, the group for a death whose age was not recorded. Listing the eleven without NS returns fewer deaths than the same query unfiltered, so include it to match an all-ages total or select it alone to count those deathsmcd_icd10 matches a cause recorded anywhere on the death certificate rather than only the one certified as underlying — "died with a respiratory condition listed", which no underlying-cause query can produce. Accepted only by the three databases marked above; the others reject it. A multiple-cause database queried without it returns the same figures as the underlying-cause database for the same years, and says soyear_range carries the union of every database's span; a range outside the span of the one selected is rejected with that database's actual years namedrace breakdown does not carry across the two race families — bridged race combines Asian and Pacific Islander into one group, single race splits them and adds a multiracial category, so the two series are not comparable999--999, CDC's marker for deaths whose cause it is still withholding under the provisional database's six-month reporting lag. Only provisional records them; the other databases reject the code, and the tool says which one to select"2024 " and "2024" would otherwise read as two different years2025 (provisional) and 2026 (provisional and partial), rather than a bare yearage_group or filtering to a single age group["year","age_group","sex","race"] can pass a thousand rows — so limit (max 5,000) and offset take it a page at a time, alongside totalCount, truncated, and a nextOffset to resume from. An offset at or past the row total returns an empty page rather than an errorcaveats and messages come back complete on each page; cellNotes covers the rows returned, with row relative to themSuppressed (withheld for confidentiality), Unreliable (a rate from fewer than 20 deaths), Not Applicable (no population denominator). Those cells read null in rows; cellNotes names the row, column, and token for eachrows with nothing marking the gap, so messages carries CDC's own statement whenever it happened| Type | Name | Description |
|---|---|---|
| Resource | cdc://datasets | 50 most-viewed catalog entries for orientation, each with its asset type and column count |
| Resource | cdc://datasets/{datasetId} | Dataset metadata plus the first 100 columns, with the dataset's total column count and a truncation flag; cdc_get_dataset_schema reaches the rest |
| Prompt | analyze_health_trend | Picks between CDC WONDER and the Socrata catalog for the question at hand, then runs a 5-step workflow: discover, inspect, baseline query, compare, synthesize |
Built on @cyanheads/mcp-ts-core:
none, jwt, oauth)in-memory, filesystem, Supabase, Cloudflare KV/R2/D1CDC-specific:
cdc_query_wonder) — national deaths, population, and crude/age-adjusted rates across five mortality databases spanning 1999 through the current year, final and provisional, underlying-cause and multiple-cause; a separate XML-over-HTTP CDC systemdomain input — data.cdc.gov (default) and chronicdata.cdc.gov, restricted to this allowlist. Both front one Socrata tenant: a single catalog whose assets — PLACES small-area estimates, the Heart Disease & Stroke Atlas and Environmental Public Health Tracking among them — are discoverable and queryable from either hostA public instance is available at https://cdc.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"cdc-health-mcp-server": {
"type": "streamable-http",
"url": "https://cdc.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"cdc-health-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/cdc-health-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"cdc-health-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/cdc-health-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"cdc-health-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/cdc-health-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/cdc-health-mcp-server.git
cd cdc-health-mcp-server
bun install
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.) | info |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
CDC_APP_TOKEN | Socrata app token for higher rate limits | none |
CDC_BASE_URL | Base URL for SODA API requests | https://data.cdc.gov |
CDC_CATALOG_URL | Base URL for Socrata Discovery API | https://api.us.socrata.com/api/catalog/v1 |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs) | false |
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more
bun run test # Runs the test suite
| Directory | Purpose |
|---|---|
src/mcp-server/tools | Tool definitions (*.tool.ts). Three CDC data tools. |
src/mcp-server/resources | Resource definitions. Catalog overview and dataset detail. |
src/mcp-server/prompts | Prompt definitions. Health trend analysis workflow. |
src/services/socrata | Socrata SODA API service layer — HTTP client, catalog search, metadata, queries. |
src/config | Server-specific environment variable parsing and validation with Zod. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging, ctx.state for storagecreateApp() arraysIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
CDC_APP_TOKENSocrata app token for higher rate limits.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.