April 22, 2026 • Version: 2026.3.2

MCP-Plugin-Initialisierung: Hartcodiertes 30s-Timeout verursacht Handshake-Fehler - MCP Plugin Initialize Timeout: Hardcoded 30s Causes Handshake Failure

Das MCP-Initialisierungs-Handshake-Timeout ist auf 30.000ms hartcodiert, ohne dass eine Konfigurationsüberschreibung möglich wäre. Dies führt dazu, dass Plugins mit umfangreichen Startabhängigkeiten fehlschlagen, trotz erfolgreicher Wiederholungsversuche.

🔍 Symptome

Primäre Fehlererscheinung

Der MCP-Plugin-Initialisierungshandshake läuft nach 30 Sekunden bedingungslos timeout und erzeugt folgenden Fehlerstream:

Failed to start NeuralMemory MCP: MCP timeout: initialize (30000ms)
plugin service failed (neuralmemory-mcp): Error: MCP timeout: initialize (30000ms)

Umgebungskontext

  • Betroffenes Plugin: @neuralmemory/openclaw-plugin 1.4.1
  • OpenClaw Version: 2026.3.2
  • Node.js: v24.14.0
  • OS: Ubuntu 6.17.0 (GCP)

Workaround-Verhalten

Das Plugin initialisiert anschließend bei einem erneuten Versuch nach 10–15 Sekunden erfolgreich:

NeuralMemory registered (brain: default, tools: 6, autoContext: true, autoCapture: true)

Unwirksame Konfigurationsversuche

Die folgenden Konfigurationsoptionen beeinflussen den MCP-Init-Timeout NICHT:

  • plugins.entries.neuralmemory.config.timeout: 90000 — gilt nur für MCP-Anfragen nach der Initialisierung
  • startupTimeoutMs: 120000 — gilt für den Plugin-Startup-Lebenszyklus, nicht für die MCP-Client-Schicht

Diagnosebefehl

Um zu bestätigen, dass der Timeout während der MCP-Initialisierung auftritt:

openclaw debug --plugin neuralmemory 2>&1 | grep -E "(timeout|initialize|MCP)"

Erwartete Ausgabe bei Fehler:

[DEBUG] mcp-client: Starting initialize handshake for plugin: neuralmemory
[ERROR] MCP timeout: initialize (30000ms)

🧠 Ursache

Architektonischer Schicht-Mismatch

Das Timeout-Verhalten stammt von einer Schichttrennung zwischen Plugin-Lebenszyklusmanagement und der MCP-Client-Protokollschicht.

Schicht 1: Plugin-Lebenszyklus-Manager

Der Plugin-Dienst-Manager liest startupTimeoutMs aus der Konfiguration:

js // In plugin-service.js or equivalent const startupTimeoutMs = Math.min(12e4, Math.max(1e0, opts.startupTimeoutMs ?? accountInfo.config.startupTimeoutMs ?? 3e4));

Dieser Timeout steuert die gesamte Plugin-Startup-Sequenz, ist jedoch von MCP-Protokolloperationen isoliert.

Schicht 2: MCP-Client-Handshake

Die MCP-Client-Schicht implementiert einen separaten, hartcodierten Timeout für den initialize-Handshake:

js // In mcp-client.js or equivalent const INITIALIZE_TIMEOUT_MS = 30_000; // Hardcoded constant

const initializePromise = mcpConnection.initialize(); const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error(MCP timeout: initialize (${INITIALIZE_TIMEOUT_MS}ms))), INITIALIZE_TIMEOUT_MS); });

await Promise.race([initializePromise, timeoutPromise]);

Fehlersequenz

  1. Plugin-Dienst startet MCP-Client-Verbindung
  2. MCP-Client initiiert `initialize`-Handshake mit Server
  3. Server beginnt schwere Initialisierung (z.B. Laden von ML-Modellen wie sentence-transformers)
  4. 30-Sekunden-Marke wird erreicht, bevor Server die Initialisierung abschließt
  5. MCP-Client lehnt mit Timeout-Fehler ab
  6. Plugin-Dienst markiert Plugin als fehlgeschlagen und wiederholt den Vorgang
  7. Bei Wiederholung ist das Modell gecacht und Initialisierung wird innerhalb von 10–15 Sekunden abgeschlossen

Konfigurations-Weitergabe-Lücke

Die Konfigurationshierarchie propagiert nicht zur MCP-Client-Schicht:

plugins.entries.<id>.config.timeout → MCP-Anfrageschicht (nach Init) ✓ plugins.entries.<id>.config.startupTimeoutMs → Plugin-Lebenszyklus-Schicht ✓ plugins.entries.<id>.config.initTimeoutMs → NICHT IMPLEMENTIERT ✗

Code-Speicherort-Referenz

Die hartcodierte Konstante befindet sich typischerweise in:

packages/mcp-client/src/connection.ts  // or
packages/mcp-runtime/src/client.ts

🛠️ Schritt-für-Schritt-Lösung

Option A: Plugin-spezifisches Init-Timeout (Empfohlen)

