Workspace root of / denies every path because the separator is appended twice

Author: wyf0931Created Sep 23, 2026Updated Sep 24, 2026
Labelsconfirmed

Description of the bug

McpContext.validatePath() rejects every path when a configured workspace root is the filesystem root.

The allowed prefix is built as canonicalRoot + path.sep in src/McpContext.ts:

typescript
if (
  canonicalPath === canonicalRoot ||
  canonicalPath.startsWith(canonicalRoot + path.sep)
)

For the filesystem root this doubles the separator — / becomes // on POSIX, and C:\ becomes C:\\ on Windows — so no path below the root ever matches, and every file-writing tool fails with:

Access denied: path /Users/me/shots/fullpage.png (canonical: /Users/me/shots/fullpage.png) is not within any of the configured workspace roots.

That makes --workspace=/ unusable, and / is exactly the value the --allow-unrestricted-paths deprecation notice recommends:

--allowUnrestrictedPaths ... [deprecated: Use --workspace=/ instead.]

Narrower roots such as --workspace=/Users/me work correctly, so this only affects a root that already ends with the separator.

Reproduction

  1. Start the server from a client that does not negotiate the MCP roots capability, with the filesystem root as the workspace root:
bash
node build/src/bin/chrome-devtools-mcp.js --headless --isolated --no-page-id-routing --workspace=/
  1. Call take_screenshot with a filePath outside the temp directory:
json
{"name": "take_screenshot", "arguments": {"filePath": "/Users/me/shots/fullpage.png"}}
  1. The call is rejected with the error above. Repeating step 2 with --workspace=/Users/me writes the screenshot as expected.

Reproduced on 1.9.0 and on main, both through a real server process.

Expectation

--workspace=/ should allow file writes anywhere, as the deprecation notice describes, while narrower roots keep their existing guardrails.

Possible fix

Only append the separator when the canonical root does not already end with one:

typescript
const rootPrefix = canonicalRoot.endsWith(path.sep)
  ? canonicalRoot
  : canonicalRoot + path.sep;
if (canonicalPath === canonicalRoot || canonicalPath.startsWith(rootPrefix)) {

I have this change plus a regression test in tests/roots.test.ts ready to go and am happy to open a PR if that is welcome.

MCP configuration

json
{
  "mcpServers": {
    "chrome-devtools": {
      "command": "node",
      "args": ["build/src/bin/chrome-devtools-mcp.js", "--headless", "--workspace=/"]
    }
  }
}

Chrome DevTools MCP version

1.9.0

Chrome version

153.0.8010.53

Coding agent version

pi-coding-agent 0.87.1 (where I first hit this); reproduced with a minimal MCP client that omits the roots capability.

Node version

v22.21.1

Operating system

macOS

Extra checklist

  • I want to provide a PR to fix this bug

Source: ChromeDevTools/chrome-devtools-mcp