What happened?
In MCP extension mode, all browser-level CDP commands fail with:
Error: Protocol error (Storage.getCookies): Unsupported command without sessionId: Storage.getCookies
This breaks every cli-client subcommand that touches browser-scoped state:
playwright-cli cookie-list (and cookie-get / cookie-set / cookie-delete / cookie-clear)
playwright-cli state-save
The browser session itself is healthy — goto, eval, snapshot, click all work fine. Only commands that hit Storage.* (and presumably Browser.* / target-less Target.*) are affected.
The same commands work correctly in non-extension (standalone) mode.
Root cause (already located)
The relay's forwardToExtension unconditionally requires a sessionId:
packages/playwright-core/src/tools/mcp/cdpRelayV2.ts (visible in shipped bundle around coreBundle.js:65914-65918):
async forwardToExtension(method, params, sessionId) {
if (!sessionId)
throw new Error(`Unsupported command without sessionId: ${method}`);
return await this._model.sendCommand(sessionId, method, params);
}
But Storage.getCookies / Storage.setCookie / Storage.clearDataForOrigin etc. are browser-level CDP commands, routed by browserContextId, not by a target sessionId. The Playwright CRBrowser already calls them that way:
// coreBundle.js:35671
const { cookies } = await this._browser._session.send(
"Storage.getCookies",
{ browserContextId: this._browserContextId }
);
So the relay's "must have sessionId" guard rejects commands that are legitimately session-less. This looks like a regression from the cli-client/extension-mode generalization landed in April–May 2026 (around #40191 / #40411).
Suggested fix
In cdpRelayV2.ts::forwardToExtension, route browser-level commands through the model's browser-level channel instead of throwing. Something like:
async forwardToExtension(method, params, sessionId) {
if (!sessionId) {
// browser-level CDP commands (Storage.*, Browser.*, target-less Target.*)
// are routed by browserContextId, not by a target sessionId.
if (method.startsWith('Storage.') || method.startsWith('Browser.'))
return await this._model.sendBrowserCommand(method, params);
throw new Error(`Unsupported command without sessionId: ${method}`);
}
return await this._model.sendCommand(sessionId, method, params);
}
(sendBrowserCommand may need to be added on BrowserModel to forward to the extension's root debugger session — happy to send a PR if that direction sounds right.)
Steps to reproduce
# 1. open browser in extension mode (relay to user's local Chrome)
PLAYWRIGHT_MCP_EXTENSION=true playwright-cli open
PLAYWRIGHT_MCP_EXTENSION=true playwright-cli goto https://example.com/
# 2. any cookie or state command fails
PLAYWRIGHT_MCP_EXTENSION=true playwright-cli cookie-list
# => ### Error
# => Error: Protocol error (Storage.getCookies): Unsupported command without sessionId: Storage.getCookies
PLAYWRIGHT_MCP_EXTENSION=true playwright-cli state-save /tmp/state.json
# => same error
# 3. but interaction commands work fine
PLAYWRIGHT_MCP_EXTENSION=true playwright-cli eval "document.title"
# => works
Same cookie-list against a standalone (non-extension) browser works correctly.
Expected behavior
In extension mode, cookie-list / cookie-get / state-save / etc. should return the cookies from the connected browser context — same behavior as in non-extension mode.
This matters because extension mode is the only way to read the user's logged-in HttpOnly cookies (e.g. for tooling that proxies authenticated requests through the user's existing browser session). document.cookie via eval is not a workaround for HttpOnly cookies.
Version
playwright-cli (@playwright/cli): 0.1.12
node: v25.8.2
OS: macOS 26.4.1 (arm64)
Chrome: connected via MCP extension
Workarounds
- ❌ Headless / standalone mode — works for
cookie-list, but loses access to the user's logged-in session (defeats the purpose of extension mode).
- ❌
document.cookie via eval — only returns non-HttpOnly cookies; auth cookies are usually HttpOnly.
- ✅ Local patch to
cdpRelayV2.ts along the lines suggested above.
Happy to send a PR if a maintainer can confirm the direction.
What happened?
In MCP extension mode, all browser-level CDP commands fail with:
This breaks every cli-client subcommand that touches browser-scoped state:
playwright-cli cookie-list(andcookie-get/cookie-set/cookie-delete/cookie-clear)playwright-cli state-saveThe browser session itself is healthy —
goto,eval,snapshot,clickall work fine. Only commands that hitStorage.*(and presumablyBrowser.*/ target-lessTarget.*) are affected.The same commands work correctly in non-extension (standalone) mode.
Root cause (already located)
The relay's
forwardToExtensionunconditionally requires a sessionId:packages/playwright-core/src/tools/mcp/cdpRelayV2.ts(visible in shipped bundle aroundcoreBundle.js:65914-65918):But
Storage.getCookies/Storage.setCookie/Storage.clearDataForOriginetc. are browser-level CDP commands, routed bybrowserContextId, not by a target sessionId. The PlaywrightCRBrowseralready calls them that way:So the relay's "must have sessionId" guard rejects commands that are legitimately session-less. This looks like a regression from the cli-client/extension-mode generalization landed in April–May 2026 (around #40191 / #40411).
Suggested fix
In
cdpRelayV2.ts::forwardToExtension, route browser-level commands through the model's browser-level channel instead of throwing. Something like:(
sendBrowserCommandmay need to be added onBrowserModelto forward to the extension's root debugger session — happy to send a PR if that direction sounds right.)Steps to reproduce
Same
cookie-listagainst a standalone (non-extension) browser works correctly.Expected behavior
In extension mode,
cookie-list/cookie-get/state-save/ etc. should return the cookies from the connected browser context — same behavior as in non-extension mode.This matters because extension mode is the only way to read the user's logged-in HttpOnly cookies (e.g. for tooling that proxies authenticated requests through the user's existing browser session).
document.cookieviaevalis not a workaround for HttpOnly cookies.Version
Workarounds
cookie-list, but loses access to the user's logged-in session (defeats the purpose of extension mode).document.cookieviaeval— only returns non-HttpOnly cookies; auth cookies are usually HttpOnly.cdpRelayV2.tsalong the lines suggested above.Happy to send a PR if a maintainer can confirm the direction.