Skip to main content
Glama

CDISC Library MCP Server β€” Query clinical data standards (SDTM, ADaM, CDASH, CT) directly from AI assistants.

Python FastMCP License: MIT Tests API

🌐 Translations: δΈ­ζ–‡ README Β· ζ—₯本θͺž README


What is This?

The CDISC MCP Server connects AI assistants (Claude, VS Code Copilot, Cursor, etc.) to the CDISC Library REST API, exposing 11 structured tools for querying clinical trial data standards. Ask your AI assistant questions like:

"What variables are in the SDTM AE domain?"/m "Show me the ADSL variables in ADaM IG 1.3" "List all available Controlled Terminology packages"

For full setup instructions, see the User Manual β†’. See Examples β†’ for real conversation samples.


Quick Start

0 Β· One-Line AI Install

Have an AI assistant install everything for you:

curl -fsSL https://raw.githubusercontent.com/Teninq/cdisc-mcp/main/install.md

Paste the output into Claude, Copilot, or any AI chat β€” it will read the guide and walk you through the full setup interactively.


1 Β· Get a CDISC Library API Key

Register at https://library.cdisc.org and obtain a personal API key.

2 Β· Install

# Runtime only
pip install -e .

# With dev dependencies
pip install -e ".[dev]"

# With web explorer
pip install -e ".[web]"

3 Β· Set API Key

# Linux / macOS
export CDISC_API_KEY=your_key_here

# Windows β€” Command Prompt
set CDISC_API_KEY=your_key_here

# Windows β€” PowerShell
$env:CDISC_API_KEY = "your_key_here"

4 Β· Run

# Start MCP server (for AI assistant integration)
cdisc-mcp

# OR: Start Web Explorer (quick interactive testing)
python web/app.py

Web Explorer β€” Quick Interactive Testing

The fastest way to verify your setup and explore tools without any AI client.

# 1. Install web dependencies
pip install -e ".[web]"

# 2. Set your API key
export CDISC_API_KEY=your_key_here   # Linux/macOS
set CDISC_API_KEY=your_key_here      # Windows CMD
$env:CDISC_API_KEY = "your_key_here" # Windows PowerShell

# 3. Start the bridge server
python web/app.py

# 4. Open in browser
#    β†’ http://localhost:8080

The explorer provides:

  • Sidebar navigation β€” all 11 tools organized by standard (SDTM / ADaM / CDASH / Terminology)

  • Auto-generated forms β€” dropdowns for versions and domains, text inputs for variables

  • Live JSON responses β€” syntax-highlighted, copyable output with response time

  • Bridge status indicator β€” confirms your API key and connectivity

Tip: Use version strings with dashes β€” 3-4 not 3.4, 1-3 not 1.3. Example: SDTM-IG 3-4, ADaM-IG 1-3, CDASH-IG 2-0


Available Tools

#

Tool

Standard

Description

1

list_products

β€”

List all available CDISC standards and published versions

2

get_sdtm_domains

SDTM

List all datasets in a SDTM-IG version

3

get_sdtm_domain_variables

SDTM

List all variables in an SDTM domain/dataset

4

get_sdtm_variable

SDTM

Get full definition of a specific SDTM variable

5

get_adam_datastructures

ADaM

List all data structures in an ADaM-IG version

6

get_adam_variable

ADaM

Get definition of a specific ADaM variable

7

get_cdash_domains

CDASH

List all domains in a CDASH-IG version

8

get_cdash_domain_fields

CDASH

Get all data collection fields for a CDASH domain

9

list_ct_packages

CT

List all available Controlled Terminology packages

10

get_codelist

CT

Get definition and metadata of a CT codelist

11

get_codelist_terms

CT

List all valid terms in a CT codelist

Version Reference

Standard

Available Versions (use dashes)

SDTM-IG

3-4 Β· 3-3 Β· 3-2 Β· 3-1-3

ADaM-IG

1-3 Β· 1-2 Β· 1-1 Β· 1-0

CDASH-IG

2-1 Β· 2-0 Β· 1-1-1


Connect to an AI Assistant

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "cdisc": {
      "command": "cdisc-mcp",
      "env": {
        "CDISC_API_KEY": "your_key_here"
      }
    }
  }
}

VS Code / Cursor

Add to .vscode/mcp.json or equivalent MCP config:

{
  "servers": {
    "cdisc": {
      "command": "cdisc-mcp",
      "env": {
        "CDISC_API_KEY": "your_key_here"
      }
    }
  }
}

Claude Code (CLI)

Claude Code supports MCP servers at two scopes: user (global, all projects) and project (local, current project only).

Option A β€” CLI command (recommended)

# Add globally (available in all projects)
claude mcp add cdisc-mcp -e CDISC_API_KEY=your_key_here -- python -m cdisc_mcp.server

# Add for the current project only
claude mcp add cdisc-mcp --scope project -e CDISC_API_KEY=your_key_here -- python -m cdisc_mcp.server

# Verify the server was registered
claude mcp list

Option B β€” Edit ~/.claude.json directly

{
  "mcpServers": {
    "cdisc-mcp": {
      "command": "python",
      "args": ["-m", "cdisc_mcp.server"],
      "env": {
        "CDISC_API_KEY": "your_key_here"
      }
    }
  }
}

Tip: If CDISC_API_KEY is already in your system environment, omit the env block entirely β€” Claude Code inherits it automatically.

Once registered, confirm with /mcp in any Claude Code session, then use the tools conversationally:

User: What SDTM domains are defined in version 3.4?
Claude: [calls get_sdtm_domains with version="3-4"] ...

Using in Your Own Python Tools

You can call CDISC MCP tools programmatically from any Python script using the official MCP client SDK.

Install the client

pip install mcp

