A food delivery MCP server that manages restaurants, menus, orders, and user information with Firebase/Firestore backend
The server defines 5 tools with clear purposes for a food delivery domain. All tools have descriptions and input schemas are visible in code. However, there are significant gaps in parameter descriptions, output schema documentation, error handling guidance, and no tool annotations (readOnlyHint/destructiveHint). Naming is mostly verb-noun compliant but could be more precise. The descriptions are adequate (100-200 chars on average) but lack actionable guidance for LLM selection and recovery. The place_order tool has a critical TODO indicating incomplete validation. Overall definition quality is fair, better than median but with clear improvement areas.
Checks the current status of an existing order using its unique ID and returns the status and updated ETA. Args: order_id: The unique identifier of the order to check. Returns: A dictionary with the order status and updated ETA (in minutes), or an error message if not found.
Fetches the menu for a specific restaurant identified by its ID. The menu is returned as a list of items, each with a name, description, and price. Args: restaurant_id: The unique identifier for the restaurant. Returns: A list of menu items as dictionaries.
Fetches the user ID for a given email address. Args: email: The user's email address. Returns: The user ID as a string, or an error message if not found.
Places a food order at a specific restaurant for a given user. This action will create a new order in the system. Args: restaurant_id: The ID of the restaurant to order from. user_id: The ID of the user placing the order. item_ids: A list of menu item IDs to be included in the order. delivery_address: The full street address for the delivery. Returns: A confirmation message including the newly created order ID.
Searches for restaurants based on a specified cuisine and a minimum rating. Returns a list of matching restaurants with their key details, including name, address, rating, and ID. Args: cuisine: The type of food to search for (e.g., 'Italian', 'Japanese'). min_rating: The minimum acceptable rating for a restaurant (e.g., 4.5).
Missing output schema documentation for all tools. No explicit structured output definitions visible in schema or descriptions. LLMs cannot infer what fields to expect from responses (e.g., search_restaurants returns restaurant objects with fields 'name, address, rating, and ID' per description, but exact field names and types are undocumented). Breaks tool chaining and forces LLMs to guess field names.
place_order contains a TODO comment: 'confirm restaurant_id, user_id, item_ids exist in the database'. This validation is incomplete, allowing invalid IDs to be passed to create_order_db. The tool will fail with generic error 'There was an error placing your order' without telling LLM which field was invalid or how to fix it.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 66 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 44 | - | v1 |
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) present. The MCP server does not declare which tools are read-only vs destructive. place_order and create_order_db should be marked destructiveHint=true. This breaks agent safety planning, agents cannot distinguish safe from risky operations.
Error handling is generic and non-actionable. place_order returns 'There was an error placing your order. Please try again. Technical details: {str(e)}' which exposes implementation details to LLM without guidance. check_order_status returns error dict without recovery hint. search_restaurants returns [{'error': '...'}] which breaks type consistency (array of dicts vs single error object). Pattern: recovery-guide.
Parameter descriptions lack actionable constraints. 'The type of food to search for (e.g., 'Italian', 'Japanese')' in search_restaurants suggests examples but no enum, format, or validation rules. LLM may pass arbitrary cuisine names not supported by DB. Missing: min/max for min_rating (defaults to 4.0 but unbounded upper limit). Breaks pattern: constrained-input.
No pagination or result limits documented. search_restaurants could return hundreds of restaurants without limit. The description states 'Returns a list of matching restaurants' but does not cap results or offer pagination (offset, limit, total_count, next_cursor). Breaks pattern: paginated-result.
Tool descriptions lack WHEN to use guidance. E.g., search_restaurants vs get_restaurant_menu both involve restaurants but no clear disambiguation. Descriptions do not hint at dependencies (e.g., 'Call search_restaurants first to get restaurant_id, then pass to get_restaurant_menu'). LLMs will struggle to sequence multi-step flows.