Skip to main content
Glama

mcp-longjobs

Dauerhafte, fortsetzbare Vorgänge für MCP – langlaufende Aufgaben und große Dateien, die Timeouts, Verbindungsabbrüche und Client-Neustarts überleben. Auf jedem Client, heute.

CI npm license

中文文档

Das Problem

Drei Dinge lassen jeden MCP-Server scheitern, der echte Arbeit leistet:

  • Langlaufende Tool-Aufrufe laufen in einen Timeout. Clients setzen Timeouts pro Aufruf (oft 10–60 s). Ein Crawl, ein Build, ein Batch-Job schlägt fehl – und der „Retry“ des Modells startet die gesamte Operation von vorn.

  • Fehler sind nicht reparierbar. Ein fehlgeschlagener Aufruf gibt einen frei formulierten Fehler zurück, also rät das Modell: blind wiederholen oder aufgeben. Es kann nicht einen Parameter korrigieren und fortsetzen.

  • Große Dateien haben kein Übertragungskonzept. Binärinhalte sind base64-in-JSON (33 % Overhead, harte Nachrichtengrößen-Grenzen) oder eine nackte URL ohne Konventionen – kein Chunking, kein Fortsetzen, keine Integritätsprüfungen.

Die MCP-Spezifikation vom 2026-07-28 hat Tasks hinzugefügt – asynchrone Ausführung mit Eingaben während des Laufs und dauerhaften Handles. Aber noch unterstützt kein Client das, und die Spezifikation verlangt, dass Server Tasks für Clients ablehnen, die nicht zugestimmt haben. Jeder langlaufende Server braucht daher einen Fallback-Pfad, der auf heutigen Clients funktioniert. Das ist dieses Paket.

Related MCP server: Simple Streamable HTTP MCP Server

Was Sie bekommen

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" });

Was das Modell auf heutigen Clients erlebt (keine Tasks-Unterstützung erforderlich):

  1. crawl-site gibt sofort eine taskId und Anweisungen zurück, durable_task_get abzufragen – keine Timeouts mehr.

  2. Die Abfragen zeigen Live-Fortschritt: { "status": "working", "progress": { "message": "Crawled /pricing", "fraction": 0.4 } }.

  3. Fragen während des Laufs pausieren die Aufgabe als input_required; das Modell antwortet über durable_task_respond, und die Aufgabe wird an der Stelle fortgesetzt, an der sie gestoppt wurde.

  4. Client abgestürzt? Neue Sitzung? durable_task_get mit derselben taskId funktioniert weiterhin – der Zustand lebt im Store, nicht in der Verbindung.

  5. durable_task_cancel bricht die Arbeit kooperativ am nächsten Checkpoint ab.

Fehler sind Daten, keine Protokollfehler – eine strukturierte Hülle, die das Modell in einem einzigen Round-Trip reparieren kann:

{
  "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 }
  }
}

Pakete (Subpath-Exporte)

Import

Zweck

mcp-longjobs/tasks

withTasks() + die durable_task_*-Fassade: Hintergrundausführung, Fortschritt, Eingaben während des Laufs, kooperativer Abbruch

mcp-longjobs/files

withFileTransfer(): Chunk-Upload/-Download, Fortsetzungs-Cursor, sha256-Verifizierung, pfadsichere Wurzelverzeichnisse

mcp-longjobs/core

Sitzungsmodell, austauschbare Stores (In-Memory, JSON-Datei), strukturierte Fehlerhülle

Designhinweise

  • Bytes fließen nie durch das Modell. Das Modell sieht nur Metadaten: Handle, Größe, sha256, Fortschritt. Chunks über Tool-Aufrufe sind für kleine bis mittlere Nutzlasten gedacht; große Dateien sollten out-of-band übertragen werden (TUS-Endpunkt geplant), wobei das Modell die Integrität prüft.

  • Das Modell ist der Regisseur, nicht der Kurier. Die Ergebnisse der Fassaden-Tools enthalten ihre eigenen Anweisungen („Rufen Sie durable_task_get mit dieser ID auf“, „Setzen Sie bei Offset N fort“), sodass jedes fähige Modell das Protokoll ohne jegliche Host-Unterstützung steuern kann.

  • Fehler sind reparierbare Daten. Jeder Fehler enthält code, retryable, recoveryHint und partial.cursor – was schiefging, ob ein erneuter Versuch funktionieren kann, was stattdessen zu tun ist und was bereits erfolgreich war.

  • Das Lebenszyklus-Vokabular entspricht der Spezifikation. working / input_required / completed / failed / cancelled, sodass der native Adapter später ohne Breaking Changes eingefügt werden kann.

Status

Komponente

Status

Tasks-Fallback-Fassade (Fortschritt / Eingabe / Abbruch)

✅ implementiert

Dauerhafte Sitzungs-Stores (In-Memory, JSON-Datei)

✅ implementiert

Chunk-Dateiübertragung mit Fortsetzen + Prüfsummen

✅ implementiert

Nativer ext-tasks-Adapter (CreateTaskResult / tasks/get)

🔜 orientiert sich an der experimentellen Tasks-API des SDKs

TUS-1.0-Out-of-Band-Endpunkt für große Dateien

🔜 geplant – siehe mcp#189

Redis-/SQLite-Stores, Python-Port

🔜 geplant

Schnellstart

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

(Sobald es auf npm veröffentlicht ist, läuft derselbe Server mit einem einzigen Befehl: npx mcp-longjobs.)

Richten Sie Ihren Client darauf aus (stdio):

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

Fragen Sie dann: „Erstelle einen Bericht über EV-Batterien mit 3 Abschnitten.“ Beobachten Sie, wie das Modell den Auftrag startet, durable_task_get abfragt und das Ergebnis abholt. Beenden Sie den Client während des Laufs, starten Sie ihn neu und fragen Sie nach derselben taskId – der Vorgang wird fortgesetzt.

Entwicklung

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

Mitwirken

PRs sind willkommen – insbesondere: Store-Backends (SQLite/Redis), der native ext-tasks-Adapter und der TUS-Endpunkt. Bitte eröffnen Sie für größere Änderungen zuerst ein Issue.

Lizenz

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