Minimal example

import asyncio
import os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

SERVER = StdioServerParameters(
    command="python",
    args=["-m", "cdisc_mcp.server"],
    env={"CDISC_API_KEY": os.environ["CDISC_API_KEY"]},
)

async def main():
    async with stdio_client(SERVER) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # List all available tools
            tools = await session.list_tools()
            print([t.name for t in tools.tools])

            # Call a tool
            result = await session.call_tool(
                "get_sdtm_domains",
                arguments={"version": "3-4"},
            )
            print(result.content[0].text)

asyncio.run(main())

Reusable helper

import asyncio, os, json
from contextlib import asynccontextmanager
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

_SERVER = StdioServerParameters(
    command="python",
    args=["-m", "cdisc_mcp.server"],
    env={"CDISC_API_KEY": os.environ["CDISC_API_KEY"]},
)

@asynccontextmanager
async def cdisc_session():
    """Async context manager that yields an initialised MCP session."""
    async with stdio_client(_SERVER) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            yield session

async def call(tool: str, **kwargs) -> dict:
    async with cdisc_session() as s:
        result = await s.call_tool(tool, arguments=kwargs)
        return json.loads(result.content[0].text)

# --- Usage examples ---
async def demo():
    # Fetch SDTM domains
    domains = await call("get_sdtm_domains", version="3-4")

    # Fetch all variables in the AE domain
    variables = await call("get_sdtm_domain_variables", version="3-4", domain="AE")

    # Look up a single variable
    aeterm = await call("get_sdtm_variable", version="3-4", domain="AE", variable="AETERM")

    print(aeterm)

asyncio.run(demo())

Available tool signatures (quick reference)

# Products / versions
await session.call_tool("list_products", {})

# SDTM
await session.call_tool("get_sdtm_domains",          {"version": "3-4"})
await session.call_tool("get_sdtm_domain_variables", {"version": "3-4", "domain": "AE"})
await session.call_tool("get_sdtm_variable",         {"version": "3-4", "domain": "AE", "variable": "AETERM"})

# ADaM
await session.call_tool("get_adam_datastructures",   {"version": "1-3"})
await session.call_tool("get_adam_variable",         {"version": "1-3", "data_structure": "ADSL", "variable": "USUBJID"})

# CDASH
await session.call_tool("get_cdash_domains",         {"version": "2-0"})
await session.call_tool("get_cdash_domain_fields",   {"version": "2-0", "domain": "AE"})

# Controlled Terminology
await session.call_tool("list_ct_packages",          {})
await session.call_tool("get_codelist",              {"package_id": "sdtmct-2024-03-29", "codelist_id": "C66781"})
await session.call_tool("get_codelist_terms",        {"package_id": "sdtmct-2024-03-29", "codelist_id": "AGEU"})

Version format: Always use dashes, not dots β€” "3-4" not "3.4".


Architecture

MCP Client (Claude / VS Code / Cursor)
        β”‚
        β”‚  MCP protocol (stdio)
        β–Ό
   server.py  ──── FastMCP tool registration
        β”‚
        β–Ό
   tools/  ──────── domain functions (sdtm, adam, cdash, terminology, search)
        β”‚
        β–Ό
   client.py  ───── CDISCClient (async HTTP Β· TTL cache Β· retry)
        β”‚
        β”‚  HTTPS
        β–Ό
   library.cdisc.org/api  ──── CDISC Library REST API

Key design decisions:

  • CDISCClient is a singleton async HTTP client with 1-hour TTL in-memory cache

  • Only 429 and 5xx responses are retried; 4xx raise immediately

  • Tool functions are pure async β€” independently testable without patching

  • format_response() strips HAL _links metadata, extracts structured data for LLM consumption


Development

Development workflow (devel-first, branch & merge SOP): See Contributing Guide.

Running Tests

# Full suite with coverage (β‰₯80% required)
pytest

# Specific modules
pytest tests/test_tools.py tests/test_client.py -v

# Single test
pytest tests/test_tools.py::test_list_products -v

Code Quality

ruff check src/ tests/    # Linting
mypy src/                 # Type checking

GitHub Branch Protection (Required Checks)

Configure main branch protection to require:

  • CI Tests / tests

  • CI Lint / lint

  • CI Types / types

Project Structure

src/cdisc_mcp/
β”œβ”€β”€ server.py              # FastMCP server + tool registration
β”œβ”€β”€ client.py              # Async HTTP client (cache, retry)
β”œβ”€β”€ config.py              # Config dataclass + env loader
β”œβ”€β”€ errors.py              # AuthenticationError, ResourceNotFoundError, RateLimitError
β”œβ”€β”€ response_formatter.py  # HAL response normalization
└── tools/
    β”œβ”€β”€ search.py          # list_products (product catalog)
    β”œβ”€β”€ sdtm.py            # SDTM domain/variable tools
    β”œβ”€β”€ adam.py            # ADaM datastructure/variable tools
    β”œβ”€β”€ cdash.py           # CDASH domain/field tools
    β”œβ”€β”€ terminology.py     # CT package/codelist tools
    └── _validators.py     # Path traversal guards
web/
β”œβ”€β”€ app.py                 # FastAPI bridge server
└── index.html             # Single-file browser explorer
tests/
β”œβ”€β”€ test_config.py
β”œβ”€β”€ test_client.py
β”œβ”€β”€ test_response_formatter.py
β”œβ”€β”€ test_tools.py
β”œβ”€β”€ test_errors.py
└── test_server.py

License

MIT license.


Built for clinical data professionals working with CDISC standards.

User Manual Β· Examples Β· CDISC Library Β· API Docs

Install Server
A
security – no known vulnerabilities
F
license - not found
-
quality - not tested

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Teninq/cdisc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server