内容
# CMS 医疗数据 MCP 服务器
> **生产级别的模型上下文协议(MCP)服务器,暴露四个 CMS 公共数据集作为 Claude 对话中的可调用工具 — 实现无需 SQL 专业知识的自然语言 RWE 分析。**
[](https://www.typescriptlang.org/)
[](https://github.com/anthropics/anthropic-sdk)
[](https://nodejs.org/)
[](LICENSE)
---
## 概述
现实世界的证据分析师在项目中花费大量时间在数据访问机制上:定位 CMS 数据集、编写参数化 SQL、处理分页和规范化模式。该服务器在协议层解决了这个基础设施问题。
服务器实现了 [模型上下文协议](https://modelcontextprotocol.io/) 规范,并作为一个本地 stdio 进程运行,Claude Desktop 将其注册为工具提供者。一旦注册,分析师就可以使用纯英语查询 HCC 风险评分、医院再入院率、MIPS 质量衡量指标和 Part D 药物利用率 — 服务器处理验证、缓存和安全查询执行。
**关键功能:**
| 功能 | 实现 |
|---|---|
| 协议遵从性 | MCP SDK v1.0.4,`StdioServerTransport` |
| 暴露的数据集 | 4 个 CMS 公共数据集 |
| 可用工具 | 6 个可调用工具 |
| 查询模板 | 12 个预先批准的、注入安全的模板 |
| 缓存 | 基于 TTL(NodeCache):24 小时引用,5 分钟事务 |
| 安全 | API 密钥身份验证、速率限制(100 请求/分钟)、Zod 验证 |
| 审计日志 | NDJSON 审计跟踪到 `outputs/audit.log` |
| 演示模式 | 嵌入式样本数据 — 无需数据库即可运行 |
| 测试套件 | 84/84 通过(验证于 2026-06-30) |
---
## 为什么使用 MCP 进行 CMS 数据访问?
传统的 CMS 数据访问需要分析师维护数据库凭证、编写参数化 SQL、管理连接池和处理 API 分页。对于临床研究人员来说,他们的主要技能是领域专业知识 — 而不是软件工程 — 这种摩擦降低了生产力并引入了错误风险。
MCP 通过标准化语言模型和外部数据系统之间的接口来解决这个问题。服务器暴露了一个类型化、版本化、审计的合约。Claude 调用工具;服务器处理调用下的所有内容。
**与替代方案的比较:**
| 方法 | 需要 SQL 专业知识 | 审计跟踪 | 协议标准 | Claude 原生 |
|---|---|---|---|---|
| 直接数据库查询 | 是 | 否 | 否 | 否 |
| REST API 包装器 | 部分 | 可选 | 否 | 否 |
| **MCP 服务器(本项目)** | **否** | **是** | **是(MCP)** | **是** |
| 自定义 Claude 插件 | 否 | 可选 | 专有 | 部分 |
---
## 架构
```
┌─────────────────────────────────────────────────────────────────┐
│ Claude Desktop │
│ (MCP 客户端,发起工具调用) │
└─────────────────────────┬───────────────────────────────────────┘
│ stdio(MCP 协议)
▼
┌─────────────────────────────────────────────────────────────────┐
│ server.ts(MCP 服务器) │
│ - StdioServerTransport │
│ - ListToolsRequestSchema 处理器 │
│ - CallToolRequestSchema 处理器 │
│ - HTTP 健康端点(:3000/health) │
└─────────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ tools.ts(请求管道) │
│ │
│ [1] API 密钥身份验证 → [2] 速率限制器 → [3] Zod 验证 │
│ [4] 缓存查找 → [5] 数据获取 → [6] 缓存存储 │
│ [7] 审计写入 → [8] JSON 响应 │
└────────────┬──────────────────────┬────────────────────────────┘
│ │
▼ ▼
┌────────────────────┐ ┌──────────────────────────────────────┐
│ validators.ts │ │ datasources.ts │
│ │ │ │
│ - Zod 模式 │ │ DEMO_MODE=true → 样本数据 │
│ - SQL 净化器 │ │ DEMO_MODE=false → PostgreSQL 连接池 │
│ - 模板 │ │ │
│ 白名单 │ │ fetchHccData() │
│ (12 个模板) │ │ fetchReadmissionData() │
│ │ │ fetchMipsData() │
└────────────────────┘ │ fetchPartdData() │
└──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ cache.ts │
│ NodeCache TTL 层级: │
│ - 引用数据(HCC,MIPS):24 小时 │
│ - 事务数据(再入院,Part D):5 分钟 │
│ - SHA-256 确定性缓存键 │
└─────────────────────────────────────────────────────────────────┘
```
**目录结构:**
```
cms-mcp-server/
├── src/
│ ├── server.ts # MCP 服务器核心,传输,健康端点
│ ├── tools.ts # 工具定义和请求处理器
│ ├── datasources.ts # CMS 数据连接器(演示 + PostgreSQL)
│ ├── validators.ts # Zod 模式,净化器,模板白名单
│ ├── cache.ts # TTL 缓存,确定性键生成
│ ├── config.ts # Zod 验证的环境配置
│ ├── logger.ts # Winston 应用程序 + 审计 + 查询日志
│ └── types.ts # 共享 TypeScript 接口
├── tests/
│ ├── unit.test.ts # 验证器,缓存,注入安全测试
│ └── integration.test.ts # 完整工具生命周期,DEMO_MODE
├── schema/
│ ├── cms_data_schema.json # JSON Schema Draft-07,用于所有记录类型
│ └── init.sql # PostgreSQL 模式,用于生产模式
├── docs/
│ └── protocol_spec.md # 完整的 MCP 协议规范
├── outputs/ # 运行时:写入 audit.log
├── .env.example
├── docker-compose.yml
├── Dockerfile
├── jest.config.cjs
├── package.json
└── tsconfig.json
```
---
## 暴露的数据集
| 数据集 ID | 来源 | 更新频率 | 缓存 TTL | 关键字段 |
|---|---|---|---|---|
| `hcc_risk_adjustment` | CMS-HCC V28 模型 | 年度 | 24 小时 | `icd10Code`,`hccCategory`,`riskScore`,`modelYear` |
| `hospital_readmission` | HCUP AHRQ | 季度 | 5 分钟 | `ccn`,`measureId`,`readmissionRate`,`state` |
| `mips_quality_measures` | CMS QPP | 年度 | 24 小时 | `npi`,`measureId`,`performanceScore`,`specialty` |
| `partd_drug_utilization` | CMS Part D PUF | 年度 | 24 小时 | `drugName`,`genericName`,`totalCost`,`claimCount` |
**数据血统元数据** 在每个响应中返回:
```json
{
"dataLineage": {
"source": "CMS-HCC V28 风险调整模型",
"sourceUrl": "https://www.cms.gov/medicare/payment/medicare-advantage/risk-adjustment",
"lastUpdated": "2024-01-01T00:00:00Z",
"lagDays": 365,
"disclaimer": "CMS 数据有 3-6 个月的延迟..."
}
}
```
---
## 工具参考
### `list_datasets`
返回所有可用的 CMS 数据集目录,包含元数据。
**参数:** 无
**返回:** 包含 ID、名称、描述、源 URL、最后更新时间戳和行数的 dataset 描述符数组。
---
### `get_schema`
返回特定数据集的字段模式。
**参数:**
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
| `datasetId` | `string` | 是 | 四个数据集 ID 之一 |
---
### `get_data`
从数据集中检索过滤的记录。
**参数:**
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
| `datasetId` | `string` | 是 | 目标数据集 |
| `filters` | `object` | 否 | 数据集特定的过滤字段(见下文) |
| `limit` | `number` | 否 | 返回的最大行数(1-1000,默认 100) |
**HCC 过滤器:** `icd10Code`(正则表达式:`/^[A-Z][0-9]{2}(\.[0-9A-Z]{1,4})?$/`),`hccCategory`(整数),`modelYear`(2020-2030),`riskScoreMin/Max`(0.0-5.0)
**再入院过滤器:** `ccn`(6 位数字),`state`(2 个字母),`measureId`,`readmissionRateMin/Max`(0.0-1.0)
**MIPS 过滤器:** `npi`(10 位数字),`specialty`(字符串),`measureId`,`performanceScoreMin/Max`(0-100)
**Part D 过滤器:** `drugName`(字符串),`genericName`(字符串),`year`(2015-2030),`minTotalCost`(数字)
---
### `run_query`
使用参数执行命名、预先批准的查询模板。
**参数:**
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
| `templateId` | `string` | 是 | 12 个批准的模板之一 |
| `params` | `object` | 否 | 模板特定的参数 |
**批准的模板:**
| 模板 ID | 数据集 | 描述 |
|---|---|---|
| `hcc_by_icd_code` | HCC | 检索特定 ICD-10 代码的 HCC 映射 |
| `hcc_by_category` | HCC | 给定 HCC 类别中的所有诊断 |
| `hcc_risk_score_distribution` | HCC | 跨模型年的风险评分分布 |
| `readmission_by_hospital` | 再入院 | 特定医院(CCN)的再入院率 |
| `readmission_by_state` | 再入院 | 国家级再入院率汇总 |
| `readmission_national_benchmark` | 再入院 | 按衡量指标的国家平均值 |
| `mips_performance_by_provider` | MIPS | 特定 NPI 的 MIPS 评分 |
| `mips_performance_by_measure` | MIPS | 质量衡量指标的性能分布 |
| `mips_specialty_summary` | MIPS | 按专业汇总的 MIPS 评分 |
| `partd_cost_by_drug` | Part D | 特定药物的成本趋势 |
| `partd_utilization_trends` | Part D | 年间索赔量趋势 |
| `partd_top_drugs_by_cost` | Part D | 按总成本排名前 N 的药物 |
---
### `cache_status`
返回当前的缓存统计信息。
**返回:**命中率、未命中率、键计数、内存使用情况、TTL 配置。
---
### `get_sample_queries`
返回数据集的即用示例查询。
**参数:**
| 参数 | 类型 | 必需 |
|---|---|---|
| `datasetId` | `string` | 是 |
---
## 如何运行
### 前提条件
- Node.js 20+
- npm 10+
- (可选,生产模式)PostgreSQL 16+
### 安装
```bash
git clone https://github.com/SaeMind/mcp-server-for-cms-healthcare-data-tools.git
cd cms-mcp-server
npm install
```
### 环境配置
```bash
cp .env.example .env
```
关键变量:
```env
# 设置为 true 以使用嵌入式样本数据(无需数据库)
DEMO_MODE=true
# 仅当 DEMO_MODE=false 时需要
DATABASE_URL=postgresql://cms_user:password@localhost:5432/cms_data
# 可选:启用 API 密钥身份验证
API_KEY=your-key-here
# 可选:覆盖速率限制(默认:100 请求/分钟)
RATE_LIMIT_PER_MINUTE=100
# 可选:覆盖 HTTP 健康端口(默认:3000)
PORT=3000
```
### 构建和启动(演示模式)
```bash
npm run build
npm start
```
服务器在 stdio 上启动,并在 `http://localhost:3000/health` 处暴露一个健康端点。
### 不构建直接启动(开发)
```bash
npm run dev
```
### Docker(PostgreSQL + 服务器)
```bash
mkdir -p outputs
docker-compose up --build
```
Compose 堆栈启动 PostgreSQL 16,监听端口 5432 和 MCP 服务器。数据库模式从 `schema/init.sql` 初始化。
---
## 配置 Claude Desktop
将以下块添加到 `~/.claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"cms-healthcare-data": {
"command": "node",
"args": ["/absolute/path/to/cms-mcp-server/dist/server.js"],
"env": {
"DEMO_MODE": "true"
}
}
}
}
```
重启 Claude Desktop。服务器工具出现在任何新对话的工具选择器下。
---
## 示例查询
注册后,直接在 Claude 中调用工具:
**列出可用数据集:**
```
Call list_datasets
```
**HCC 风险评分,适用于 E11.9(2 型糖尿病):**
```
Call get_data with datasetId=hcc_risk_adjustment, filters={icd10Code: "E11.9"}
```
**按州划分的医院再入院率:**
```
Call run_query with templateId=readmission_by_state, params={state: "TX"}
```
**特定提供者的 MIPS 性能:**
```
Call run_query with templateId=mips_performance_by_provider, params={npi: "1234567890"}
```
**按总成本排名前 10 的 Part D 药物:**
```
Call run_query with templateId=partd_top_drugs_by_cost, params={limit: 10}
```
**适用于二甲双胍的药物利用趋势:**
```
Call run_query with templateId=partd_cost_by_drug, params={drugName: "metformin"}
```
---
## 安全性和验证
安全性分为多个层次。每个工具调用在访问任何数据之前都会经过整个管道:
```
[1] API 密钥身份验证 → 常时间比较(crypto.timingSafeEqual)
[2] 速率限制 → RateLimiterMemory, 100 请求/分钟每键
[3] 输入验证 → Zod 模式,每个数据集;禁用类型强制
[4] 字符串净化 → 删除 SQL 元字符:' ; -- /* */ xp_ EXEC
[5] 模板白名单 → run_query 仅从 12 个批准的模板执行
[6] 参数化 SQL → 所有 PostgreSQL 查询都使用 $N 位置参数
[7] 审计日志 → 每个调用写入 outputs/audit.log(NDJSON)
```
**审计日志条目格式(NDJSON):**
```json
{
"timestamp": "2024-06-01T14:23:11.042Z",
"level": "audit",
"tool": "run_query",
"templateId": "readmission_by_state",
"params": {"state": "TX"},
"cacheHit": false,
"rowsReturned": 47,
"durationMs": 12,
"apiKeyHash": "sha256:a1b2c3..."
}
```
---
## 演示模式 vs. 生产模式
**DEMO_MODE=true(默认):** 服务器返回 `src/datasources.ts` 中的嵌入式样本记录 — 10 个 HCC 记录、5 个再入院记录、4 个 MIPS 记录和 5 个 Part D 记录。不需要数据库。这些记录代表真实的 CMS 数据格式,但 **不是** 实时 CMS 数据。
**DEMO_MODE=false:** 服务器查询一个使用 `schema/init.sql` 初始化的 PostgreSQL 数据库。模式已准备好用于生产,但不包含 ETL 脚本来加载真实的 CMS 数据。此模式需要单独填充的数据库。
包含在本存储库中的 Tableau 仪表盘是使用 DEMO_MODE=true 样本数据集构建的。它可视化了服务器的工具接口和数据模式;它不反映实时 CMS 人口统计数据。
---
## Tableau 仪表盘
**[CMS MCP 服务器 - 高管仪表盘](https://public.tableau.com/views/CMSMCPServer-ExecutiveDashboard/CMSMCPServerExecutiveDashboard)**
包含的视图:
- 按疾病等级分组的 HCC 风险因素分布
- 按设施和衡量指标划分的医院再入院率与国家基准
- 按药物类别划分的 Part D 药物成本每索赔
用于构建仪表盘的 CSV 导出文件位于 `outputs/`(由 `scripts/export_demo_csv.ts` 生成)。
---
## 测试
```bash
# 完整测试套件
npm test
# 仅单元测试(验证器、缓存、注入安全性)
npm run test:unit
# 仅集成测试(完整工具生命周期,DEMO_MODE)
npm run test:integration
# 类型检查,无输出
npm run typecheck
```
**单元测试覆盖率:
| 区域 | 测试 |
|---|---|
| `validateDatasetId` | 有效 ID,无效字符串,非字符串输入 |
| `assertApprovedTemplate` | 所有 12 个有效模板,拒绝任意字符串 |
| HCC 参数验证 | ICD-10 正则表达式,风险评分边界,限制边界,模型年份范围 |
| 再入院验证 | CCN 格式,速率边界,SQL 注入到自由文本字段 |
| MIPS 验证 | NPI 正则表达式,评分边界 |
| Part D 验证 | 年范围,成本下限 |
| 缓存 | 键确定性(参数顺序独立性),存储/检索,TTL 过期,刷新,统计信息 |
| SQL 注入对抗性套件 | 6 种注入模式,跨所有字符串过滤字段 |
**集成测试覆盖率:
| 场景 | 断言 |
|---|---|
| `list_datasets` 返回 4 个条目 | 数据集 ID 与预期集合匹配 |
| `get_schema` 返回字段元数据 | 数据集的模式字段存在 |
| `get_data` HCC 采用 ICD 过滤器 | 结果行与过滤器匹配 |
| `get_data` 再入院采用州过滤器 | 状态字段与过滤器值匹配 |
| 缓存命中重复请求 | 第二个相同调用返回 `cacheHit: true` |
| 错误响应形状 | 无堆栈跟踪;`error` 字段存在 |
| `run_query` 模板路由 | 所有 12 个模板无错误解析 |
| `get_sample_queries` | 返回每个数据集的非空数组 |
---
## 使用的技术
| 技术 | 版本 | 角色 |
|---|---|---|
| TypeScript | 5.3 | 语言(严格模式)|
| `@modelcontextprotocol/sdk` | 1.0.4 | MCP 服务器和传输 |
| `zod` | 3.22 | 运行时模式验证 |
| `node-cache` | 5.1 | 基于 TTL 的进程内缓存 |
| `rate-limiter-flexible` | 5.0 | 内存速率限制 |
| `pg` | 8.11 | PostgreSQL 客户端(生产模式)|
| `winston` | 3.11 | 结构化日志和审计跟踪 |
| `dotenv` | 16.4 | 环境配置 |
| Jest + ts-jest | 29.7 | 单元和集成测试 |
| Docker + PostgreSQL 16 | — | 可选生产后端 |
---
## 数据源
| 数据集 | 来源 | 网址 |
|---|---|---|
| CMS-HCC V28 风险调整 | CMS Medicare Advantage | https://www.cms.gov/medicare/payment/medicare-advantage/risk-adjustment |
| 医院再入院率 | HCUP AHRQ | https://hcupnet.ahrq.gov/ |
| MIPS 质量衡量指标 | CMS QPP | https://qpp.cms.gov/mips/quality-measures |
| Part D 药物利用率 | CMS Part D PUF | https://data.cms.gov/provider-summary-by-type-of-service/medicare-part-d-prescribers |
所有数据集均为 CMS 公共数据。未访问或存储任何 PHI。所有输出根据 CMS 数据使用协议按聚合或去标识处理。
---
## 扩展服务器
要添加新的数据集:
1. 将数据集 ID 添加到 `src/types.ts` 中的 `DatasetId` 联合类型。
2. 在 `src/validators.ts` 中定义过滤器接口和 Zod 模式。
3. 在 `src/datasources.ts` 中添加一个获取函数。
4. 在 `src/tools.ts` 中添加工具处理分支。
5. 将数据集条目添加到 `DATASET_CATALOG`。
6. 添加相应的单元和集成测试。
7. 更新 `schema/cms_data_schema.json` 以包含新的记录类型。
---
## 相关工作
本服务器实现了与企业 RWE 平台(如 Flatiron、IQVIA、Komodo Health)用于通过类型化接口公开索赔数据相同的模式 — 但在协议层而不是应用层,实现了 LLM 原生访问,无需特制的 frontend。
**相关文献:
- Bodenreider O. (2004). 统一医学语言系统(UMLS):集成生物医学术语。 *核酸研究*,32(数据库问题),D267–D270。
- Forrest CB 等人 (2014). PCORnet:国家患者中心临床研究网络。 *美国医学信息学协会杂志*,21(4),574–577。
- Mandl KD 等人 (2020). 基于 SMART/HL7 FHIR 的生态系统。 *美国医学信息学协会杂志*,23(3),447–452。
---
## 许可
MIT — 参见 [LICENSE](LICENSE).
---
*由医疗分析临床数据科学组合中的 RWE 分析师角色构建。作者:Andrew Lee | [GitHub](https://github.com/SaeMind) | [LinkedIn](https://linkedin.com/in/agllee) | [ORCID](https://orcid.org/0009-0006-6489-3807)*
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器