Clinical Trials Data Server
Provide structured access to ClinicalTrials.gov data for searching, retrieving, and analyzing clinical trial information. Enable multi-parameter searches, detailed trial retrievals, and statistical an
Description
Clinical Trials MCP Server
An MCP (Model Context Protocol) server that provides structured access to ClinicalTrials.gov data, allowing LLMs to search, retrieve, and analyze clinical trial information.
Features
- Multi-parameter Search: Search trials by condition, intervention, sponsor, NCT ID, or combination
- Detailed Retrieval: Get comprehensive trial details including results, eligibility, outcomes
- Statistical Analysis: Analyze trial phases, field statistics, and data distributions
- Flexible Field Selection: Request specific data fields to optimize responses
- Error Handling: Robust error handling with meaningful error messages
Installation
- Install dependencies (Python runtime is required):
pip install -r requirements.txt
Note: JavaScript package managers like
npm,pnpm, orbunare not required for this project because all runtime dependencies are Python packages managed throughrequirements.txt.
- Run the MCP server:
python mcp_server.py
Deployment Options
Option 1: AWS Lambda + Function URL (Recommended - FREE & Fastest)
Cost: FREE for first 1M requests/month, then $0.20 per 1M requests Setup time: 2 minutes
-
Install AWS CLI and configure credentials:
aws configure # Enter your AWS Access Key ID, Secret Key, and region -
Deploy to Lambda:
./deploy-lambda.sh # Takes ~60 seconds, automatically creates function + public URL -
Copy the Function URL and configure Cloudflare:
npx wrangler secret put BACKEND_URL # Paste your Lambda Function URL when prompted -
Deploy Cloudflare Worker:
npx wrangler deploy
Your MCP server will be available at: https://<worker-name>.workers.dev/sse
Pros: Completely free tier, auto-scales, no server management Cons: Cold starts (~1-2s first request after idle)
Option 2: AWS App Runner (Always-on, Low Cost)
Cost: ~$5/month for 1 vCPU + 2GB RAM (pay per use) Setup time: 5 minutes
Use this if you need consistent performance without cold starts.
See deploy-apprunner.sh for instructions or deploy via AWS Console.
Option 3: Railway (Easiest, No AWS Required)
Cost: Free 500 hours/month, then $5/month Setup time: 3 minutes
- Sign up at railway.app
- New Project → Deploy from GitHub → Select this repo
- Copy deployment URL
npx wrangler secret put BACKEND_URL(paste Railway URL)npx wrangler deploy
Option 4: Render (Alternative to Railway)
Cost: Free 750 hours/month, then $7/month
Same process as Railway, uses render.yaml config.
Option 5: Local Development with Cloudflare Tunnel
If you want to test locally while keeping everything fronted by Cloudflare:
-
Start Python backend locally:
npm run backend:http # Listens on http://127.0.0.1:8081 -
Create Cloudflare tunnel:
# Install cloudflared brew install cloudflare/cloudflare/cloudflared # macOS # Create tunnel cloudflared tunnel --url http://127.0.0.1:8081 # Copy the https://*.trycloudflare.com URL -
Configure Worker for local dev: Create
.dev.vars:BACKEND_URL="https://your-tunnel.trycloudflare.com" -
Test locally:
npm run cf:dev # Worker runs at http://localhost:8788 -
Deploy to production:
npx wrangler secret put BACKEND_URL # Paste your tunnel URL npx wrangler deploy
Architecture
MCP Client (Playground/Claude)
↓
Cloudflare Worker (proxy)
↓
Python FastMCP Backend (Lambda/App Runner/Railway/Render)
↓
ClinicalTrials.gov API
Cost Comparison
| Option | Free Tier | After Free Tier | Best For |
|---|---|---|---|
| AWS Lambda | 1M requests/month | $0.20 per 1M | Personal use, low traffic |
| AWS App Runner | None | ~$5/month | Production, no cold starts |
| Railway | 500 hours/month | $5/month | Quick setup, no AWS |
| Render | 750 hours/month | $7/month | Alternative to Railway |
Recommendation: Start with AWS Lambda (completely free for most use cases)
Fully Cloudflare entrypoint (keep Python) using Cloudflare Tunnel
If you want everything to be fronted and managed by Cloudflare while keeping the Python backend, use Cloudflare Tunnel to expose your local/server backend securely and set the Worker to proxy to it.
-
Install and authenticate Cloudflared on the machine running your Python backend:
- macOS:
brew install cloudflare/cloudflare/cloudflared - Login:
cloudflared tunnel login
- macOS:
-
Quick dev tunnel (ephemeral URL):
- Start your backend:
npm run backend:http(listens onhttp://127.0.0.1:8081) - Open a tunnel:
cloudflared tunnel --url http://127.0.0.1:8081 - Copy the printed
https://<random>.trycloudflare.comand set it as your Worker secret:npx wrangler secret put FASTMCP_BASE_URL # paste: https://<random>.trycloudflare.com - Deploy the Worker:
npm run cf:deploy
- Start your backend:
-
Stable tunnel with your domain (recommended):
- Create a named tunnel:
cloudflared tunnel create clintrials-mcp - Route DNS (replace
mcp.yourdomain.comwith a hostname in a Cloudflare-managed zone):cloudflared tunnel route dns clintrials-mcp mcp.yourdomain.com - Create
~/.cloudflared/config.ymlwith:tunnel: clintrials-mcp credentials-file: /Users/<you>/.cloudflared/<tunnel-id>.json ingress: - hostname: mcp.yourdomain.com service: http://127.0.0.1:8081 - service: http_status:404 - Run it:
cloudflared tunnel run clintrials-mcp - Verify:
curl https://mcp.yourdomain.com/healthzreturns{ "status": "ok" } - Set the Worker secret to your stable hostname:
npx wrangler secret put FASTMCP_BASE_URL # paste: https://mcp.yourdomain.com - Deploy:
npm run cf:deploy
- Create a named tunnel:
Result:
- Users and MCP clients connect only to Cloudflare (
workers.devor your domain). - The Worker proxies
/sseand other API calls to your Python backend over the private tunnel, preserving SSE streams. - You keep your existing Python tools; no TypeScript porting required.
Available Tools
Search Tools
search_trials_by_acronym
Search clinical trials by study acronym (protocolSection.identificationModule.acronym).
Parameters:
acronyms(required): Array of acronyms to search for (e.g., ["TETON"]).max_studies(optional): Maximum number of studies to return (default: 50)fields(optional): Specific fields to return (Acronym is always included for filtering)exact_match(optional): Exact match when true; partial contains match when false (default: true)
Example:
{
"acronyms": ["TETON"],
"max_studies": 100,
"exact_match": true
}
search_trials_by_condition
Search clinical trials by medical condition(s).
Parameters:
conditions(required): Array of medical conditions to search formax_studies(optional): Maximum number of studies to return (default: 50)fields(optional): Specific fields to return
Example:
{
"conditions": ["lung cancer", "breast cancer"],
"max_studies": 100,
"fields": ["NCTId", "BriefTitle", "OverallStatus", "Phase"]
}
search_trials_by_intervention
Search clinical trials by intervention/treatment.
Parameters:
interventions(required): Array of interventions/treatments to search formax_studies(optional): Maximum number of studies to return (default: 50)fields(optional): Specific fields to return
Example:
{
"interventions": ["pembrolizumab", "immunotherapy"],
"max_studies": 50
}
search_trials_by_sponsor
Search clinical trials by sponsor/organization.
Parameters:
sponsors(required): Array of sponsor organizations to search formax_studies(optional): Maximum number of studies to return (default: 50)fields(optional): Specific fields to return
Example:
{
"sponsors": ["Pfizer", "Novartis"],
"max_studies": 75
}
search_trials_by_nct_ids
Retrieve specific clinical trials by NCT ID(s).
Parameters:
nct_ids(required): Array of NCT IDs to retrievefields(optional): Specific fields to return
Example:
{
"nct_ids": ["NCT04852770", "NCT01728545"],
"fields": ["NCTId", "BriefTitle", "DetailedDescription"]
}
search_trials_combined
Search clinical trials using multiple criteria.
Parameters:
conditions(optional): Array of medical conditionsinterventions(optional): Array of interventions/treatmentssponsors(optional): Array of sponsor organizationsterms(optional): Array of general search termsnct_ids(optional): Array of specific NCT IDs to includemax_studies(optional): Maximum number of studies to return (default: 50)fields(optional): Specific fields to return
Example:
{
"conditions": ["diabetes"],
"interventions": ["insulin"],
"sponsors": ["Novo Nordisk"],
"max_studies": 100
}
Detailed Retrieval Tools
get_trial_details
Get comprehensive details for a single clinical trial.
Parameters:
nct_id(required): NCT ID of the trial to retrievefields(optional): Specific fields to return
Example:
{
"nct_id": "NCT04852770",
"fields": ["ProtocolSection", "ResultsSection"]
}
Analysis Tools
analyze_trial_phases
Analyze the distribution of trial phases for given search criteria.
Parameters:
conditions(optional): Array of medical conditions to analyzeinterventions(optional): Array of interventions to analyzesponsors(optional): Array of sponsors to analyzemax_studies(optional): Maximum number of studies to analyze (default: 1000)
Example:
{
"conditions": ["cancer"],
"max_studies": 500
}
get_field_statistics
Get statistical information about field values.
Parameters:
field_names(optional): Array of field names to get statistics forfield_types(optional): Array of field types to filter by (ENUM, STRING, DATE, INTEGER, NUMBER, BOOLEAN)
Example:
{
"field_names": ["Phase", "OverallStatus"],
"field_types": ["ENUM"]
}
Search Result Fields
All search tools return a standardized, minimal set of fields to keep payloads small:
NCTId: Trial identifierBriefTitle: TitleAcronym: Study acronymInterventionName: Intervention namesCondition: Medical conditionsPhase: Trial phase(s)LeadSponsorNameandCollaboratorName: SponsorsHasResults: Whether results are posted
Use get_trial_details_batched to fetch full details once you’ve identified relevant trials.
Common Field Names
Here are some commonly used field names you can specify in the fields parameter:
Basic Information
NCTId- Clinical trial identifierBriefTitle- Short title of the studyOfficialTitle- Full official titleAcronym- Study acronymOverallStatus- Current status (e.g., RECRUITING, COMPLETED)
Study Design
Phase- Study phases (e.g., PHASE1, PHASE2, PHASE3)StudyType- Type of study (INTERVENTIONAL, OBSERVATIONAL)PrimaryPurpose- Main purpose (TREATMENT, PREVENTION, etc.)InterventionModel- Study design model
Participants
Condition- Medical conditions studiedEligibilityCriteria- Inclusion/exclusion criteriaHealthyVolunteers- Whether healthy volunteers are acceptedSex- Participant sex (MALE, FEMALE, ALL)MinimumAge- Minimum age for participationMaximumAge- Maximum age for participation
Interventions
InterventionName- Names of interventionsInterventionType- Types of interventions (DRUG, DEVICE, etc.)InterventionDescription- Detailed intervention descriptions
Outcomes
PrimaryOutcome- Primary endpoint measuresSecondaryOutcome- Secondary endpoint measuresOtherOutcome- Other outcome measures
Administrative
LeadSponsorName- Name of the lead sponsorCollaborator- Collaborating organizationsStartDate- Study start dateCompletionDate- Study completion dateLastUpdatePostDate- Last update date
Results
HasResults- Whether results are availableResultsFirstPostDate- Date results were first posted
Usage Examples
Search for COVID-19 vaccine trials, then fetch details in batches:
{
"tool": "search_trials_by_condition",
"arguments": {
"conditions": ["COVID-19"],
"max_studies": 50
}
}
Then, request detailed records in batches of 10:
{
"tool": "get_trial_details_batched",
"arguments": {
"nct_ids": ["NCT01234567", "NCT07654321"],
"batch_size": 10
}
}
Get detailed information about a specific trial:
{
"tool": "get_trial_details",
"arguments": {
"nct_id": "NCT04368728"
}
}
Analyze cancer trial phases by pharmaceutical companies:
{
"tool": "analyze_trial_phases",
"arguments": {
"conditions": ["cancer"],
"sponsors": ["Pfizer", "Merck", "Bristol-Myers Squibb"],
"max_studies": 1000
}
}
Search for trials with multiple criteria:
{
"tool": "search_trials_combined",
"arguments": {
"conditions": ["Alzheimer's disease"],
"interventions": ["monoclonal antibody"],
"max_studies": 100,
"fields": ["NCTId", "BriefTitle", "Phase", "OverallStatus", "LeadSponsorName"]
}
}
API Integration
This server integrates with the ClinicalTrials.gov API v2:
- Base URL:
https://clinicaltrials.gov/api/v2 - Uses proper error handling and retry logic
- Supports all major search parameters and filters
- Handles pagination automatically
- Respects API rate limits
Error Handling
The server includes comprehensive error handling:
- API request failures are caught and reported
- Invalid parameters are validated
- Network issues are handled gracefully
- Meaningful error messages are returned to the client
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
License
This project is open source and available under the MIT License.
HTTP Server Usage (Local)
The server runs in HTTP mode by default and is compatible with Claude Code, Smithery, and other MCP desktop servers that support Streamable HTTP.
- Install:
pip install -r requirements.txt - Run:
PORT=8081 python mcp_server.py - Health check:
curl -s http://localhost:8081/healthz→{ "status": "ok" }
Transport Modes (Auto)
This server now auto-detects the transport to run:
- Auto detection order:
MCP_TRANSPORT=stdio|httpforces a mode- If stdin is not a TTY (launched by an MCP host), uses
stdio - If
PORTis set, useshttp - Otherwise defaults to
http
Force a mode
- STDIO:
MCP_TRANSPORT=stdio python mcp_server.py - HTTP:
MCP_TRANSPORT=http PORT=8081 python mcp_server.py
Cline configuration examples
- HTTP entry:
"clinical-trials-mcp": {
"disabled": false,
"timeout": 120,
"type": "http",
"url": "http://localhost:8081",
"autoApprove": []
}
- STDIO entry:
"clinical-trials-mcp": {
"disabled": false,
"timeout": 120,
"type": "stdio",
"command": "/path/to/venv/bin/python",
"args": [ "/path/to/clintrials-mcp/mcp_server.py" ]
}
Docker
- Build:
docker build -t clinical-trials-mcp . - Run:
docker run -p 8081:8081 -e PORT=8081 clinical-trials-mcp
CORS Preflight Test
curl -i -X OPTIONS \
-H 'Origin: http://localhost:3000' \
-H 'Access-Control-Request-Method: POST' \
http://localhost:8081/
You should see HTTP/1.1 200 OK and permissive access-control-allow-* headers.
Smithery
This repo includes a Dockerfile and smithery.yaml configured for container runtime with HTTP transport. Deploy via https://smithery.ai/new and ensure the app listens on the PORT environment variable (Smithery sets it to 8081).
Reviews (0)
No reviews yet. Be the first to review!
Comments (0)
No comments yet. Be the first to share your thoughts!