diff --git a/packages/playwright-core/src/tools/backend/runCode.ts b/packages/playwright-core/src/tools/backend/runCode.ts
index 62905a7b0c9ed..cfe8d84b7c06f 100644
--- a/packages/playwright-core/src/tools/backend/runCode.ts
+++ b/packages/playwright-core/src/tools/backend/runCode.ts
@@ -22,6 +22,13 @@ import { ManualPromise } from '@isomorphic/manualPromise';
import { defineTabTool } from './tool';
+const exposedGlobals = [
+ 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate', 'queueMicrotask',
+ 'URL', 'URLSearchParams', 'TextEncoder', 'TextDecoder', 'AbortController', 'AbortSignal',
+ 'fetch', 'Headers', 'Request', 'Response', 'FormData', 'Blob',
+ 'Buffer', 'crypto', 'atob', 'btoa', 'structuredClone',
+];
+
const codeSchema = z.object({
code: z.string().optional().describe(`A JavaScript function containing Playwright code to execute. It will be invoked with a single argument, page, which you can use for any page interaction. For example: \`async (page) => { await page.getByRole('button', { name: 'Submit' }).click(); return await page.title(); }\``),
filename: z.string().optional().describe('Load code from the specified file. Relative file names are resolved against the workspace root. If both code and filename are provided, code will be ignored.'),
@@ -49,6 +56,8 @@ const runCode = defineTabTool({
page: tab.page,
__end__,
};
+ for (const name of exposedGlobals)
+ context[name] = globalThis[name as keyof typeof globalThis];
vm.createContext(context);
// User-installed callbacks (e.g. page.route handlers) can throw
// asynchronously while __fn__ awaits an operation that depends on them
diff --git a/packages/playwright-core/src/tools/skills/playwright-cli/references/running-code.md b/packages/playwright-core/src/tools/skills/playwright-cli/references/running-code.md
index 98b541fb54cd6..5bf7e8cfb5211 100644
--- a/packages/playwright-core/src/tools/skills/playwright-cli/references/running-code.md
+++ b/packages/playwright-core/src/tools/skills/playwright-cli/references/running-code.md
@@ -21,6 +21,10 @@ playwright-cli run-code --filename=./my-script.js
The code must be a single function expression, it is wrapped in `(...)` and evaluated.
import/export/require syntax is not supported.
+The code runs in an isolated context, not in a full Node.js environment. `require`, `process` and Node modules are not
+available. Timers (`setTimeout`, `setInterval`), `fetch`, `URL`, `Buffer`, `crypto`, `AbortController`, `TextEncoder`
+and `TextDecoder` are available.
+
## Geolocation
```bash
diff --git a/tests/mcp/cli-run-code.spec.ts b/tests/mcp/cli-run-code.spec.ts
index f14eff4b0a1dc..7bb97ce92c9b5 100644
--- a/tests/mcp/cli-run-code.spec.ts
+++ b/tests/mcp/cli-run-code.spec.ts
@@ -58,3 +58,16 @@ test('run-code from file with template literals', async ({ cli, server }) => {
const { output } = await cli('run-code', '--filename=template-script.js');
expect(output).toContain('result: templated');
});
+
+test('run-code delayed route with setTimeout', async ({ cli, server }) => {
+ server.setContent('/', '