Skip to main content
Glama

mcp-longjobs

Operaciones duraderas y reanudables para MCP — tareas de larga duración y archivos grandes que sobreviven a tiempos de espera, desconexiones y reinicios del cliente. En todos los clientes, hoy.

CI npm license

中文文档

El problema

Tres cosas rompen todo servidor MCP que hace trabajo real:

  • Las llamadas a herramientas de larga duración agotan el tiempo de espera. Los clientes imponen tiempos de espera por llamada (a menudo 10–60s). Un rastreo, una compilación, un trabajo por lotes falla — y el "reintento" del modelo reinicia toda la operación desde cero.

  • Los fallos son irreparables. Una llamada fallida devuelve un error de formato libre, así que el modelo adivina: reintentar a ciegas o rendirse. No puede corregir un parámetro y reanudar.

  • Los archivos grandes no tienen un mecanismo de transferencia. El contenido binario es base64 en JSON (33 % de sobrecarga, límites estrictos de tamaño de mensaje) o una URL simple sin convenciones: sin fragmentación, sin reanudación, sin comprobaciones de integridad.

La especificación MCP 2026-07-28 añadió Tasks — ejecución asíncrona con entrada durante la ejecución y manejadores duraderos. Pero ningún cliente lo soporta todavía, y la especificación exige que los servidores rechacen tareas para clientes que no optaron por ello. Por lo tanto, todo servidor de larga duración necesita una ruta de respaldo que funcione en los clientes actuales. Eso es este paquete.

Related MCP server: Simple Streamable HTTP MCP Server

Qué obtienes

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

Lo que el modelo experimenta en los clientes actuales (sin necesidad de soporte de Tasks):

  1. crawl-site devuelve al instante un taskId e instrucciones para consultar durable_task_get — no más tiempos de espera.

  2. Las consultas muestran progreso en vivo: { "status": "working", "progress": { "message": "Crawled /pricing", "fraction": 0.4 } }.

  3. Las preguntas durante la ejecución pausan la tarea como input_required; el modelo responde mediante durable_task_respond y la tarea continúa donde se detuvo.

  4. ¿El cliente se bloqueó? ¿Nueva sesión? durable_task_get con el mismo taskId sigue funcionando — el estado vive en el almacén, no en la conexión.

  5. durable_task_cancel aborta el trabajo de forma cooperativa en su siguiente punto de control.

Los fallos son datos, no errores de protocolo — una envoltura estructurada que el modelo puede reparar en una sola interacción:

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

Paquetes (exportaciones de subruta)

Import

Propósito

mcp-longjobs/tasks

withTasks() + la fachada durable_task_*: ejecución en segundo plano, progreso, entrada durante la ejecución, cancelación cooperativa

mcp-longjobs/files

withFileTransfer(): carga/descarga por fragmentos, cursor de reanudación, verificación sha256, raíces seguras de rutas

mcp-longjobs/core

Modelo de sesión, almacenes conectables (memoria, archivo JSON), envoltura de error estructurada

Notas de diseño

  • Los bytes nunca pasan por el modelo. El modelo solo ve metadatos: identificador, tamaño, sha256, progreso. Los fragmentos a través de llamadas a herramientas son para cargas pequeñas o medianas; los archivos grandes deberían moverse fuera de banda (endpoint TUS planificado) con el modelo verificando la integridad.

  • El modelo es el director, no el mensajero. Los resultados de las herramientas de la fachada llevan sus propias instrucciones ("llama a durable_task_get con este id", "reanuda en el offset N"), por lo que cualquier modelo capaz puede manejar el protocolo sin soporte del lado del host.

  • Los fallos son datos reparables. Cada fallo lleva code, retryable, recoveryHint y partial.cursor — qué salió mal, si un reintento puede funcionar, qué hacer en su lugar y qué ya tuvo éxito.

  • El vocabulario del ciclo de vida coincide con la especificación. working / input_required / completed / failed / cancelled, de modo que el adaptador nativo puede integrarse más adelante sin cambios que rompan la compatibilidad.

Estado

Componente

Estado

Fachada de respaldo de Tasks (progreso / entrada / cancelación)

✅ implementado

Almacenes de sesión duraderos (memoria, archivo JSON)

✅ implementado

Transferencia de archivos por fragmentos con reanudación y sumas de verificación

✅ implementado

Adaptador nativo de ext-tasks (CreateTaskResult / tasks/get)

🔜 sigue la API experimental de Tasks del SDK

Endpoint TUS 1.0 fuera de banda para archivos grandes

🔜 planificado — ver mcp#189

Almacenes Redis / SQLite, port a Python

🔜 planificado

Inicio rápido

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

(Una vez publicado en npm, el mismo servidor se ejecuta con un solo comando: npx mcp-longjobs.)

Apunta tu cliente a él (stdio):

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

Luego pide: "Genera un informe sobre baterías de vehículos eléctricos con 3 secciones." Observa cómo el modelo inicia el trabajo, consulta durable_task_get y recoge el resultado. Mata el cliente a mitad de ejecución, reinícialo y pide el mismo taskId — se reanuda.

Desarrollo

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

Contribuciones

Se aceptan PRs, especialmente: backends de almacenamiento (SQLite/Redis), el adaptador nativo de ext-tasks y el endpoint TUS. Por favor, abre un issue primero para cualquier cosa de mayor envergadura.

Licencia

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