MCP server with ten logged tools over contacts, deals, tasks, inventory and sales orders, with read only mode, dry run orders and an audit log. SQLite backend swappable for any CRM or ERP.
Strong foundation with 10 well-named tools, complete input schemas, and comprehensive descriptions. Tool names follow verb_noun pattern (search_contacts, get_contact, list_tasks, etc.). All parameters have type definitions and descriptions. Descriptions average ~120 chars, within the 10-1024 char baseline. Tool annotations present (readOnlyHint, destructiveHint, idempotentHint). Key gaps: output schemas not explicitly documented in code; error handling lacks recovery guidance; no pagination metadata (total_count, next_cursor) in list responses; dry_run pattern for create_order is good but not universally applied to other write tools.
Append a timestamped note to a contact's timeline (max 2,000 characters).
Stock levels. Pass a SKU for one item, or low_stock_only=true for items at/below their reorder level.
Mark a task done (idempotent).
Place a sales order for a contact. Checks stock first. dry_run=true (default) only returns a priced preview, confirm with the user, then call again with dry_run=false to commit and decrement inventory.
Create an open task for a contact. due_date is YYYY-MM-DD and may not be in the past.
Full view of one contact: profile, deals, open tasks, last 5 notes, last 5 orders. Use the id from search_contacts (e.g. C-1007).
Output schemas not documented in code. While tool descriptions explain what is returned (e.g., 'Full view of one contact: profile, deals, open tasks, last 5 notes, last 5 orders'), the actual JSON structure of responses is not visible in the source. LLMs cannot plan downstream tool calls without knowing which fields to extract.
List tools (search_contacts, list_tasks, check_inventory) lack pagination metadata. No total_count, next_cursor, or has_more fields visible in schema. Large result sets risk context window exhaustion. Descriptions mention limits but not how to fetch additional pages.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 69 | 2026-07-28+ | v2 |
List tasks, default open ones, optionally filtered by assignee (hamza|sana|ali) and due date (YYYY-MM-DD). Sorted by due date.
Deals by stage (count + AED value), open pipeline total, and open deals expected to close in the next 30 days.
Find contacts by name, company, email, phone or city (case-insensitive substring). Returns up to `limit` (max 50).
Move a deal to a new pipeline stage.
Error handling in logged() decorator catches ToolError and ValueError but does not provide recovery guidance. Error messages like 'contact not found' lack actionable next steps (e.g., 'Try search_contacts() with a partial name'). Agents cannot self-correct.
Dry-run pattern applied only to create_order. Other write tools (add_note, create_task, update_deal_stage) lack confirmation or preview steps. Agents cannot preview consequences before committing irreversible changes.
Parameter descriptions use example values (e.g., 'e.g. C-1007' for contact_id, 'hamza|sana|ali' for assignee). LLMs may reuse these literals in real calls. Replace with formal constraints: enums for assignee, pattern/description for contact_id format.