Static source inference · medium confidence · detected: stateful session
Deprecated protocol patterns detected
Summary
The server provides 8 read-only tools with reasonable naming conventions (all verb-starting: search_*, get_, analyze_), but has significant gaps in schema visibility, parameter descriptions, and error handling guidance. Tool definitions are partially inferred from package.json rather than directly visible in the Python source code provided (mcp_server.py is truncated). All tools are READ_ONLY risk category, which is positive for safety. Descriptions are present but vary in completeness. Parameter descriptions exist but lack constraint details (ranges, patterns, enum declarations). Output schemas are not documented in the provided code. Error handling and recovery guidance are absent.
Tool definitions inferred from package.json rather than visible in Python source code. The mcp_server.py implementation is truncated, preventing verification of actual tool registration, parameter validation, and error handling. Cannot confirm schemas are enforced at runtime.
Output schemas not documented. Tools return results but no structured schema is visible for pagination fields, trial object structure, or statistics format. LLMs cannot predict response structure for downstream reasoning.
Expose tool registration directly in mcp_server.py using FastMCP decorators with complete schema definitions. Include input_schema with JSON Schema types, minLength/maxLength, minimum/maximum, enum constraints, and pattern rules for all parameters.
Document output schemas for each tool. Example: search_trials_combined returns { trials: [ { nct_id, brief_title, phase, status, sponsor, ... } ], total: int, next_offset?: int }. Make this explicit in a schema definition or docstring.
Replace free-form 'fields' array with an enum of valid field names OR a new tool like list_available_trial_fields() that returns { categories: { identification: [...], status: [...], ... }, fields: [...] } so LLMs can discover valid options.
Add enum constraints to 'status' (recruiting|not_yet_recruiting|active|completed|suspended|terminated|withdrawn) and 'phase' (Phase 1|Phase 2|Phase 3|Phase 4|Early Phase 1|N/A) in search_trials_combined. Move examples from descriptions to enum declarations.
Add numeric bounds: limit [1-10000], offset [0-infinity]. Document that limit defaults to 10 and typical query returns 10-100 trials to guide LLM pagination decisions.
Document pagination pattern: if search returns 10 trials and total is 150, explain how to call again with offset=10 to get next batch. Include a next_offset field in responses for clarity.
Add error recovery guidance: 'If no trials found, try broadening the search (remove phase filter) or search by a parent condition (e.g., "cancer" instead of "melanoma"). If NCT ID is invalid, use search_trials_combined to verify it exists first.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Stateful initialize / Mcp-Session-Id (removed; protocol is stateless) - make each request self-contained
Parameter constraints not formalized. 'limit' (max 10000) and 'offset' lack minimum bounds, enum validation, or format patterns. 'fields' array accepts arbitrary strings with no enum of valid field names. 'status' and 'phase' in search_trials_combined have no enum constraint, descriptions say 'e.g. recruiting' but do not enforce valid values.
Error handling and recovery guidance missing. No indication of what errors are retryable, what status codes mean, or what the LLM should do if a search returns no results or a trial NCT ID is invalid.
Parameter descriptions are generic. 'fields' (array) states 'Specific fields to return in results (optional, uses defaults if not specified)' but does not name the available fields or link to the field categories defined in code (identification, status, conditions, design, interventions, arms, outcomes, eligibility, locations, sponsors). LLM cannot discover valid field names.
'limit' parameter default is 10 but max is 10000, a 1000x range with no guidance on when to use each. No indication of typical result sizes or performance implications of large limits.
No tool annotations (readOnlyHint, idempotentHint). While all tools are READ_ONLY by risk classification, the protocol does not carry this metadata in tool definitions, so clients cannot reason about retry safety or side effects.
analyze_trial_phases accepts only optional parameters (condition, intervention, sponsor). No clarity on what 'statistics' means: count by phase? enrollment by phase? success rates? Description does not specify output structure.
analyze_trial_phases
Clarify analyze_trial_phases output. Example: Returns { phases: { 'Phase 1': { count: 42, enrollment: 500 }, ... }, total: 156 } so LLMs can format results for users.
Add tool annotations: readOnlyHint=true for all 8 tools so clients know these are safe to retry and have no side effects.
For search_trials_by_nct_ids, clarify the 'nct_ids' parameter: 'Array of National Clinical Trial identifiers (format: NCTxxxxxxxx, e.g., NCT03088969). Invalid IDs are silently ignored; missing IDs return empty results.' This prevents LLM confusion.
Expand get_trial_details description: 'Use this to fetch comprehensive trial information (arms, eligibility, outcomes, locations) after narrowing with search tools. Returns all available fields unless fields parameter filters them.'
Add a new discovery tool: list_trial_search_options() returns { trial_statuses: [...], trial_phases: [...], intervention_types: [...], study_types: [...] } so LLMs self-discover valid filters without trial-and-error searches.