A small, dependency-free Model Context Protocol server core, extracted from Kelo. Hand-rolled JSON-RPC, read-and-draft-only tool surface for UK service business invoice chasing and financial insights.
Kelo demonstrates solid fundamentals: all 6 tools have clear verb-noun naming (get_*, draft_*), descriptions are well-crafted (avg 156 chars, within 10 - 1024 baseline), and input schemas are properly defined with JSON Schema. All parameters have type declarations and descriptions. However, output schemas are not documented in the source, LLMs cannot see what fields to expect from responses. Parameter descriptions are strong but lack explicit format/constraint guidance (e.g., 'customer_id from get_chase_queue' assumes prior context). No tool annotations (readOnlyHint, destructiveHint) despite all tools being read-only or draft-only, a missed opportunity for clarity. Error handling is not visible in the tool definitions themselves.
Draft a chase message for one case, in the sender's own voice. Returns a subject and body to review and send from your own inbox. It never sends anything.
The prioritised list of who to chase first, by value and days late. Returns open cases with the customer, amount and how overdue each is.
Detail for one customer: total outstanding, overdue case count, average payment delay, and whether they are escalation territory (deeply overdue and already chased).
Invoices due in the next two weeks that are worth a friendly heads-up before they slip, ranked by how likely each client is to pay late. Getting paid on time beats chasing late.
A read on the outstanding book: overdue total, average days overdue, an aging breakdown by bucket, and the worst-paying customers.
Output schemas not documented. LLMs cannot see what fields to expect from tool responses (e.g., get_weekly_number returns verified_owed_gbp, estimate_at_risk_gbp, open_cases, but this is not in the tool definition). Without documented return types, agents cannot plan downstream calls or extract the right data.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). All 6 tools are read-only or return drafts (never send/delete), but this is not signaled in the schema. Tool annotations would let clients and LLMs understand safety guarantees without parsing descriptions.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 66 | 2026-07-28+ | v2 |
The headline: what this workspace is owed right now. Verified overdue invoices, plus an estimate figure from quotes and enquiries, with the open-case count.
Parameter descriptions assume prior context. 'customer_id from get_chase_queue' and 'case_id from get_chase_queue' require the LLM to have already called get_chase_queue. Descriptions should be self-contained: 'The customer ID (string, obtained from get_chase_queue or get_customer responses).'
No error handling guidance in tool definitions. If a customer_id is invalid or a case_id does not exist, what does the tool return? Null? An error? The definitions do not specify recovery paths, forcing LLMs to guess.
get_chase_queue limit parameter lacks explicit bounds in description. Schema declares minimum: 1, maximum: 25, but the description only says 'How many to return (default 5).' LLMs may not parse JSON Schema constraints, state bounds in the description text.