Skip to main content
Glama

mcp-longjobs

Durable, resumable operations for MCP — long-running tasks and large files that survive timeouts, disconnects, and client restarts. On every client, today.

CI npm license

中文文档

The problem

Three things break every MCP server that does real work:

  • Long-running tool calls time out. Clients impose per-call timeouts (often 10–60s). A crawl, a build, a batch job fails — and the model's "retry" restarts the whole operation from scratch.

  • Failures are unrepairable. A failed call returns a freeform error, so the model guesses: retry blindly, or give up. It can't fix one parameter and resume.

  • Large files have no transfer story. Binary content is base64-in-JSON (33% overhead, hard message-size caps) or a bare URL with zero conventions — no chunking, no resume, no integrity checks.

The 2026-07-28 MCP spec added Tasks — async execution with mid-flight input and durable handles. But no client supports it yet, and the spec requires servers to refuse tasks for clients that didn't opt in. Every long-running server therefore needs a fallback path that works on today's clients. That is this package.

Related MCP server: Simple Streamable HTTP MCP Server

What you get

import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { JsonFileSessionStore, withTasks, withFileTransfer, asToolRegistrar } from "mcp-longjobs";

const mcp = new McpServer({ name: "my-server", version: "1.0.0" });
const registrar = asToolRegistrar(mcp);
const store = new JsonFileSessionStore("./state/sessions.json");

const tasks = withTasks(registrar, { store });

tasks.taskTool("crawl-site", {
  description: "Crawl a site and produce a report (takes minutes)",
  inputSchema: { url: z.string(), maxPages: z.number().default(50) },
}, async (args, ctx) => {
  for (const page of pages) {
    if (ctx.signal.aborted) throw new Error("cancelled");
    await ctx.progress(`Crawled ${page.url}`, done / total);

    if (needsConfirmation(page)) {
      const answer = await ctx.needInput({ prompt: `Include ${page.url}?`, choices: ["yes", "no"] });
      if (answer === "no") continue;
    }
  }
  return { summary, reportPath }; // small result for the model; big artifacts go through file transfer
});

withFileTransfer(registrar, { store, storageDir: "./state/blobs" });

What the model experiences on today's clients (no Tasks support required):

  1. crawl-site returns instantly with a taskId and instructions to poll durable_task_get — no more timeouts.

  2. Polls show live progress: { "status": "working", "progress": { "message": "Crawled /pricing", "fraction": 0.4 } }.

  3. Mid-flight questions pause the task as input_required; the model answers via durable_task_respond and the task continues where it stopped.

  4. Client crash? New session? durable_task_get with the same taskId still works — state lives in the store, not in the connection.

  5. durable_task_cancel aborts the work cooperatively at its next checkpoint.

Failures are data, not protocol errors — a structured envelope the model can repair in one round-trip:

{
  "status": "failed",
  "error": {
    "code": "offset_mismatch",
    "message": "Expected offset 131072, got 0.",
    "retryable": true,
    "recoveryHint": "Do NOT resend the whole file. Re-send this chunk starting at offset 131072.",
    "partial": { "cursor": 131072 }
  }
}

Packages (subpath exports)

Import

Purpose

mcp-longjobs/tasks

withTasks() + the durable_task_* facade: background execution, progress, mid-flight input, cooperative cancellation

mcp-longjobs/files

withFileTransfer(): chunked upload/download, resume cursor, sha256 verification, path-safety roots

mcp-longjobs/core

Session model, pluggable stores (memory, JSON file), structured error envelope

Design notes

  • Bytes never flow through the model. The model sees metadata only: handle, size, sha256, progress. Chunks through tool calls are for small-to-medium payloads; large files should move out-of-band (TUS endpoint planned) with the model verifying integrity.

  • The model is the director, not the courier. Facade tool results carry their own instructions ("call durable_task_get with this id", "resume at offset N"), so any capable model can drive the protocol with zero host-side support.

  • Failures are repairable data. Every failure carries code, retryable, recoveryHint, and partial.cursor — what went wrong, whether a retry can work, what to do instead, and what already succeeded.

  • Lifecycle vocabulary matches the spec. working / input_required / completed / failed / cancelled, so the native adapter can slot in later without breaking changes.

Status

Component

Status

Tasks fallback facade (progress / input / cancel)

✅ implemented

Durable session stores (memory, JSON file)

✅ implemented

Chunked file transfer with resume + checksums

✅ implemented

Native ext-tasks adapter (CreateTaskResult / tasks/get)

🔜 tracks the SDK's experimental Tasks API

TUS 1.0 out-of-band endpoint for large files

🔜 planned — see mcp#189

Redis / SQLite stores, Python port

🔜 planned

Quickstart

git clone https://github.com/ljppanda/mcp-longjobs
cd mcp-longjobs
npm install && npm run build
node dist/examples/report-generator.js

(Once published to npm, the same server runs with a single command: npx mcp-longjobs.)

Point your client at it (stdio):

{
  "mcpServers": {
    "report-generator": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-longjobs/dist/examples/report-generator.js"]
    }
  }
}

Then ask: "Generate a report on EV batteries with 3 sections." Watch the model start the job, poll durable_task_get, and pick up the result. Kill the client mid-run, restart it, and ask for the same taskId — it resumes.

Development

npm install
npm test         # vitest
npm run build    # tsc -> dist/
npm run example  # build + run the demo server

Contributing

PRs welcome — especially: store backends (SQLite/Redis), the native ext-tasks adapter, and the TUS endpoint. Please open an issue first for anything larger.

License

MIT

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A reference implementation demonstrating proper MCP server patterns with HTTP transport, featuring session management, progress notifications, and example tools for testing server functionality. Serves as a clean template for building MCP servers with streamable responses and comprehensive error handling.
    7
  • F
    license
    Not graded
    quality
    B
    maintenance
    Remote MCP server that launches user-supplied scripts inside disposable Docker containers, returning task IDs for async tracking and bounded output tails.

View all related MCP servers

Related MCP Connectors

  • MCP server for the FFmpeg Micro video transcoding API — create, monitor, download transcodes.

  • MCP protocol requiring task acceptance and provenance tags. Self-hosted only - see README.

  • Remote MCP server for RunComfy Serverless API (ComfyUI): deployments and async inference.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ljppanda/mcp-longjobs'

If you have feedback or need assistance with the MCP directory API, please join our Discord server