simple-job
mcp-simple-job
Übergib eine Teilaufgabe an ein lokales Modell auf einer anderen Maschine und prüfe das Ergebnis, bevor du es zurückgibst.
Gebaut für eine bestimmte Art von Problem: Der leistungsfähige, gemessene Assistent läuft auf der Maschine, vor der du sitzt, während eine völlig brauchbare GPU-Box nutzlos in der Ecke steht. Vierzig Dateien lesen, eine lange Seite zusammenfassen, einen Datensatz herunterladen – nichts davon braucht das teure Modell, und es im Kontext des Assistenten zu erledigen, verbraucht die eine Ressource, die wirklich knapp ist.
Gemessen am Setup des Autors, im Vergleich zu denselben vier Aufgaben im Kontext: ~2,7x schneller und 6,1x weniger Kontext verbraucht, weil die rohen Seiten ihn nie erreichen.
Die eine Regel
Ein Auftrag muss eine Prüfung mitbringen. Eine Aufgabe, die nicht angeben kann, woran man erkennen würde, dass sie funktioniert hat, wird abgelehnt – nicht gewarnt, abgelehnt.
Das ist kein Misstrauen gegenüber dem lokalen Modell. Es liegt daran, dass der Aufrufer es nicht erkennen kann. Wenn der Assistent eine Zusammenfassung delegiert und vierhundert selbstbewusste Wörter zurückbekommt, hat er keine unabhängige Möglichkeit zu wissen, ob diese Wörter das Dokument beschreiben oder etwas anderes. Delegieren ohne Prüfung fügt eine zweite Stelle hinzu, an der ein grünes Licht nichts bedeutet.
Prüfungen sind bewusst langweilig: nonempty, contains, regex, json_keys, line_count, shell (deine argv, Exit 0 besteht, Ausgabe wird an stdin gepipet) und summary_of (kürzer als die Quelle und keine Kopie davon).
Related MCP server: any-model-plugin
Die vier Teilaufgaben
tool | was es tut | wo die Arbeit passiert |
| ein einfacher Prompt mit eigener Prüfung | der Modell-Host |
| Text oder url/urls, zuerst geholt | Arbeitsmaschine (Fetch + Modell) |
| suchen, die Top-Seiten lesen, zusammenfassen | Suche wechselt Hosts, Rest auf der Arbeitsmaschine |
| eine Datei holen, Bytes + sha256 melden | standardmäßig Arbeitsmaschine, jeder konfigurierte Host |
simple_job_stats berichtet, wie alle tatsächlich gelaufen sind, aus einer Ledger-Zeile, die für jeden Auftrag geschrieben wird.
Ausführen
Voraussetzungen
Node 18+ auf der Maschine, die den MCP-Server ausführt.
Ein OpenAI-kompatibler Chat-Endpunkt. llama.cpps
llama-server, Ollama, vLLM, LM Studio oder eine gehostete API – alles, wasPOST /v1/chat/completionsbeantwortet.Python 3.9+ auf der Maschine, die das Holen übernimmt. Nur Standardbibliothek; keine pip-Installation, kein node, kein beautifulsoup.
SSH-Schlüssel-Authentifizierung zur zweiten Maschine, falls du eine verwendest. Sie ist optional (siehe unten).
Wie es auf den Maschinen des Autors verdrahtet ist
Zwei Computer:
Ein Mac mini – die tägliche Workstation. 16 GB, normalerweise ein paar Gigabyte im Swap. Er führt Claude Desktop und damit diesen MCP-Server aus.
Eine Pop!_OS-Box mit einer RTX 5070 Ti – das Labor. Sie führt ein 35B-Modell namens ornith unter
llama-serverauf Port 8080 aus und ist die meiste Zeit des Tages untätig.
Ein SSH-Tunnel lässt das entfernte Modell für den Mac lokal aussehen:
ssh -N -o ServerAliveInterval=30 -L 127.0.0.1:8081:127.0.0.1:8080 pop-ospop-os ist ein ~/.ssh/config-Alias mit einem Schlüssel und IdentitiesOnly yes, sodass der Server ihn nicht-interaktiv mit BatchMode=yes erreichen kann.
Der MCP-Client-Eintrag ist einfach:
{ "mcpServers": { "simple-job": { "command": "node", "args": ["/path/to/mcp-simple-job/index.js"] } } }Standardwerte erledigen den Rest: das Modell unter 127.0.0.1:8081, die Arbeitsmaschine unter pop-os und das Ledger in einem vorhandenen ~/Code/harness/, falls es eines gibt.
Nichts wird jemals von Hand aufgerufen. Der Assistent wählt das Tool – was ein schwierigeres Problem ist, als es klingt, und unten behandelt wird.
Ausführen auf deinem Setup
Zwei Maschinen, eine führt den Client aus, eine das Modell:
{
"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"
}
}
}
}Eine Maschine – alles lokal, kein SSH irgendwohin:
{
"env": {
"ORNITH_URL": "http://127.0.0.1:11434/v1/chat/completions",
"ORNITH_MODEL": "qwen3:8b",
"SEARCH_HOSTS": "mac"
}
}SEARCH_HOSTS=mac ist der Schalter, der sagt: „Es gibt keine zweite Maschine". Holen, Herunterladen und Suchen passieren alle lokal, und die Suche hat einfach ein Ratenbudget statt zwei. Alles andere verhält sich gleich.
Umgebungsvariablen
variable | standard | was sie tut |
|
| der Chat-Endpunkt |
|
| Modellname, der in der Anfrage gesendet wird |
|
| SSH-Alias der Arbeitsmaschine |
|
| Maschinen, zwischen denen Suchen abwechseln; auf |
|
| Mindestabstand zwischen Suchen von einer Maschine |
|
| wie lange eine Maschine nach einer Drosselung aussetzt |
| neben | wo der Such-Timing-Zustand gespeichert wird |
|
| das SQLite-Ledger |
|
| optionale Trace-ID zum Stempeln auf Zeilen |
Das Ledger ist optional. Es wird bei der ersten Verwendung erstellt, und wenn es nicht beschrieben werden kann, laufen die Aufträge trotzdem – Protokollierung ist Best-Effort und blockiert nie Arbeit. HARNESS_TRACE ist ein Haken für die eigene Tracing-Einrichtung des Autors; ignoriere ihn und Zeilen haben einfach eine null-Trace-ID.
Damit es tatsächlich genutzt wird
Das ist der Teil, den die meisten überspringen, und es ist der Teil, der entscheidet, ob irgendetwas davon eine Rolle spielt.
Ein Tool, zu dem nichts weiterleitet, ist unsichtbar, egal wie gut es funktioniert. Der Autor hat einen separaten MCP-Server, der einwandfrei funktioniert und monatelang null Aufrufe hatte, nur weil nichts dem Assistenten je gesagt hat, danach zu greifen. Eine Fähigkeit zu bauen und dorthin weiterzuleiten sind zwei verschiedene Aufgaben, und die erste zu beenden fühlt sich an wie Fertigwerden.
Drei Möglichkeiten, diese Lücke zu schließen, die günstigste zuerst. Die meisten wollen die zweite.
1. Nichts tun und sehen. Manche Clients lesen Tool-Beschreibungen gut genug, dass eine ausreichend offensichtliche Anfrage – „fasse diese vierzig Seiten zusammen" – das Tool von selbst findet. Einen Tag wert, es auszuprobieren, bevor man Maschinerie hinzufügt. Beobachte, ob es tatsächlich aufgerufen wird.
2. Lege eine Regel dort ab, wo dein Client dauerhafte Anweisungen aufbewahrt. Claude-Desktop-Projektanweisungen, eine CLAUDE.md für Claude Code, .cursorrules, die Anweisungen eines benutzerdefinierten GPT – was auch immer dein Client bei jeder Runde liest. Etwa so:
Es gibt ein lokales Modell, das über
simple-jobverfügbar ist. Verwende es, wenn das Material noch nicht im Kontext ist und die Aufgabe mechanisch ist: Seiten oder Dateien zusammenfassen, Websuche plus Lesen, Downloads holen, Extrahieren und Neuformatieren. Es ist kostenlos und verbraucht keinen Kontext für die Quelle.Mach es selbst, wenn der Text bereits im Kontext ist, wenn die Aufgabe Interpretation statt Transkription braucht, oder wenn Richtigsein wichtiger ist als Prüfbarkeit. Delegiere niemals Ermessensentscheidungen, Code, der korrekt sein muss, oder Dateibearbeitungen.
Jeder Auftrag muss eine Prüfung mitbringen – der Server lehnt Arbeit ab, die er nicht verifizieren kann.
Verwende genauso viele Wörter für wann nicht zu delegieren wie für wann. Die Fehlerart beim Weiterleiten eines Delegierungstools ist Über-Delegierung, und ein Assistent, der alles nach unten schickt, wird dir treue Transkription liefern, wo du Urteilsvermögen wolltest.
3. Verdrahte es in einen Router, falls du einen hast. Wenn dein Setup bereits Situationen Tools zuordnet, füge einen Eintrag für „Massenlesen oder Holen von Material, das noch nicht im Kontext ist" hinzu. Der Vorteil gegenüber einer dauerhaften Anweisung ist, dass es messbar ist – du kannst zählen, ob es ausgelöst hat, als es hätte sollen. Eine dauerhafte Anweisung funktioniert entweder oder nicht, und nichts zeichnet auf, welches.
Was du nicht hinschicken solltest
Alles, wo „sieht richtig aus" der einzige Test ist. Ermessensentscheidungen. Code, der korrekt sein muss. Dateien bearbeiten.
Und eine Grenze, die durch Messung statt Geschmack gefunden wurde: Ein kleines lokales Modell transkribiert treu, interpretiert aber nicht. Im Test reproduzierte es die mehrdeutige Formulierung einer Quelle wörtlich, statt aufzulösen, was sie bedeutete, und fasste die Sternanzahl eines Repositorys so zusammen, als wäre sie Teil eines Fehlerberichts. Schick ihm Transkription. Behalte Interpretation.
Notizen vom Bauen
Alles unten ist eine Messung, keine Meinung. Die Zahlen stehen auch in den Code-Kommentaren.
Denken ist standardmäßig aus
Reasoning-Modelle geben ihre Überlegung und ihre Antwort aus demselben Token-Budget aus. Bei einem Zusammenfassungsauftrag, der dreimal identisch ausgeführt wurde, verbrauchten zwei von drei 5.500–6.000 Zeichen fürs Denken, trafen die Obergrenze und gaben eine leere Antwort mit HTTP 200 zurück.
max_tokens zu erhöhen behob es nicht. reasoning_effort: "low" behob es nicht. Ein /no_think-System-Tag behob es nicht. Nur chat_template_kwargs: {enable_thinking: false} tat es, und derselbe Auftrag antwortete dann in 258 Tokens. Übergib think: true für einen Auftrag, der wirklich Überlegung braucht, und erhöhe max_tokens damit.
Suche ist rationiert, und DuckDuckGo lügt darüber, warum
DuckDuckGo drosselt nicht höflich:
eine bediente Abfrage ist HTTP 200, ~28 KB, zehn Ergebnislinks
eine verweigerte ist HTTP 202, ~14,2 KB, und ihr Text lautet „Bitte löse die folgende Herausforderung... Wähle alle Quadrate aus, die eine Ente enthalten"
Es ist ein Captcha-Flag auf der IP, kein zeitliches Limit, und Abstände räumen eines nicht ab. Nach vier Minuten Stille waren sechs Abfragen im 30-s-Abstand von einer Maschine und sechs im 15-s-Abstand von der anderen 0 von 12. Abfragen alle 5 s während einer Sperre erholten sich nie in 162 s – Wiederholen füttert es. Das Flag verfiel von selbst in ungefähr zwanzig Minuten.
Also werden Suchen verteilt, über Maschinen abgewechselt (zwei IPs sind zwei Budgets), und eine Drosselung wird als throttled gemeldet, nie als „keine Ergebnisse". Diese bedeuten Gegenteiliges.
Lesen folgt der Frage
Eine lange Seite wird beschnitten, um ins Fenster des Modells zu passen, und das Beschneiden von oben beantwortet die falsche Frage stillschweigend. Gefragt nach „sparse gating and load balancing" auf einer 40.063-Zeichen-Seite mit einem 8.000-Zeichen-Fenster gab die erste Version eine flüssige Zusammenfassung der Eröffnung des Artikels zurück – in der „load balancing" nie vorkommt (es beginnt bei Zeichen 16.181) und „sparse" nie vorkommt (14.671).
Also steuert focus das Fenster: ein Kopf für den Kontext, dann die Passagen um jeden benannten Begriff, ein garantiertes Fenster pro Begriff, bevor ein Begriff ein zweites bekommt. Zwei frühere Versionen waren nicht genug – Substring-Abgleich fand „load" in „download" und meldete 42 Treffer Rauschen, und das Nehmen von Passagen in Dokumentreihenfolge verbrauchte das Budget, bevor es Zeichen 16.181 erreichte.
Wenn die Seite diese Wörter nie verwendet, gibt der Aufruf ok:false mit focus_not_found zurück. Null Treffer ist eine bessere Antwort als eine plausible Zusammenfassung anderen Materials.
Eine Seite, die größtenteils Skript ist, wird abgelehnt
Eine Website lieferte 68.896 Bytes mit 40 Zeichen Text („Loading..."), was der ursprüngliche if not text-Schutz passieren ließ – also ging die Shell als Quellmaterial in eine Zusammenfassung ein und das Modell schrieb eine selbstbewusste Benchmark-Zahl, die darauf verwies.
Jetzt zwei Tests, weil jeder allein getäuscht wird: eine absolute Untergrenze und ein Text-zu-Bytes-Verhältnis, das nur eine Seite verurteilt, die auch kurz ist. Ein GitHub-Issue ist 290.000 Bytes Markup um 3.896 Zeichen echter Diskussion, und das Verhältnis allein hat es verworfen.
Zitate sind nummeriert, damit sie überprüft werden können
search_and_summarize nummeriert die Seiten und fragt nach [1], [2] statt nach URLs. Auf URLs angesprochen, schrieb das Modell eine Zahl, die es in einem Blog gelesen hatte, einer Dokumentationsseite zu – die Tatsache war real und im Material vorhanden, die Zuordnung war es nicht, und summary_of kann das nicht erkennen, weil ein falsch beschrifteter Aufzählungspunkt die richtige Länge hat und keine Kopie ist.
Eine URL ist eine lange undurchsichtige Zeichenkette, die man korrekt kopieren muss. Eine Ganzzahl ist das nicht, und sie kann gegen die tatsächlich gelesenen Seiten auf ihren Bereich geprüft werden – was der Code tut, indem er den Aufruf bei einer Zahl außerhalb des Bereichs fehlschlagen lässt und Aufzählungspunkte ohne Quelle überhaupt zählt.
Welche Maschine ist schneller?
Verifiziert durch identische sha256 auf beiden Seiten:
Client-Maschine | Worker-Maschine | |
ssh-Roundtrip | — | ~185 ms pro Aufruf |
4 Seiten abrufen | ~1.7 s | ~2.0 s |
20 MB herunterladen | 17.5 MB/s | 12.6 MB/s |
Die Client-Maschine war bei beidem schneller. Geschwindigkeit ist nicht der Grund, Arbeit an den Worker zu senden. Die Gründe sind, dass sie das Modell enthält, dass sie im Leerlauf ist, während die andere Maschine benutzt wird, und dass eine zweite Maschine ein zweites Suchbudget ist. Wählen Sie den Host für einen Download danach, wo die Datei benötigt wird, nicht nach dem Durchsatz.
Tests
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 checksDie End-to-End-Suite startet den tatsächlichen Server so, wie es ein Client tun würde, gegen ein Wegwerf-Ledger. Ein In-Process-Test würde einen PATH- oder Umgebungsfehler nicht erkennen, und genau diese treten nur nach einem Neustart auf.
Änderungen an index.js werden wirksam, wenn der Client den Server das nächste Mal startet. pop_agent.py wird bei jedem Aufruf neu gelesen, sodass Änderungen am Abrufen, Suchen und Herunterladen sofort live sind.
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