From 7cb98308c8016f2abd11891f428e2e8907053671 Mon Sep 17 00:00:00 2001 From: Antonio Netto Date: Wed, 25 Mar 2026 22:23:23 -0300 Subject: [PATCH] fix: MCPServerCheck false negative in subdirectory projects --- Sources/mcs/Doctor/CoreDoctorChecks.swift | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Sources/mcs/Doctor/CoreDoctorChecks.swift b/Sources/mcs/Doctor/CoreDoctorChecks.swift index 1580804..ce8a252 100644 --- a/Sources/mcs/Doctor/CoreDoctorChecks.swift +++ b/Sources/mcs/Doctor/CoreDoctorChecks.swift @@ -68,13 +68,22 @@ struct MCPServerCheck: DoctorCheck { guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return .fail("~/.claude.json contains invalid JSON") } - // Check project-scoped servers first (stored under projects[path].mcpServers) + // Walk up to the git root: Claude CLI keys local-scope servers by the git root, + // which may differ from the mcs project root in subdirectory projects. if let root = projectRoot, - let projects = json[Constants.JSONKeys.projects] as? [String: Any], - let projectEntry = projects[root.path] as? [String: Any], - let projectMCP = projectEntry[Constants.JSONKeys.mcpServers] as? [String: Any], - projectMCP[serverName] != nil { - return .pass("registered") + let projects = json[Constants.JSONKeys.projects] as? [String: Any] { + var candidate: URL? = root + while let path = candidate, path.path != "/" { + if let projectEntry = projects[path.path] as? [String: Any], + let projectMCP = projectEntry[Constants.JSONKeys.mcpServers] as? [String: Any], + projectMCP[serverName] != nil { + return .pass("registered") + } + if FileManager.default.fileExists(atPath: path.appendingPathComponent(".git").path) { + break + } + candidate = path.deletingLastPathComponent() + } } // Fall back to global/user-scoped servers if let mcpServers = json[Constants.JSONKeys.mcpServers] as? [String: Any],