From f269d2fcc5eeb800c6f70877fa8d7bee3aa559f6 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 3 Apr 2026 17:14:40 +0900 Subject: [PATCH] Fix local MCP scope path containment Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../claude-code-mcp-loader/scope-filter.ts | 15 ++--------- src/shared/contains-path.ts | 27 +++++++++++++++---- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/features/claude-code-mcp-loader/scope-filter.ts b/src/features/claude-code-mcp-loader/scope-filter.ts index 690421e0c..6da03829c 100644 --- a/src/features/claude-code-mcp-loader/scope-filter.ts +++ b/src/features/claude-code-mcp-loader/scope-filter.ts @@ -1,17 +1,6 @@ -import { existsSync, realpathSync } from "fs" -import { resolve } from "path" +import { containsPath } from "../../shared/contains-path" import type { ClaudeCodeMcpServer } from "./types" -function normalizePath(path: string): string { - const resolvedPath = resolve(path) - - if (!existsSync(resolvedPath)) { - return resolvedPath - } - - return realpathSync(resolvedPath) -} - export function shouldLoadMcpServer( server: Pick, cwd = process.cwd() @@ -24,5 +13,5 @@ export function shouldLoadMcpServer( return false } - return normalizePath(server.projectPath) === normalizePath(cwd) + return containsPath(server.projectPath, cwd) } diff --git a/src/shared/contains-path.ts b/src/shared/contains-path.ts index bd37a5bb9..f51d1f70d 100644 --- a/src/shared/contains-path.ts +++ b/src/shared/contains-path.ts @@ -1,6 +1,22 @@ import { existsSync, realpathSync } from "fs" import { basename, dirname, isAbsolute, join, normalize, relative, resolve } from "path" +function findNearestExistingAncestor(resolvedPath: string): string { + let candidatePath = resolvedPath + + while (!existsSync(candidatePath)) { + const parentPath = dirname(candidatePath) + + if (parentPath === candidatePath) { + return candidatePath + } + + candidatePath = parentPath + } + + return candidatePath +} + function toCanonicalPath(pathToNormalize: string): string { const resolvedPath = resolve(pathToNormalize) @@ -12,12 +28,13 @@ function toCanonicalPath(pathToNormalize: string): string { } } - const parentDirectory = dirname(resolvedPath) - const canonicalParentDirectory = existsSync(parentDirectory) - ? realpathSync.native(parentDirectory) - : parentDirectory + const nearestExistingAncestor = findNearestExistingAncestor(resolvedPath) + const canonicalAncestor = existsSync(nearestExistingAncestor) + ? realpathSync.native(nearestExistingAncestor) + : nearestExistingAncestor + const relativePathFromAncestor = relative(nearestExistingAncestor, resolvedPath) - return normalize(join(canonicalParentDirectory, basename(resolvedPath))) + return normalize(join(canonicalAncestor, relativePathFromAncestor || basename(resolvedPath))) } export function containsPath(rootPath: string, candidatePath: string): boolean {