# 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
