Handles
ctx.handle(), HandleStore, and no sessions.
bitmcp is stateless. There is no Mcp-Session-Id and no sticky server memory.
import { memoryHandleStore, type HandleStore } from "bitmcp";
type Job = { status: string; progress: number; source: string };
export const jobs: HandleStore<Job> = memoryHandleStore();
async execute({ jobId, source }, ctx) {
const id = jobId ?? ctx.handle();
const existing = await jobs.get(id);
if (!existing) {
await jobs.set(id, { status: "running", progress: 0, source });
}
const job = (await jobs.get(id)) ?? { status: "running", progress: 0, source };
return { jobId: id, ...job };
}ctx.handle()
Mints an opaque id (UUID). Store whatever you need under that id with a HandleStore:
memoryHandleStore()in development- KV, Redis, or D1 in production, same
{ get, set }shape
The model and the View pass jobId back as a normal argument on the next call.
Stateless requests
Every HTTP request builds a fresh MCP server. Tool code must assume the next call may hit another replica.
Handles make that safe. Sessions do not.
Long work
Return a handle immediately. Let the View poll status via a backing tool. See the task example.