clinicaltrials-mcp
by agents100x
README.md
# clinicaltrials-mcp
**Conversational access to 400,000+ clinical trials — for pharma analysts, CRO teams, and health-tech builders.**
A Python MCP server that connects Cursor, Claude Desktop, and any MCP-compatible client directly to ClinicalTrials.gov. Ask questions in plain English. Get clean, structured answers in seconds — no API keys, no setup, no parsing raw JSON.
[](https://pypi.org/project/clinicaltrials-mcp/)
[](https://www.python.org/downloads/)
[](LICENSE)
---
## The Problem
ClinicalTrials.gov is the world's largest registry of clinical research — 400,000+ trials, decades of outcomes data, all publicly accessible via a free API.
But the API gives you this:
```json
{
"protocolSection": {
"eligibilityModule": {
"eligibilityCriteria": "Inclusion Criteria:\n\n* Willing to sign the informed consent form;\n* ≥18 years old;\n* Diagnosed histologically or cytologically with local advanced or metastatic HER2-positive malignant solid cancer...",
"stdAges": ["ADULT", "OLDER_ADULT"]
},
"adverseEventsModule": {
"eventGroups": [...],
"seriousEvents": [...],
"otherEvents": [...]
}
}
}
```
Every field is optional. Eligibility criteria are a single wall of free text. Adverse events are split across two arrays that reference a separate groups table by ID. Every trial returns a different shape.
To compare eligibility across 10 trials, you write 10 scripts — or spend two days copying into Excel. To find the adverse event profile of a completed study, you navigate five nested objects and cross-reference three tables. To do a competitive landscape analysis across a therapeutic area, you're looking at a week of work.
**This is not a data problem. It is a tooling problem.**
With clinicaltrials-mcp, the same work takes a conversation:
> *"Compare the eligibility criteria for these 5 NASH trials"*
> *"What were the Grade 3+ adverse events in NCT02142803?"*
> *"Find recruiting HER2-positive trials near Mumbai"*
Seconds. Followed up. Drilled down. No scripts, no parsing, no Excel.
---
## Install & Setup
### Step 1 — Install
```bash
pip install clinicaltrials-mcp
```
No API key. No account. No configuration required.
### Step 2 — Add to your MCP client
```json
{
"mcpServers": {
"clinicaltrials": {
"command": "uvx",
"args": ["clinicaltrials-mcp"]
}
}
}
```
`uvx` runs the package without requiring it on your `$PATH`. If you don't have `uv`: `pip install uv`.
Restart your MCP client. The 5 tools appear automatically.
---
### Running from source (contributors / developers)
```bash
git clone https://github.com/agents100x/clinicaltrials-mcp
cd clinicaltrials-mcp
uv sync
```
```json
{
"mcpServers": {
"clinicaltrials": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/clinicaltrials-mcp",
"clinicaltrials-mcp"
]
}
}
}
```
---
### Where is the config file?
| Client | Config file location |
|---|---|
| **Claude Desktop** (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| **Claude Desktop** (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
| **Cursor** | `.cursor/mcp.json` or Settings → MCP |
| **VS Code / forks** | Settings → MCP Servers → Edit config |
Restart the client after saving. The 5 tools appear automatically.
---
## Sample Queries
Organised by real analyst workflows. All queries work in plain English — no syntax required.
---
### Competitive Intelligence
```
"Show me recruiting Phase III trials for breast cancer"
"Find all active Phase II Alzheimer's trials in Europe"
"What NASH trials completed in the last 2 years?"
"Are there any recruiting trials for KRAS-mutant lung cancer?"
"Show me TERMINATED trials for diabetes — I want to know what failed"
```
The last query uses the status override: *"...status='TERMINATED'"* — WITHDRAWN and TERMINATED
trials are excluded by default, but you can always ask for them explicitly.
---
### Patient Eligibility & Site Feasibility (CRO Teams)
```
"Get the full eligibility criteria for NCT04280341"
"Find recruiting HER2-positive breast cancer trials near Mumbai, India"
"Find Type 2 Diabetes trials recruiting near Bangalore, India"
"Are there any recruiting immunotherapy trials near London?"
```
> **Note on site status:** Results are filtered by overall trial status. Always verify
> the specific site's recruitment status at clinicaltrials.gov before contacting a site.
---
### Protocol Comparison (Medical Writers / Researchers)
```
"Compare NCT04280341 and NCT02142803 on eligibility criteria"
"Compare the design and timeline of NCT04280341 and NCT03817944"
"Compare the endpoints of these three pembrolizumab trials: NCT04280341, NCT03817944, NCT02142803"
```
Focus the comparison with `compare_on`:
- `"...compare on design"` — phase, randomisation, blinding, arms
- `"...compare on eligibility"` — inclusion/exclusion criteria side by side
- `"...compare on endpoints"` — primary and secondary outcomes
- `"...compare on timeline"` — start dates, completion dates, enrollment targets
- `"...compare on locations"` — countries and site counts
---
### Results & Safety Review
```
"What were the adverse events reported in NCT02142803?"
"Show me all Grade 1 and above adverse events for NCT02142803"
"Give me a quick summary of the primary outcome of NCT02142803"
"What were the participant flow and dropout reasons in NCT02142803?"
```
Results options:
- Default shows **serious adverse events only** (Grade 3+)
- *"...include all grades"* → adds Grade 1/2 events
- *"...summary only"* → returns just the primary outcome in 2–3 lines, useful for scanning many trials
---
### Edge Cases the Tool Handles Cleanly
```
"Get results for NCT03444521"
→ Returns: "Trial completed in 2022 but no results posted — this is common,
~60% of completed trials never post results. It does not mean the trial failed."
"Find recruiting trials for Niemann-Pick disease near Paris"
→ Returns: helpful no-results message with suggestions to broaden the search
"Find terminated trials for a condition"
→ Requires explicit status override — the tool tells you exactly how
```
---
## The 5 Tools
| Tool | What It Does | Key Design Decision |
|---|---|---|
| `search_trials` | Search by condition, phase, status, location | WITHDRAWN + TERMINATED excluded by default — always explained, always overridable |
| `get_trial_details` | Full structured summary by NCT ID | Eligibility always verbatim — never paraphrased |
| `compare_trials` | Side-by-side comparison of 2–5 trials | `compare_on` param: all, design, eligibility, endpoints, timeline, locations |
| `get_trial_results` | Outcomes, AEs, participant flow | AE grade note top + bottom; 4-case no-results handling |
| `find_recruiting_near` | Recruiting trials near a location | City → country location rings, honest about CT.gov's city-level data |
---
## Why This Is Different
Every other ClinicalTrials.gov MCP passes raw JSON from the API to the LLM and calls it done.
This is a **workflow tool**, not an API wrapper:
- **Outputs designed around what analysts do** — not what the API can return
- **Opinionated defaults** — RECRUITING sorts first, Grade 3+ AEs shown, status filter always explained
- **Honest about data gaps** — ~60% of completed trials never post results; we say so every time
- **Verbatim eligibility criteria** — never paraphrased, too risky to interpret clinical text
- **Verification by design** — NCT hyperlinks appear at the top and bottom of every trial detail
---
## Limitations
- Data is self-reported by sponsors on ClinicalTrials.gov — not independently verified by us
- ~60% of completed trials have no posted results on CT.gov
- Trial status and site data may lag real-world updates by weeks
- Location filtering is city/country level — no GPS radius search available
- Not all trials in the world are registered on CT.gov
**Data returned by this tool should never be used directly in regulatory submissions,
publications, or clinical decisions without independent verification at clinicaltrials.gov.**
Full scope and data disclaimer: [DISCLAIMER.md](DISCLAIMER.md)
---
## How It Works
```
Claude or Cursor
|
| MCP tool call over stdio
|
server.py — registers 5 tools, routes calls, catches all errors gracefully
|
client.py — async httpx client for CT.gov API v2 (public, no auth required)
|
ClinicalTrials.gov — public REST API, 400,000+ registered trials
|
formatters.py — transforms raw JSON into clean, structured markdown
|
Claude or Cursor — reads formatted output and responds to the user
```
**Stack:** Python 3.12+ · [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) · [httpx](https://www.python-httpx.org/) · [uv](https://github.com/astral-sh/uv)
---
## Contributing
```bash
git clone https://github.com/agents100x/clinicaltrials-mcp
cd clinicaltrials-mcp
uv sync
uv run pytest tests/ -m "not integration" # offline unit tests, ~0.3s
uv run pytest tests/ # full suite including live API
```
Bug reports and pull requests welcome at
[github.com/agents100x/clinicaltrials-mcp/issues](https://github.com/agents100x/clinicaltrials-mcp/issues).
---
## License
MIT — see [LICENSE](LICENSE) for details.
Built by [agents100x](https://github.com/agents100x).
TDQS
A4.1/5.0
Scored across 5 tools
Disambiguation5/5
Each tool has a clearly distinct purpose: searching, getting details, getting results, comparing, and finding recruiting trials by location. No overlap in functionality.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern (e.g., search_trials, get_trial_details) using underscores, making them predictable and easy to understand.
Tool Count5/5
5 tools cover the essential operations for clinical trials access without being excessive or insufficient, making the server well-scoped.
Completeness4/5
The set covers searching, details, results, comparison, and location-based filtering. Minor gaps like advanced filters or site-specific status do not hinder primary workflows.
Maintenance
ActivityInactive
ResponsivenessUnresponsive