Imaging data commons

Query and download public cancer imaging data from NCI Imaging Data Commons.

How to use it

  1. Hit Copy SKILL.md — or use the Claude Code line below to get every file.
  2. Claude: ⋯ → Download .md, then Customize → Skills → Add → Upload skill.
    ChatGPT: make a Project and paste it into Instructions.
    Neither? Paste it at the top of a new chat — it works for that chat.
  3. Describe your job in plain words. The AI follows the skill from there.
Claude Code — installs the whole folder, not just SKILL.md
npx degit K-Dense-AI/scientific-agent-skills/skills/imaging-data-commons#main ~/.claude/skills/imaging-data-commons

For one project only, change the path to .claude/skills/imaging-data-commons. This skill also uses check_version.py, index_tables_guide.md, use_cases.md, sql_patterns.md, clinical_data_guide.md, licensing_and_citation.md — copying SKILL.md alone won't be enough. See the folder on GitHub.

Not working?
  • Check which app you pasted it into — the steps above name the right one.
  • Some skills need the paid tier of Claude or ChatGPT.
Step-by-step guide with screenshots · Ask in the forum

Paste into Claude, ChatGPT or Cursor.

Show the full text497 lines
imaging-data-commons/SKILL.md497 lines29.7 KBpushed 42d agoRawView on GitHub

Imaging Data Commons

Overview

Query and download public cancer imaging data from the National Cancer Institute Imaging Data Commons (IDC). No authentication required for data access.

Expected network access: IDC metadata is reachable three ways — a local DuckDB index shipped with the idc-index Python package (no network), or the hosted IDC service over MCP or REST (api.imaging.datacommons.cancer.gov, no authentication). File downloads use public GCS (storage.googleapis.com) and AWS S3 (s3.amazonaws.com) — no authentication required. DICOMweb access uses either the public IDC proxy (proxy.imaging.datacommons.cancer.gov, no auth) or the Google Cloud Healthcare API (healthcare.googleapis.com, requires GCP authentication). Optional BigQuery queries (bigquery.googleapis.com) also require GCP authentication. No credentials or environment variables are accessed by this skill.

Current IDC Data Version: v24 (always verify — see Best Practices)

Choose the access path first. There is no single default: the cheapest correct path depends on the session and the task.

  1. Session already has the IDC MCP server? Route discovery and metadata there — see IDC MCP Server.
  2. Otherwise, is idc-index installed? Run python scripts/check_version.py. If it passes, use idc-index for everything.
  3. Not installed, and the task is read-only metadata — counts, attribute values, collection lookups, SQL under 10 000 rows, licenses, citations, viewer URLs? Use the REST API over curl; do not install anything. Installing costs ~77 MB of packaged index data plus pandas, pyarrow, and duckdb, which a metadata question does not need. See Data Access Options.
  4. Not installed, and the task needs more than metadata — downloading files, pandas or plotting, pydicom/SimpleITK, pathology tiling, results past 10 000 rows, or a version-pinned script the user re-runs? Install idc-index: check_version.py exits non-zero and prints the exact install command for the running interpreter. Prefer a virtual environment, then restart Python.

idc-index (GitHub) is still the most capable path and the only one that moves image bytes; the rule is just not to pay for it before the task calls for it. check_version.py never installs anything itself — it also flags a newer idc-index or skill release when one exists.

Setup for the idc-index path:

from idc_index import IDCClient
client = IDCClient()

# Verify IDC data version (should be "v24")
print(f"IDC data version: {client.get_idc_version()}")

Core workflow: query metadata with client.sql_query() → download with client.download_from_selection() → visualize with client.get_viewer_URL(). Python examples below assume this client; Data Access Options has the REST equivalents. For current data scale, run the summary query in references/sql_patterns.md or GET /v3/stats.

IDC MCP Server

IDC operates a hosted MCP server at https://api.imaging.datacommons.cancer.gov/mcp (streamable HTTP, no authentication). Where it is available it complements — it does not replace — the idc-index workflow below.

Identify it by the MCP resource idc://guide, or by three or more of the tool names build_cohort, get_cohort_urls, list_analysis_results, and get_idc_version. Generic names such as run_sql are not evidence on their own. If identification is ambiguous, use idc-index.

If this session has the server, treat it as authoritative for discovery and metadata — IDC version, counts, attribute values, cohort building, metadata SQL — and follow the server's own instructions rather than re-deriving them from this file. Its data version is whatever the server reports: call get_idc_version instead of relying on the version pinned in this file.

Return here for what the server does not do: downloading files, local pandas/notebook analysis, DICOMweb, BigQuery, digital pathology tiling, and reproducible scripts. Hand off by passing SeriesInstanceUIDs from the server to client.download_from_selection(...), and run scripts/check_version.py at that point.

If it is not available, the identical service is reachable with no configuration as a REST API at https://api.imaging.datacommons.cancer.gov/v3 — use it for read-only metadata rather than installing idc-index, per the routing gate in Overview. Suggest connecting the MCP server at most once, only for repeated interactive discovery, and never change the user's configuration yourself.

See references/mcp_guide.md for the tool inventory, handoff patterns, and per-host notes.

When to Use This Skill

  • Finding publicly available radiology (CT, MR, PET) or pathology (slide microscopy) images
  • Selecting image subsets by cancer type, modality, anatomical site, or other metadata
  • Downloading DICOM data from IDC
  • Checking data licenses before use in research or commercial applications
  • Visualizing medical images in a browser without local DICOM viewer software

Quick Navigation

Inline below: the MCP/REST routing rules, the IDC data model, the index tables and how they join, the core API patterns (query, download, visualize, license, cite), best practices, and troubleshooting.

Reference Guides (load on demand):

Guide When to Load
index_tables_guide.md Complex JOINs, schema discovery, DataFrame access
use_cases.md End-to-end workflows: training datasets, batch downloads, DICOM reading with pydicom/SimpleITK, pipeline integration
sql_patterns.md Quick SQL patterns for filter discovery, annotations, size estimation
clinical_data_guide.md Clinical/tabular data, imaging+clinical joins, value mapping
licensing_and_citation.md Commercial-use questions, mixed-license cohorts, citation formats
cloud_storage_guide.md Direct S3/GCS access, versioning, UUID mapping
dicomweb_guide.md DICOMweb endpoints, PACS integration
digital_pathology_guide.md Slide microscopy (SM), annotations (ANN), pathology workflows
bigquery_guide.md Full DICOM metadata, private elements (requires GCP)
cli_guide.md Command-line tools (idc download, manifest files)
parquet_access_guide.md Direct Parquet queries via GCS (no idc-index install needed)
mcp_guide.md Hosted IDC MCP server: tool inventory, identification, handoff to idc-index
rest_api_guide.md Hosted IDC REST API: endpoints, filter syntax, SQL over HTTP, manifests

IDC Data Model

IDC adds two grouping levels above the standard DICOM hierarchy (Patient → Study → Series → Instance):

  • collection_id: Groups patients by disease, modality, or research focus (e.g., tcga_luad, nlst). A patient belongs to exactly one collection.
  • analysis_result_id: Identifies derived objects (segmentations, annotations, radiomics features) across one or more original collections. Use it to find AI-generated or expert annotations, while collection_id finds original imaging data (which may itself include deposited annotations).

