内容
# dicom-mcp
一个用Rust编写的[MCP](https://modelcontextprotocol.io)服务器,允许个人通过Claude阅读**他们自己的**DICOM医学影像——列出他们的检查,研究单个图像,并生成PDF以便带给医生或专家。
它故意设计得狭隘且优先考虑隐私:
- **只读。** 它从不写入、移动或删除源DICOM文件。导出(PNG/PDF)仅写入服务器自己的输出文件夹(或配置的路径)。
- **仅CT、MR和X射线**(`CT`、`MR`和投影放射学家族`CR`/`DX`/`XA`/`RF`)。其他模式在扫描时被过滤掉。
- **匿名化。** 返回给模型的图像元数据是允许的非识别性集合。患者姓名、ID、出生日期、访问号码、机构和DICOM UID永远不会被读取或显示。
- **不是医疗建议。** 服务器帮助**显示**和**组织**个人的影像并准备问题。诊断应由临床医生进行。
> ⚕️ 这个工具使个人能够访问和理解他们自己的影像。它不是诊断设备,不取代专业放射科解读。
## 工作原理
DICOM检查——无论是导出自门户还是烧录在光盘上——都由一个`DICOMDIR`文件(一个名为`DICOMDIR`的文件,无扩展名)索引。服务器指向影像所在的目录;它扫描该目录和**所有子目录**,查找每个`DICOMDIR`(包括复制到磁盘的光盘),解析`患者 → 检查 → 系列 → 图像`层次结构,保持CT/MR/XR系列,并报告找到的检查:
> **检查名称 · 日期 · 系列数 · 总图像数**
## 工具
| 工具 | 功能 |
|------|--------------|
| `scan_folder` | 递归扫描文件夹中的DICOMDIR并加载CT/MR/XR检查。回复找到的检查。 |
| `list_studies` | 列出当前加载的检查(重启后仍保持)。 |
| `get_study` | 单个检查的系列分解(模式、编号、名称、图像计数)以及任何附加报告。 |
| `get_report` | 检索检查报告:结构化报告渲染为内联文本,或封装的PDF写入输出文件夹。 |
| `get_image_info` | 单个图像的匿名技术元数据(见下文)。 |
| `view_image` | 内联8位、窗口级别**预览**,以便查看和讨论图像。 |
| `export_image_png` | **无损**PNG导出——默认情况下为原生位深度的原始存储值(或窗口级别16位)。 |
| `generate_pdf` | 生成PDF,以`邻接`或`网格`布局与临床医生共享。 |
| `clear_studies` | 删除加载的集合(不影响源文件)。需要`confirm: true`。 |
| `build_info` | 版本、git构建/提交、**UTC编译时间**、目标、rustc。 |
### 返回的图像元数据
仅技术、非识别属性:
- **位置:** 图像*N / M*、系列、系列名称、模式。
- **尺寸/大小/类型:** 行×列、每像素样本、分配/存储的位、有符号/无符号、光度解释、帧、未压缩存储字节大小和一行摘要。
- **切片几何:** 切片厚度、切片位置、切片间距、像素间距、切片位置(z)、kVp。
- **采集日期时间**和**扫描仪制造商/型号**。
- **强度映射:** 缩放斜率/截距和窗口中心/宽度——以便临床医生可以解释低/高强度。
### 报告
检查通常附带报告,作为DICOM**结构化报告**(SR)或**封装PDF**。这些位于`SR`/`DOC`系列中,CT/MR/XR过滤器会删除它们,因此它们会被单独捕获并按检查列出(`report_count` / `get_study`中的`reports`数组)。`get_report`将SR渲染为可读文本内联(辐射剂量报告、关键对象选择、发现——无论SR包含什么,都从其内容树中遍历)或将封装的PDF写入输出文件夹。报告是患者自己的文档,可能包含他们的姓名,因此——与图像元数据不同——它按原样返回,不进行匿名化。
### 无损导出和保真度
医学解读依赖于位深度(低/高强度存在于存储的像素值中),因此导出围绕保真度构建:
- `export_image_png`默认情况下为**原生位深度的原始存储像素值**,不应用模式LUT / VOI窗口 / 缩放——16位灰度PNG,**最大**(`Compression::High`)无损压缩。带符号像素通过记录的`applied_offset`移位到无符号范围(减去它以恢复原始带符号值)。传递`windowed: true`以获取显示级别的16位图像。
- **PDF生成器无损嵌入图像**,以原生分辨率作为16位灰度,并简单地通过PDF转换缩放以适应每个单元格——不进行重采样。流使用无损**FlateDecode**(无DCT/JPEG,无降采样),因此嵌入的像素保持精确,同时保持PDF紧凑。(图像显示级别以提高可见性。)
- `view_image`返回一个8位、缩小预览,纯粹是为了让模型看到图片——它明确地*不是*忠实的副本。
### PDF布局
- **`邻接`** — 选定的图像居中,带有其系列邻居在一个十字交叉中:**左侧** = 前一层,**右侧** = 下一层,**顶部** = 两层前,**底部** = 两层后。超出系列末端的邻居以相同单元格大小的灰色占位符绘制。
- **`网格`** — 一个联系表,整个系列(或包含`from..to`范围)以`cols`列(默认为4)排列,每个图像标题为`YYYY-MM 模式 系列名称 Image##`。
## 构建
```sh
cargo build --release
```
需要Rust ≥ 1.85(2024版)和**C编译器**(`cc`/MSVC)——JPEG 2000支持编译了一个捆绑的C OpenJPEG库(`openjpeg-sys`)。不需要单独的GDCM/OpenJPEG/`cmake`安装。
解码器:未压缩、RLE和基线/扩展JPEG通过纯Rust `native`;**JPEG 2000**(`1.2.840.10008.1.2.4.90/.91`,在PACS导出中非常常见)通过C OpenJPEG。JPEG-LS和JPEG XL不启用。`get_image_info`中的`transfer_syntax`字段报告每个图像使用的语法。参见[KNOWN_ISSUES.md](KNOWN_ISSUES.md),了解为什么纯Rust JPEG 2000解码器被故意避免(它中止进程)以及如何构建时不依赖C。
## 运行
服务器通过**stdio**(stdout保留用于协议)以JSON-RPC方式讲话。
```sh
dicom-mcp serve
```
标志:
- `--ephemeral` — 不要在运行之间持久化加载的检查。
- `--state-file <path>` — 覆盖状态文件位置。
- `--allowed-root <dir>` — 将`scan_folder`限制在该根目录下的路径(可重复)。默认值:无限制。
- `dicom-mcp version` — 打印构建信息并退出。
### Claude Desktop 配置
```json
{
"mcpServers": {
"dicom": {
"command": "/path/to/dicom-mcp",
"args": ["serve"]
}
}
}
```
## 文件和日志记录
服务器写入的所有内容都位于OS标准的用户数据目录下(从不进入影像文件夹):
- Windows `…\AppData\Local\dicom-mcp\`
- macOS `~/Library/Application Support/dicom-mcp/`
- Linux `~/.local/share/dicom-mcp/`
| 路径 | 内容 |
|------|----------|
| `state.json` | 加载的检查集(仅元数据——从不像素数据)。 |
| `logs/dicom-mcp.log` | 滚动每日运行时日志(也镜像到stderr)。 |
| `error.log` | 意外错误的擦除JSONL记录(仅版本+类型——无路径或图像数据)。 |
| `out/` | 导出的PNG和生成的PDF。 |
## 隐私
该软件读取私人医疗数据。通过设计,它只会显示上述匿名技术元数据,从不显示患者标识符或UID,并且不会将任何内容写回影像。擦除的`error.log`存在,以便可以**自愿**将其附加到错误报告中;在附加之前请先查看它。
## 许可证
MIT — 见[LICENSE](LICENSE)。