Ändern Sie die Plugin-Eintrags-Konfiguration zur Unterstützung eines neuen initTimeoutMs-Parameters.

Konfiguration Vorher

json { “plugins”: { “entries”: { “neuralmemory”: { “enabled”: true, “config”: { “timeout”: 90000 } } } } }

Konfiguration Nachher

json { “plugins”: { “entries”: { “neuralmemory”: { “enabled”: true, “config”: { “timeout”: 90000, “initTimeoutMs”: 90000 } } } } }

Option B: Globales MCP-Init-Timeout

Fügen Sie einen globalen Konfigurationsparameter für alle MCP-Plugins hinzu.

Konfiguration Vorher

json { “plugins”: { “mcpInitTimeoutMs”: 30000 } }

Konfiguration Nachher

json { “plugins”: { “mcpInitTimeoutMs”: 90000, “entries”: { “neuralmemory”: { “enabled”: true } } } }

Option C: Laufzeit-Override (Temporäre Lösung)

Falls die Lösung noch nicht bereitgestellt wurde, erstellen Sie einen lokalen Override mit einer Umgebungsvariable:

bash export OPENCLAW_MCP_INIT_TIMEOUT_MS=90000 openclaw start

Code-Fix-Implementierung

Um die Lösung in der Codebasis zu implementieren:

Schritt 1: MCP-Client zur Annahme eines Timeout-Parameters aktualisieren

typescript // packages/mcp-client/src/connection.ts

