{"record":{"id":"d15a725caedd6b3a","repo":"angular/angular-cli","slug":"the-current-directory-resolves-to-a-workspace-outs","errorCode":null,"errorMessage":"The current directory resolves to a workspace outside the allowed MCP roots: ${found}. You can use 'list_projects' to find available workspaces.","messagePattern":"The current directory resolves to a workspace outside the allowed MCP roots: (.+?)\\. You can use 'list_projects' to find available workspaces\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular/cli/src/commands/mcp/workspace-utils.ts","lineNumber":193,"sourceCode":"      workspace = await AngularWorkspace.load(configPath);\n    } catch (e) {\n      throw new Error(`Failed to load workspace configuration at ${configPath}`, { cause: e });\n    }\n  } else if (mcpWorkspace) {\n    workspace = mcpWorkspace;\n    workspacePath = workspace.basePath;\n  } else {\n    const found = findAngularJsonDir(process.cwd(), host);\n\n    if (!found) {\n      throw new Error(\n        'Could not find an Angular workspace (angular.json) in the current directory. ' +\n          \"You can use 'list_projects' to find available workspaces.\",\n      );\n    }\n\n    if (server && !(await isAllowedWorkspacePath(server, found))) {\n      throw new Error(\n        `The current directory resolves to a workspace outside the allowed MCP roots: ${found}. ` +\n          \"You can use 'list_projects' to find available workspaces.\",\n      );\n    }\n\n    workspacePath = found;\n    const configPath = join(workspacePath, 'angular.json');\n    try {\n      workspace = await AngularWorkspace.load(configPath);\n    } catch (e) {\n      throw new Error(`Failed to load workspace configuration at ${configPath}.`, { cause: e });\n    }\n  }\n\n  let projectName = projectNameInput;\n  if (projectName) {\n    if (!workspace.projects.has(projectName)) {\n      throw new Error(","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/cli/src/commands/mcp/workspace-utils.ts#L175-L211","documentation":"Same sandbox check as error 35, but applied to a workspace discovered automatically: after `findAngularJsonDir` locates the nearest angular.json above `process.cwd()`, `isAllowedWorkspacePath` verifies the found directory (after realpath resolution) is inside the MCP client's allowed roots. If the discovered workspace falls outside them, the server refuses to operate and throws this error to keep tool access confined to the opened workspace folders.","triggerScenarios":"Invoking an MCP tool without `workspacePath` while `process.cwd()` sits inside (or under a path whose nearest angular.json belongs to) a directory outside the MCP roots — e.g. cwd is a sibling repo, a symlinked directory resolving elsewhere, or the client only opened one of several projects.","commonSituations":"Terminal/MCP server started from outside the IDE-opened folder; the project is accessed through a symlink into another location; multiple repos side by side with the server launched from the wrong one; the user opened only a subfolder but the angular.json found belongs to a parent outside the roots.","solutions":["Open the correct workspace folder in the IDE/MCP client so the discovered angular.json directory is within the allowed roots, then retry","Call `list_projects` to see which workspaces are allowed and select one explicitly via `workspacePath`","Remove symlinks causing the resolved real path to fall outside the roots, or add the real target to the workspace","Relaunch the MCP server with its working directory inside the allowed workspace"],"exampleFix":"// before (cwd = /work/repos-a, but IDE opened /work/repos-b)\ncd /work/repos-a && mcp ng_search\n// after\ncd /work/repos-b && mcp ng_search  // or open /work/repos-a in the IDE","handlingStrategy":"validation","validationCode":"import { existsSync, realpathSync } from 'node:fs';\nimport { join } from 'node:path';\n// allowedRoots: real paths of MCP client workspace folders\nfunction findAngularJsonDir(startDir: string): string | null {\n  let dir = startDir;\n  while (true) {\n    if (existsSync(join(dir, 'angular.json'))) return dir;\n    const parent = join(dir, '..');\n    if (parent === dir) return null;\n    dir = parent;\n  }\n}\nconst found = findAngularJsonDir(process.cwd());\nconst allowed = found != null && allowedRoots.some((root) => {\n  const r = realpathSync(root), f = realpathSync(found);\n  return f === r || f.startsWith(r + '/');\n});\nif (!allowed) {\n  throw new Error(`Discovered workspace ${found} is outside allowed MCP roots; open it in the IDE or pass an allowed workspacePath`);\n}","typeGuard":"function isPathWithinRoot(childPath: string, rootPath: string): boolean {\n  const rel = path.relative(path.resolve(rootPath), path.resolve(childPath));\n  return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n}","tryCatchPattern":"try {\n  return await mcp.callTool('ng_search', {});\n} catch (e) {\n  if (String(e?.message).includes('outside the allowed MCP roots')) {\n    const projects = await mcp.callTool('list_projects', {});\n    return mcp.callTool('ng_search', { workspacePath: pickAllowedWorkspace(projects) });\n  }\n  throw e;\n}","preventionTips":["Start the MCP server from a cwd inside the IDE-opened workspace folders","Open all relevant project folders (multi-root workspace) so discovery lands inside allowed roots","Avoid symlinked working directories whose real path falls outside the opened folder","Use list_projects to confirm which workspaces are allowed before invoking tools","Pass an explicit, allowed workspacePath instead of relying on cwd discovery"],"tags":["mcp","security","path-validation","workspace","cwd","angular-cli"],"backgroundTag":"path-outside-allowed-roots","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}