mcp-longjobs
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.
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):
crawl-sitedevuelve al instante untaskIde instrucciones para consultardurable_task_get— no más tiempos de espera.Las consultas muestran progreso en vivo:
{ "status": "working", "progress": { "message": "Crawled /pricing", "fraction": 0.4 } }.Las preguntas durante la ejecución pausan la tarea como
input_required; el modelo responde mediantedurable_task_respondy la tarea continúa donde se detuvo.¿El cliente se bloqueó? ¿Nueva sesión?
durable_task_getcon el mismotaskIdsigue funcionando — el estado vive en el almacén, no en la conexión.durable_task_cancelaborta 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 |
|
|
|
|
| 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_getcon 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,recoveryHintypartial.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 ( | 🔜 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 serverContribuciones
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
Maintenance
Related MCP Servers
- AlicenseAqualityBmaintenanceAsync MCP server for running long-running AI tasks with real-time progress monitoring, enabling users to start, monitor, and manage complex AI workflows across multiple models.6345MIT
- FlicenseNot gradedqualityDmaintenanceA 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
- AlicenseAqualityAmaintenanceA fire-and-poll MCP server that lets Claude Code run long background jobs without hitting tool-call timeouts.3MIT
- FlicenseNot gradedqualityBmaintenanceRemote MCP server that launches user-supplied scripts inside disposable Docker containers, returning task IDs for async tracking and bounded output tails.
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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