A Spring Boot application that implements an MCP server for medical data management, providing tools to manage patient information and medical reports through a PostgreSQL database backend
Spring AI MCP server exposes 5 tools with basic schemas and descriptions, but lacks production-grade definition quality. All tools have names starting with action verbs (list_, get_, add_, update_) and include descriptions, which meets baseline naming conventions. However, descriptions are extremely brief (8-53 chars), well below the 50-200 char optimized range for LLM selection. Input schemas are present and correctly typed, but lack depth in parameter descriptions, most parameter descriptions are single-phrase clarifications rather than actionable guidance for LLM usage (e.g., 'The ID of the patient' vs 'The unique numeric patient ID (1-999999). Required to match patient records in the system.'). No output schemas are documented, critical for chaining and downstream tool calls. Error handling is not visible in the provided code; no guidance for recovery or retry strategies. Security posture is opaque, no evidence of input validation, injection protection, or audit logging. Tools lack the contextual richness that would guide LLM selection and parameter binding.
Add a new medical report for a patient by patient ID, diagnosis, and content
Get information about a patient by name
Get a list of all patients
Get all medical reports for a patient by patient ID
Update an existing medical report by report ID, new diagnosis, and new content
Descriptions critically underdeveloped (8-53 chars, below 50-char minimum). Examples: 'Get a list of all patients' (28 chars), 'Get all medical reports for a patient by patient ID' (53 chars). Baseline for A+ tools is 50-200 chars with LLM-optimized guidance on WHEN and WHY to call the tool.
Parameter descriptions are minimal placeholders (e.g., 'The name of the patient to retrieve'). Missing: expected format, constraints (length, type), dependency relationships, and guidance for LLM value binding. Baseline: 72 char average per param across A+ tools.
No output/response schemas documented. LLMs cannot plan downstream calls or extract required fields without knowing what each tool returns. For example, does list_patients() return patient objects with {id, name, age, email}? Unknown. Does add_medical_report() return the reportId for use in update_medical_report()? Not documented.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 54 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 30 | - | v1 |
No pagination support visible on list_* tools. list_patients and list_reports_for_patient lack page/offset, limit, and total_count parameters. Large result sets will blow context windows; LLMs cannot bound results or iterate through pages.
No error handling guidance visible. Code does not show try-catch blocks, validation logic, or error response schemas. LLMs will receive raw exceptions or generic 500 errors with no recovery path (e.g., 'User not found. Try search_users() first.').
Destructive tools (add_medical_report, update_medical_report) lack confirmation or dry-run support. No evidence of confirmation_required pattern or reversibility indicators. Agents can accidentally spam the database or overwrite records without safeguards.
Security posture opaque. No visible input validation, SQL injection protection, or audit logging in provided code. No scopes declared for tools. Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are missing, LLMs cannot infer tool safety without explicit hints.
Tool chaining support is unclear. When get_patient_info returns a patient, does it include a patientId field that add_medical_report and list_reports_for_patient accept? Response field naming must match parameter naming (RFC mxe:response-field-naming). Not documented.