clinicaltrialsgov-mcp-server
Version:
Search ClinicalTrials.gov trials, retrieve study details and results, and match patients to eligible trials via MCP. STDIO or Streamable HTTP.
79 lines • 3.96 kB
TypeScript
/**
* @fileoverview ClinicalTrials.gov REST API v2 client with retry, rate limiting, and timeout.
* @module services/clinical-trials/clinical-trials-service
*/
import type { Context } from '@cyanheads/mcp-ts-core';
import { type ServerConfig } from '../../config/server-config.js';
import { type FieldIndexEntry } from './field-search.js';
import type { FieldNode, FieldValueStats, PagedStudiesResponse, SearchParams, Study } from './types.js';
/** Constructor options for overriding retry/backoff/validation behavior (primarily for tests). */
export interface ClinicalTrialsServiceOptions {
baseBackoffMs?: number;
maxBackoffMs?: number;
maxRetries?: number;
/**
* Whether to validate `fields` against the cached metadata index before
* making API calls. Defaults to true; lazy-fetches /studies/metadata on
* first use, then caches the index in-memory.
*/
validateFieldsLocally?: boolean;
}
export declare class ClinicalTrialsService {
private readonly baseUrl;
private readonly timeoutMs;
private readonly maxPageSize;
private readonly maxRetries;
private readonly baseBackoffMs;
private readonly maxBackoffMs;
private readonly validateFieldsLocally;
private lastRequestAt;
private fieldIndexPromise;
constructor(config: ServerConfig, options?: ClinicalTrialsServiceOptions);
/** Search studies with query, filters, pagination, and field selection. */
searchStudies(params: SearchParams, ctx: Context): Promise<PagedStudiesResponse>;
/** Fetch a single study by NCT ID. */
getStudy(nctId: string, ctx: Context): Promise<Study>;
/** Fetch multiple studies by NCT IDs in a single request. Returns identification and results section data. */
getStudiesBatch(nctIds: string[], ctx: Context): Promise<Study[]>;
/** Get field definitions (metadata tree) from the data model. */
getMetadata(includeIndexedOnly: boolean, ctx: Context): Promise<FieldNode[]>;
/** Get field value statistics for the specified fields. */
getFieldValues(fields: string[], ctx: Context): Promise<FieldValueStats[]>;
/**
* Mark each stat as multi-valued by checking the metadata node `type` for an
* array marker (`[]`, e.g. `Phase[]`, `text[]`) — the durable source of
* cardinality. Note: the stat's own `type` (`ENUM`/`STRING`) is the value
* domain, not the array marker, so the metadata node type is the only signal.
* Reuses the cached field index (no round-trip); fails open silently if the
* metadata index is unavailable.
*/
private annotateMultiValued;
/**
* Search the field model by keyword, returning ranked matches with paths and
* types plus the pre-cap match total for accurate truncation disclosure.
*/
searchFieldDefinitions(query: string, limit: number, ctx: Context): Promise<{
entries: FieldIndexEntry[];
total: number;
}>;
/** Lazy-load and memoize the flattened field index from /studies/metadata. */
private getFieldIndex;
/**
* Apply unambiguous fixes (whitespace, case-only) to field names before
* validation. Returns the corrected list — anything still invalid falls
* through to validateFields and surfaces the structured did-you-mean error.
* Logs corrections via ctx.log.notice so operators can spot recurring LLM
* mistakes without forcing a tool-call round-trip.
*/
private normalizeFields;
/** Reject invalid field names locally with did-you-mean suggestions. */
private validateFields;
private buildSearchQuery;
private throttle;
private fetchJson;
}
/** Initialize the ClinicalTrials service. Call from createApp setup(). */
export declare function initClinicalTrialsService(): void;
/** Get the initialized ClinicalTrials service instance. */
export declare function getClinicalTrialsService(): ClinicalTrialsService;
//# sourceMappingURL=clinical-trials-service.d.ts.map