Spring Boot AI MCP Server that exposes cake inventory and order management as MCP tools, with integration to Ollama LLM and filesystem access via MCP client
This MCP server exposes 3 tools for a cake ordering system. Tool definitions are partially visible in the source code and service classes. All three tools have descriptions and declared input schemas, but descriptions are brief (30-60 chars) and lack critical context about when to use each tool, prerequisites, and return structure. Parameter descriptions are present but minimal. Error handling is not visible in the provided code. The server uses Spring AI's MethodToolCallbackProvider to register tools, but explicit tool annotations (readOnlyHint, destructiveHint, idempotentHint) are not present in the visible code. Output schemas are not documented. Tool definitions appear to be inferred from method signatures rather than explicitly registered with formal descriptions.
Tools (3)
createOrderwrite50/100
Create a new order with cakeId and size. Returns the generated order id.
getAvailableCakesread only50/100
Return available cakes and sizes. Provide a catalog of cakes when user asks for available cakes.
Descriptions are too brief (30-60 chars) and lack actionable context. E.g., 'Return available cakes and sizes' does not explain WHEN to call this vs other discovery tools, what structure is returned, or how results guide downstream calls to createOrder.
Output schemas are not documented in any visible code. LLMs cannot plan downstream tool calls or extract results without knowing what fields are returned. E.g., does getAvailableCakes return [{id, name, sizes}] or {cakes: [...]}?
Parameter descriptions are sparse. E.g., getOrderStatus's 'orderId' parameter is described as 'Order Status e.g. orderId 1234', this conflates the parameter name with its description and embeds an example value. LLMs may reuse '1234' literally instead of adapting to actual order IDs.
getOrderStatus
Recommendations
Expand tool descriptions to 100-200 characters. Each must answer: What does it do? When should the LLM call it? What does it return? E.g., 'Retrieve the complete cake catalog with available sizes and pricing. Call this first to show users options before creating an order. Returns a list of cakes, each with id, name, description, available sizes, and prices.'
Add explicit output schema documentation for each tool. Define the return type as a JSON object with named fields, types, and descriptions. E.g., getAvailableCakes returns: {cakes: [{id: string, name: string, description: string, sizes: ["small", "medium", "large"], prices: {[size]: number}}]}
Replace example values in parameter descriptions with formal constraints. For createOrder's 'size' parameter, use an enum: {type: 'string', enum: ['small', 'medium', 'large'], description: 'Cake size.'}. Remove 'e.g. small/medium/large' from the description text.
Fix the getOrderStatus parameter description. Change from 'Order Status e.g. orderId 1234' to 'The unique identifier of the order (e.g. a numeric ID or UUID). Use this to retrieve order status, estimated delivery, and payment details.' Separate the parameter name from its documentation.
Add tool annotations to the tool registration. Mark getAvailableCakes and getOrderStatus with readOnlyHint: true; mark createOrder with destructiveHint: true (or idempotentHint: true if retries are safe). These help agents reason about side effects and error recovery.
Implement structured error handling. For createOrder, if cakeId is invalid, return: {error: 'Invalid cakeId', valid_options: ['cake001', 'cake002', ...], suggestion: 'Call getAvailableCakes() to see available cakes.'}. This guides the LLM to self-correct without a separate discovery call.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are missing. The tool risk metadata indicates createOrder is WRITE and getOrderStatus/getAvailableCakes are READ_ONLY, but these are not declared in the tool schema or registration code visible.
No error handling guidance is visible. If createOrder fails due to invalid cakeId or size, there is no indication of what the LLM should do next or how to correct the input. Error responses likely expose raw exceptions rather than actionable guidance.
createOrder parameter 'size' lacks constraint documentation. Description states 'Size, e.g. small/medium/large' but does not declare these as an enum, leaving room for invalid values like 'xl' or 'tiny'. Formal constraints (enum, pattern) are missing.
Tool definitions appear to be inferred from method signatures in CakeInventoryMcpService and OrderMcpService rather than explicitly registered with full schemas. The McpServerApplication.java code shows MethodToolCallbackProvider.builder().toolObjects(...).build(), but actual method signatures and detailed parameter/return documentation are not visible in the provided source.
getAvailableCakesgetOrderStatuscreateOrder
Document parameter relationships. If createOrder's size parameter must match one of the sizes returned by getAvailableCakes, state this explicitly: 'Size must be one of the sizes returned by getAvailableCakes(). Call getAvailableCakes first to see available options for the selected cakeId.'
Add a dependency hint to getOrderStatus: 'Use createOrder() to generate an order ID first. Without a valid order ID, this tool will fail.'
Validate inputs early and return clear errors. For createOrder(cakeId='invalid', size='small'), return a structured error like {error: 'Invalid cakeId', message: 'Cake "invalid" not found. Available cakes: cake001 (Chocolate), cake002 (Vanilla), ...', error_code: 'INVALID_CAKE_ID', retryable: false} instead of a 500 error or exception stack trace.
If getAvailableCakes returns a large catalog, add pagination support: limit, offset, and total fields. Document in the description: 'Returns up to 20 cakes per call. Use offset to retrieve additional cakes.'