Backend application for SpeisList - a collaborative shopping list and inventory management system with MCP server capabilities
The SpeisList backend service implements 14 tools with reasonable structure and consistent verb-noun naming. All tools have descriptions and input schemas are visible in the source code. However, there are significant gaps in schema completeness, parameter descriptions, and error handling guidance. Output schemas are not documented, and descriptions lack depth about when to use each tool and what the results contain. The server uses Spring AI's @McpTool annotation framework correctly, but the implementation falls short of production-grade quality standards.
Adds an item to an inventory.
Adds an item to a shopping list.
Creates a new inventory for the user.
Creates a new shopping list for the user.
Retrieves all inventories for the user.
Retrieves all shopping lists for the user.
Invites a user to an inventory.
No output schemas documented. Tools like get-inventories, get-shopping-lists, and all create/update operations return DTOs (InventoryDTO, InventoryItemDTO, ShoppingListDTO) but the response structure is never specified. LLMs cannot plan downstream operations or extract needed fields without knowing the response schema.
Descriptions are generic and lack context about when to call each tool. 'Retrieves all inventories for the user' does not explain: Will this return all user inventories or only shared ones? How many results? What fields are included? When should an LLM call this vs create-inventory? Generic descriptions force LLMs to guess at tool purpose.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 56 | 2026-07-28+ | v2 |
Invites a user to a shopping list.
Removes the current user from an inventory. If the user is the last member, the inventory is deleted.
Removes the current user from a shopping list. If the user is the last member, the list is deleted.
Removes items from an inventory.
Removes items from a shopping list.
Updates an item in an inventory.
Updates an item in a shopping list.
Parameter descriptions lack constraints and format guidance. 'Name for the inventory' does not specify: min/max length, allowed characters, uniqueness requirements. 'Expiration date of the item' lacks format specification (ISO 8601? Locale-dependent?). Without constraints, LLMs pass invalid values and errors offer no recovery guidance.
No error handling guidance. If create-inventory fails because a user already has an inventory with that name, what does the error response say? If invite-user-to-inventory fails because the user doesn't exist, does it suggest 'Did you mean: john_doe, jane_doe?' Errors should guide the LLM toward recovery, not just report failure.
Destructive operations (remove-inventory-items, remove-shopping-list-items, leave-or-delete-inventory, leave-or-delete-shopping-list) lack confirmation or dry-run support. An LLM could accidentally delete all items or an entire inventory. No description warns of irreversibility or suggests a confirmation step.
Tool names 'leave-or-delete-inventory' and 'leave-or-delete-shopping-list' combine two distinct actions (leave vs delete). Per pattern:tool, a name containing 'and' or 'or' signals multiple responsibilities. This should split into leave-inventory and delete-inventory so agents understand the consequence. Current name is ambiguous about which action is taken under what conditions.
Parameter 'userName' in invite-user-to-inventory and invite-user-to-shopping-list requires a username string, but no guidance on whether to accept email, display name, or user_id instead. Pattern:natural-identifiers expects tools to accept human-friendly identifiers; requiring a specific 'username' format forces extra lookup calls and mismatches chat data model.
No pagination support documented for get-inventories and get-shopping-lists. If a user has hundreds of inventories, these tools will return all of them, bloating the response and exhausting context. Per pattern:paginated-result, list operations should accept limit/offset/cursor parameters and return total counts or next_cursor.
update-inventory-item has a 'putUpdate' boolean parameter to toggle between PATCH and PUT semantics, but descriptions do not explain the distinction or when to use each. 'Update should behave like a PUT action, where all fields are replaced' is vague, does PUT require all fields to be provided? What happens to unspecified fields? This undocumented dependency risks silent misuse.
Array parameter itemIds in remove-shopping-list-items and inventoryItemIds in remove-inventory-items lack min/max length constraints or batch size limits. An LLM could attempt to delete 10,000 items in one call, causing timeouts or resource exhaustion. Descriptions should specify 'max 100 items per call' or similar.