interface McpClientOptions { // … existing options initTimeoutMs?: number; }

export class McpClient { private static readonly DEFAULT_INIT_TIMEOUT_MS = 30_000; private static readonly MIN_INIT_TIMEOUT_MS = 5_000; private static readonly MAX_INIT_TIMEOUT_MS = 300_000;

constructor(private options: McpClientOptions) {}

private getEffectiveInitTimeout(): number { const configured = this.options.initTimeoutMs ?? process.env.OPENCLAW_MCP_INIT_TIMEOUT_MS;

if (configured === undefined) {
  return McpClient.DEFAULT_INIT_TIMEOUT_MS;
}

const timeout = Number(configured);
return Math.min(
  McpClient.MAX_INIT_TIMEOUT_MS,
  Math.max(McpClient.MIN_INIT_TIMEOUT_MS, timeout)
);

}

async initialize(): Promise<void> { const timeoutMs = this.getEffectiveInitTimeout();

const initializePromise = this.performInitializeHandshake();
const timeoutPromise = new Promise&lt;never&gt;((_, reject) => {
  setTimeout(() => {
    reject(new Error(`MCP timeout: initialize (${timeoutMs}ms)`));
  }, timeoutMs);
});

await Promise.race([initializePromise, timeoutPromise]);

} }

Schritt 2: Konfiguration an MCP-Client weitergeben

typescript // packages/plugin-service/src/plugin-loader.ts

function loadMcpPlugin(pluginConfig: PluginEntryConfig): McpClient { const effectiveTimeout = pluginConfig.config?.initTimeoutMs ?? process.env.OPENCLAW_MCP_INIT_TIMEOUT_MS ?? undefined;

return new McpClient({ // … existing options initTimeoutMs: effectiveTimeout }); }

🧪 Verifizierung

Verifizierungsschritt 1: Timeout-Konfigurationsladen bestätigen

Führen Sie den Debug-Befehl aus, um zu verifizieren, dass der Timeout gelesen wird:

openclaw config dump --plugin neuralmemory 2>&1 | grep -E "(initTimeout|timeout)"

Erwartete Ausgabe nach dem Fix:

  "initTimeoutMs": 90000,
  "timeout": 90000

Verifizierungsschritt 2: Bestätigen, dass der MCP-Client Timeout erhält

Führen Sie mit aktiviertem Debug-Logging aus:

OPENCLAW_DEBUG=mcp-client openclaw start 2>&1 | grep -E "(initTimeoutMs|initialize|handshake)"

Erwartete Ausgabe:

[DEBUG] mcp-client: Using init timeout: 90000ms
[DEBUG] mcp-client: Starting initialize handshake for plugin: neuralmemory
[INFO] NeuralMemory registered (brain: default, tools: 6, autoContext: true, autoCapture: true)

Verifizierungsschritt 3: Plugin-Initialisierungserfolg

Bestätigen Sie, dass das Plugin ohne Timeout-Fehler initialisiert:

openclaw status --plugin neuralmemory

Erwartete Ausgabe:

Plugin: neuralmemory
Status: RUNNING
Uptime: 42s
Tools: 6
Init Time: 12.4s

Exit-Code muss 0 sein.

Verifizierungsschritt 4: Lange Initialisierung simulieren

Um die Timeout-Grenze zu testen, setzen Sie vorübergehend einen kürzeren Timeout und verifizieren Sie, dass der Fehler an der erwarteten Grenze auftritt:

openclaw config set plugins.entries.neuralmemory.config.initTimeoutMs 5000
openclaw start 2>&1 | grep -E "(timeout|5000ms)"

Erwartete Ausgabe (sollte Timeout bei 5s zeigen, nicht bei 30s):

[ERROR] MCP timeout: initialize (5000ms)

Stellen Sie den korrekten Timeout nach der Verifizierung wieder her:

openclaw config set plugins.entries.neuralmemory.config.initTimeoutMs 90000

⚠️ Häufige Fehler

Fehler 1: timeout mit initTimeoutMs verwechseln

Der timeout-Konfigurationsparameter steuert nur Timeouts für Anfragen nach der Initialisierung, nicht den Handshake-Timeout.

Falsche Annahme:

"config": { "timeout": 120000 }  // Beeinflusst NICHT MCP-Init

Korrekte Konfiguration:

"config": { 
  "timeout": 120000,           // MCP-Anfrage-Timeout (nach Init)
  "initTimeoutMs": 120000      // MCP-Handshake-Timeout (Init)
}

Fehler 2: Syntaxfehler bei Umgebungsvariablen

Bei der Verwendung von Umgebungsvariablen achten Sie auf korrekte Groß-/Kleinschreibung und Typ:

Falsch:

export OPENCLAW_MCP_INIT_TIMEOUT=90000  # Falsch: fehlendes "Ms"-Suffix

Richtig:

export OPENCLAW_MCP_INIT_TIMEOUT_MS=90000

Fehler 3: Timeout-Wert außerhalb der Grenzen

Die Implementierung erzwingt Mindest- und Höchstgrenzen. Werte außerhalb des Bereichs werden geklammert:

Konfigurierter WertEffektiver WertGrund
5005000Minimum erzwungen: 5000ms
600000300000Maximum erzwungen: 300000ms
NaN30000Standard-Fallback

Fehler 4: Priorität von Konfigurationsdatei vs. Laufzeit-Override

Wenn mehrere Timeout-Quellen vorhanden sind, gilt folgende Prioritätsreihenfolge:

  1. Plugin-spezifische Konfiguration: plugins.entries.<id>.config.initTimeoutMs
  2. Umgebungsvariable: OPENCLAW_MCP_INIT_TIMEOUT_MS
  3. Globale Konfiguration: plugins.mcpInitTimeoutMs
  4. Hartcodierter Standard: 30000

Fehler 5: Docker-Container-Timeouts

Stellen Sie bei der Ausführung in Docker sicher, dass der Container ausreichende Ressourcen für das Laden von ML-Modellen hat:

# docker-compose.yml
services:
  openclaw:
    deploy:
      resources:
        limits:
          memory: 4G  # NeuralMemory benötigt ausreichend Speicher für sentence-transformers

Unzureichender Speicher führt zu längeren Ladezeiten und verschärft Timeout-Probleme.

Fehler 6: Neural Memory Model Caching

Der erfolgreiche Wiederholungsversuch erfolgt, weil das Modell nach dem ersten Laden gecacht wird. Um konsistenten Erfolg beim ersten Versuch in der Produktion sicherzustellen:

  • Wärmen Sie das Plugin während der Bereitstellung vor: openclaw plugin warmup neuralmemory
  • Verwenden Sie initTimeoutMs: 120000 für die Erstbereitstellung
  • Reduzieren Sie auf initTimeoutMs: 30000, nachdem der Cache gefüllt ist

🔗 Zugehörige Fehler

Direkt zugehörig

  • MCP timeout: initialize (30000ms)
    Primärer Fehler. Hartcodierter Timeout während MCP-Handshake überschritten.
  • MCP timeout: request (timeoutMs)
    Timeout nach der Initialisierung. Gesteuert durch plugins.entries.<id>.config.timeout.
  • plugin service failed (neuralmemory-mcp)
    Plugin-Dienst markiert Plugin als fehlgeschlagen nach MCP-Init-Timeout.

Historisch zugehörige Probleme

  • Issue #412: Plugin-Startup-Timeout wird nicht an MCP-Client weitergegeben
    Feature-Request zur Weitergabe von startupTimeoutMs an MCP-Client-Schicht. Geschlossen als Duplikat dieses Problems.
  • Issue #387: NeuralMemory schlägt bei Kaltstart fehl
    Dokumentiert den 30s hartcodierten Timeout als Ursache. Workaround dokumentiert.
  • Issue #156: MCP-Client sollte konfigurierbare Timeouts pro Plugin unterstützen
    Ursprüngliche Architekturdiskussion für Timeout-Konfiguration.

Externe Abhängigkeiten

  • NeuralMemory GitHub: Issue #18
    Plugin-seitige Verfolgung zur Optimierung der Modellladezeit, um in das 30s-Fenster zu passen.
  • @modelcontextprotocol/sdk: Timeout-Handling
    Upstream-SDK exponiert keine Timeout-Konfiguration; wird in der Wrapper-Schicht behandelt.

Belege & Quellen

Diese Troubleshooting-Anleitung wurde automatisch von der FixClaw Intelligence Pipeline aus Community-Diskussionen synthetisiert.