Skip to content

fix(mcp): create the parent directory for an explicit output file name - #42494

Open
Rizwan Saleem (theRizwan) wants to merge 1 commit into
microsoft:mainfrom
theRizwan:fix-mcp-explicit-filename-parent-dir
Open

fix(mcp): create the parent directory for an explicit output file name#42494
Rizwan Saleem (theRizwan) wants to merge 1 commit into
microsoft:mainfrom
theRizwan:fix-mcp-explicit-filename-parent-dir

Conversation

@theRizwan

@theRizwan Rizwan Saleem (theRizwan) commented Sep 1, 2026

Copy link
Copy Markdown

Fixes #42487

The ENOENT

Every tool that takes a filename resolves it through Response.resolveClientFile(), and only one of that method's two branches creates the directory it is about to write into:

  • no filenameContext.outputFile(), which resolves against the output directory and mkdir -ps the parent;
  • explicit filenameResponse.resolveClientFilename()Context.workspaceFile(), which resolves against the client workspace and creates nothing.

So a name containing a subdirectory fails with a raw ENOENT, as reported:

browser_take_screenshot { "filename": "sub/shot.png" }
Error: ENOENT: no such file or directory, open '<cwd>/sub/shot.png'

The mkdir added here runs after workspaceFile() has already applied its checkFile() allowed-roots check, so it can only create directories under roots the caller was allowed to write to in the first place. resolveClientFilename() itself is left alone, because it is also the read path for browser_file_upload, browser_drop, browser_set_storage_state and browser_run_code_unsafe, where creating a directory for a path that does not exist would be wrong.

The descriptions

The issue also reports that a relative filename does not land in --output-dir. That half is what the code intends rather than a bug: an explicit name is resolved against the client workspace (an MCP root, _meta.cwd for the CLI, otherwise the server's cwd), and three existing tests pin it (screenshot.spec.ts "filename: "output.png"", storage.spec.ts "saves to custom filename", roots.spec.ts "should return relative paths when root is specified").

What is wrong is the parameter description on browser_take_screenshot and browser_pdf_save, which tells the model the opposite:

Prefer relative file names to stay within the output directory.

This corrects those two strings to describe the actual behaviour. If you would rather keep the description and route relative names into the output directory instead, that is a bigger change and I am happy to redo it that way. I went with the direction the tests already commit to.

Test

browser_take_screenshot (filename with a subdirectory) in tests/mcp/screenshot.spec.ts. On main it fails with exactly the ENOENT above; with the change it passes.

Verified on macOS arm64 (M1 Max): the full tests/mcp chromium project, 639 passed / 107 skipped / 0 failed, plus npm run tsc, npx eslint on the touched files and node utils/lint_tests.js.

On the contribution policy

CONTRIBUTING asks that an issue be assigned before a PR goes up, and #42487 is not assigned to anyone. I have commented there asking; close this without ceremony if you would rather own it.

Tools that accept a `filename` resolve it through
`Response.resolveClientFile()`, which resolves the name against the client
workspace but never creates its parent directory. So
`browser_take_screenshot` with `filename: "sub/shot.png"` fails with a raw
ENOENT, while the auto-named branch of the same method goes through
`outputFile()`, which does create it.

Also correct the `filename` description on `browser_take_screenshot` and
`browser_pdf_save`. Both said a relative name stays within the output
directory; it is resolved against the working directory, which is the
behaviour the existing tests pin.

Fixes microsoft#42487
@theRizwan

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MCP]: browser_take_screenshot resolves an explicit filename against the server cwd, not the output directory

1 participant