
ClinicalTrials.gov MCP Server
MCPSearches 600,000+ studies registered on ClinicalTrials.gov, shows protocols and posted results (efficacy, adverse events), and matches patients to recruiting trials by age, sex, condition and location. Public data, no API key; needs Node.js 24+. Unofficial; results must be reviewed by a doctor.
clinicaltrialsgov-mcp-server
Search ClinicalTrials.gov trials, retrieve study details and results, and match patients to candidate trials via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://clinicaltrials.caseyjhand.com/mcp
Overview
Clinical trial data from the ClinicalTrials.gov REST API v2 — the US National Library of Medicine's registry of 600K+ clinical trial studies. Search trials, fetch full study records and posted results, discover field names and valid values, and match patient demographics to candidate recruiting trials. Public, read-only, no authentication required. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
| Tool | Description |
|---|---|
clinicaltrials_search_studies | Search studies with full-text and field-specific queries, status/phase/geographic filters, pagination, sorting, and field selection |
clinicaltrials_get_study_record | Fetch a single study by NCT ID — full protocol record with optional location/outcome/reference caps |
clinicaltrials_get_study_count | Fast total study count for a query, without fetching data |
clinicaltrials_get_field_values | Discover valid values for API fields, with per-value study counts |
clinicaltrials_get_field_definitions | Resolve valid field names — keyword search, path drill-down, or top-level overview |
clinicaltrials_get_study_results | Fetch posted results — outcomes, adverse events, participant flow, baseline — for completed studies |
clinicaltrials_find_eligible | Match patient demographics and conditions to candidate recruiting trials, without checking inclusion/exclusion criteria |
Resources
| Resource | Description |
|---|---|
clinicaltrials://{nctId} | Fetch a single clinical study by NCT ID as JSON, with capped lists and results replaced by counts |
Prompts
| Prompt | Description |
|---|---|
analyze_trial_landscape | Guides a data-driven clinical trial landscape analysis using the count and search tools |
Capability reference
clinicaltrials_search_studies tool
- Free-text
queryplus field-specificconditionQuery/interventionQuery/locationQuery/sponsorQuery/titleQuery/outcomeQuery,statusFilter/phaseFilterenums (case and spacing variants accepted; aphaseFilterentry that names no phase, such as anORexpression, fails asenum_invalid),advancedFilter(AREA[FieldName]value/RANGE[min, max]), andgeoFilter(distance(lat,lon,radius)with ami/kmsuffix);pageSize1–200 (default 10),pageTokencursor,sorton up to 2 fields - Returns a compact per-study index by default (
nctId,briefTitle,overallStatus,phases,enrollmentCount,hasResults, …);fields(PascalCase leaves) selects a full-fidelity projection — full records run ~70KB - Typed errors:
blank_value,ids_not_found,field_invalid,enum_invalid,query_parse_error,geo_invalid,sort_invalid,page_token_invalid,rate_limited
clinicaltrials_get_study_record tool
- Full protocol record by
nctId, with optionallocationLimit(≤500),outcomeLimit/referenceLimit(≤100), andnearLocation(lat,lon,radiusMi) to bound and sort locations filtersAppliedreports upstream totals when a cap trims a list;resultsSectionis replaced byresultsSummarycounts. Typed errors:study_not_found,rate_limited
clinicaltrials_get_study_count tool
- Same query and filter surface as
clinicaltrials_search_studies, returning onlytotalCount— no study data fetched - Typed errors:
blank_value,field_invalid,enum_invalid,query_parse_error,rate_limited
clinicaltrials_get_field_values tool
- One or more PascalCase
fields(e.g.OverallStatus,Phase) — returns each field's type and top values with study counts (capped at 250 by the API), ormin/max/avgfor numeric and date fields andtrueCount/falseCountfor booleans multiValuedflags fields whose per-value counts can sum above the study total. Typed errors:blank_value,field_invalid,rate_limited
clinicaltrials_get_field_definitions tool
mode:search(keywordquery,limit≤100, default 20),drill(dot-notationpath), oroverview— resolves the PascalCase names accepted byfields,advancedFilter,sort, andclinicaltrials_get_field_values- Typed errors:
blank_value,mode_mismatch,mode_requires,path_not_found,rate_limited
clinicaltrials_get_study_results tool
- Up to 20
nctIdsper call;sections(outcomes,adverseEvents,participantFlow,baseline,moreInfo),summaryto condense a result set that can exceed 500KB per study, andoutcomeLimit(≤100) /adverseEventLimit(≤500) with resumableoutcomeOffset/seriousEventOffset/otherEventOffset - Per-study
fetchErrors/studiesWithoutResultsinstead of a whole-batch failure, andcanonicalNctIdwhen an alias ID resolves to another study. Typed errors:blank_value,offset_not_applicable,rate_limited
clinicaltrials_find_eligible tool
age,sex(FEMALE/MALE/ALL),conditions[],location(countryrequired,state/cityoptional),healthyVolunteer,recruitingOnly(default true),maxResults(≤50),locationLimit(≤500)- Each candidate's locations are bounded to the sites matching the requested location, plus one recruiting site when none of those is open;
funnelreports match counts per filter stage (condition → +location → +demographics) - Candidates are matched on age, sex, location, recruitment status, and a fuzzy condition search; a
noticeon every non-empty response says inclusion/exclusion criteria were not checked and points toclinicaltrials_get_study_recordfor review - Typed errors:
blank_value,rate_limited
clinicaltrials://{nctId} resource
- Full protocol record as
application/json, with locations, secondary/other outcomes, and references each capped at 50 — fixed server-side, no arguments - Results data is replaced by
resultsSummarycounts;truncatedandfiltersApplieddisclose what was capped, withretrievalnaming the tools that fetch the full data - Typed errors:
study_not_found,rate_limited
analyze_trial_landscape prompt
- Arguments:
topicrequired;focusAreas(comma-separated) optional - Returns one user message pointing the agent at the count, search, field-discovery, and results tools for a data-driven landscape analysis
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
ClinicalTrials.gov-specific:
- Type-safe client for the ClinicalTrials.gov REST API v2 — public, no authentication or API keys required
- Serialized request queue enforcing ClinicalTrials.gov's ~1 req/sec rate limit, with retry and exponential backoff on 429/5xx responses
- Auto-corrects field names passed to
fields/sort— case/whitespace fixes and known legacy aliases (e.g.RecruitmentStatus→OverallStatus) — before validating, logging every correction; a comma- or pipe-joinedfieldsentry ("NCTId,BriefTitle") is split into separate names first, each name kept once - Detects upstream HTML error pages returned with a JSON content-type and retries rather than parsing them as data
- Geographic proximity search and nearest-site re-ranking, with no geocoding dependency
- Excludes ClinicalTrials.gov's "unknown" enrollment sentinel (
99999999) from searches and counts by default —includeUnknownEnrollmentbrings it back, and annctIdslookup never filters it
Agent-friendly output:
- Provenance —
clinicaltrials_search_studies/clinicaltrials_get_study_count/clinicaltrials_find_eligibleechosearchCriteriaon every call, includingsentinelFilterActivewhen the default unknown-enrollment exclusion applies, andclinicaltrials_get_study_resultsnamescanonicalNctIdwhen a previous (alias) ID resolves to a different study - Graceful partial failure —
clinicaltrials_get_study_resultsreturns per-studyfetchErrors/studiesWithoutResultsrows instead of failing the whole batch when one ID is malformed or lacks results - Discriminated output — typed error
reasoncodes per tool (study_not_found,blank_value,offset_not_applicable, …), and bounded lists (filtersApplied,locationSummary) carry anext*Offsetonly when more remains, so callers branch on presence instead of parsing text - Response shaping —
clinicaltrials_search_studiesandclinicaltrials_find_eligiblereturn a compact per-study index or location-bounded set by default instead of the ~70KB full record, escalating to full fidelity only viafieldsorclinicaltrials_get_study_record
Getting started
Public Hosted Instance
A public instance is available at https://clinicaltrials.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"clinicaltrialsgov-mcp-server": {
"type": "streamable-http",
"url": "https://clinicaltrials.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"clinicaltrialsgov-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["clinicaltrialsgov-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"clinicaltrialsgov-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "clinicaltrialsgov-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"clinicaltrialsgov-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/clinicaltrialsgov-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
Installation
- Clone the repository:
git clone https://github.com/cyanheads/clinicaltrialsgov-mcp-server.git
- Navigate into the directory:
cd clinicaltrialsgov-mcp-server
- Install dependencies:
bun install
Configuration
All configuration is optional — the server works with defaults and no API keys.
| Variable | Description | Default |
|---|---|---|
CT_API_BASE_URL | ClinicalTrials.gov API base URL. | https://clinicaltrials.gov/api/v2 |
CT_REQUEST_TIMEOUT_MS | Per-request timeout in milliseconds. | 30000 |
CT_MAX_PAGE_SIZE | Maximum page size cap. | 200 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry tracing. | false |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP base URL; traces export to /v1/traces, metrics to /v1/metrics. Unset exports nothing. | — |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Opt-in OTLP log export; the base endpoint never enables it. | — |
LOG_TOOL_FAILURE_PAYLOADS | Log each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted. | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdio -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, and security audit bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t clinicaltrialsgov-mcp-server .
docker run --rm -p 3010:3010 clinicaltrialsgov-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/clinicaltrialsgov-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources/prompts and inits the ClinicalTrials.gov service. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/mcp-server/resources | Resource definitions (*.resource.ts). |
src/mcp-server/prompts | Prompt definitions (*.prompt.ts). |
src/services/clinical-trials | ClinicalTrials.gov REST API v2 client — retry, rate limiting, field search, types. |
tests/ | Unit and integration tests. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging, noconsolecalls - Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts - Validate raw API responses, normalize to domain types, and never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
관련 리소스

DICOM MCP
MCPConnects to PACS and other DICOM servers: query images by patient, study and series, read text from PDF reports embedded in DICOM, and forward series to AI nodes such as segmentation. Needs uv and a YAML config. Not for clinical use or real patient data (per the author).
ChristianHinge/dicom-mcp102
Snowstorm MCP Server
MCPSNOMED International's official MCP: search and validate SNOMED CT terms, browse concept hierarchies and expand value sets in the International, US, UK, Australian and other editions. Hosted, no account. Unlicensed use is evaluation only, not for coding records. Clinicians should review.
IHTSDO/snowstorm-mcp-server8
OpenClaw Medical Skills
Skill869 medical skills compiled by FreedomIntelligence from a dozen open-source libraries: SOAP notes, discharge summaries, drug interactions, clinical guidelines, PubMed/FDA lookups, genomics and device regulation. Made for OpenClaw, usable elsewhere; some need API keys. Doctors must review output.
FreedomIntelligence/OpenClaw-Medical-Skills3.1k
Claude for Healthcare
PluginAnthropic's official healthcare plugin for the US system: extract data from clinical notes, assign ICD-10 and CPT/HCPCS codes, review prior auths, screen for fraud and draft trial protocols, with hosted CMS, NPI and PubMed connectors. FHIR access needs API rights; clinicians must review.
anthropics/healthcare425
Agent Skills for Healthcare & Life Sciences
Skill42 official AWS skills for healthcare and life sciences: medical coding and terminology mapping, FHIR/HL7 parsing, claims and prior authorization rules, medical imaging, pharmacoepidemiology and genomics, per US standards. Some need local software. Not for clinical decisions; expert review required.
awslabs/hcls-agent-skills63
ToolUniverse
MCPFrom Harvard Medical School's Zitnik Lab: one MCP connecting 1,000+ scientific tools and databases for drugs and targets, genes and proteins, clinical trials, FDA data and PubMed, for biomedical and drug research. Runs with uv; some sources need API keys; medical conclusions need expert review.
mims-harvard/ToolUniverse1.7k