DICOM Modality Worklist (MWL) server for managing scheduled breast screening appointments and providing worklist information to imaging modalities.
The MWL server is a lightweight, production-ready DICOM worklist solution that:
- Provides scheduled procedure information via DICOM C-FIND protocol
- Stores worklist items in SQLite database
- Supports filtering by modality, date, and patient ID
- Resets the worklist daily via a scheduled
reset_main.pyscript invoked by Windows Task Scheduler - Runs as a Python process on a Windows VM managed by Azure Arc
┌─────────────────────────────────────────────────────────────┐
│ MWL Server (Port 4243) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ C-FIND │─────▶│ Storage │─────▶│ SQLite │◀──┼──────────────────┐
│ │ Handler │ │ Layer │ │ Database │ │ │
│ └──────────────┘ └──────────────┘ └──────────┘ │ │
│ │ ▲ │ │
│ │ │ │ backup + clear
│ └──────────────────────┘ │ (Task Scheduler)
│ Query & Response │ │
└─────────────────────────────────────────────────────────────┘ │
▲ ▲ ┌───────┴────────┐
│ │ │ reset_main.py │
┌──────┴──────┐ ┌───────┴────────┐ └────────────────┘
│ Modality │ │ Relay Listener │
│ (SCU) │ │ (Populates DB) │
└─────────────┘ └────────────────┘
- Worklist Creation: Relay listener receives appointments from Manage Breast Screening and creates worklist items
- Worklist Query: Modality sends C-FIND request to MWL server
- Filtering: MWL server filters by modality, date, patient ID, status
- Response: Server returns matching worklist items to modality
- Status Updates: C-STORE receipt transitions items from
SCHEDULEDtoIN PROGRESS; MPPS transitions items toCOMPLETEDorDISCONTINUED - Daily Reset: Windows Task Scheduler invokes
reset_main.py, which backs up and clears the database
The gateway runs as a Python process on a Windows VM:
# Start the MWL server
uv run python -m mwl_main
# Run a one-shot backup and reset (normally invoked by Task Scheduler)
uv run python -m reset_mainFor local development, Docker Compose is available:
docker compose up -d mwl
docker compose logs -f mwl| Variable | Default | Description |
|---|---|---|
MWL_AET |
MWL_SCP |
Application Entity Title |
MWL_PORT |
4243 |
DICOM service port |
MWL_DB_PATH |
/var/lib/pacs/worklist.db |
SQLite database path |
LOG_LEVEL |
INFO |
Logging level |
| Variable | Default | Description |
|---|---|---|
MWL_DB_PATH |
/var/lib/pacs/worklist.db |
SQLite database path |
BACKUP_PATH |
/var/lib/pacs/backups |
Directory for database backups |
LOG_LEVEL |
INFO |
Logging level |
The reset schedule is configured in Windows Task Scheduler (registered via scripts/bat/schtasks.bat), not in the application.
Register the scheduled task (run once, on the gateway VM):
scripts\bat\schtasks.batThis creates a Task Scheduler task that runs reset_main.py daily at midnight. The schedule can be adjusted in Task Scheduler or via Azure Arc without any code change.
from pynetdicom import AE, QueryRetrievePresentationContexts
from pydicom import Dataset
ae = AE()
ae.requested_contexts = QueryRetrievePresentationContexts
# Create query dataset
ds = Dataset()
ds.PatientID = '9876543210'
ds.PatientName = ''
ds.AccessionNumber = ''
# Scheduled procedure step query
sps = Dataset()
sps.Modality = 'MG'
sps.ScheduledProcedureStepStartDate = '20260108'
ds.ScheduledProcedureStepSequence = [sps]
# Send C-FIND with Worklist Information Model ('W')
assoc = ae.associate('localhost', 4243, ae_title='MWL_SCP')
responses = assoc.send_c_find(ds, query_model='W')
for (status, identifier) in responses:
if status.Status in (0xFF00, 0xFF01):
print(f"Found: {identifier.PatientName}")
assoc.release()Check worklist items:
sqlite3 /var/lib/pacs/worklist.db \
"SELECT accession_number, patient_name, scheduled_date, status FROM worklist_items;"Add test worklist item:
sqlite3 /var/lib/pacs/worklist.db <<EOF
INSERT INTO worklist_items (
accession_number, patient_id, patient_name, patient_birth_date,
scheduled_date, scheduled_time, modality, study_description
) VALUES (
'ACC001', '9876543210', 'TEST^PATIENT', '19800101',
'20260108', '100000', 'MG', 'Bilateral Screening Mammogram'
);
EOFRunning integration tests:
uv run pytest tests/integration/test_c_find_returns_worklist_items.py -v
uv run pytest tests/integration/test_request_cfind_on_worklist.py -vSCHEDULED ──(first C-STORE)──▶ IN PROGRESS ──(MPPS N-SET)──▶ COMPLETED
│
└────────(MPPS N-SET)──▶ DISCONTINUED
See ADR-003: Separate containers for PACS and MWL and ADR-004: Daily backup and reset of the MWL database for architectural decisions.