diff --git a/README.md b/README.md
index 709df800..522f3bf9 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,7 @@
Free desktop app for AI agent teams. Auto-detects Claude/Codex. Use the provider access you already have - subscriptions or API keys. Not just coding agents.
-
-
+
diff --git a/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts b/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts
index 716236db..46521eeb 100644
--- a/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts
+++ b/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts
@@ -61,6 +61,8 @@ export class ClaudeExtensionsAdapter implements ExtensionsRuntimeAdapter {
export class MultimodelExtensionsAdapter implements ExtensionsRuntimeAdapter {
readonly flavor = 'agent_teams_orchestrator' as const;
+ constructor(private readonly stateReader = new McpConfigStateReader()) {}
+
async buildManagementCliEnv(binaryPath: string): Promise {
return buildManagementCliEnvForBinary(binaryPath);
}
@@ -72,13 +74,21 @@ export class MultimodelExtensionsAdapter implements ExtensionsRuntimeAdapter {
}
const env = await this.buildManagementCliEnv(binaryPath);
- const { stdout } = await execCli(binaryPath, ['mcp', 'list', '--json'], {
- timeout: MCP_LIST_TIMEOUT_MS,
- cwd: projectPath,
- env,
- });
+ try {
+ const { stdout } = await execCli(binaryPath, ['mcp', 'list', '--json'], {
+ timeout: MCP_LIST_TIMEOUT_MS,
+ cwd: projectPath,
+ env,
+ });
- return parseInstalledMcpJsonOutput(stdout);
+ return parseInstalledMcpJsonOutput(stdout);
+ } catch (error) {
+ if (!isUnsupportedMcpJsonContractError(error)) {
+ throw error;
+ }
+
+ return this.stateReader.readInstalled(projectPath);
+ }
}
async diagnoseMcp(projectPath?: string): Promise {
@@ -88,16 +98,44 @@ export class MultimodelExtensionsAdapter implements ExtensionsRuntimeAdapter {
}
const env = await this.buildManagementCliEnv(binaryPath);
- const { stdout } = await execCli(binaryPath, ['mcp', 'diagnose', '--json'], {
- timeout: MCP_DIAGNOSE_TIMEOUT_MS,
- cwd: projectPath,
- env,
- });
+ try {
+ const { stdout } = await execCli(binaryPath, ['mcp', 'diagnose', '--json'], {
+ timeout: MCP_DIAGNOSE_TIMEOUT_MS,
+ cwd: projectPath,
+ env,
+ });
- return parseMcpDiagnosticsJsonOutput(stdout);
+ return parseMcpDiagnosticsJsonOutput(stdout);
+ } catch (error) {
+ if (!isUnsupportedMcpJsonContractError(error)) {
+ throw error;
+ }
+
+ const { stdout, stderr } = await execCli(binaryPath, ['mcp', 'list'], {
+ timeout: MCP_DIAGNOSE_TIMEOUT_MS,
+ cwd: projectPath,
+ env,
+ });
+
+ return parseMcpDiagnosticsOutput([stdout, stderr].filter(Boolean).join('\n'));
+ }
}
}
+function isUnsupportedMcpJsonContractError(error: unknown): boolean {
+ const message = error instanceof Error ? error.message : String(error);
+ const normalized = message.toLowerCase();
+
+ return (
+ normalized.includes("unknown command 'diagnose'") ||
+ normalized.includes('unknown command "diagnose"') ||
+ normalized.includes('unknown option') ||
+ normalized.includes('unknown argument') ||
+ normalized.includes('unexpected argument') ||
+ normalized.includes('unrecognized option')
+ );
+}
+
class RuntimeSwitchingExtensionsAdapter implements ExtensionsRuntimeAdapter {
constructor(
private readonly claudeAdapter: ClaudeExtensionsAdapter,