Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
This Spring AI-based MCP server has 4 tools with acceptable naming and basic descriptions, but suffers from incomplete parameter documentation, missing output schemas, and lack of error recovery guidance. Tool names follow verb-noun convention (createAppointment, getAllBotConfigs, getBotConfigById, getBotConfigsByName), which is correct. However, parameter descriptions are minimal, output schemas are entirely undocumented, and error handling provides no recovery guidance. The server registers tools via Spring's @Tool annotation with explicit names and basic descriptions, but does not document what fields clients should expect in responses or how to handle errors gracefully. The parameter for createAppointment (appointmentCreationRequestDTO) is documented in the schema with correct JSON Schema types (string, date-time), but other tools have sparse descriptions. No tool documents pagination behavior, result limits, or output structure. Security is reasonable (no secrets in params), but composition could be improved, the tools appear to be thin wrappers around backend services without cross-tool chaining guidance.
Tools (4)
createAppointmentwritesource verified69/100
Create an appointment with appointment date and license plate.
No output schemas documented for any tool. Clients and LLMs cannot know what fields to expect. Response shapes are inferred from return types (List<BotConfigEntity>, String) but internal field structure is completely undocumented.
Parameter descriptions are absent or minimal for discovery tools. getAllBotConfigs() has no parameters but provides no guidance on pagination, result limits, or response structure. getBotConfigsByName() accepts 'name' but does not specify: is it exact match or substring search? Fuzzy? Case-sensitive?
Error responses provide no recovery guidance. In AppointmentTools, validation errors return plain strings like 'ERROR: License plate is required.' An LLM cannot infer what to do next, ask the user? Retry? Abandon the operation? Errors should categorize as retryable, user-fixable, or fatal.
createAppointment
Recommendations
Document output schemas for all tools. For getAllBotConfigs() and getBotConfigsByName(), explicitly define: List<BotConfigEntity> returns an array of objects with fields {id: integer, name: string, description: string?, ...}. For getBotConfigById(), return a single BotConfigEntity object with the same structure. For createAppointment(), document the response structure (success message with appointment ID? confirmation object?).
Add pagination support to list tools. Modify getAllBotConfigs() and getBotConfigsByName() to accept optional parameters: limit (1-100, default 20), offset (0 or higher). Return a structured response: {items: [...], total: count, has_more: boolean}. Document result limits in tool descriptions.
Improve parameter descriptions. For getBotConfigsByName(), clarify: 'Search for bot configurations by exact name match (case-sensitive) or substring search?' For createAppointment(), add: 'Appointment date must be in the future and within 12 months.' For getBotConfigById(), add: 'The unique numeric identifier of the bot configuration (e.g. 1, 42, 100).'
Add error categorization and recovery guidance. Instead of 'ERROR: License plate is required', return: '{error: "MISSING_FIELD", field: "licensePlate", message: "License plate is required. Ask the user for their vehicle license plate.", retryable: false, recovery: "Request the license plate from the user."}'. Apply this pattern to all validation errors.
Document idempotency. Add to createAppointment description: 'This operation is [idempotent / non-idempotent]. Retrying with the same inputs will [result in duplicate appointments / safely return the existing appointment]. Consider using an idempotency key to prevent duplicates.' Implement idempotency or provide clear guidance.
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
No pagination or result limiting documented. getAllBotConfigs() returns List<BotConfigEntity> with no limit, offset, or pagination support visible. If a system has thousands of bot configs, returning all at once will exhaust context and waste tokens. Tool description should declare limits and support pagination params.
Parameter 'name' in getBotConfigsByName() uses a generic string with minimal description. No guidance on: substring vs exact match? Case sensitivity? Partial matching rules? This forces the LLM to guess or iterate through test calls.
No idempotency guarantee documented for createAppointment(). If an agent retries due to transient error, will it create a duplicate appointment? Tool description and implementation should clarify idempotency behavior or provide an idempotent request ID parameter.
Tool composition incomplete. createAppointment accepts licensePlate and appointmentDate, but there is no search_vehicle or get_vehicle_by_plate tool to help an LLM validate or look up the plate first. If the provided plate is invalid, createAppointment returns a validation error with no recovery path.
createAppointment
Add tool annotations. Use Spring AI's destructiveHint and idempotentHint to mark createAppointment as destructive (WRITE risk) and clarify idempotency. E.g., @Tool(name="createAppointment", description="...", destructiveHint=true, idempotentHint=false).
Add validation and return structured errors. Instead of logging and returning plain strings, return JSON with error codes: {status: "ERROR", code: "INVALID_LICENSE_PLATE", message: "License plate must be 2-8 characters. You provided: '${value}'.", retryable: false}. This lets the LLM parse and respond to specific error types.
Provide discovery/lookup tools. Add a search_vehicles(search_term) or get_vehicle(license_plate) tool to help agents validate plates before calling createAppointment(). This reduces failed appointment creation attempts.
Document tool composition. In README or tool descriptions, note: 'To create an appointment, first use getBotConfigById() to confirm the bot is active, then call createAppointment(). Results from getBotConfigById() include an id that can be chained to other operations.' Explicitly list which tools return IDs used by other tools.