255 lines
10 KiB
Markdown
255 lines
10 KiB
Markdown
|
|
# DICOM MCP Server
|
||
|
|
|
||
|
|
A Model Context Protocol (MCP) server for analyzing DICOM medical imaging files, specifically designed for QA workflows in body composition analysis and liver imaging.
|
||
|
|
|
||
|
|
## Who is this for?
|
||
|
|
|
||
|
|
This server is designed primarily for **Claude Desktop users** — radiographers, QA analysts, and other non-technical team members who need to inspect and validate DICOM files but don't write code. Claude Desktop has no shell or filesystem access, so the MCP server is the only way to give it DICOM analysis capabilities.
|
||
|
|
|
||
|
|
**Claude Code users** (developers, engineers) generally don't need this. Claude Code can run Python and use pydicom directly, offering more flexibility than the predefined tools here. That said, the MCP can still be useful in Claude Code as a convenience layer if you want consistent, structured QA outputs without writing ad-hoc scripts each session.
|
||
|
|
|
||
|
|
## What is this for?
|
||
|
|
|
||
|
|
This MCP server provides a **plain-language API** for interacting with DICOM data. It doesn't eliminate the need for Python/pydicom knowledge, but it significantly reduces the cognitive load for many common tasks.
|
||
|
|
|
||
|
|
**What it does well:**
|
||
|
|
- Makes common QA tasks instant (Dixon detection, header comparison, protocol validation)
|
||
|
|
- Removes boilerplate — no more writing the same pydicom scripts repeatedly
|
||
|
|
- Natural language interface — "find Dixon sequences" vs `pydicom.dcmread()` loops
|
||
|
|
- Pixel-level analysis — render images, measure signal statistics, compute SNR
|
||
|
|
- Consistent output formats across all operations
|
||
|
|
- Configurable PII filtering to redact patient tags when required
|
||
|
|
|
||
|
|
**What it doesn't (and shouldn't) try to do:**
|
||
|
|
- Replace pydicom for custom/novel analyses
|
||
|
|
- Handle every edge case in DICOM
|
||
|
|
- Be a full DICOM viewer/editor
|
||
|
|
|
||
|
|
It's the perfect "80/20" tool — handles 80% of routine QA tasks with 20% of the effort. For the remaining 20% of complex cases, users still have full Python/pydicom access.
|
||
|
|
|
||
|
|
## Tools
|
||
|
|
|
||
|
|
The DICOM MCP server provides 17 tools across six categories:
|
||
|
|
|
||
|
|
### Directory & File Discovery
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
|------|-------------|
|
||
|
|
| `dicom_list_files` | List DICOM files with metadata filtering and optional `count_only` mode |
|
||
|
|
| `dicom_summarize_directory` | High-level overview with unique tag values and file counts |
|
||
|
|
| `dicom_find_dixon_series` | Locate and classify Dixon (chemical shift) sequences |
|
||
|
|
| `dicom_search` | Find files matching filter criteria (text, numeric, presence operators) |
|
||
|
|
|
||
|
|
### Metadata & Validation
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
|------|-------------|
|
||
|
|
| `dicom_get_metadata` | Extract header information organised by tag groups |
|
||
|
|
| `dicom_compare_headers` | Side-by-side comparison of up to 10 files |
|
||
|
|
| `dicom_validate_sequence` | Check acquisition parameters against expected values |
|
||
|
|
| `dicom_analyze_series` | Comprehensive series consistency and completeness check |
|
||
|
|
| `dicom_query` | Query arbitrary tags across all files with optional grouping |
|
||
|
|
|
||
|
|
### Philips Private Tags
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
|------|-------------|
|
||
|
|
| `dicom_query_philips_private` | Query Philips private DICOM tags by DD number and element offset |
|
||
|
|
|
||
|
|
### Pixel Analysis
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
|------|-------------|
|
||
|
|
| `dicom_read_pixels` | Pixel statistics (min, max, mean, std, percentiles, histogram) with optional ROI |
|
||
|
|
| `dicom_compute_snr` | Signal-to-noise ratio from signal and noise ROIs |
|
||
|
|
| `dicom_render_image` | Render DICOM to PNG with configurable windowing and ROI overlays |
|
||
|
|
|
||
|
|
### Structure & Comparison
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
|------|-------------|
|
||
|
|
| `dicom_dump_tree` | Full hierarchical dump of DICOM structure including nested sequences |
|
||
|
|
| `dicom_compare_uids` | Compare UID sets between two directories to find shared, missing, or extra UIDs |
|
||
|
|
|
||
|
|
### Segmentation & T1 Mapping
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
|------|-------------|
|
||
|
|
| `dicom_verify_segmentations` | Validate that segmentation files correctly reference their source images |
|
||
|
|
| `dicom_analyze_ti` | Extract and validate inversion times from MOLLI/NOLLI T1 mapping sequences across vendors |
|
||
|
|
|
||
|
|
For detailed usage examples, parameter reference, and QA workflows, see **[docs/USAGE.md](docs/USAGE.md)**. For a plain-English summary of what each tool does, see **[docs/CAPABILITIES.md](docs/CAPABILITIES.md)**. For behavioural constraints and regulatory context, see **[docs/GUIDELINES.md](docs/GUIDELINES.md)**.
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
See **[INSTALL.md](INSTALL.md)** for complete installation instructions covering:
|
||
|
|
|
||
|
|
- **Standalone package** — No Python required, ideal for non-developers
|
||
|
|
- **Claude Desktop** — Poetry-based developer setup with GUI configuration
|
||
|
|
- **Claude Code** — Adding the MCP server to your Claude Code environment
|
||
|
|
- **PII filtering** — How to enable patient data redaction for team deployments
|
||
|
|
|
||
|
|
### Quick Start (Developer)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install dependencies
|
||
|
|
poetry install --with dev
|
||
|
|
|
||
|
|
# Run tests to verify
|
||
|
|
poetry run pytest -v --tb=short
|
||
|
|
|
||
|
|
# Start the server
|
||
|
|
poetry run python -m dicom_mcp
|
||
|
|
```
|
||
|
|
|
||
|
|
## PII Filtering
|
||
|
|
|
||
|
|
Patient-identifying tags can be redacted from all tool output by setting an environment variable:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
export DICOM_MCP_PII_FILTER=true
|
||
|
|
```
|
||
|
|
|
||
|
|
When enabled, the following tags are replaced with `[REDACTED]` in tool responses:
|
||
|
|
- PatientName
|
||
|
|
- PatientID
|
||
|
|
- PatientBirthDate
|
||
|
|
- PatientSex
|
||
|
|
|
||
|
|
This affects `dicom_get_metadata`, `dicom_compare_headers`, `dicom_summarize_directory`, and `dicom_query`. All other tools do not expose patient data and are unaffected.
|
||
|
|
|
||
|
|
To disable, unset the variable or set it to any value other than `true`, `1`, or `yes`.
|
||
|
|
|
||
|
|
## Project Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
dicom_mcp/ # Python package
|
||
|
|
__init__.py # Re-exports all public symbols
|
||
|
|
__main__.py # Entry point: python -m dicom_mcp
|
||
|
|
server.py # FastMCP instance and run()
|
||
|
|
config.py # Environment-driven configuration
|
||
|
|
constants.py # Enums and tag group definitions
|
||
|
|
pii.py # PII redaction functions
|
||
|
|
helpers/ # Internal helper functions
|
||
|
|
tags.py # Tag reading, formatting, resolution
|
||
|
|
sequence.py # Sequence type identification
|
||
|
|
files.py # DICOM file discovery
|
||
|
|
philips.py # Philips private tag resolution
|
||
|
|
pixels.py # Pixel array and statistics
|
||
|
|
filters.py # Search filter parsing
|
||
|
|
tree.py # DICOM tree building and formatting
|
||
|
|
tools/ # MCP tool definitions
|
||
|
|
discovery.py # dicom_list_files, dicom_find_dixon_series
|
||
|
|
metadata.py # dicom_get_metadata, dicom_compare_headers
|
||
|
|
query.py # dicom_query, dicom_summarize_directory
|
||
|
|
validation.py # dicom_validate_sequence, dicom_analyze_series
|
||
|
|
search.py # dicom_search
|
||
|
|
philips.py # dicom_query_philips_private
|
||
|
|
pixels.py # dicom_read_pixels, dicom_compute_snr, dicom_render_image
|
||
|
|
tree.py # dicom_dump_tree
|
||
|
|
uid_comparison.py # dicom_compare_uids
|
||
|
|
segmentation.py # dicom_verify_segmentations
|
||
|
|
ti_analysis.py # dicom_analyze_ti
|
||
|
|
docs/ # Documentation
|
||
|
|
USAGE.md # Detailed tool reference and QA workflows
|
||
|
|
TODO.md # Planned improvements and known issues
|
||
|
|
CAPABILITIES.md # Plain-English summary of all capabilities
|
||
|
|
GUIDELINES.md # Behavioural constraints and regulatory context
|
||
|
|
dicom_mcp.py # Backward-compatible entry point shim
|
||
|
|
test_dicom_mcp.py # Test suite (138 tests)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Development
|
||
|
|
|
||
|
|
### Running Tests
|
||
|
|
|
||
|
|
```bash
|
||
|
|
poetry run pytest -v --tb=short
|
||
|
|
```
|
||
|
|
|
||
|
|
The test suite includes 138 tests covering tool registration, helper functions, PII filtering, and full pipeline integration tests using synthetic DICOM files.
|
||
|
|
|
||
|
|
### Linting
|
||
|
|
|
||
|
|
```bash
|
||
|
|
ruff check dicom_mcp/ dicom_mcp.py test_dicom_mcp.py
|
||
|
|
black --check dicom_mcp/ dicom_mcp.py test_dicom_mcp.py
|
||
|
|
```
|
||
|
|
|
||
|
|
### Building Standalone Packages
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# macOS (detects architecture automatically)
|
||
|
|
./build_standalone.sh
|
||
|
|
|
||
|
|
# Linux
|
||
|
|
./build_standalone_linux.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
This bundles Python 3.12, fastmcp, pydicom, numpy, and Pillow into a self-contained package (~50MB) that requires no system Python.
|
||
|
|
|
||
|
|
### MCP Inspector
|
||
|
|
|
||
|
|
To test the server interactively outside of Claude:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npx @modelcontextprotocol/inspector poetry run python -m dicom_mcp
|
||
|
|
```
|
||
|
|
|
||
|
|
### Extending the Server
|
||
|
|
|
||
|
|
New tools can be added by creating a module in `dicom_mcp/tools/` and importing it from `dicom_mcp/tools/__init__.py`. Each tool module imports the shared `mcp` instance from `dicom_mcp.server` and uses the `@mcp.tool()` decorator.
|
||
|
|
|
||
|
|
Other extension points:
|
||
|
|
- **Custom tag groups**: Edit `COMMON_TAGS` in `dicom_mcp/constants.py`
|
||
|
|
- **Sequence type detection**: Modify `_identify_sequence_type()` in `dicom_mcp/helpers/sequence.py`
|
||
|
|
- **PII tag set**: Edit `PII_TAGS` in `dicom_mcp/pii.py` (derived from `COMMON_TAGS["patient_info"]`)
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### "Module not found" errors
|
||
|
|
|
||
|
|
Install all dependencies:
|
||
|
|
```bash
|
||
|
|
poetry install --with dev
|
||
|
|
```
|
||
|
|
|
||
|
|
If the MCP server starts but fails with `ModuleNotFoundError` for numpy or Pillow, the Claude Desktop config may be pointing to a different Python than the Poetry virtualenv. Either install the missing packages into that Python or update the config to use the virtualenv Python directly (see [INSTALL.md](INSTALL.md)).
|
||
|
|
|
||
|
|
### "File not found" errors
|
||
|
|
|
||
|
|
Use absolute paths, not relative paths. Check that the path exists and is accessible.
|
||
|
|
|
||
|
|
### "Not a valid DICOM file" errors
|
||
|
|
|
||
|
|
Verify the file is actually a DICOM file. Try opening with another DICOM viewer or `pydicom.dcmread()` directly.
|
||
|
|
|
||
|
|
### Server not appearing in Claude Desktop
|
||
|
|
|
||
|
|
- Verify the configuration file path is correct
|
||
|
|
- Check that the configured Python can find all dependencies
|
||
|
|
- Restart Claude Desktop after configuration changes
|
||
|
|
- Check Claude Desktop logs for error messages
|
||
|
|
|
||
|
|
### "No pixel data" errors
|
||
|
|
|
||
|
|
Some DICOM files (presentation states, structured reports, derived objects) don't contain pixel data. Use `dicom_get_metadata` to check the file's SOP Class or ImageType before attempting pixel operations.
|
||
|
|
|
||
|
|
## Example Screenshot
|
||
|
|
|
||
|
|
<img src="img/claude_desktop_example.png" width="623" alt="Claude Desktop session example">
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
This MCP server is provided as-is for QA and testing purposes.
|
||
|
|
|
||
|
|
## Support
|
||
|
|
|
||
|
|
For issues or questions:
|
||
|
|
|
||
|
|
1. Check the Troubleshooting section above
|
||
|
|
2. See **[docs/USAGE.md](docs/USAGE.md)** for detailed tool reference and workflow examples
|
||
|
|
3. See **[INSTALL.md](INSTALL.md)** for installation help
|
||
|
|
4. Verify your DICOM files with pydicom directly
|
||
|
|
5. Review MCP server logs in Claude Desktop
|