simple-job
mcp-simple-job
Pasa una subtarea a un modelo local en otra máquina y verifica el resultado antes de devolverlo.
Construido para una forma concreta de problema: el asistente capaz y medido se ejecuta en la máquina ante la que estás sentado, mientras una caja con GPU perfectamente buena permanece inactiva en un rincón. Leer cuarenta archivos, resumir una página larga, descargar un conjunto de datos — nada de eso necesita el modelo caro, y hacerlo en el contexto del asistente gasta el único recurso que es genuinamente escaso.
Medido en la configuración del autor, frente a hacer los mismos cuatro trabajos en contexto: ~2,7 veces más rápido, y 6,1 veces menos contexto gastado, porque las páginas en bruto nunca entran en él.
La única regla
Un trabajo debe venir con una verificación. Una tarea que no pueda decir cómo se sabría que ha funcionado es rechazada — no advertida, rechazada.
Esto no es desconfianza del modelo local. Es que el que llama no puede saberlo. Cuando el asistente delega un resumen y recibe cuatrocientas palabras confiadas, no tiene ninguna forma independiente de saber si esas palabras describen el documento o algo más. Delegar sin una verificación añade un segundo punto donde una luz verde no significa nada.
Las verificaciones son deliberadamente aburridas: nonempty, contains, regex, json_keys,
line_count, shell (tu argv, salida 0 pasa, salida canalizada a stdin) y summary_of
(más corto que la fuente y no una copia de ella).
Related MCP server: any-model-plugin
Las cuatro subtareas
tool | qué hace | dónde ocurre el trabajo |
| una solicitud sencilla con tu propia verificación | el host del modelo |
| texto, o URL(s) obtenidas primero | máquina trabajadora (obtención + modelo) |
| buscar, leer las páginas principales, resumir | la búsqueda alterna hosts, el resto en la máquina trabajadora |
| obtener un archivo, informar bytes + sha256 | máquina trabajadora por defecto, cualquier host configurado |
simple_job_stats informa de cómo han ido realmente todos ellos, a partir de una fila del registro escrita
para cada trabajo.
Poniéndolo en marcha
Requisitos
Node 18+ en la máquina que ejecuta el servidor MCP.
Un endpoint de chat compatible con OpenAI.
llama-serverde llama.cpp, Ollama, vLLM, LM Studio o una API alojada: cualquier cosa que responda aPOST /v1/chat/completions.Python 3.9+ en cualquier máquina que haga la obtención. Solo biblioteca estándar; sin pip install, sin node, sin beautifulsoup.
Autenticación por clave SSH a la segunda máquina, si usas una. Es opcional (ver más abajo).
Cómo está conectado en las máquinas del autor
Dos ordenadores:
Un Mac mini — la estación de trabajo diaria. 16 GB, normalmente unos pocos gigabytes en swap. Ejecuta Claude Desktop y, por tanto, este servidor MCP.
Una máquina Pop!_OS con una RTX 5070 Ti — el laboratorio. Ejecuta un modelo de 35B llamado ornith bajo
llama-serveren el puerto 8080, y está inactiva la mayor parte del día.
Un túnel SSH hace que el modelo remoto parezca local para el Mac:
ssh -N -o ServerAliveInterval=30 -L 127.0.0.1:8081:127.0.0.1:8080 pop-ospop-os es un alias de ~/.ssh/config con una clave y IdentitiesOnly yes, de modo que el servidor puede
alcanzarlo de forma no interactiva con BatchMode=yes.
La entrada del cliente MCP es simplemente:
{ "mcpServers": { "simple-job": { "command": "node", "args": ["/path/to/mcp-simple-job/index.js"] } } }Los valores por defecto hacen el resto: el modelo en 127.0.0.1:8081, la máquina trabajadora en pop-os y
el registro en un ~/Code/harness/ existente, si lo hay.
Nada se llama nunca a mano. El asistente elige la herramienta — que es un problema más difícil de lo que parece, y se cubre más abajo.
Ejecutándolo en las tuyas
Dos máquinas, una que ejecuta el cliente y otra que ejecuta el modelo:
{
"mcpServers": {
"simple-job": {
"command": "node",
"args": ["/path/to/mcp-simple-job/index.js"],
"env": {
"ORNITH_URL": "http://127.0.0.1:8081/v1/chat/completions",
"ORNITH_MODEL": "your-model-name",
"POP_HOST": "your-ssh-alias"
}
}
}
}Una sola máquina — todo local, sin SSH en ningún sitio:
{
"env": {
"ORNITH_URL": "http://127.0.0.1:11434/v1/chat/completions",
"ORNITH_MODEL": "qwen3:8b",
"SEARCH_HOSTS": "mac"
}
}SEARCH_HOSTS=mac es el interruptor que dice «no hay segunda máquina». La obtención,
la descarga y la búsqueda suceden todas localmente, y la búsqueda simplemente tiene un presupuesto de frecuencia
en lugar de dos. Todo lo demás se comporta igual.
Variables de entorno
variable | valor por defecto | qué hace |
|
| el endpoint de chat |
|
| nombre del modelo enviado en la solicitud |
|
| alias SSH de la máquina trabajadora |
|
| máquinas entre las que alternar las búsquedas; establece |
|
| intervalo mínimo entre búsquedas desde una misma máquina |
|
| cuánto tiempo permanece fuera una máquina tras ser limitada |
| junto a | dónde se guarda el estado de temporización de la búsqueda |
|
| el registro SQLite |
|
| identificador de traza opcional para estampar en las filas |
El registro es opcional. Se crea en el primer uso, y si no se puede escribir los
trabajos siguen ejecutándose: el registro se hace con el mejor esfuerzo y nunca bloquea el trabajo. HARNESS_TRACE es un gancho
para la configuración de trazado del propio autor; ignóralo y las filas simplemente tendrán un identificador de traza nulo.
Conseguir que se use de verdad
Esta es la parte que la mayoría de la gente se salta, y es la parte que decide si todo lo anterior importa.
Una herramienta a la que nada enruta es invisible, por muy bien que funcione. El autor tiene un servidor MCP aparte que funciona perfectamente y tuvo cero llamadas en meses, puramente porque nada le dijo nunca al asistente que lo utilizara. Construir una capacidad y enrutar hacia ella son dos trabajos distintos, y terminar el primero se siente como terminar.
Hay tres maneras de cerrar esa brecha, la más barata primero. La mayoría de la gente quiere la segunda.
1. No hagas nada, y observa. Algunos clientes leen las descripciones de herramientas lo bastante bien como para que una solicitud suficientemente obvia — «resume estas cuarenta páginas» — encuentre la herramienta por sí sola. Vale la pena probarlo durante un día antes de añadir mecanismos. Observa si realmente se llama.
2. Pon una regla donde tu cliente guarde las instrucciones permanentes. Instrucciones de proyecto de Claude Desktop,
un CLAUDE.md para Claude Code, .cursorrules, las instrucciones de un GPT personalizado —
lo que sea que tu cliente lea en cada turno. Algo así:
Hay un modelo local disponible a través de
simple-job. Úsalo cuando el material no esté ya en contexto y el trabajo sea mecánico: resumir páginas o archivos, búsqueda web más lectura, descargar archivos, extracción y reformateo. Es gratis y no gasta contexto en la fuente.Hazlo tú mismo cuando el texto ya esté en contexto, cuando el trabajo necesite interpretación en lugar de transcripción, o cuando acertar importe más que poder verificarlo. Nunca delegues decisiones de criterio, código que deba ser correcto o edición de archivos.
Cada trabajo debe llevar una verificación: el servidor rechaza el trabajo que no puede verificar.
Dedica tantas palabras a cuándo no delegar como a cuándo hacerlo. El modo de fallo de enrutar hacia una herramienta de delegación es la sobredelegación, y un asistente que lo envía todo cuesta abajo te entregará una transcripción fiel donde querías criterio.
3. Conéctalo a un enrutador, si tienes uno. Si tu configuración ya hace corresponder situaciones con herramientas, añade una entrada para «lectura masiva u obtención de material aún no en contexto». La ventaja sobre una instrucción permanente es que es medible: puedes contar si se activó cuando debería. Una instrucción permanente o funciona o no, y nada registra cuál de las dos.
Qué no enviarle
Cualquier cosa donde «tiene buena pinta» sea la única prueba. Decisiones de criterio. Código que deba ser correcto. Editar archivos.
Y un límite encontrado por medición más que por gusto: un modelo local pequeño transcribe fielmente pero no interpreta. En las pruebas reprodujo literalmente el fraseo ambiguo de una fuente en lugar de resolver lo que significaba, y resumió el número de estrellas de un repositorio como si formara parte de un informe de error. Envíale transcripción. Conserva la interpretación.
Notas al construirlo
Todo lo que sigue es una medición, no una opinión. Los números están también en los comentarios del código.
El razonamiento está desactivado por defecto
Los modelos de razonamiento emiten su deliberación y su respuesta desde el mismo presupuesto de tokens. En un trabajo de resumen ejecutado tres veces de forma idéntica, dos de las tres veces gastaron 5.500–6.000 caracteres pensando, alcanzaron el límite y devolvieron una respuesta vacía con HTTP 200.
Subir max_tokens no lo arregló. reasoning_effort: "low" no lo arregló. Una
etiqueta de sistema /no_think no lo arregló. Solo chat_template_kwargs: {enable_thinking: false} lo hizo, y el mismo trabajo respondió entonces en 258 tokens. Pasa think: true para un trabajo
que realmente necesite deliberación, y sube max_tokens con él.
La búsqueda está racionada, y DuckDuckGo miente sobre el motivo
DuckDuckGo no limita la tasa de forma educada:
una consulta atendida es HTTP 200, ~28 KB, diez enlaces de resultados
una rechazada es HTTP 202, ~14,2 KB, y su texto dice "Please complete the following challenge... Select all squares containing a duck"
Es una marca de captcha en la IP, no un límite temporal, y espaciar no la elimina. Después de cuatro minutos de silencio, seis consultas con 30 s de separación desde una máquina y seis con 15 s desde la otra fueron 0 de 12. El sondeo cada 5 s durante un bloque no se recuperó en 162 s — reintentar la alimenta. La marca se disipó por sí sola en unos veinte minutos.
Por eso las búsquedas se espacian, se alternan entre máquinas (dos IP son dos presupuestos), y una
limitación se informa como throttled, nunca como «sin resultados». Esas dos cosas significan lo contrario.
La lectura sigue a la pregunta
Una página larga se recorta para que quepa en la ventana del modelo, y recortar desde arriba responde a la pregunta equivocada en silencio. Al preguntar por "sparse gating and load balancing" en una página de 40.063 caracteres con una ventana de 8.000 caracteres, la primera versión devolvió un resumen fluido del inicio del artículo — en el que "load balancing" nunca aparece (empieza en el carácter 16.181) y "sparse" nunca aparece (14.671).
Así que focus dirige la ventana: una cabecera para el contexto, luego los pasajes alrededor de cada término
nombrado, una ventana garantizada por término antes de que ningún término tenga una segunda. Dos versiones
anteriores no fueron suficientes: la coincidencia de subcadenas encontró "load" dentro de "download" e informó de
42 coincidencias de ruido, y tomar los pasajes en orden del documento gastó el presupuesto antes de llegar al
carácter 16.181.
Si la página nunca usa esas palabras, la llamada devuelve ok:false con focus_not_found.
Cero coincidencias es una respuesta mejor que un resumen plausible de otro material.
Una página que es mayormente script es rechazada
Un sitio sirvió 68.896 bytes que contenían 40 caracteres de texto ("Loading..."), que el
guard if not text original dejó pasar, así que el armazón entró en un resumen como material fuente
y el modelo escribió con total confianza una cifra de referencia citándolo.
Ahora hay dos pruebas, porque cada una por separado se deja engañar: un mínimo absoluto y una proporción de texto a bytes que solo condena a una página que también es corta. Un issue de GitHub son 290.000 bytes de marcado alrededor de 3.896 caracteres de discusión real, y la proporción por sí sola lo descartó.
Las citas están numeradas para poder comprobarse
search_and_summarize numera las páginas y pide [1], [2] en lugar de urls. Al pedirle urls, el modelo atribuyó una cifra que había leído en un blog a una página de documentación: el dato era real y estaba en el material, la atribución no lo era, y summary_of no puede verlo porque una viñeta mal etiquetada tiene la longitud correcta y no es una copia.
Una url es una cadena larga y opaca de copiar correctamente. Un entero no lo es, y se puede comprobar su rango contra las páginas realmente leídas, lo que el código hace, fallando la llamada si el número está fuera de rango y contando las viñetas sin ninguna fuente.
¿Qué máquina es más rápida?
Verificado con sha256 idéntico en ambos lados:
máquina cliente | máquina trabajadora | |
ida y vuelta de ssh | — | ~185 ms por llamada |
obtener 4 páginas | ~1,7 s | ~2,0 s |
descargar 20 MB | 17,5 MB/s | 12,6 MB/s |
La máquina cliente fue más rápida en ambas. La velocidad no es la razón para enviar trabajo a la trabajadora. Las razones son que contiene el modelo, que está inactiva mientras la otra máquina está en uso, y que una segunda máquina es un segundo presupuesto de búsqueda. Elige el host de una descarga según dónde se necesite el archivo, no según el rendimiento.
Pruebas
node test_e2e.mjs # 24 assertions, spawns the real server over JSON-RPC
node --test test/simple-job.test.mjs # 19 unit assertions on the checksLa suite de extremo a extremo lanza el servidor real de la misma manera que lo haría un cliente, contra un libro de contabilidad desechable. Una prueba en proceso no detectaría un error de PATH o de entorno, y esos son exactamente los que solo aparecen después de un reinicio.
Los cambios en index.js surten efecto la próxima vez que el cliente inicie el servidor. pop_agent.py se vuelve a leer en cada llamada, por lo que los cambios en la obtención, la búsqueda y la descarga se aplican de inmediato.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseAqualityCmaintenanceLocal MCP server that enables delegating low-risk tasks like summarization or code patches to a low-cost model, with the main agent reviewing results.2
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to delegate tasks, run adversarial reviews, and manage background jobs across multiple models and providers via anymodel_* tools.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables Claude Code to delegate mechanical tasks (summaries, boilerplate, reformatting) to local models running in LM Studio.1MIT
- AlicenseNot gradedqualityAmaintenanceDelegates replaceable grunt work (boilerplate, formatting, translation, long-document summarizing) from a premium agent to cheap models behind a local LiteLLM proxy, auto-routing each task by type. Delegated calls run in a separate process, so the subscription session and the API credentials never share an environment.MIT
Related MCP Connectors
Verifies AI agent work end to end: real artifacts and outcomes checked, not self-reported success.
LLM chat, text summarization and AI image generation
Free OpenAI-compatible inference with signed provenance receipts and 3 focused MCP tools.
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/MikeyBeez/mcp-simple-job'
If you have feedback or need assistance with the MCP directory API, please join our Discord server