From 83047c1ce7600e1d53cb4d66bcac3df8c09332c5 Mon Sep 17 00:00:00 2001 From: caoximu Date: Tue, 7 Jul 2026 15:20:44 +0800 Subject: [PATCH] fix(opencode): detect global config so doctor lists configured servers The OpenCode generator declared `globalConfigPaths: null` while its `detectInstalled()` checked for `~/.config/opencode`. As a result, `getmcp doctor` marked OpenCode as installed but always read the relative `opencode.json` path (which usually does not exist), returning an empty config and listing zero servers. This was especially confusing because the report said "OpenCode: config file is valid" while silently ignoring the user's real `~/.config/opencode/opencode.jsonc`. Two changes: 1. `packages/generators/src/opencode.ts` Declare `globalConfigPaths` pointing at `~/.config/opencode/opencode.jsonc` (darwin/linux) and `%AppData%/opencode/opencode.jsonc` (win32), matching the OpenCode documented global config location. 2. `packages/cli/src/detect.ts` For dual-scope apps, when the project config file does not exist but the global one does, point `configPath` at the global file. This makes `doctor`/`list` reflect the config the user is actually using. Also benefits Claude Code users who only keep `~/.claude.json`. Tests updated to classify OpenCode as dual-scope. Verified locally: `getmcp doctor` now lists all 6 configured servers (previously 0). --- packages/cli/src/detect.ts | 16 +++++++++++++++- packages/cli/tests/detect.test.ts | 4 ++-- packages/generators/src/opencode.ts | 12 +++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/detect.ts b/packages/cli/src/detect.ts index 5b7fc36..7470aa1 100644 --- a/packages/cli/src/detect.ts +++ b/packages/cli/src/detect.ts @@ -7,6 +7,7 @@ import * as path from "node:path"; import * as os from "node:os"; +import * as fs from "node:fs"; import { generators } from "@getmcp/generators"; import type { AppIdType, AppMetadata } from "@getmcp/core"; import { supportsBothScopes } from "@getmcp/core"; @@ -91,10 +92,23 @@ export function detectApps(): DetectedApp[] { const hasBothScopes = supportsBothScopes(generator.app); const globalConfigPath = hasBothScopes ? getConfigPath(generator.app, "global") : undefined; + // For dual-scope apps, prefer the project config when it exists; otherwise + // fall back to the global config so that doctor/list reflect the config + // the user is actually using. This matters for apps like OpenCode and + // Claude Code where many users only keep a global config. + let effectiveConfigPath = configPath; + if (hasBothScopes && globalConfigPath) { + const projectExists = fs.existsSync(configPath); + const globalExists = fs.existsSync(globalConfigPath); + if (!projectExists && globalExists) { + effectiveConfigPath = globalConfigPath; + } + } + results.push({ id: generator.app.id, name: generator.app.name, - configPath, + configPath: effectiveConfigPath, exists: generator.detectInstalled(), supportsBothScopes: hasBothScopes, ...(globalConfigPath ? { globalConfigPath } : {}), diff --git a/packages/cli/tests/detect.test.ts b/packages/cli/tests/detect.test.ts index 87b99fa..715d6cf 100644 --- a/packages/cli/tests/detect.test.ts +++ b/packages/cli/tests/detect.test.ts @@ -56,7 +56,7 @@ describe("detectApps", () => { it("dual-scope apps have supportsBothScopes true", () => { const apps = detectApps(); - const dualScopeIds = ["claude-code", "cursor", "codex"]; + const dualScopeIds = ["claude-code", "cursor", "codex", "opencode"]; for (const app of apps) { if (dualScopeIds.includes(app.id)) { expect(app.supportsBothScopes).toBe(true); @@ -67,7 +67,7 @@ describe("detectApps", () => { it("single-scope apps have supportsBothScopes false", () => { const apps = detectApps(); - const singleScopeIds = ["claude-desktop", "vscode", "cline", "goose", "opencode"]; + const singleScopeIds = ["claude-desktop", "vscode", "cline", "goose"]; for (const app of apps) { if (singleScopeIds.includes(app.id)) { expect(app.supportsBothScopes).toBe(false); diff --git a/packages/generators/src/opencode.ts b/packages/generators/src/opencode.ts index 75bc9a6..6990a37 100644 --- a/packages/generators/src/opencode.ts +++ b/packages/generators/src/opencode.ts @@ -35,8 +35,18 @@ export class OpenCodeGenerator extends BaseGenerator { id: "opencode", name: "OpenCode", description: "Open-source AI coding agent by Anomaly", + // Project-level config. OpenCode accepts both opencode.json and opencode.jsonc; + // we write .json because it is the most widely compatible default. configPaths: "opencode.json", - globalConfigPaths: null, + // Global config. Per OpenCode docs, global settings live in + // ~/.config/opencode/opencode.jsonc (JSONC to allow comments). + // On Windows the equivalent location is %AppData%\opencode\. + // See https://opencode.ai/docs/config/ + globalConfigPaths: { + darwin: "~/.config/opencode/opencode.jsonc", + win32: "%AppData%/opencode/opencode.jsonc", + linux: "~/.config/opencode/opencode.jsonc", + }, configFormat: "jsonc", docsUrl: "https://opencode.ai/docs/mcp-servers/", };