task-queue-mcp
task-queue-mcp
Ein FastMCP-Server, der die Task-Warteschlange der Agenten-Orchestrierung als MCP-Tool-Schnittstelle bereitstellt. Agenten übermitteln Tasks, prüfen Status und erfassen Abschlüsse über typisierte, validierte Tools statt über rohe YAML-Dateiänderungen.
Läuft als Docker-Container auf Port 8485. Global in ~/.claude.json eingebunden, sodass alle Claude-Code-Agent-Sitzungen darauf zugreifen können.
Tools
Tool | Description |
| Neuen Task mit |
| Tasks mit optionalen Filtern auflisten; TTL-abgelaufene Tasks werden ausgeschlossen |
| Einzelnen Task per UUID abrufen (auch archivierte Tasks werden aufgelöst) |
| Agentenbezogene Statusüberführung (streng); hängt einen Historieeintrag an |
| Operator-Statusänderung – genehmigen, abbrechen, parken oder einen übersehenen Task vorziehen (auditierte Überschreibung) |
| Sauberer Endzustand |
| Einen Task pausieren, ohne ihn zu verstecken – bleibt gelistet, von TTL ausgenommen, nichts pickt ihn auf |
| Einen geparkten Task in den Status zurückführen, aus dem er geparkt wurde |
| Korrektur an einen in der Warteschlange befindlichen Task anhängen; ursprüngliche Beschreibung wird nie überschrieben |
Agenten nutzen den strengen update_task-Pfad; Operatoren (über die HTTP-Steuer-API) verwenden
set_task_status / cancel_task / park_task / unpark_task. Agenten können weder abbrechen noch
parken – beides ist Operatoren vorbehalten. amend_task ist die Ausnahme: Der Quell-Agent des Tasks darf ihn
änder, ändern, aber der Ziel-Agent nicht.
submit_task
submit_task(
source_agent="research",
target_agent="deploy-agent", # agent name or "auto" for dispatcher routing
# build | deploy | fix | research | review | audit | notify | docs |
# ticket_audit | ticket_audit_complete
task_type="build",
summary="Deploy qmd update",
description="Apply the qmd stack update from build plan...",
risk_level="low", # low | medium | high (default: low)
requires_approval=False, # explicit override of approval gate
priority="normal", # normal | high | urgent (default: normal)
context_refs=["/srv/agents/build-plans/qmd/plan.md"], # absolute paths only
ttl_days=30,
workflow_mode="semi-auto", # semi-auto | auto (default: semi-auto)
originating_task_id=None, # UUID of the parent task, if this is a return task
)
# → {"ok": true, "task_id": "<uuid>", "filename": "<timestamp>-<slug>.yml"}context_refs müssen absolute Pfade sein. risk_level und priority werden gegen Allowlisten validiert. workflow_mode steuert das Dispatcher-Verhalten: semi-auto (Standard) reiht den Task zur Operator-Übernahme mit einer Matrix-Benachrichtigung in die Warteschlange ein, während auto den Dispatcher veranlasst, den Ziel-Agenten ohne Oberfläche (headless) zu starten. Der Server erzeugt die UUID, setzt created und initialisiert retry_policy.
Automatischer Abschluss des Ursprungs-Tasks (seit v0.6.0)
Übergib originating_task_id, und der Parent-Task wird als completed geschlossen – das Einreichen des Rückgabe-Tasks ist das, was die Anfrage schließt. Die Antwort erhält auto_closed_task_id, wenn dies zutrifft.
Es wird nur ausgelöst, wenn alle diese Bedingungen erfüllt sind:
Bedingung | Warum |
der Parent-Task existiert und ist nicht archiviert | sonst gibt es nichts zu schließen |
| die Begrenzung des gesamten Features – Agent A darf nicht durch die Angabe als Parent-Task stehenden Tasks von Agent B schließen können. Dies wird explizit geprüft und nicht der Besitzkontrolle von |
| die andere Hälfte der Rückgabe-Gestalt – du beantwortest den, der gefragt hat. Ohne diese sieht eine Weiterleitungsanfrage identisch mit einer Rückgabe aus (siehe unten) |
Parent-Task ist bei |
|
Warum beide Hälften (seit v0.6.1). originating_task_id ist überladen: Bei einem Rückgabe-Task bedeutet es „das beantwortet diese Anfrage“, bei einer Weiterleitungsanfrage bedeutet es „workflow_mode von diesem Parent-Task erben“ – genau das übergibt ein Build-Agent, wenn er eine Audit-Anfrage für seinen eigenen laufenden Build einreicht. Mit nur der ersten Prüfung werden beide Fälle verwechselt: Wenn der Build-Task den Build-Agenten als Ziel hat und der Build-Agent der Absender ist, schloss v0.6.0 mit nur der ersten Bedingung innerhalb prompt einen echten laufenden Build-Task ab.
Eine echte Rückgabe ist symmetrisch; eine Weiterleitung ist es nicht.
parent-Task | neuer Task | löst aus? | |
Rückgabe | Audit |
| ja – beide Hälften gelten |
Weiterleitung | Build | Audit-Anfrage | nein – |
Ein approved Parent-Task wird zuerst durch in-progress geführt, sodass die History als „beansprucht, dann geschlossen“ gelesen wird, statt teleportiert zu werden.
Dies ist ein Sicherheitsnetz, kein Primärweg. Continue to expect agents to close their own tasks explicitly – that puts the agent's own note in the history, while this writes only auto-closed: return task <id> submitted. Every failure in close is logged at warning level and the return Task is executed normally; it can never fail the task created by this side effect.
reword a sentence
list_tasks
list_tasks(
target_agent="deploy-agent", # optional
source_agent="research", # optional
status="approved,in-progress", # comma-separated, optional
task_type="build", # optional
include_archived=False, # include archive/ subdirectory
limit=20, # max 200
)
# → list of task dicts, sorted by created descendingEin nicht erkannter status ist ein Fehler, kein leeres Ergebnis (seit v0.6.0). Früher wurde stillschweigend gefiltert. So lieferte eine Suche nach status="pending" – hier kein echter Status – monatelang [], ununterscheidbar von „keine Arbeit für dich“. Eine leere Liste ist diekorrekte Antwort auf eine wohlgeformte Frage; daher ist die einzige Möglichkeit, einen Tippfehler von einer leeren Warteschlange zu unterscheiden, den Tippfehler abzulehnen. Leerzeichen und ein abschließendes Komma werden weiterhin toleriert; ein leerer String weiterhin gilt als Filter.
Terminale Tasks, deren, deren Zeit nicht funktioniert, mehr als ttl_days beträgt, werden ausgeschlossen. Der Dispatcher ist maßgeblich für die TTL-Archivierung, aber list_tasks filtert abgeschlossene Datensätze proaktiv heraus, damit Agenten nicht mit veralteten Elementen arbeiten.
Nicht-terminale Tasks sind niemals TTL-gefiltert (seit v0.8.1, vikunja#395). Offene Arbeiten verschwanden nach ttl_days aus den Auflistungen, obwohl sie noch auf der Disk warteten – eine blinder Fleck, keine Schutzmechanismus; dies hatte bereits dazu geführt, dass eine Warteschlangenaktion 17 verwaiste Tasks fand, wo dieses Tool 13 gemeldet hatte. Nichts, was noch zu jemandes Verantwortung ist, sollte eine Uhr unsichtbar machen: Ein Agent kann einen veralteten offenen Task beurteilen; niemand kann auf einen Task zugreifen, den er nicht sieht.
Parked Tasks sind von der TTL-Filterung ausgenommen. Parken ist eine bewusste „Pause, ich komme zurück“ – ein geparkter Task, der leise aus der Liste entschwindet, würde den Status ad absurdumeführen.
get_task
get_task(task_id="a7f3d2c1-1234-5678-abcd-000000000000")
# → full task dict, or {"ok": false, "error": "not found"}Durchsucht zuerst die Hauptwarteschlange, danach archive/. Erfordert eine vollständige UUID – kein Präfix-Abglecich.
update_task
update_task(
task_id="a7f3d2c1-1234-5678-abcd-000000000000",
status="in-progress", # see transition table below
actor="deploy-agent",
note="Claimed task, starting build.",
output=None, # written to result.output on completed/failed
)
# → {"ok": true, "task_id": "<uuid>"} or {"ok": false, "error": "..."}Besitzprüfung (seit v0.5.0): actor muss mit target_agent des Tasks übereinstimmen oder "operator" sein – jeder andere Ausführer wird abgeleehnt. Das schließt die Lücke, durch die ein Agent, andere der das Task zugewiesen wurde, es beanspricht oder abschließt.
Zulässige Überführungen:
Von | Zu |
|
|
|
|
Beliebiger nicht-tendler Status |
|
Nicht-terminal: submitted, pending-approval, approved, in-progress, parked, routing-failed.
Terminal: completed, failed, cancelled.
routing-failed ist der Dispatcher-schreibt und ist aus der Zeile Any non-terminal → failed oben bewusst herausgenommen – ein Agent darf eine von einem Dispatcher noch erneut versuchendem Task nicht endparamterial schließen. Es ist eine ganz normale Quelle für die Operator-Übergänge unten (cancelled, parked, override).
retry_policy ist im Dispatcher-Besitz; update_task rührt ihn nie an.
Operator-Überführungen (set_task_status)
Wieder mehr Möglichkeiten als update_task, aber weiterhin überwacht und begrenzt:
Von | Zu | Hinweise |
|
| Standard |
Beliebiger nicht-terminaler Status |
| Standard (auch über |
Beliebiger nicht-terminaler Status |
| Standard (auch über |
Beliebiger nicht-terminaler Status | Beliebiger nicht-terminal Status | Erfordert |
Beliebiger unerkannten Status | Beliebiger gültiger Status | Erfordert |
Terminale Tasks sind auch für Operatoren unveränderlich. Jede Operator-Änderung fügt einen Historieeintrag mit actor + note hinzu.
Der Reparaturpfad existiert, weil das Warteschlangenverzeichnis mehr als einen Schreiber hat. Ein Datensatz, dessen Status komplett außerhalb des Vokabulars dieses Servers schlägt – ein historischer Tippfehler complete oder ein zukünftigen dispatcher-Status, der hier noch nicht zugelassen ist – ist über alle anderen Zweige unerreichbar und wäre sonst permanent gerutschtert. Die Reparatur bewegt einen Task immer aus einem ungültigen Status; das Ziel muss weiterhin gültig sein und der Historieintrag erfasst repaired_from. routing-failed braucht diesen Pfad nicht mehr – es ist jetzt ein erstklassiger nicht-terminaler Status (siehe oben), erreichbar über die normalen cancelled/parked-Zeilen oder die normale Override-Zeile.
park_task / unpark_task
park_task(task_id="...", actor="operator", note="waiting on upstream fix")
# → {"ok": true, "task_id": "<uuid>"}
unpark_task(task_id="...", actor="operator", status=None)
# → returns the task to the status it was parked fromParken ändert nur den Status – YAML wird nie bewegt. Der Task bleibt in in list_tasks sichtbar, ist von TTL-Ablauf ausgenommen, und nichts pickt ihn auf, genau die Dispatcher-Holschleifen matchen nur submitted und routing-failed. Der vorherige Status wird in parked_from gespeichert und beim Verlassen entfernt, er kann also nie überaltern. Übergib status an unpark_task, damit der Task wo anders hingeschickt wird, als er herkam – daher erforderlich für für einen _Task, der direkt per YAML geschrieben wurde und findet kein parked_from vor.
Parken ist für „nicht jetzt, aber bitte nicht verlieren“. Ein lange unbeparkter Task ist nicht zwangsläufig Vernachlässigung, und parked ist die Vokabular, die ein absichtliches Lesezeichen von etwas wirklich Verlassenem unterscheidet.
amend_task
amend_task(
task_id="...",
amendment="Preflight answered the open question — FastMCP mount() is live-linked.",
actor="research", # the task's source_agent, or "operator"
reason="preflight ran after queuing",
)
# → {"ok": true, "task_id": "...", "amendment_count": 1, "agent_may_have_started": false}Sobald ein Task eingereiht ist, ist seine Beschreibung unveränderlich. Wenn sich zwischen Einreihung und Start etwas ändert – eine Preflight-Check beantwortet eine offene Frage, eine Dependency ist fertig, ein Reviewer entdeckt einen Fehler, den Scope verengt sich – die konnte die Korrektur sonst nirgendwo hingehen, und ein Agent, der die Beschreibung des Task vertraut, macht falsch.
amend_task schließt diese Lücke nur durch Anhängen (append-only). payload.description wird nie verändert; Änderungen werden unter payload.amendments als {timestamp, actor, reason, text} gesammelt und von Lesern nach der Beschreibung gerendert. Das, was ursprünglich gefragt war, bleibt im Datensatz erhalten.
Regel | Verhalten |
Wer ändern darf | Die |
Wann | Jede nicht-abgeschlossene Aufgabe, einschließlich |
in-progress | Zulässig — es ist der Fall, der am meisten zählt — aber die Antwort setzt |
Grenzen | 10 Änderungen pro Aufgabe, jeweils 4096 Zeichen. |
Umfangswarnung: Mehr als ein oder zwei Änderungen an einer Aufgabe sind ein Signal zum Abbrechen und erneuten Einreihen, statt weiter anzusammeln. Die Grenzen sind eine Absicherung, kein Budget.
Related MCP server: task-manager-mcp
Status-Lebenszyklus
submitted → [pending-approval] → approved → in-progress → completed
↓
failed
routing-failed # dispatcher-written on a failed dispatch attempt; non-terminal
Any non-terminal ──(operator)──> cancelled # graceful dismissal, record kept
Any non-terminal <──(operator)──> parked # pause; stays listed, TTL-exemptDer Dispatcher besitzt die Übergänge submitted → approved/pending-approval und schreibt außerdem
routing-failed, wenn ein Zustellversuch fehlschlägt (er wiederholt nach eigenem Zeitplan; Operatoren
können den Status auch über set_task_status an anderer Stelle abbrechen, parken oder erzwingen). Agenten besitzen approved → in-progress → completed (oder failed) — routing-failed ist über update_task nicht erreichbar.
Operatoren besitzen cancelled, parked und geprüfte Statusüberschreibungen. Die Freigabe wird
durch Agenten-Manifeste und das Feld requires_approval gesteuert.
Jede Aufgabe wird von ihrem Ziel-Agenten geschlossen. Das folgt aus der Eigentümerprüfung
von update_task, und es ist die eine Regel, die man beim Verdrahten eines neuen agentenübergreifenden
Workflows im Kopf behalten sollte: Der Agent, der eine Anfrage einreicht, kann sie nicht schließen,
weil die Anfrage an jemand anderen gerichtet ist. Ein Anfrage-/Antwort-Paar
benötigt daher den empfangenden Agenten, um seinen eigenen Eintrag zu beanspruchen und zu schließen — zwei Aufrufe, da
completed nur von in-progress aus erreichbar ist. Der Auto-Schließen
ist die Absicherung für den Fall, dass es nicht passiert, kein Ersatz dafür.
HTTP-Steuerungs-API
Nicht-MCP-Clients (das CloudCLI-Plugin und der Matrix-Bot) können den Python-Kern nicht importieren, daher laufen alle ihre Änderungen über eine schlanke HTTP-Steuerungs-API, die als FastMCP-Custom-Routen auf Port 8485 bereitgestellt wird. Jeder Endpunkt delegiert an die oben genannten Tool-Handler und erbt damit die Übergangsvalidierung, fcntl-Sperrung und atomare Schreibvorgänge — es gibt also genau einen validierten Schreibpfad für das gesamte System.
Methode | Pfad | Delegiert an |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Zählungen nach Status über die aktive Warteschlange |
Body-Felder: note, plus status / allow_override für die Status-Route, amendment / reason für Amend, status / output / on_behalf_of für Update. Antworten bilden das kanonische Ergebnis ab: 200 ok, 404 nicht gefunden, 400 Validierungs-/Übergangsfehler.
actor ist auf jeder dieser Routen an operator gebunden und wird nicht aus dem Body gelesen (seit v0.8.0). Zuvor war es body.get("actor", "operator") — in der Praxis korrekt, aber es machte die Operator-Identität zu etwas, das ein Aufrufer durch Weglassen erbte, statt zu etwas, das jemand wählte. Die Bindung bedeutet, dass ein zukünftiger Nicht-Operator-Client hier nicht stillschweigend die Identität erlangen kann, die jede Eigentümerprüfung ausnimmt.
Der Operator-Durchgriff — POST /tasks/{id}/update
Der einzige Pfad zu einem abschließenden Übergang bei der Aufgabe eines anderen Agenten. Er existiert, weil v0.8.0 die unehrliche Variante schloss: Agenten pflegten eine gestrandete Aufgabe aufzuräumen, indem sie den Namen dieses Agenten als actor übergaben, was die Bindung von actor an ein Inhaber-Token unmöglich macht. Nichts anderes erreicht ihn — set_task_status kann keine abschließenden Übergänge vornehmen und das update_task-Tool verlangt nun die aufgelöste Identität — daher müsste ohne dies jede verwaiste Aufgabe einen manuellen Eingriff des Operators benötigen.
Übergib on_behalf_of mit dem Namen des Agenten, dessen Aufgabe es ist. Der Handler prüft ihn gegen den tatsächlichen target_agent der Aufgabe (eine Abweichung ist ein 400, denn einem Operator, der eine falsch identifizierte Aufgabe schließt, soll das mitgeteilt werden, nicht als vorsätzlicher Fehler protokolliert werden) und schreibt beide Namen in die Historie:
history:
- timestamp: ...
status: completed
actor: operator
on_behalf_of: developer
note: "stranded; swept during queue cleanup"Ein Durchgriff soll Jahre später auch als Durchgriff lesbar sein, nicht so, als hätte der Agent seine eigene Arbeit stillschweigend abgeschlossen. on_behalf_of ist optional — das Weglassen bedeutet, dass der Operator in eigenem Namen handelt — und wird für jeden Nicht-operator-Actor ausdrücklich abgelehnt.
GET /queue/summary gibt {"ok": true, "counts": {...}, "active": N, "total": N} zurück, wobei active die Summe der nicht-abgeschlossenen Status ist (jetzt einschließlich routing-failed, nach Name gezählt). Status außerhalb des Vokabulars werden unter "unknown" einsortiert statt verworfen, sodass Einträge anderer direkter YAML-Schreiber sichtbar bleiben.
Auth: Die Custom-Routen umgehen die Bearer-Authentifizierung des Transports, daher ist ein Shared-Secret-Header das Tor — und diese Routen liegen bewusst außerhalb davon, weil sie die Operator-Oberfläche sind:
Sende
X-Task-Queue-Secret: $TASK_QUEUE_API_SECRETbei jeder Änderung.Der Server vergleicht es in konstanter Zeit (
hmac.compare_digest) und schließt fehlgeschlagen ab (401), wenn das Secret fehlt, falsch oder nicht konfiguriert ist.Das Secret liegt in einer vom Operator verwalteten Env-Datei außerhalb des Repos und wird über
env_filein den Container und in die Umgebung jedes Clients injiziert — niemals ins Quellverzeichnis committet.
Bereitstellung
Docker (Produktion)
services:
task-queue-mcp:
image: task-queue-mcp:latest
container_name: task-queue-mcp
ports:
# The loopback bind is load-bearing, not cosmetic. The MCP transport on this port
# is unauthenticated (see Trust model below), so publishing it as "8485:8485"
# would expose an unauthenticated queue-mutation endpoint to your whole LAN.
- "127.0.0.1:8485:8485"
volumes:
- ~/.claude/task-queue:/task-queue # host queue directory
environment:
- TASK_QUEUE_DIR=/task-queue
# 0.0.0.0 here is the *container-internal* bind and must stay wide, or the port
# mapping above has nothing to forward to. The host-side bind is what limits reach.
- MCP_HOST=0.0.0.0
- MCP_PORT=8485
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
read_only: true
tmpfs: [/tmp]
user: "1000:1000"
restart: unless-stopped
networks:
- agent-netDer Container mountet nur das Task-Queue-Verzeichnis beschreibbar. Der Rest des Dateisystems ist schreibgeschützt. /tmp ist ein tmpfs für flüchtigen Zwischenspeicher.
Claude-Code-Einstellungen
{
"mcpServers": {
"task-queue-mcp": {
"type": "url",
"url": "http://localhost:8485/mcp"
}
}
}Umgebungsvariablen
Variable | Standard | Beschreibung |
|
| Pfad zum Task-Queue-Verzeichnis im Container |
|
| Bind-Adresse für den HTTP-Server |
|
| Port für den HTTP-Server |
| — | Gemeinsames Secret für die HTTP-Steuerungs-API. Erforderlich für jede Steuerungs-API-Änderung — schließt fehlgeschlagen ab (401), wenn nicht gesetzt. Die MCP-Tools selbst verwenden es nicht. |
| — | Bearer-Token für einen aufrufenden Agenten, z. B. |
Jeder Agent benötigt sein eigenes Token — das Token ist das, was den Aufrufer identifiziert, daher macht das Teilen eines Tokens
zwischen zwei Agenten die Zuordnung bedeutungslos. Der Server weigert sich zu starten bei einem geteilten
Token, einem leeren Wert, einem Token unter 16 Zeichen oder einem Token, das für die reservierte
operator-Identität geprägt wurde. Erzeugen mit:
python -c "import secrets; print(secrets.token_urlsafe(32))"Aufrufer übergeben es als standardmäßigen Bearer-Header:
headers:
Authorization: "Bearer ${TASK_QUEUE_TOKEN}"Erstellung
docker build -t task-queue-mcp:latest .Entwicklung
Erfordert Python 3.11+.
pip install -e ".[dev]"
# Lint + format (Baseline gate)
ruff check .
ruff format --check .
# Tests with coverage (gate: >=80%)
python -m pytest --cov=src --cov-report=term-missing
# Run server locally against a local task-queue directory
TASK_QUEUE_DIR=~/.claude/task-queue python -m src.serverDie Testsuite deckt jedes Tool und die HTTP-Steuerungs-API ab — Validierungsgrenzfälle, feindselige YAML-Zeichenketten, unzulässige Übergänge, den Park/Unpark-Roundtrip, amend_task-Autorisierung (einschließlich des abgelehnten Ziel-Agenten), Operator-Override-Prüfung, Reparatur von Status außerhalb des Vokabulars und das Shared-Secret-Tor (fehlendes/falsches Secret → 401). Alle Schreibvorgänge verwenden yaml.dump — niemals String-Interpolation — um YAML-Injection zu verhindern.
Sicherheit
Beide Oberflächen auf Port 8485 erfordern eine Berechtigung:
MCP-Tool-Pfad (
/mcp) — ein pro-Agent-Bearer-Token, verifiziert durch FastMCPsStaticTokenVerifier. Fehlendes oder unbekanntes Token → 401. Der Transport weigert sich, ohne konfigurierte Token zu starten, sodass dies nicht stillschweigend offen fehlschlagen kann.HTTP-Steuerungsrouten (
/tasks/...,/queue/summary) — ein Shared-Secret-Header (X-Task-Queue-Secret, Konstantzeit-Vergleich, Fail-Closed). Siehe HTTP-Steuerungs-API.
Der Container läuft als UID 1000 mit cap_drop: ALL, no-new-privileges und einem schreibgeschützten Root-Dateisystem (nur /task-queue ist beschreibbar).
Vertrauensmodell
Bis v0.7.0 war der MCP-Tool-Pfad unauthentifiziert und die README argumentierte, dass Loopback eine ausreichende Vertrauensgrenze sei. Das war sie nicht: Der Port ist veröffentlicht und der Container tritt einem gemeinsamen Docker-Netzwerk bei, sodass jeder Container in diesem Netzwerk ebenfalls den Tool-Pfad erreichen konnte. Jeder von ihnen konnte set_task_status, cancel_task, park_task, unpark_task oder amend_task aufrufen und dabei einen beliebigen actor behaupten — einschließlich operator, den die Eigentümerprüfungen ausdrücklich ausnehmen. Das machte completed_by und history[].actor zu Behauptungen statt zu Belegen. (vikunja#387)
v0.7.0 schließt diesen Pfad. Jeder Agent hält ein eigenes Token, daher authentifiziert das Token den Aufrufer und identifiziert ihn zugleich. Es gibt bewusst keinen separaten Identitäts-Header: Sobald ein Agent ein Token besitzt, kann er bei einer direkten Anfrage jeden beliebigen Header setzen, daher wäre eine aus dem Header abgeleitete Identität ein strikt schwächerer zweiter Kanal, der mit dem aus dem Token abgeleiteten konkurriert. Eine Identitätsquelle, nicht zwei.
Was dies leistet und was nicht. Es enthält einen fehlgeleiteten oder prompt-injizierten Agenten, der über seine eigene Werkzeugoberfläche agiert, und es stellt sicher, dass das Audit-Protokoll das bedeutet, was es sagt. Es ist bewusst keine Grenze gegen einen Agenten, der nach Anmeldeinformationen sucht: Wenn Agenten über ein Shell-Werkzeug verfügen und als derselbe Betriebssystem-Benutzer laufen, dem die geheimen Dateien gehören, ist jedes Token auf dem Host für jeden von ihnen lesbar. Um das zu schließen, braucht es betriebssystemweite Benutzerkonten pro Agent oder einen Anmeldeinformations-Vermittler – beides liegt außerhalb des Rahmens dieses Servers.
Die operator-Identität ist ausschließlich über die HTTP-Steuerungsrouten erreichbar. Ein TASK_QUEUE_TOKEN_OPERATOR wird beim Start abgelehnt, weil operator von jeder Besitzprüfung ausgenommen ist und ein Token, das über den agentenorientierten Transport geprägt wird, dem Inhaber die gesamte Warteschlange übergeben würde.
Identitätsbindung (seit v0.8.0)
actor wird aus dem Bearer-Token abgeleitet, nicht aus der Übergabe übernommen. Die Übergabe eines Namens, der nicht mit der authentifizierten Identität übereinstimmt, wird abgelehnt, statt stillschweigend korrigiert zu werden – ein falscher Name in einem Aufruf ist ein Fehler, der sichtbar gemacht werden sollte. Das Weglassen ist in Ordnung; der Wert wird aus dem Token befüllt.
Dies gilt auch für source_agent bei submit_task, das eine Identitätsangabe und nicht nur ein Label ist: Die automatische Schließung zum Zeitpunkt der Einreichung entscheidet anhand von source_agent/target_agent, ob sie ausgelöst wird – eine Fälschung würde also die Aufgabe eines anderen Agenten endgültig schließen, ohne dass jemals update_task aufgerufen wird.
Werkzeug | Wer es aufrufen darf |
| jeder authentifizierte Agent ( |
| der |
| der |
| der |
| nur |
set_task_status ist nur für den operator vorgesehen, weil sein allow_override-Pfad eine Aufgabe zwischen zwei beliebigen Nicht-Endstatus verschieben kann – genau so lässt sich eine Übergangsregel umgehen, statt sie zu erfüllen. cancel_task ist ein endgültiges, unwiderrufliches Urteil über die Arbeit eines anderen; ein Agent, der seine eigene Aufgabe abbricht, markiert sie über update_task mit einer Begründung als failed.
Schema der Aufgabendatei
Aufgaben sind YAML-Dateien in ~/.claude/task-queue/, benannt nach dem Muster YYYYMMDD-HHMMSS-<uuid-präfix>.yml. Alle Schreibvorgänge sind atomar (zuerst in .tmp schreiben, dann os.rename()). Dateisperren pro Aufgabe über fcntl.flock verhindern Wettlaufsituationen zwischen gleichzeitigen MCP-Aufrufen und dem Dispatcher.
Die vollständige Dokumentation zu Schema und Lebenszyklus finden Sie in der homelab-agent-Komponentendokumentation.
Verwandte Themen
homelab-agent — Dokumentation zur Agenten-Orchestrierung
task-dispatcher — der Dispatcher, der Aufgaben weiterleitet und steuert
This server cannot be installed
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
- AlicenseAqualityDmaintenanceModel Context Protocol server for Task Management. This allows Claude Desktop (or any MCP client) to manage and execute tasks in a queue-based system.10154215MIT
- FlicenseNot gradedqualityCmaintenanceA task manager MCP server that demonstrates all three MCP primitives (tools, resources, prompts). Enables users to manage tasks, read task summaries and details, and run structured planning/review prompts through natural language.
- FlicenseNot gradedqualityCmaintenanceExposes task management (add, list, complete tasks) and document search (RAG) as MCP tools for AI agents.
- FlicenseAqualityCmaintenanceA production-ready MCP server for task management, enabling LLMs to create, list, and manage tasks via tools and resources, with support for local stdio and cloud Streamable HTTP deployment.5
Related MCP Connectors
Project management MCP for AI agents with safe task reads and writes.
Reliable async execution for agent tool calls: schema gating, retries, idempotency, audit trail.
Coordinate multiple AI agents over MCP: atomic claims, leases, shared ledger, handoffs, tasks.
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/TadMSTR/task-queue-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server