examples/MCP-tools Public
// Calls per tool per day, in KV. One key per tool and UTC day, `calls:2026-10-10:convert_units`,// holding { calls, errors } both as the value and as the key's metadata, so /stats can read a// whole day with one list() and no gets.//// The counter is a read, then a write, so two calls that land at the same moment can count as// one, and KV takes about a minute to show a write everywhere. That is fine for seeing which// tools get used; it is not billing.export type Counts = { calls: number; errors: number };export type Day = { date: string; tools: Record<string, Counts> };const PREFIX = "calls:";const KEEP_SECONDS = 90 * 24 * 60 * 60;export const MAX_DAYS = 31;export function dayOf(date: Date): string { return date.toISOString().slice(0, 10);}export async function countCall(kv: KVNamespace, tool: string, ok: boolean, now = new Date()): Promise<void> { const key = `${PREFIX}${dayOf(now)}:${tool}`; const prev = (await kv.get<Counts>(key, "json")) ?? { calls: 0, errors: 0 }; const next: Counts = { calls: prev.calls + 1, errors: prev.errors + (ok ? 0 : 1) }; await kv.put(key, JSON.stringify(next), { metadata: next, expirationTtl: KEEP_SECONDS });}// The last `days` UTC days, newest first, including days with no calls.export async function readUsage(kv: KVNamespace, days: number, now = new Date()): Promise<Day[]> { const out: Day[] = []; for (let i = 0; i < days; i++) { const date = dayOf(new Date(now.getTime() - i * 86_400_000)); const prefix = `${PREFIX}${date}:`; const tools: Record<string, Counts> = {}; let cursor: string | undefined; do { const page = await kv.list<Counts>({ prefix, cursor }); for (const k of page.keys) if (k.metadata) tools[k.name.slice(prefix.length)] = k.metadata; cursor = page.list_complete ? undefined : page.cursor; } while (cursor); out.push({ date, tools }); } return out;}