Key identifiers for queries:

Identifier Scope Use for
collection_id Dataset grouping Filtering by project/study
PatientID Patient Grouping images by patient
StudyInstanceUID DICOM study Grouping of related series, visualization
SeriesInstanceUID DICOM series Grouping of related series, visualization

Index Tables

The idc-index package provides multiple metadata index tables, accessible via SQL or as pandas DataFrames. The REST API exposes the same tables through GET /tables and POST /sql.

Important: client.indices_overview is the authoritative source for current table descriptions, available columns, and their types — query it when writing SQL or exploring data structure. It also answers "which table contains column X"; see references/index_tables_guide.md for that search pattern and full schema discovery.

Available Tables

Always call client.fetch_index("table_name") before querying any index table — it is safe and idempotent for all tables, including those loaded automatically at startup.

Family Tables Granularity
Core index (primary metadata for all current data), collections_index, analysis_results_index series / collection / analysis result
Modality acquisition parameters ct_index, mr_index, pt_index, contrast_index 1 row = 1 series of that modality
Derived objects seg_index, rtstruct_index, ann_index, ann_group_index 1 row = 1 series (or annotation group)
Microscopy sm_index, sm_instance_index 1 row = 1 SM series / instance
Geometry, clinical, history volume_geometry_index, clinical_index, version_metadata_index, prior_versions_index see guide

references/index_tables_guide.md has the full inventory with each table's columns and contents — load it when you need to know what a specialized table actually holds.

prior_versions_index is for reproducibility only. It contains series permanently removed from IDC, with zero overlap with index. Use it only to reproduce work against a prior IDC version. Do NOT use it for version history or "what's new" questions — those use series_init_idc_version / series_revised_idc_version in the main index table, which are not equivalent to this table's min_idc_version / max_idc_version.

Joining Tables

SeriesInstanceUID is the universal join key for all series-level specialized tables: sm_index, sm_instance_index, seg_index, ann_index, ann_group_index, contrast_index, volume_geometry_index, rtstruct_index, ct_index, mr_index, pt_index. Always join these to index on SeriesInstanceUID. The exceptions below use different column names.

Join Column Tables Use Case
collection_id index, prior_versions_index, collections_index, clinical_index Link series to collection metadata or clinical data
analysis_result_id index, analysis_results_index Link series to analysis result metadata (annotations, segmentations)
source_DOI index, analysis_results_index Link by publication DOI
segmented_SeriesInstanceUID seg_index → index Link segmentation to its source image series (seg_index.segmented_SeriesInstanceUID = index.SeriesInstanceUID)
referenced_SeriesInstanceUID ann_index → index, rtstruct_index → index Link annotation or RTSTRUCT to its source image series

Note: subjects, updated, and description appear in multiple tables but have different meanings (counts vs identifiers, different update contexts). Joining prior_versions_index to index on SeriesInstanceUID always returns zero rows — see the warning above.

For detailed join examples, schema discovery patterns, key columns reference, and DataFrame access, see references/index_tables_guide.md.

Clinical Data Access

Clinical (non-imaging) attributes — staging, demographics, therapy — live in per-collection tables. client.fetch_index("clinical_index") loads the dictionary mapping columns to collections; client.get_clinical_table(name) returns one table as a DataFrame.

See references/clinical_data_guide.md for the discovery workflow, coded-value mapping, and joining clinical data with imaging.

Data Access Options

Method Auth Best For Reference
idc-index No Downloads, pandas analysis, unbounded queries — the most capable path This document
IDC MCP server No Discovery, cohort building, metadata when the session already has it mcp_guide.md
IDC REST API No Metadata with no install, from any language or shell — the default when idc-index is absent rest_api_guide.md
Direct Parquet (GCS) No Version-pinned queries, or results past the REST row cap parquet_access_guide.md
Cloud storage (S3/GCS) No Direct file access, bulk transfer, custom pipelines cloud_storage_guide.md
DICOMweb via IDC proxy No Tool and PACS integration; daily quota, so testing and moderate use dicomweb_guide.md
DICOMweb via Google Healthcare Yes (GCP) The same DICOMweb API at production volume, without the proxy quota dicomweb_guide.md
SlicerIDCBrowser No 3D visualization and analysis in 3D Slicer https://github.com/ImagingDataCommons/SlicerIDCBrowser
BigQuery Yes (GCP) Full DICOM metadata, private elements, SR measurements — last resort bigquery_guide.md

