Skip to main content
Glama

kelo-mcp

A small Model Context Protocol server that lets a Claude user ask what their business is owed, who to chase first, and get a chase email drafted in their own voice.

It cannot send anything. Every tool either reads or returns a draft. That is a product decision, not an oversight, and DESIGN.md explains what it costs and what it buys.

Extracted from Kelo, where it backs a live MCP endpoint. No SDK dependency: the JSON-RPC layer is hand-rolled, about 120 lines, and has no runtime dependencies at all.

Try it in 30 seconds

npm install
npm run example
curl -s localhost:8787 -H 'authorization: Bearer demo-key' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_weekly_number","arguments":{}}}'
{
  "verified_owed": "£6,050",
  "estimate_at_risk": "£9,600",
  "open_cases": 3,
  "note": "Verified is real overdue invoices. Estimate is quotes and enquiries, and is less certain."
}

That runs against an in-memory demo backend. No database, no Kelo account, no API key beyond the literal string demo-key.

Related MCP server: Xero MCP Server

The tools

Tool

Returns

get_weekly_number

Total owed, split into verified invoices and less certain estimates

get_chase_queue

Who to chase first, sorted by priority, value or age

get_customer

One customer's outstanding total, payment history and escalation status

draft_chase

A subject and body for one case. Returns text; never sends

get_due_soon

Invoices due within two weeks, ranked by how likely the client is to pay late

get_insights

Overdue total, average days overdue, aging buckets, worst payers

Wiring it to your own data

The protocol layer knows nothing about invoices. Implement ToolBackend and pass it in:

import { createPostHandler, callTool, TOOL_DEFS, SERVER_INFO, INSTRUCTIONS } from 'kelo-mcp'

export const POST = createPostHandler({
  config: { serverInfo: SERVER_INFO, tools: TOOL_DEFS, instructions: INSTRUCTIONS, callTool },
  resolveKey: async token => {
    const row = await db.apiKeys.findByHash(sha256(token))
    return row && !row.revoked_at ? { workspaceId: row.workspace_id } : null
  },
  makeContext: workspaceId => ({ workspaceId, backend: myBackend }),
})

createPostHandler takes and returns Web-standard Request/Response, so it drops into Next.js route handlers, Cloudflare Workers, Deno, Bun or plain Node 18+ without adaptation.

Layout

src/protocol.ts      JSON-RPC and MCP methods. No product knowledge, no dependencies.
src/tools.ts         Tool definitions: the surface a model actually sees.
src/backend.ts       The seam. Dispatch, formatting, and the ToolBackend interface.
src/demo-backend.ts  In-memory data so the thing runs out of the box.
src/http.ts          Bearer auth and the stateless POST transport.

The split exists so the protocol can be tested without a database. All 18 tests run in well under a second and touch nothing external.

npm test

What is not here

The live Kelo server backs these tools with Postgres queries, a drafting service and a billing entitlement check. That is Kelo's business logic and it is not in this repo. What is here is the protocol layer, the transport, the tool surface, and a demo backend that satisfies the same interface.

Notes on the protocol

Three things the spec asks for that are easy to get subtly wrong, and how this handles them:

  • Notifications get silence, not a response. A message with no id returns null internally and is dropped. If a batch was entirely notifications, the transport answers 202 with an empty body rather than 200 and [].

  • An unknown tool is a tool error, not a protocol error. It comes back as a normal result with isError: true so the model can read it and pick another tool. Reserving -32601 for genuinely unknown methods keeps the two failure modes distinct.

  • The client's protocol version is echoed when it sends one, rather than forcing the server's own.

Licence

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to interact with QuickFile UK accounting software, providing access to invoicing, client management, purchases, banking, and financial reporting through 40+ tools covering the complete QuickFile API.
    11 npm
    4
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables interaction with the Xero Accounting API to manage contacts, invoices, payments, accounts, and financial reports. It provides a suite of tools for natural language access to accounting records and business performance data.
    20
    1
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides structured, read-mostly access to small-business back-office data including customers, invoices, and account notes, allowing Claude to query overdue invoices, revenue summaries, and more.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables LLM agents to manage QuickBooks Online invoices, customers, and payments via typed tools with OAuth 2.1 authentication, rate limiting, and retries, plus read-only resources for company and receivables summaries.
    18
    MIT