{"id":"c518fbcb-800f-4ba7-80f9-bc4e3ff1d23b","slug":"nhanes-mcp","kind":"mcp","name":"nhanes-mcp","summary":"MCP server for design-correct, conversational analysis of NHANES public-use data (weights, pooling, survey variance, mortality linkage)","owner":"Black-Swan-Causal-Labs","repoUrl":"https://github.com/Black-Swan-Causal-Labs/nhanes-mcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":null,"addedAt":"2026-10-13T22:02:24.870Z","logoUrl":"https://avatars.githubusercontent.com/u/281048007?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["cloud-infra","data-analytics","design-media"],"tags":[],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T04:59:07.494Z","sample":false,"url":"https://conduits.dev/tools/nhanes-mcp","language":"Python","transports":["stdio"],"install":{"pypi":"nhanes-mcp"},"requirements":{"env":[{"name":"NHANES_MCP_CACHE","secret":false,"required":false,"description":"Folder for downloaded NHANES files (default ~/.cache/nhanes-mcp)"},{"name":"NHANES_MCP_DATA_DIR","secret":false,"required":false,"description":"Folder of manually downloaded .xpt files, for offline use"}],"upstreamMayCharge":false},"tools":null,"readme":"# nhanes-mcp\n\n<!-- mcp-name: com.blackswancausallabs/nhanes-mcp -->\n\nAn MCP server for **design-correct**, conversational access to NHANES public-use data.\nBlack Swan Causal Labs · MIT license · v0.5 · [PyPI](https://pypi.org/project/nhanes-mcp/) · [MCP Registry](https://registry.modelcontextprotocol.io/v0/servers?search=nhanes-mcp)\n\nMost \"chat with a dataset\" layers let an agent compute an unweighted mean. With NHANES that\nanswer is wrong. This server makes the defensible analysis the default: the agent asks a question\nin plain language, and the server finds the files, merges them on `SEQN`, picks the right weight,\nkeeps the full survey design, and reports design-based estimates with NCHS reliability flags.\n\n> **Not affiliated with, or endorsed by, NCHS or CDC.** Data are the public-use NHANES files\n> published by the National Center for Health Statistics and downloaded directly from cdc.gov.\n> Users are responsible for following the [NCHS data use agreement](https://www.cdc.gov/nchs/data_access/restrictions.htm).\n\n## What it handles for you\n\n| Pitfall | What the server does |\n|---|---|\n| Wrong / no weight | `build_dataset` picks the most restrictive weight (interview → MEC → fasting / phlebotomy / surplus-serum subsample → dietary day-1/day-2), explains why, and stores it in `WT_ANALYSIS`. Overrides (`build_dataset(weight=...)`, `set_weight`) are reported with every result; `WT_ANALYSIS` cannot be overwritten silently |\n| Subsetting before estimation | `domain=` expressions keep the full design (zero weight outside the domain) |\n| Pooling cycles | Weights rescaled by cycle years / total years (2017–March 2020 counts as 3.2 years); 1999–2002 uses 4-year weights; strata made cycle-unique; refuses 2017–2018 + 2017–2020 overlap |\n| Long-format tables (e.g. prescriptions) | Refuses to join tables with repeated `SEQN` (which would silently duplicate weights); `flag_from_long_table` collapses them to one row per person |\n| Refused / don't-know codes | `describe_variable` reads the CDC codebook and suggests sentinel codes; `set_missing` recodes them |\n| Silent 0 for missing | `derive_variable` propagates missingness (`any` / `all` / `none`); `coalesce`, `fillna`, `isna`, `notna`, `where` handle missingness deliberately |\n| Irregular file names | Tries known variants (e.g. 1999–2000 surplus-serum files `SSCMV_A`, `SSMUMP_A`) |\n| Variance | Taylor linearization, strata × PSU, design df; Korn–Graubard CIs and NCHS 2017 reliability flags for proportions |\n| Age adjustment | Direct adjustment to the 2000 US standard (20–39 / 40–59 / 60+) with linearized SE, or to any caller-supplied standard (age groups + population), with a warning for in-domain records outside the groups |\n| Mortality | Optional join of the public-use Linked Mortality File (follow-up through 2019) and a design-based Cox model |\n\n## Tools (17)\n\n| Step | Tools |\n|---|---|\n| Orient | `list_cycles`, `analysis_guidance` |\n| Find | `list_files`, `search_variables`, `describe_variable` |\n| Build | `build_dataset` (optional mortality join), `describe_dataset` |\n| Clean / derive | `set_missing`, `derive_variable`, `flag_from_long_table`, `set_weight` |\n| Analyze | `survey_frequency`, `survey_estimate`, `survey_regression` (linear / logistic), `survey_cox` (Cox PH, Binder variance) |\n| Present | `show_results` — text + structured results; interactive view with the optional Results Explorer add-on |\n| Export | `export_dataset` |\n\nCycles: 1999–2000 through 2017–2018, 2017–March 2020 (pre-pandemic, `P_` files) and August 2021–August 2023.\n\n## Results Explorer (optional add-on)\n\n`show_results` returns design-based results as text plus structured data in every client. With the\noptional **NHANES Results Explorer** add-on installed, MCP Apps hosts (Claude Desktop/web, ChatGPT,\nVS Code, Goose) also render an interactive view: headline estimate with CI and NCHS reliability badge,\na crude / age-adjusted toggle that re-runs the estimate on the server, the analysis plan, subgroup\npanels, server warnings, benchmarks against published estimates, and design provenance.\n\nThe add-on is a separate package from Black Swan Causal Labs under the **PolyForm Noncommercial\nLicense 1.0.0** (free for academic, public-health and other noncommercial use; commercial use needs a\nlicense — https://blackswancausallabs.com). It is not part of this MIT repository. nhanes-mcp finds it if\nit is installed in the same Python environment, if `NHANES_MCP_EXPLORER_PATH` points to it, or if a\nfolder named `nhanes-mcp-explorer` sits next to the `nhanes-mcp` folder.\n\n## Validation\n\nEstimates were checked against published NCHS results (`validation/`):\n\n- **Prevalence:** 57 of 57 published NCHS estimates reproduced (Data Briefs 360, 363, 508, 515;\n  pooled 2015–2018; 2017–March 2020 pre-pandemic).\n- **Standard errors:** 20 of 20 match; 11 of 12 published 95% CI bounds identical (the 12th differs by 0.1 at a rounding edge).\n- **Mortality:** a design-based Cox model on NHANES 1999–2006 (adults 25+) reproduces 6 of 7 published\n  hazard ratios within their CIs (NHSR 155). The Mexican American contrast does not reproduce\n  (0.71 vs 1.12 published); this is under investigation and the linked file here has longer follow-up (2019 vs 2015).\n- **Hypertension** (NCHS Data Brief 511, 2021–2023, adults 18+): prevalence (crude and age-adjusted, by sex and\n  age), awareness, treatment and control — 17 of 17 published estimates reproduced exactly.\n- **CMV seroprevalence** (Bate et al., *Clin Infect Dis* 2010; NHANES 1999–2004, ages 6–49, surplus-serum\n  weights): see `tests/benchmark_nchs.py`. Before v0.4 the server silently used MEC weights here and could not\n  load the 1999–2000 file.\n- **Unit tests** (`tests/`): variance checked against an independent loop implementation and a\n  delete-one-PSU jackknife; Cox model checked against statsmodels PHReg and a jackknife; weight\n  selection, pooling, guards, expression semantics, long-table and dietary-weight handling.\n\n## Install\n\n### Easiest: let your AI assistant do it\n\nPaste this into Claude (Cowork or Claude Code), or any agent that can run commands on your computer:\n\n> Install the nhanes-mcp MCP server (PyPI package `nhanes-mcp`) for Claude Desktop. Install `uv` if it is\n> missing, then add this entry to my Claude Desktop config (`claude_desktop_config.json`), using the full\n> path to `uvx`: `\"nhanes\": {\"command\": \"uvx\", \"args\": [\"nhanes-mcp\"]}`.\n> Keep my existing servers. Then tell me to restart Claude Desktop.\n\n### One line in the config (uvx)\n\nWith [uv](https://docs.astral.sh/uv/) installed, add to `claude_desktop_config.json` and restart Claude Desktop\n(on macOS use the full path from `which uvx`, e.g. `/Users/<you>/.local/bin/uvx`):\n\n```json\n\"nhanes\": {\n  \"command\": \"uvx\",\n  \"args\": [\"nhanes-mcp\"]\n}\n```\n\n`uvx` fetches the server from [PyPI](https://pypi.org/project/nhanes-mcp/) into an isolated environment on\nfirst launch; no clone or virtual environment to manage. To run the latest code from GitHub instead, use\n`\"args\": [\"--from\", \"git+https://github.com/Black-Swan-Causal-Labs/nhanes-mcp\", \"nhanes-mcp\"]`.\n\n### From source (for development)\n\n```bash\npython3 -m venv ~/.nhanes-mcp-venv\n~/.nhanes-mcp-venv/bin/pip install \"mcp>=1.2,<2\" pandas numpy scipy pyreadstat httpx beautifulsoup4 lxml\ngit clone https://github.com/Black-Swan-Causal-Labs/nhanes-mcp.git ~/nhanes-mcp\n```\n\n```json\n\"nhanes\": {\n  \"command\": \"/Users/<you>/.nhanes-mcp-venv/bin/python\",\n  \"args\": [\"-m\", \"nhanes_mcp\"],\n  \"env\": {\"PYTHONPATH\": \"/Users/<you>/nhanes-mcp\"}\n}\n```\n\nAny MCP client that runs local stdio servers works the same way. Data are downloaded from\ncdc.gov on first use and cached in `~/.cache/nhanes-mcp` (override with `NHANES_MCP_CACHE`).\nSet `NHANES_MCP_DATA_DIR` to a folder of manually downloaded `.xpt` files to work offline.\n\nNeed help setting it up for your team, or adapting it to another survey or dataset?\nContact [Black Swan Causal Labs](https://blackswancausallabs.com).\n\n## Tests\n\n```bash\npython tests/test_offline.py            # synthetic NHANES-shaped data, no network\npython tests/test_cox.py\npython tests/test_long_and_dietary.py\npython tests/benchmark_nchs.py          # reproduces published NCHS estimates (needs network)\n```\n\n## Known open issues\n\n- Age-adjusted adult obesity for 2009–2010 and earlier runs 0.1–0.7 points below NCHS Health E-Stat 111\n  (2011–2012 onward matches exactly). Pooling and pregnancy-code handling were ruled out; cause under investigation.\n- The CMV analysis finds 14,198 tested participants aged 6–49 in the public surplus-serum files versus 15,310\n  reported by Bate et al.; unexplained.\n- NHANES III (1988–1994) is not supported.\n\n## Changelog\n\n- **0.5.1** — First release on PyPI (`uvx nhanes-mcp`) and the official MCP Registry\n  (`com.blackswancausallabs/nhanes-mcp`). Packaging metadata only; no analysis changes.\n- **0.5.0** — `show_results` tool (text + structured results; interactive view via the optional\n  Results Explorer add-on); one-command install with `uvx`; analysis guidance rule 11.\n- **0.4.1** — Comparisons inside missing-aware functions now return missing when an operand is missing, so\n  skip-pattern definitions such as `where(BPQ020 == 1, fillna(BPQ150, 2) == 1, 0)` are missing (not 0) for people\n  never asked the screener. Hypertension benchmark (NCHS Data Brief 511) added.\n- **0.4.0** — Surplus-serum and other file-specific subsample weights with `2Y`/`4Y` suffixes are detected\n  and pooled; 1999–2000 `_A` file names resolved; `build_dataset(weight=...)` and new `set_weight` tool, both\n  recorded in every result; design columns protected from `derive_variable`; missing-aware expression functions;\n  custom age standards; CMV benchmark added.\n- **0.3.0** — Initial public release.\n\n## Limitations\n\n- Public-use files only. Restricted-use data (including the NHANES–CMS Medicare/Medicaid linkage) require an NCHS Research Data Center.\n- Variance uses Taylor linearization with PSUs treated as sampled with replacement, as NCHS recommends; replicate weights are not used.\n- The server reports what the data support; it does not choose a study design for you.\n"}