feat(mcp): reconnect failed MCP servers in managed OpenCode
OpenCode marks an MCP server failed when it does not come up at startup or when a live connection drops, and never retries. A new managed plugin reconnects those servers with a per-server backoff (1s doubling to a 30s cap), wakes early on mcp.tools.changed, and stops on dispose. Only the failed state is retried; disabled and auth states stay untouched. The OPENCODE_CONFIG_CONTENT merge that agent-tool and system-prompt each carried is now one shared helper so the three managed plugins compose. Claude-Session: https://claude.ai/code/session_01VqV56Hez25hTxXH4ipJfzH
This commit is contained in:
@@ -111,6 +111,7 @@ import { createDevServerScanner } from './lib/dev-servers/routes.js';
|
||||
import { createDevTunnelRuntime } from './lib/dev-tunnel/runtime.js';
|
||||
import { registerBrowserControlRoutes } from './lib/browser-control/routes.js';
|
||||
import { createSystemPromptRuntime } from './lib/system-prompt/runtime.js';
|
||||
import { createMcpReconnectRuntime } from './lib/mcp-reconnect/runtime.js';
|
||||
import { createOpenChamberSessionService } from './lib/openchamber-sessions/routes.js';
|
||||
import { createScheduledTaskService } from './lib/scheduled-tasks/service.js';
|
||||
import { createOpenChamberControlService } from './lib/openchamber-control/service.js';
|
||||
@@ -285,6 +286,7 @@ const readCustomThemesFromDisk = (...args) => themeRuntime.readCustomThemesFromD
|
||||
let notificationTemplateRuntime = null;
|
||||
let agentToolRuntime = null;
|
||||
let systemPromptRuntime = null;
|
||||
let mcpReconnectRuntime = null;
|
||||
|
||||
const createTimeoutSignal = (...args) => notificationTemplateRuntime.createTimeoutSignal(...args);
|
||||
const formatProjectLabel = (...args) => notificationTemplateRuntime.formatProjectLabel(...args);
|
||||
@@ -1222,11 +1224,15 @@ const openCodeLifecycleRuntime = createOpenCodeLifecycleRuntime({
|
||||
const managedEnv = includeControl || includeWeb || includeMemory
|
||||
? await (agentToolRuntime?.prepareManagedOpenCodeEnv({ includeControl, includeWeb, includeMemory }) || {})
|
||||
: {};
|
||||
if (settings?.optimizeSystemPrompt !== true) return managedEnv;
|
||||
|
||||
const configContent = managedEnv.OPENCODE_CONFIG_CONTENT ?? process.env.OPENCODE_CONFIG_CONTENT;
|
||||
const systemPromptEnv = await systemPromptRuntime.prepareManagedOpenCodeEnv(configContent);
|
||||
return { ...managedEnv, ...systemPromptEnv };
|
||||
// Each managed plugin appends itself to the config the previous one produced.
|
||||
let configContent = managedEnv.OPENCODE_CONFIG_CONTENT ?? process.env.OPENCODE_CONFIG_CONTENT;
|
||||
if (settings?.optimizeSystemPrompt === true) {
|
||||
({ OPENCODE_CONFIG_CONTENT: configContent } = await systemPromptRuntime.prepareManagedOpenCodeEnv(configContent));
|
||||
}
|
||||
// Always on for managed OpenCode: it only retries servers OpenCode gave up on.
|
||||
const mcpReconnectEnv = await mcpReconnectRuntime.prepareManagedOpenCodeEnv(configContent);
|
||||
return { ...managedEnv, ...mcpReconnectEnv };
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1500,6 +1506,11 @@ async function main(options = {}) {
|
||||
path,
|
||||
dataDir: OPENCHAMBER_DATA_DIR,
|
||||
});
|
||||
mcpReconnectRuntime = createMcpReconnectRuntime({
|
||||
fsPromises,
|
||||
path,
|
||||
dataDir: OPENCHAMBER_DATA_DIR,
|
||||
});
|
||||
|
||||
// Pairing transports advertised to the create-device dialog. LAN reachability is
|
||||
// derived from the SERVER's actual bind (a wildcard bind → the machine's LAN IP;
|
||||
|
||||
Reference in New Issue
Block a user