clinicaltrialsgov-mcp-server-216ddf — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited clinicaltrialsgov-mcp-server-216ddf (Plugin) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<div align="center"> <h1>clinicaltrialsgov-mcp-server</h1> <p><b>Search ClinicalTrials.gov trials, retrieve study details and results, and match patients to candidate trials via MCP. STDIO or Streamable HTTP.</b> <div>7 Tools • 1 Resource • 1 Prompt</div> </p> </div>
<div align="center">
</div>
<div align="center">
</div>
<div align="center">
Public Hosted Server: https://clinicaltrials.caseyjhand.com/mcp
</div>
Search 600K+ studies on ClinicalTrials.gov, the US National Library of Medicine's trial registry. Fetch full study records and posted results, discover fields and valid values, and match a patient's profile to recruiting trials. No API key required.
| 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 |
| Resource | Description |
|---|---|
clinicaltrials://{nctId} | Fetch a single clinical study by NCT ID as JSON, with capped lists and results replaced by counts |
| Prompt | Description |
|---|---|
analyze_trial_landscape | Guides a data-driven clinical trial landscape analysis using the count and search tools |
clinicaltrials_search_studies <sub>tool</sub>query plus field-specific conditionQuery / interventionQuery / locationQuery / sponsorQuery / titleQuery / outcomeQuery, statusFilter / phaseFilter enums (case and spacing variants accepted), advancedFilter (AREA[FieldName]value / RANGE[min, max]), and geoFilter (distance(lat,lon,radius) with a mi/km suffix); pageSize 1–1000 (default 10; above the server's per-page cap, 200 by default, a page is served at the cap with truncated / shown / cap), pageToken cursor, sort on up to 2 fieldsnctId, briefTitle, overallStatus, phases, enrollmentCount, hasResults, …); fields (PascalCase leaves) selects a full-fidelity projection — full records run ~70KBblank_value, ids_not_found, field_invalid, enum_invalid, query_parse_error, geo_invalid, sort_invalid, page_token_invalid, rate_limitedclinicaltrials_get_study_record <sub>tool</sub>nctId, with optional locationLimit, outcomeLimit / referenceLimit, and nearLocation (lat, lon, radiusMi) to bound and sort locations — none has an upper bound; a value past the list returns all of itfiltersApplied reports upstream totals when a cap trims a list; resultsSection is replaced by resultsSummary counts. Typed errors: study_not_found, rate_limitedclinicaltrials_get_study_count <sub>tool</sub>clinicaltrials_search_studies, returning only totalCount — no study data fetchedblank_value, field_invalid, enum_invalid, query_parse_error, rate_limitedclinicaltrials_get_field_values <sub>tool</sub>fields (e.g. OverallStatus, Phase) — returns each field's type and top values with study counts (capped at 250 by the API), or min / max / avg for numeric and date fields and trueCount / falseCount for booleanslongest value; past 2,000 characters it is a preview flagged truncated, with the full length and a notice naming the clinicaltrials_search_studies call that returns the whole text. Free-text fields the API does not count distinct values on carry uniqueValuesCounted: false, marking their uniqueValuesCount of 0 as no countmultiValued flags fields whose per-value counts can sum above the study total. Typed errors: blank_value, field_invalid, rate_limitedclinicaltrials_get_field_definitions <sub>tool</sub>mode: search (keyword query, limit default 20, no upper bound), drill (dot-notation path), or overview — resolves the PascalCase names accepted by fields, advancedFilter, sort, and clinicaltrials_get_field_valuesblank_value, mode_mismatch, mode_requires, path_not_found, rate_limitedclinicaltrials_get_study_results <sub>tool</sub>nctIds fetched per call, with any further IDs (up to 500 entries) returned in deferredNctIds; sections (outcomes, adverseEvents, participantFlow, baseline, moreInfo), summary to condense a result set that can exceed 500KB per study, and outcomeLimit / adverseEventLimit with resumable outcomeOffset / seriousEventOffset / otherEventOffsetfetchErrors / studiesWithoutResults instead of a whole-batch failure, and canonicalNctId when an alias ID resolves to another study. Typed errors: blank_value, offset_not_applicable, rate_limitedclinicaltrials_find_eligible <sub>tool</sub>age (whole number 0–120) with optional ageUnit (years default, months, weeks, days) for infants and young children, sex (FEMALE / MALE / ALL), conditions[], location (country required, state / city optional), healthyVolunteer, recruitingOnly (default true), maxResults (up to 1000; each call returns at most 50, disclosing the rest via truncated / shown / cap and a replayable searchCriteria), locationLimit (no upper bound; a value past the matched sites returns them all)funnel reports match counts per filter stage, and a notice says inclusion/exclusion criteria were not checked (use clinicaltrials_get_study_record to review them)blank_value, rate_limitedclinicaltrials://{nctId} <sub>resource</sub>application/json, with locations, secondary/other outcomes, and references each capped at 50 — fixed server-side, no argumentsresultsSummary counts; truncated and filtersApplied disclose what was capped, with retrieval naming the tools that fetch the full datastudy_not_found, rate_limitedanalyze_trial_landscape <sub>prompt</sub>topic required; focusAreas (comma-separated) optionalBuilt 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:
fields/sort (case, whitespace, legacy aliases like RecruitmentStatus → OverallStatus) and logs each correction99999999) from searches and counts by default; includeUnknownEnrollment brings it backAgent-friendly output:
searchCriteria; clinicaltrials_get_study_results names canonicalNctId when an alias ID resolves to another studyclinicaltrials_get_study_results returns per-study fetchErrors / studiesWithoutResults instead of failing the whole batchreason codes (study_not_found, blank_value, …), and bounded lists carry a next*Offset only when more remainsA 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"
}
}
}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/mcpgit clone https://github.com/cyanheads/clinicaltrialsgov-mcp-server.gitcd clinicaltrialsgov-mcp-serverbun installAll 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; a positive integer. | 30000 |
CT_MAX_PAGE_SIZE | Most studies one clinicaltrials_search_studies page returns; an integer ≥ 1, values above 1000 clamp to 1000. | 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 for traces and metrics. | — |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | OTLP endpoint for log export. | — |
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.
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio bun run devcheck # Lint, format, typecheck, and security audit
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against specdocker build -t clinicaltrialsgov-mcp-server .
docker run --rm -p 3010:3010 clinicaltrialsgov-mcp-serverThe 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.
| 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. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, no console callssrc/mcp-server/*/definitions/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testApache-2.0 — see LICENSE for details.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.