The IDC Portal (https://portal.imaging.datacommons.cancer.gov/) is interactive only — browser-based exploration, manual cohort selection, and download. Unlike every option above it has no programmatic interface, so point a user there to browse or click through data themselves; never use it as a step in a script or workflow.

REST API — the no-install metadata path

https://api.imaging.datacommons.cancer.gov/v3, no authentication: discovery, cohort counts and manifests, read-only SQL, clinical tables, viewer URLs, licenses, citations. It is the same service as the MCP server over plain HTTP, so it needs no configuration. It never moves image bytes — switch to idc-index to download, to get a DataFrame, or for results past 10 000 rows.

B=https://api.imaging.datacommons.cancer.gov/v3
curl -s $B/version   # idc_version, idc_index_data_version, api_version
curl -s $B/stats     # collections, patients, studies, series, instances, size_TB
curl -s "$B/attributes/Modality/values?limit=5"   # real filter values, with counts
curl -s $B/sql -H 'content-type: application/json' \
  -d '{"sql":"SELECT collection_id, COUNT(*) n FROM index GROUP BY 1 ORDER BY n DESC LIMIT 3"}'
curl -s $B/cohort/counts -H 'content-type: application/json' \
  -d '{"filters":{"terms":{"collection_id":["rider_pilot"]}}}'

The filter object always goes under filters — on cohort/counts, cohort/manifest, cohort/manifest.txt, licenses, and citations alike. A bare filter or an unrecognized key is a 422 naming the fix; an unfiltered series-enumerating request is a 400, not the whole archive. Every filtered response echoes filters_applied and warnings — read them, because they name any predicate the server dropped. A zero count with empty warnings therefore means the filter matched nothing, not that a value was miscased; miscasing produces a warning that says so.

POST /sql takes one read-only SELECT/WITH over the tables idc-index exposes plus clinical.; max_rows defaults to 5 000, caps at 10 000, and truncated flags clipping. GET /attributes lists the 19 filterable attributes — clinical values, segmented anatomy, and acquisition parameters are not among them and need SQL. There is no rate limit or quota. Use v3 only: V1 and V2 are superseded and scheduled for shutdown, so port any /v1/- or Modality_btw-style example a user brings rather than extending it.

Both sides build on idc-index-data, so compare the API's idc_index_data_version against local idc_index_data.__version__ before mixing them: the major is the IDC data release (24.x.y serves v24), so differing minor/patch means the series are identical. If the API is a whole release ahead, idc-index cannot download the extra series — it silently skips what its own index does not list — so either upgrade it (run scripts/check_version.py for the right command) or transfer directly from the bucket with s5cmd --no-sign-request.

See references/rest_api_guide.md for the endpoint reference, filter grounding, limits, and the manifest-based download flow.

Cloud storage organization

All DICOM files live in public buckets mirrored between AWS S3 and GCS, organized by CRDC UUIDs (not DICOM UIDs) to support versioning, as <crdc_series_uuid>/<crdc_instance_uuid>.dcm. Access is free (no egress fees) via AWS CLI, gsutil, or s5cmd with anonymous access; use the series_aws_url column for S3 URLs. Note that idc-open-data-cr / idc-open-cr (~4% of data) is commercial-use restricted (CC BY-NC). See references/cloud_storage_guide.md for the full bucket list and UUID mapping.

DICOMweb access

IDC data is available via DICOMweb (Google Cloud Healthcare API) for PACS integration and DICOMweb-compatible tools: a public proxy (no auth, daily quota) for testing and moderate queries, or Google Healthcare (GCP auth) for production volumes. See references/dicomweb_guide.md.

Direct Parquet access

The idc-index metadata tables are also published as Parquet on a public GCS bucket (idc-index-data-artifacts), queryable with DuckDB or pandas. This needs DuckDB installed and cannot reach the per-collection clinical tables, so prefer REST /sql for ad-hoc metadata; choose Parquet to pin a data version or for results past the REST row cap. See references/parquet_access_guide.md.

Core Capabilities

The patterns below are the ones that go wrong when recalled from memory rather than checked. Worked examples for each area live in the reference guides named inline.

1. Discovery — enumerate values before filtering on them

Filtering on a guessed Modality or BodyPartExamined string is the most common cause of an empty result set. Enumerate first:

modalities = client.sql_query("""
    SELECT DISTINCT Modality, COUNT(*) as series_count
    FROM index
    GROUP BY Modality
    ORDER BY series_count DESC
""")
print(modalities)

The same pattern works for any filter column, optionally narrowed by another — BodyPartExamined within a Modality, Manufacturer, collection_id. On the REST path this grounding is a single call — GET /attributes/{attr}/values returns values with counts — and the cohort endpoints report a miscased value in warnings rather than as an empty result.

Two indices carry curated collection-level metadata the primary index does not, both requiring client.fetch_index(...) first: collections_index (cancer types, tumor locations, species, subject counts) and analysis_results_index (derived datasets — AI segmentations, expert annotations, radiomics — with their source collections and modalities).

Cancer type lives in collections_index.cancer_types, not in index — filtering by cancer type requires a join:

client.fetch_index("collections_index")
results = client.sql_query("""
    SELECT i.collection_id, i.PatientID, i.SeriesInstanceUID, i.Modality
    FROM index i
    JOIN collections_index c ON i.collection_id = c.collection_id
    WHERE c.cancer_types LIKE '%Breast%'
      AND i.Modality = 'MR'
    LIMIT 20
""")

client.sql_query() returns a pandas DataFrame. Confirm column names with client.get_index_schema('index') or client.indices_overview before writing a query rather than assuming them.

See references/sql_patterns.md for filter-value discovery, annotation and segmentation queries, size estimation, clinical linking, and version tracking ("what's new in vX" — use series_init_idc_version / series_revised_idc_version in index, never prior_versions_index).

2. Downloading DICOM files

The two download methods take their first two arguments in opposite order. This is the most common source of broken IDC code — check it rather than recalling it:

Method First arg Second arg Use when
download_from_selection downloadDir (required) filter kwargs (optional) Filtering by collection, patient, study, or series
download_dicom_series seriesInstanceUID (required) downloadDir (required) Downloading specific series by UID only

download_from_selection takes filter keyword arguments, NOT a DataFrame. The name "from_selection" refers to filtering the IDC index by criteria — not to accepting a pandas DataFrame. To download query results, extract the UIDs into a list first:

# Step 1: Query for series UIDs
series_df = client.sql_query("""
    SELECT SeriesInstanceUID
    FROM index
    WHERE Modality = 'CT'
      AND BodyPartExamined = 'CHEST'
      AND collection_id = 'nlst'
    LIMIT 5
""")

# Step 2: Extract UIDs as a list from the DataFrame
uids = list(series_df['SeriesInstanceUID'].values)

# Step 3: Pass the list to download_from_selection (NOT the DataFrame itself)
client.download_from_selection(
    downloadDir="./data/lung_ct",
    seriesInstanceUID=uids       # list of strings, not a DataFrame
)

# Alternative: download_dicom_series has seriesInstanceUID as FIRST arg (different order!)
client.download_dicom_series(
    seriesInstanceUID=uids,      # FIRST arg here
    downloadDir="./data/lung_ct"
)

# Whole collection: downloadDir is still the FIRST positional argument
client.download_from_selection(downloadDir="./data/rider", collection_id="rider_pilot")

Both methods default to AWS; pass source_bucket_location="gcs" to pull from Google Storage.

Downloaded files are named <crdc_instance_uuid>.dcm, not by SOPInstanceUID. The DICOM UIDs are preserved inside the file metadata, not in the filename. Use the crdc_instance_uuid column to map files back to the series they came from.

idc download <collection|series-uid|manifest> --download-dir ./data does the same from a shell. See references/cli_guide.md for the dirTemplate hierarchy options (Python default: %collection_id/%PatientID/%StudyInstanceUID/%Modality_%SeriesInstanceUID; dirTemplate="" flattens), manifest downloads with resume, and dry-run size estimation.

3. Visualizing IDC images

viewer_url = client.get_viewer_URL(seriesInstanceUID=uid)        # one series
viewer_url = client.get_viewer_URL(studyInstanceUID=study_uid)   # all series in a study

Returns a browser URL — nothing is downloaded. The method selects OHIF v3 for radiology or SLIM for slide microscopy automatically. Viewing by study is useful when a single DICOM Study holds several Series (T1, T2, and DWI from one MRI session).

4. Licenses and citations — obligations, not optional steps

IDC data carries license terms and attribution requirements that follow it into any downstream publication or product, and neither is inferable from the pixel data. Check the license before use, and generate citations for whatever you download.

# License breakdown for a selection
licenses = client.sql_query("""
    SELECT DISTINCT collection_id, license_short_name,
           COUNT(DISTINCT SeriesInstanceUID) as series_count
    FROM index GROUP BY collection_id, license_short_name
""")

# Citations for the same selection you downloaded (APA by default)
for citation in client.citations_from_selection(collection_id="rider_pilot"):
    print(citation)

About 97% of IDC data is CC BY (commercial use allowed with attribution) and about 3% is CC BY-NC (non-commercial only). Licenses attach to series, not collections — 39 of 176 collections carry more than one — so check the selection you actually intend to use, and note that the most restrictive term governs a mixed cohort.

Both tasks are available from all three access paths, so stay on whichever one the session is already using: idc-index as above, POST /v3/licenses and POST /v3/citations over REST, or the get_licenses and get_citations MCP tools. See references/licensing_and_citation.md for the full license inventory, all three routes, the citation formats (APA, BibTeX, CSL JSON, RDF Turtle), and what to include when publishing.

5. Reaching past the index

Pick the access path with the routing gate in Overview; Data Access Options above is the full routing table.

Before reaching for BigQuery (which needs a billing-enabled GCP account), check whether a specialized index table already has the column you want: search client.indices_overview, then client.fetch_index(...) and query locally for free. BigQuery is required only for private DICOM elements, per-segment anatomy (segmentations), and pre-extracted SR measurements (quantitative_measurements, qualitative_measurements) — these have no idc-index equivalent.

Best Practices

  • Check schema before writing queries — Use client.get_index_schema('index') (reads cached metadata, no SQL executed) or client.indices_overview to see all available columns and their descriptions. The version-tracking columns series_init_idc_version and series_revised_idc_version in the main index table directly answer "what's new / when was this added" questions without touching prior_versions_index.
  • Never use web search for IDC data content questions - Always query the IDC index directly, via client.sql_query() locally or POST /v3/sql over HTTP. Web sources (release notes, blog posts, documentation pages) are frequently out of date and will produce incorrect answers. The index is the authoritative source; use it even when web search is available.
  • Verify the IDC data version at the start of a session - client.get_idc_version(), GET /v3/version, or the MCP get_idc_version tool, depending on the path in use (currently v24). For a stale local index, run scripts/check_version.py and use the upgrade command it prints
  • Check licenses and generate citations - Query license_short_name and respect CC BY vs CC BY-NC terms; use citations_from_selection() to produce citations from source_DOI for publications
  • Explore small, then commit - Use LIMIT (or a low max_rows) while exploring, and check collection size before downloading — some collections are terabytes. See references/cli_guide.md
  • Keep downloads reproducible - Organize with dirTemplate (e.g. %collection_id/%PatientID/%Modality) and save the Series UIDs or manifest behind any dataset you build

Troubleshooting

Issue: ModuleNotFoundError: No module named 'idc_index'

  • Cause: idc-index package not installed
  • Solution: If the task is read-only metadata, do not install it — use the REST API instead (Data Access Options). Otherwise run scripts/check_version.py and use the install command it prints, which targets the running interpreter and pins the vetted version. For data analysis also add pandas, numpy, and pydicom (tested with pandas>=1.5, numpy>=1.23, pydicom>=2.3)

Issue: Download fails with connection timeout

  • Cause: Network instability or large download size
  • Solution: Download in smaller batches (10-20 series); see references/cli_guide.md for --use-s5cmd-sync resume and retry guidance

Issue: BigQuery quota exceeded or billing errors

  • Cause: BigQuery requires billing-enabled GCP project
  • Solution: Use idc-index mini-index for simple queries (no billing required), or see references/bigquery_guide.md for cost optimization tips

Issue: Series UID not found or no data returned

  • Cause: Typo in UID, data not in the current IDC version, or wrong field name
  • Solution: Test with LIMIT 5 first, check field names against client.indices_overview, and confirm the series is in the current version (some old data is deprecated)

Issue: Column not found in index table (e.g., SliceThickness, PixelSpacing, KVP, EchoTime, InjectedDose)

  • Cause: The index table contains series-level metadata only; modality-specific acquisition and reconstruction parameters live in dedicated tables (ct_index, mr_index, pt_index)
  • Solution: Search client.indices_overview for the column to find its table — the loop is under Finding which table contains a column in references/index_tables_guide.md — then fetch and join on SeriesInstanceUID:
    client.fetch_index("ct_index")
    result = client.sql_query("""
        SELECT i.SeriesInstanceUID, i.Modality, c.SliceThickness, c.KVP, c.PixelSpacing_row_mm
        FROM index i
        JOIN ct_index c USING (SeriesInstanceUID)
        WHERE i.collection_id = 'your_collection'
    """)
    

Issue: Downloaded DICOM files won't open

  • Cause: Corrupted download, or an object type the viewer does not handle — SEG, RTSTRUCT, SR, and slide microscopy all need specialized tools
  • Solution: Check Modality and SOPClassUID first, validate with pydicom.dcmread(file, force=True), try another viewer (3D Slicer, QuPath for pathology), then re-download

Resources

Reference guides and their decision triggers are listed in Quick Navigation above.

1---
2name: imaging-data-commons
3description: Query and download public cancer imaging data from NCI Imaging Data Commons. Invoke for any question about IDC collections, cancer imaging datasets, DICOM data access, radiology (CT, MR, PET) or pathology AI training sets, metadata queries, visualization, or license checks — even when the user doesn't explicitly mention "IDC". No authentication required.
4license: This skill is provided under the MIT License. IDC data itself has individual licensing (mostly CC-BY, some CC-NC) that must be respected when using the data.
5metadata:
6 version: "1.5"
7 source-skill-version: 1.8.1
8 skill-author: Andrey Fedorov, @fedorov
9 idc-index: "0.12.5"
10 idc-data-version: "v24"
11 repository: https://github.com/ImagingDataCommons/imaging-data-commons-skill
12---
13 
14# Imaging Data Commons
15 
16## Overview
17 
18Query and download public cancer imaging data from the National Cancer Institute Imaging Data Commons (IDC). No authentication required for data access.
19 
20**Expected network access:** IDC metadata is reachable three ways — a local DuckDB index shipped with the `idc-index` Python package (no network), or the hosted IDC service over MCP or REST (`api.imaging.datacommons.cancer.gov`, no authentication). File downloads use public GCS (`storage.googleapis.com`) and AWS S3 (`s3.amazonaws.com`) — no authentication required. DICOMweb access uses either the public IDC proxy (`proxy.imaging.datacommons.cancer.gov`, no auth) or the Google Cloud Healthcare API (`healthcare.googleapis.com`, requires GCP authentication). Optional BigQuery queries (`bigquery.googleapis.com`) also require GCP authentication. No credentials or environment variables are accessed by this skill.
21 
22**Current IDC Data Version: v24** (always verify — see *Best Practices*)
23 
24**Choose the access path first.** There is no single default: the cheapest correct path depends
25on the session and the task.
26 
271. **Session already has the IDC MCP server?** Route discovery and metadata there — see *IDC
28 MCP Server*.
292. **Otherwise, is `idc-index` installed?** Run `python scripts/check_version.py`. If it passes,
30 use `idc-index` for everything.
313. **Not installed, and the task is read-only metadata** — counts, attribute values, collection
32 lookups, SQL under 10 000 rows, licenses, citations, viewer URLs? **Use the REST API over
33 `curl`; do not install anything.** Installing costs ~77 MB of packaged index data plus
34 pandas, pyarrow, and duckdb, which a metadata question does not need. See *Data Access
35 Options*.
364. **Not installed, and the task needs more than metadata** — downloading files, pandas or
37 plotting, pydicom/SimpleITK, pathology tiling, results past 10 000 rows, or a version-pinned
38 script the user re-runs? Install `idc-index`: `check_version.py` exits non-zero and prints
39 the exact install command for the running interpreter. Prefer a virtual environment, then
40 restart Python.
41 
42`idc-index` ([GitHub](https://github.com/imagingdatacommons/idc-index)) is still the most
43capable path and the only one that moves image bytes; the rule is just not to pay for it before
44the task calls for it. `check_version.py` never installs anything itself — it also flags a newer
45`idc-index` or skill release when one exists.
46 
47**Setup for the `idc-index` path:**
48 
49```python
50from idc_index import IDCClient
51client = IDCClient()
52 
53# Verify IDC data version (should be "v24")
54print(f"IDC data version: {client.get_idc_version()}")
55```
56 
57**Core workflow:** query metadata with `client.sql_query()` → download with
58`client.download_from_selection()` → visualize with `client.get_viewer_URL()`. Python examples
59below assume this `client`; *Data Access Options* has the REST equivalents. For current data
60scale, run the summary query in `references/sql_patterns.md` or `GET /v3/stats`.
61 
62## IDC MCP Server
63 
64IDC operates a hosted MCP server at `https://api.imaging.datacommons.cancer.gov/mcp`
65(streamable HTTP, no authentication). Where it is available it complements — it does not
66replace — the `idc-index` workflow below.
67 
68**Identify it** by the MCP resource `idc://guide`, or by three or more of the tool names
69`build_cohort`, `get_cohort_urls`, `list_analysis_results`, and `get_idc_version`. Generic
70names such as `run_sql` are not evidence on their own. If identification is ambiguous, use
71`idc-index`.
72 
73**If this session has the server**, treat it as authoritative for discovery and metadata —
74IDC version, counts, attribute values, cohort building, metadata SQL — and follow the
75server's own instructions rather than re-deriving them from this file. Its data version is
76whatever the server reports: call `get_idc_version` instead of relying on the version pinned
77in this file.
78 
79Return here for what the server does not do: downloading files, local pandas/notebook
80analysis, DICOMweb, BigQuery, digital pathology tiling, and reproducible scripts. Hand off by
81passing SeriesInstanceUIDs from the server to `client.download_from_selection(...)`, and run
82`scripts/check_version.py` at that point.
83 
84**If it is not available**, the identical service is reachable with no configuration as a REST
85API at `https://api.imaging.datacommons.cancer.gov/v3` — use it for read-only metadata rather
86than installing `idc-index`, per the routing gate in *Overview*. Suggest connecting the MCP
87server at most once, only for repeated interactive discovery, and never change the user's
88configuration yourself.
89 
90See `references/mcp_guide.md` for the tool inventory, handoff patterns, and per-host notes.
91 
92## When to Use This Skill
93 
94- Finding publicly available radiology (CT, MR, PET) or pathology (slide microscopy) images
95- Selecting image subsets by cancer type, modality, anatomical site, or other metadata
96- Downloading DICOM data from IDC
97- Checking data licenses before use in research or commercial applications
98- Visualizing medical images in a browser without local DICOM viewer software
99 
100## Quick Navigation
101 
102Inline below: the MCP/REST routing rules, the IDC data model, the index tables and how they
103join, the core API patterns (query, download, visualize, license, cite), best practices, and
104troubleshooting.
105 
106**Reference Guides (load on demand):**
107 
108| Guide | When to Load |
109|-------|--------------|
110| `index_tables_guide.md` | Complex JOINs, schema discovery, DataFrame access |
111| `use_cases.md` | End-to-end workflows: training datasets, batch downloads, DICOM reading with pydicom/SimpleITK, pipeline integration |
112| `sql_patterns.md` | Quick SQL patterns for filter discovery, annotations, size estimation |
113| `clinical_data_guide.md` | Clinical/tabular data, imaging+clinical joins, value mapping |
114| `licensing_and_citation.md` | Commercial-use questions, mixed-license cohorts, citation formats |
115| `cloud_storage_guide.md` | Direct S3/GCS access, versioning, UUID mapping |
116| `dicomweb_guide.md` | DICOMweb endpoints, PACS integration |
117| `digital_pathology_guide.md` | Slide microscopy (SM), annotations (ANN), pathology workflows |
118| `bigquery_guide.md` | Full DICOM metadata, private elements (requires GCP) |
119| `cli_guide.md` | Command-line tools (`idc download`, manifest files) |
120| `parquet_access_guide.md` | Direct Parquet queries via GCS (no idc-index install needed) |
121| `mcp_guide.md` | Hosted IDC MCP server: tool inventory, identification, handoff to `idc-index` |
122| `rest_api_guide.md` | Hosted IDC REST API: endpoints, filter syntax, SQL over HTTP, manifests |
123 
124## IDC Data Model
125 
126IDC adds two grouping levels above the standard DICOM hierarchy (Patient → Study → Series → Instance):
127 
128- **collection_id**: Groups patients by disease, modality, or research focus (e.g., `tcga_luad`, `nlst`). A patient belongs to exactly one collection.
129- **analysis_result_id**: Identifies derived objects (segmentations, annotations, radiomics features) across one or more original collections. Use it to find AI-generated or expert annotations, while `collection_id` finds original imaging data (which may itself include deposited annotations).
130 
131**Key identifiers for queries:**
132| Identifier | Scope | Use for |
133|------------|-------|---------|
134| `collection_id` | Dataset grouping | Filtering by project/study |
135| `PatientID` | Patient | Grouping images by patient |
136| `StudyInstanceUID` | DICOM study | Grouping of related series, visualization |
137| `SeriesInstanceUID` | DICOM series | Grouping of related series, visualization |
138 
139## Index Tables
140 
141The `idc-index` package provides multiple metadata index tables, accessible via SQL or as pandas DataFrames. The REST API exposes the same tables through `GET /tables` and `POST /sql`.
142 
143**Important:** `client.indices_overview` is the authoritative source for current table descriptions, available columns, and their types — query it when writing SQL or exploring data structure. It also answers "which table contains column X"; see `references/index_tables_guide.md` for that search pattern and full schema discovery.
144 
145### Available Tables
146 
147Always call `client.fetch_index("table_name")` before querying any index table — it is safe and idempotent for all tables, including those loaded automatically at startup.
148 
149| Family | Tables | Granularity |
150|--------|--------|-------------|
151| Core | `index` (primary metadata for all current data), `collections_index`, `analysis_results_index` | series / collection / analysis result |
152| Modality acquisition parameters | `ct_index`, `mr_index`, `pt_index`, `contrast_index` | 1 row = 1 series of that modality |
153| Derived objects | `seg_index`, `rtstruct_index`, `ann_index`, `ann_group_index` | 1 row = 1 series (or annotation group) |
154| Microscopy | `sm_index`, `sm_instance_index` | 1 row = 1 SM series / instance |
155| Geometry, clinical, history | `volume_geometry_index`, `clinical_index`, `version_metadata_index`, `prior_versions_index` | see guide |
156 
157`references/index_tables_guide.md` has the full inventory with each table's columns and
158contents — load it when you need to know what a specialized table actually holds.
159 
160**`prior_versions_index` is for reproducibility only.** It contains series permanently *removed*
161from IDC, with zero overlap with `index`. Use it only to reproduce work against a prior IDC
162version. Do NOT use it for version history or "what's new" questions — those use
163`series_init_idc_version` / `series_revised_idc_version` in the main `index` table, which are
164not equivalent to this table's `min_idc_version` / `max_idc_version`.
165 
166### Joining Tables
167 
168**`SeriesInstanceUID` is the universal join key** for all series-level specialized tables: `sm_index`, `sm_instance_index`, `seg_index`, `ann_index`, `ann_group_index`, `contrast_index`, `volume_geometry_index`, `rtstruct_index`, `ct_index`, `mr_index`, `pt_index`. Always join these to `index` on `SeriesInstanceUID`. The exceptions below use different column names.
169 
170| Join Column | Tables | Use Case |
171|-------------|--------|----------|
172| `collection_id` | index, prior_versions_index, collections_index, clinical_index | Link series to collection metadata or clinical data |
173| `analysis_result_id` | index, analysis_results_index | Link series to analysis result metadata (annotations, segmentations) |
174| `source_DOI` | index, analysis_results_index | Link by publication DOI |
175| `segmented_SeriesInstanceUID` | seg_index → index | Link segmentation to its source image series (`seg_index.segmented_SeriesInstanceUID = index.SeriesInstanceUID`) |
176| `referenced_SeriesInstanceUID` | ann_index → index, rtstruct_index → index | Link annotation or RTSTRUCT to its source image series |
177 
178**Note:** `subjects`, `updated`, and `description` appear in multiple tables but have different meanings (counts vs identifiers, different update contexts). Joining `prior_versions_index` to `index` on `SeriesInstanceUID` always returns zero rows — see the warning above.
179 
180For detailed join examples, schema discovery patterns, key columns reference, and DataFrame access, see `references/index_tables_guide.md`.
181 
182### Clinical Data Access
183 
184Clinical (non-imaging) attributes — staging, demographics, therapy — live in per-collection
185tables. `client.fetch_index("clinical_index")` loads the dictionary mapping columns to
186collections; `client.get_clinical_table(name)` returns one table as a DataFrame.
187 
188See `references/clinical_data_guide.md` for the discovery workflow, coded-value mapping, and
189joining clinical data with imaging.
190 
191## Data Access Options
192 
193| Method | Auth | Best For | Reference |
194|--------|------|----------|-----------|
195| `idc-index` | No | Downloads, pandas analysis, unbounded queries — the most capable path | This document |
196| IDC MCP server | No | Discovery, cohort building, metadata when the session already has it | `mcp_guide.md` |
197| IDC REST API | No | Metadata with no install, from any language or shell — the default when `idc-index` is absent | `rest_api_guide.md` |
198| Direct Parquet (GCS) | No | Version-pinned queries, or results past the REST row cap | `parquet_access_guide.md` |
199| Cloud storage (S3/GCS) | No | Direct file access, bulk transfer, custom pipelines | `cloud_storage_guide.md` |
200| DICOMweb via IDC proxy | No | Tool and PACS integration; daily quota, so testing and moderate use | `dicomweb_guide.md` |
201| DICOMweb via Google Healthcare | Yes (GCP) | The same DICOMweb API at production volume, without the proxy quota | `dicomweb_guide.md` |
202| SlicerIDCBrowser | No | 3D visualization and analysis in 3D Slicer | https://github.com/ImagingDataCommons/SlicerIDCBrowser |
203| BigQuery | Yes (GCP) | Full DICOM metadata, private elements, SR measurements — last resort | `bigquery_guide.md` |
204 
205**The IDC Portal (https://portal.imaging.datacommons.cancer.gov/) is interactive only**
206browser-based exploration, manual cohort selection, and download. Unlike every option above it
207has no programmatic interface, so point a user there to browse or click through data
208themselves; never use it as a step in a script or workflow.
209 
210**REST API — the no-install metadata path**
211 
212`https://api.imaging.datacommons.cancer.gov/v3`, no authentication: discovery, cohort counts and
213manifests, read-only SQL, clinical tables, viewer URLs, licenses, citations. It is the same
214service as the MCP server over plain HTTP, so it needs no configuration. It never moves image
215bytes — switch to `idc-index` to download, to get a DataFrame, or for results past 10 000 rows.
216 
217```bash
218B=https://api.imaging.datacommons.cancer.gov/v3
219curl -s $B/version # idc_version, idc_index_data_version, api_version
220curl -s $B/stats # collections, patients, studies, series, instances, size_TB
221curl -s "$B/attributes/Modality/values?limit=5" # real filter values, with counts
222curl -s $B/sql -H 'content-type: application/json' \
223 -d '{"sql":"SELECT collection_id, COUNT(*) n FROM index GROUP BY 1 ORDER BY n DESC LIMIT 3"}'
224curl -s $B/cohort/counts -H 'content-type: application/json' \
225 -d '{"filters":{"terms":{"collection_id":["rider_pilot"]}}}'
226```
227 
228**The filter object always goes under `filters`** — on `cohort/counts`, `cohort/manifest`,
229`cohort/manifest.txt`, `licenses`, and `citations` alike. A bare filter or an unrecognized key is
230a 422 naming the fix; an unfiltered series-enumerating request is a 400, not the whole archive.
231Every filtered response echoes `filters_applied` and `warnings` — read them, because they name
232any predicate the server dropped. A zero count with empty `warnings` therefore means the filter
233matched nothing, not that a value was miscased; miscasing produces a warning that says so.
234 
235`POST /sql` takes one read-only `SELECT`/`WITH` over the tables `idc-index` exposes plus
236`clinical.<table>`; `max_rows` defaults to 5 000, caps at 10 000, and `truncated` flags clipping.
237`GET /attributes` lists the 19 filterable attributes — clinical values, segmented anatomy, and
238acquisition parameters are not among them and need SQL. There is no rate limit or quota. **Use
239v3 only:** V1 and V2 are superseded and scheduled for shutdown, so port any `/v1/`- or
240`Modality_btw`-style example a user brings rather than extending it.
241 
242Both sides build on `idc-index-data`, so compare the API's `idc_index_data_version` against local
243`idc_index_data.__version__` before mixing them: the **major is the IDC data release** (`24.x.y`
244serves `v24`), so differing minor/patch means the series are identical. If the API is a whole
245release ahead, `idc-index` **cannot download the extra series** — it silently skips what its own
246index does not list — so either upgrade it (run `scripts/check_version.py` for the right command)
247or transfer directly from the bucket with `s5cmd --no-sign-request`.
248 
249See `references/rest_api_guide.md` for the endpoint reference, filter grounding, limits, and the
250manifest-based download flow.
251 
252**Cloud storage organization**
253 
254All DICOM files live in public buckets mirrored between AWS S3 and GCS, organized by CRDC UUIDs
255(not DICOM UIDs) to support versioning, as `<crdc_series_uuid>/<crdc_instance_uuid>.dcm`. Access
256is free (no egress fees) via AWS CLI, gsutil, or s5cmd with anonymous access; use the
257`series_aws_url` column for S3 URLs. Note that `idc-open-data-cr` / `idc-open-cr` (~4% of data)
258is commercial-use restricted (CC BY-NC). See `references/cloud_storage_guide.md` for the full
259bucket list and UUID mapping.
260 
261**DICOMweb access**
262 
263IDC data is available via DICOMweb (Google Cloud Healthcare API) for PACS integration and
264DICOMweb-compatible tools: a public proxy (no auth, daily quota) for testing and moderate
265queries, or Google Healthcare (GCP auth) for production volumes. See
266`references/dicomweb_guide.md`.
267 
268**Direct Parquet access**
269 
270The idc-index metadata tables are also published as Parquet on a public GCS bucket
271(`idc-index-data-artifacts`), queryable with DuckDB or pandas. This needs DuckDB installed
272and cannot reach the per-collection clinical tables, so prefer REST `/sql` for ad-hoc metadata;
273choose Parquet to pin a data version or for results past the REST row cap. See
274`references/parquet_access_guide.md`.
275 
276## Core Capabilities
277 
278The patterns below are the ones that go wrong when recalled from memory rather than checked.
279Worked examples for each area live in the reference guides named inline.
280 
281### 1. Discovery — enumerate values before filtering on them
282 
283Filtering on a guessed `Modality` or `BodyPartExamined` string is the most common cause of an
284empty result set. Enumerate first:
285 
286```python
287modalities = client.sql_query("""
288 SELECT DISTINCT Modality, COUNT(*) as series_count
289 FROM index
290 GROUP BY Modality
291 ORDER BY series_count DESC
292""")
293print(modalities)
294```
295 
296The same pattern works for any filter column, optionally narrowed by another —
297`BodyPartExamined` within a `Modality`, `Manufacturer`, `collection_id`. On the REST path this
298grounding is a single call — `GET /attributes/{attr}/values` returns values with counts — and the
299cohort endpoints report a miscased value in `warnings` rather than as an empty result.
300 
301Two indices carry curated collection-level metadata the primary `index` does not, both
302requiring `client.fetch_index(...)` first: `collections_index` (cancer types, tumor locations,
303species, subject counts) and `analysis_results_index` (derived datasets — AI segmentations,
304expert annotations, radiomics — with their source collections and modalities).
305 
306**Cancer type lives in `collections_index.cancer_types`, not in `index`** — filtering by
307cancer type requires a join:
308 
309```python
310client.fetch_index("collections_index")
311results = client.sql_query("""
312 SELECT i.collection_id, i.PatientID, i.SeriesInstanceUID, i.Modality
313 FROM index i
314 JOIN collections_index c ON i.collection_id = c.collection_id
315 WHERE c.cancer_types LIKE '%Breast%'
316 AND i.Modality = 'MR'
317 LIMIT 20
318""")
319```
320 
321`client.sql_query()` returns a pandas DataFrame. Confirm column names with
322`client.get_index_schema('index')` or `client.indices_overview` before writing a query rather
323than assuming them.
324 
325See `references/sql_patterns.md` for filter-value discovery, annotation and segmentation
326queries, size estimation, clinical linking, and version tracking ("what's new in vX" — use
327`series_init_idc_version` / `series_revised_idc_version` in `index`, never
328`prior_versions_index`).
329 
330### 2. Downloading DICOM files
331 
332**The two download methods take their first two arguments in opposite order.** This is the
333most common source of broken IDC code — check it rather than recalling it:
334 
335| Method | First arg | Second arg | Use when |
336|--------|-----------|------------|----------|
337| `download_from_selection` | `downloadDir` (required) | filter kwargs (optional) | Filtering by collection, patient, study, or series |
338| `download_dicom_series` | `seriesInstanceUID` (required) | `downloadDir` (required) | Downloading specific series by UID only |
339 
340**`download_from_selection` takes filter keyword arguments, NOT a DataFrame.** The name
341"from_selection" refers to filtering the IDC index by criteria — not to accepting a pandas
342DataFrame. To download query results, extract the UIDs into a list first:
343 
344```python
345# Step 1: Query for series UIDs
346series_df = client.sql_query("""
347 SELECT SeriesInstanceUID
348 FROM index
349 WHERE Modality = 'CT'
350 AND BodyPartExamined = 'CHEST'
351 AND collection_id = 'nlst'
352 LIMIT 5
353""")
354 
355# Step 2: Extract UIDs as a list from the DataFrame
356uids = list(series_df['SeriesInstanceUID'].values)
357 
358# Step 3: Pass the list to download_from_selection (NOT the DataFrame itself)
359client.download_from_selection(
360 downloadDir="./data/lung_ct",
361 seriesInstanceUID=uids # list of strings, not a DataFrame
362)
363 
364# Alternative: download_dicom_series has seriesInstanceUID as FIRST arg (different order!)
365client.download_dicom_series(
366 seriesInstanceUID=uids, # FIRST arg here
367 downloadDir="./data/lung_ct"
368)
369 
370# Whole collection: downloadDir is still the FIRST positional argument
371client.download_from_selection(downloadDir="./data/rider", collection_id="rider_pilot")
372```
373 
374Both methods default to AWS; pass `source_bucket_location="gcs"` to pull from Google Storage.
375 
376**Downloaded files are named `<crdc_instance_uuid>.dcm`, not by SOPInstanceUID.** The DICOM
377UIDs are preserved inside the file metadata, not in the filename. Use the `crdc_instance_uuid`
378column to map files back to the series they came from.
379 
380`idc download <collection|series-uid|manifest> --download-dir ./data` does the same from a
381shell. See `references/cli_guide.md` for the `dirTemplate` hierarchy options (Python default:
382`%collection_id/%PatientID/%StudyInstanceUID/%Modality_%SeriesInstanceUID`; `dirTemplate=""`
383flattens), manifest downloads with resume, and dry-run size estimation.
384 
385### 3. Visualizing IDC images
386 
387```python
388viewer_url = client.get_viewer_URL(seriesInstanceUID=uid) # one series
389viewer_url = client.get_viewer_URL(studyInstanceUID=study_uid) # all series in a study
390```
391 
392Returns a browser URL — nothing is downloaded. The method selects OHIF v3 for radiology or
393SLIM for slide microscopy automatically. Viewing by study is useful when a single DICOM Study
394holds several Series (T1, T2, and DWI from one MRI session).
395 
396### 4. Licenses and citations — obligations, not optional steps
397 
398IDC data carries license terms and attribution requirements that follow it into any downstream
399publication or product, and neither is inferable from the pixel data. **Check the license
400before use, and generate citations for whatever you download.**
401 
402```python
403# License breakdown for a selection
404licenses = client.sql_query("""
405 SELECT DISTINCT collection_id, license_short_name,
406 COUNT(DISTINCT SeriesInstanceUID) as series_count
407 FROM index GROUP BY collection_id, license_short_name
408""")
409 
410# Citations for the same selection you downloaded (APA by default)
411for citation in client.citations_from_selection(collection_id="rider_pilot"):
412 print(citation)
413```
414 
415About 97% of IDC data is CC BY (commercial use allowed with attribution) and about 3% is
416CC BY-NC (non-commercial only). **Licenses attach to series, not collections** — 39 of 176
417collections carry more than one — so check the selection you actually intend to use, and note
418that the most restrictive term governs a mixed cohort.
419 
420Both tasks are available from all three access paths, so stay on whichever one the session is
421already using: `idc-index` as above, `POST /v3/licenses` and `POST /v3/citations` over REST,
422or the `get_licenses` and `get_citations` MCP tools. See
423`references/licensing_and_citation.md` for the full license inventory, all three routes, the
424citation formats (APA, BibTeX, CSL JSON, RDF Turtle), and what to include when publishing.
425 
426### 5. Reaching past the index
427 
428Pick the access path with the routing gate in *Overview*; *Data Access Options* above is the
429full routing table.
430 
431Before reaching for BigQuery (which needs a billing-enabled GCP account), check whether a
432specialized index table already has the column you want: search `client.indices_overview`,
433then `client.fetch_index(...)` and query locally for free. BigQuery is required only for
434private DICOM elements, per-segment anatomy (`segmentations`), and pre-extracted SR
435measurements (`quantitative_measurements`, `qualitative_measurements`) — these have no
436idc-index equivalent.
437 
438## Best Practices
439 
440- **Check schema before writing queries** — Use `client.get_index_schema('index')` (reads cached metadata, no SQL executed) or `client.indices_overview` to see all available columns and their descriptions. The version-tracking columns `series_init_idc_version` and `series_revised_idc_version` in the main `index` table directly answer "what's new / when was this added" questions without touching `prior_versions_index`.
441- **Never use web search for IDC data content questions** - Always query the IDC index directly, via `client.sql_query()` locally or `POST /v3/sql` over HTTP. Web sources (release notes, blog posts, documentation pages) are frequently out of date and will produce incorrect answers. The index is the authoritative source; use it even when web search is available.
442- **Verify the IDC data version at the start of a session** - `client.get_idc_version()`, `GET /v3/version`, or the MCP `get_idc_version` tool, depending on the path in use (currently v24). For a stale local index, run `scripts/check_version.py` and use the upgrade command it prints
443- **Check licenses and generate citations** - Query `license_short_name` and respect CC BY vs CC BY-NC terms; use `citations_from_selection()` to produce citations from `source_DOI` for publications
444- **Explore small, then commit** - Use `LIMIT` (or a low `max_rows`) while exploring, and check collection size before downloading — some collections are terabytes. See `references/cli_guide.md`
445- **Keep downloads reproducible** - Organize with `dirTemplate` (e.g. `%collection_id/%PatientID/%Modality`) and save the Series UIDs or manifest behind any dataset you build
446 
447## Troubleshooting
448 
449**Issue: `ModuleNotFoundError: No module named 'idc_index'`**
450- **Cause:** idc-index package not installed
451- **Solution:** If the task is read-only metadata, do not install it — use the REST API instead (*Data Access Options*). Otherwise run `scripts/check_version.py` and use the install command it prints, which targets the running interpreter and pins the vetted version. For data analysis also add pandas, numpy, and pydicom (tested with pandas>=1.5, numpy>=1.23, pydicom>=2.3)
452 
453**Issue: Download fails with connection timeout**
454- **Cause:** Network instability or large download size
455- **Solution:** Download in smaller batches (10-20 series); see `references/cli_guide.md` for
456 `--use-s5cmd-sync` resume and retry guidance
457 
458**Issue: `BigQuery quota exceeded` or billing errors**
459- **Cause:** BigQuery requires billing-enabled GCP project
460- **Solution:** Use idc-index mini-index for simple queries (no billing required), or see `references/bigquery_guide.md` for cost optimization tips
461 
462**Issue: Series UID not found or no data returned**
463- **Cause:** Typo in UID, data not in the current IDC version, or wrong field name
464- **Solution:** Test with `LIMIT 5` first, check field names against `client.indices_overview`,
465 and confirm the series is in the current version (some old data is deprecated)
466 
467**Issue: Column not found in `index` table (e.g., `SliceThickness`, `PixelSpacing`, `KVP`, `EchoTime`, `InjectedDose`)**
468- **Cause:** The `index` table contains series-level metadata only; modality-specific acquisition and reconstruction parameters live in dedicated tables (`ct_index`, `mr_index`, `pt_index`)
469- **Solution:** Search `client.indices_overview` for the column to find its table — the loop is under *Finding which table contains a column* in `references/index_tables_guide.md` — then fetch and join on `SeriesInstanceUID`:
470 ```python
471 client.fetch_index("ct_index")
472 result = client.sql_query("""
473 SELECT i.SeriesInstanceUID, i.Modality, c.SliceThickness, c.KVP, c.PixelSpacing_row_mm
474 FROM index i
475 JOIN ct_index c USING (SeriesInstanceUID)
476 WHERE i.collection_id = 'your_collection'
477 """)
478 ```
479 
480**Issue: Downloaded DICOM files won't open**
481- **Cause:** Corrupted download, or an object type the viewer does not handle — SEG, RTSTRUCT,
482 SR, and slide microscopy all need specialized tools
483- **Solution:** Check `Modality` and `SOPClassUID` first, validate with
484 `pydicom.dcmread(file, force=True)`, try another viewer (3D Slicer, QuPath for pathology),
485 then re-download
486 
487## Resources
488 
489Reference guides and their decision triggers are listed in *Quick Navigation* above.
490 
491- **IDC Portal**: https://portal.imaging.datacommons.cancer.gov/explore/
492- **Documentation**: https://learn.canceridc.dev/ — **Tutorials**: https://github.com/ImagingDataCommons/IDC-Tutorials
493- **User Forum**: https://discourse.canceridc.dev/ — **idc-index**: https://github.com/ImagingDataCommons/idc-index
494- **[indices_reference](https://idc-index.readthedocs.io/en/latest/indices_reference.html)** — external index-table docs (may be ahead of the installed version)
495- **Citation**: Fedorov, A., et al. "National Cancer Institute Imaging Data Commons: Toward Transparency, Reproducibility, and Scalability in Imaging Artificial Intelligence." RadioGraphics 43.12 (2023). https://doi.org/10.1148/rg.230180
496- **Skill updates**: [releases page](https://github.com/ImagingDataCommons/imaging-data-commons-skill/releases); watch the repository (Watch → Custom → Releases)
497 

Discussion

Alternatives

Also in Services & APIs
Context7Pulls up-to-date, version-specific library docs and code examples into the prompt so the AI stops inventing old APIs.Coding · MITAdaptyv Bio Foundry APIHow to use the Adaptyv Bio Foundry API and Python SDK for protein experiment design, submission, and results retrieval. Use this skill whenever the user mentions Adaptyv, Foundry API, protein binding assays, protein screening experiments, BLI/SPR assays, thermostability assays, or wants to submit protein sequences for experimental characterization. Also trigger when code imports `adaptyv`, `adaptyv_sdk`, or `FoundryClient`, or references `foundry-api-public.adaptyvbio.com`.Science · MIT.NET Backend Development PatternsMaster C#/.NET backend development patterns for building robust APIs, MCP servers, and enterprise applications. Covers async/await, dependency injection, Entity Framework Core, Dapper, configuration, caching, and testing with xUnit. Use when developing .NET backends, reviewing C# code, or designing API architectures.Coding · MITAdd AI protectionProtect AI chat and completion endpoints from abuse — detect prompt injection and jailbreak attempts, block PII and sensitive info from leaking in responses, and enforce token budget rate limits to control costs. Use this skill when the user is building or securing any endpoint that processes user prompts with an LLM, even if they describe it as "preventing jailbreaks," "stopping prompt attacks," "blocking sensitive data," or "controlling AI API costs" rather than naming specific protections.Coding · CC0-1.0