chore: roll to 1.59.0-alpha-1769176698000 (#1327)

This commit is contained in:
Dmitry Gozman
2026-01-23 17:24:40 +00:00
committed by GitHub
parent 6aab683338
commit fbd62cd838
10 changed files with 162 additions and 57 deletions

View File

@@ -400,6 +400,10 @@ Playwright MCP server supports following arguments. They can be provided in the
--no-sandbox disable the sandbox for all process
types that are normally sandboxed.
--output-dir <path> path to the directory for output files.
--output-mode <mode> whether to save snapshots, console
messages, network logs to a file or to
the standard output. Can be "file" or
"stdout". Default is "stdout".
--port <port> port to listen on for SSE transport.
--proxy-bypass <bypass> comma-separated domains to bypass proxy,
for example
@@ -436,6 +440,10 @@ Playwright MCP server supports following arguments. They can be provided in the
created.
--viewport-size <size> specify browser viewport size in pixels,
for example "1280x720"
--codegen <lang> specify the language to use for code
generation, possible values:
"typescript", "none". Default is
"typescript".
```
<!--- End of options generated section -->
@@ -659,6 +667,11 @@ npx @playwright/mcp@latest --config path/to/config.json
*/
outputDir?: string;
/**
* Whether to save snapshots, console messages, network logs and other session logs to a file or to the standard output. Defaults to "stdout".
*/
outputMode?: 'file' | 'stdout';
console?: {
/**
* The level of console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
@@ -705,13 +718,18 @@ npx @playwright/mcp@latest --config path/to/config.json
* When taking snapshots for responses, specifies the mode to use.
*/
mode?: 'incremental' | 'full' | 'none';
}
};
/**
* Whether to allow file uploads from anywhere on the file system.
* By default (false), file uploads are restricted to paths within the MCP roots only.
*/
allowUnrestrictedFileAccess?: boolean;
/**
* Specify the language to use for code generation.
*/
codegen?: 'typescript' | 'none';
}
```
@@ -811,7 +829,7 @@ http.createServer(async (req, res) => {
- Title: Click
- Description: Perform click on a web page
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- `doubleClick` (boolean, optional): Whether to perform a double click instead of a single click
- `button` (string, optional): Button to click, defaults to left
@@ -832,7 +850,8 @@ http.createServer(async (req, res) => {
- Title: Get console messages
- Description: Returns all console messages
- Parameters:
- `level` (string, optional): Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
- `level` (string): Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
- `filename` (string, optional): Filename to save the console messages to. If not provided, messages are returned as text.
- Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js -->
@@ -892,7 +911,7 @@ http.createServer(async (req, res) => {
- Title: Hover mouse
- Description: Hover over element on page
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- Read-only: **false**
@@ -909,7 +928,7 @@ http.createServer(async (req, res) => {
- **browser_navigate_back**
- Title: Go back
- Description: Go back to the previous page
- Description: Go back to the previous page in the history
- Parameters: None
- Read-only: **false**
@@ -919,7 +938,8 @@ http.createServer(async (req, res) => {
- Title: List network requests
- Description: Returns all network requests since loading the page
- Parameters:
- `includeStatic` (boolean, optional): Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.
- `includeStatic` (boolean): Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.
- `filename` (string, optional): Filename to save the network requests to. If not provided, requests are returned as text.
- Read-only: **true**
<!-- NOTE: This has been generated via update-readme.js -->
@@ -956,7 +976,7 @@ http.createServer(async (req, res) => {
- Title: Select option
- Description: Select an option in a dropdown
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- `values` (array): Array of values to select in the dropdown. This can be a single value or multiple values.
- Read-only: **false**
@@ -976,7 +996,7 @@ http.createServer(async (req, res) => {
- Title: Take a screenshot
- Description: Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.
- Parameters:
- `type` (string, optional): Image format for the screenshot. Default is png.
- `type` (string): Image format for the screenshot. Default is png.
- `filename` (string, optional): File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified. Prefer relative file names to stay within the output directory.
- `element` (string, optional): Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.
- `ref` (string, optional): Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.
@@ -989,7 +1009,7 @@ http.createServer(async (req, res) => {
- Title: Type text
- Description: Type text into editable element
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- `text` (string): Text to type into the element
- `submit` (boolean, optional): Whether to submit entered text (press Enter after)
@@ -1046,18 +1066,25 @@ http.createServer(async (req, res) => {
- Title: Click
- Description: Click left mouse button at a given position
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `x` (number): X coordinate
- `y` (number): Y coordinate
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_down**
- Title: Press mouse down
- Description: Press mouse down
- Parameters:
- `button` (string, optional): Button to press, defaults to left
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_drag_xy**
- Title: Drag mouse
- Description: Drag left mouse button to a given position
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `startX` (number): Start X coordinate
- `startY` (number): Start Y coordinate
- `endX` (number): End X coordinate
@@ -1070,11 +1097,29 @@ http.createServer(async (req, res) => {
- Title: Move mouse
- Description: Move mouse to a given position
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `x` (number): X coordinate
- `y` (number): Y coordinate
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_up**
- Title: Press mouse up
- Description: Press mouse up
- Parameters:
- `button` (string, optional): Button to press, defaults to left
- Read-only: **false**
<!-- NOTE: This has been generated via update-readme.js -->
- **browser_mouse_wheel**
- Title: Scroll mouse wheel
- Description: Scroll mouse wheel
- Parameters:
- `deltaX` (number): X delta
- `deltaY` (number): Y delta
- Read-only: **false**
</details>
<details>
@@ -1100,7 +1145,7 @@ http.createServer(async (req, res) => {
- Title: Create locator for element
- Description: Generate locator for the given element to use in tests
- Parameters:
- `element` (string): Human-readable element description used to obtain permission to interact with the element
- `element` (string, optional): Human-readable element description used to obtain permission to interact with the element
- `ref` (string): Exact target element reference from the page snapshot
- Read-only: **true**

69
package-lock.json generated
View File

@@ -12,8 +12,8 @@
"packages/*"
],
"devDependencies": {
"@modelcontextprotocol/sdk": "^1.24.0",
"@playwright/test": "1.58.0-alpha-2026-01-16",
"@modelcontextprotocol/sdk": "^1.25.2",
"@playwright/test": "1.59.0-alpha-1769176698000",
"@types/node": "^24.3.0"
}
},
@@ -724,6 +724,19 @@
"node": ">=18"
}
},
"node_modules/@hono/node-server": {
"version": "1.19.9",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
"integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.14.1"
},
"peerDependencies": {
"hono": "^4"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -775,12 +788,13 @@
}
},
"node_modules/@modelcontextprotocol/sdk": {
"version": "1.24.3",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.24.3.tgz",
"integrity": "sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==",
"version": "1.25.3",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz",
"integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@hono/node-server": "^1.19.9",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
"content-type": "^1.0.5",
@@ -791,6 +805,7 @@
"express": "^5.0.1",
"express-rate-limit": "^7.5.0",
"jose": "^6.1.1",
"json-schema-typed": "^8.0.2",
"pkce-challenge": "^5.0.0",
"raw-body": "^3.0.0",
"zod": "^3.25 || ^4.0",
@@ -825,13 +840,13 @@
"link": true
},
"node_modules/@playwright/test": {
"version": "1.58.0-alpha-2026-01-16",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.0-alpha-2026-01-16.tgz",
"integrity": "sha512-zhOc7QhE1FcIFUa1GNzs30phACtSLOgObjiz1GJSAcfp1OetskyjvspJPgHxrHggWphkQaj8IYoDe4y03rd6eg==",
"version": "1.59.0-alpha-1769176698000",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0-alpha-1769176698000.tgz",
"integrity": "sha512-n0R0xysvhuQ7XZnNrYBjB1wA3d6+UC1kneg8yqAdnUe+SpkWSRYoH4fA4gfLK/gcb9bskb5N+/nEQaoUC9jbGQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.58.0-alpha-2026-01-16"
"playwright": "1.59.0-alpha-1769176698000"
},
"bin": {
"playwright": "cli.js"
@@ -2148,6 +2163,17 @@
"node": ">= 0.4"
}
},
"node_modules/hono": {
"version": "4.11.5",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.5.tgz",
"integrity": "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -2306,6 +2332,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/json-schema-typed": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
"integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -2582,12 +2615,12 @@
}
},
"node_modules/playwright": {
"version": "1.58.0-alpha-2026-01-16",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.0-alpha-2026-01-16.tgz",
"integrity": "sha512-Ix0VALX+fNrXICSNnrfsvTMch0LA3WdVY8q71ReQzQ+UF0lCK9YbtRwBz65BJLBsWE1j38vBLR+YYE93MezYZA==",
"version": "1.59.0-alpha-1769176698000",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0-alpha-1769176698000.tgz",
"integrity": "sha512-e6r9Ivkm7PJIeMU8zl1JIwktAGZD6gXb6OCegdXpqlyH43OF9EBImLrIl8ovn2hWtmQPSeTDQyaBELSL89ZR6w==",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.58.0-alpha-2026-01-16"
"playwright-core": "1.59.0-alpha-1769176698000"
},
"bin": {
"playwright": "cli.js"
@@ -2600,9 +2633,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.58.0-alpha-2026-01-16",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.0-alpha-2026-01-16.tgz",
"integrity": "sha512-r3XM/xwmyoKLgHI8+ooCoKaRv8mch39UoHyLfWSols6GB2H9Lx3JhvhzRep+rYBYk+GDj0222GKuwg1PnVF8zA==",
"version": "1.59.0-alpha-1769176698000",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0-alpha-1769176698000.tgz",
"integrity": "sha512-5w4TFCd2ucGVc3eeYmnNHr3oqkeYW9Du2Sr9kXCo16yLPD82ssYdd7CwzfARSsYNr0AOH5yrYwBpzsWR9H0+/Q==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
@@ -3820,8 +3853,8 @@
"version": "0.0.56",
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.58.0-alpha-2026-01-16",
"playwright-core": "1.58.0-alpha-2026-01-16"
"playwright": "1.59.0-alpha-1769176698000",
"playwright-core": "1.59.0-alpha-1769176698000"
},
"bin": {
"mcp-server-playwright": "cli.js"

View File

@@ -21,8 +21,8 @@
"packages/*"
],
"devDependencies": {
"@modelcontextprotocol/sdk": "^1.24.0",
"@playwright/test": "1.58.0-alpha-2026-01-16",
"@modelcontextprotocol/sdk": "^1.25.2",
"@playwright/test": "1.59.0-alpha-1769176698000",
"@types/node": "^24.3.0"
}
}

View File

@@ -134,7 +134,7 @@ test(`navigate with extension`, async ({ browserWithExtension, startClient, serv
await selectorPage.getByRole('button', { name: 'Allow' }).click();
expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
});
});
@@ -166,7 +166,7 @@ test(`snapshot of an existing page`, async ({ browserWithExtension, startClient,
await selectorPage.locator('.tab-item', { hasText: 'Title' }).getByRole('button', { name: 'Connect' }).click();
expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
});
expect(browserContext.pages()).toHaveLength(4);
@@ -187,7 +187,7 @@ test(`extension not installed timeout`, async ({ browserWithExtension, startClie
name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD },
})).toHaveResponse({
result: expect.stringContaining('Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed.'),
error: expect.stringContaining('Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed.'),
isError: true,
});
@@ -216,7 +216,7 @@ testWithOldExtensionVersion(`works with old extension version`, async ({ browser
await selectorPage.getByRole('button', { name: 'Allow' }).click();
expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
});
});
@@ -242,7 +242,7 @@ test(`extension needs update`, async ({ browserWithExtension, startClient, serve
await expect(confirmationPage.locator('.status-banner')).toContainText(`Playwright MCP version trying to connect requires newer extension version`);
expect(await navigateResponse).toHaveResponse({
result: expect.stringContaining('Extension connection timeout.'),
error: expect.stringContaining('Extension connection timeout.'),
isError: true,
});
});
@@ -267,10 +267,9 @@ test(`custom executablePath`, async ({ startClient, server, useShortConnectionTi
const navigateResponse = await client.callTool({
name: 'browser_navigate',
arguments: { url: server.HELLO_WORLD },
timeout: 1000,
});
expect(await navigateResponse).toHaveResponse({
result: expect.stringContaining('Extension connection timeout.'),
error: expect.stringContaining('Extension connection timeout.'),
isError: true,
});
expect(await fs.promises.readFile(test.info().outputPath('output.txt'), 'utf8')).toContain('Custom exec args: chrome-extension://jakfalbnbhgkpmoaakfflhflbfpkailf/connect.html?');
@@ -300,6 +299,6 @@ test(`bypass connection dialog with token`, async ({ browserWithExtension, start
});
expect(await navigateResponse).toHaveResponse({
pageState: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
snapshot: expect.stringContaining(`- generic [active] [ref=e1]: Hello, world!`),
});
});

View File

@@ -16,7 +16,17 @@
import type * as playwright from 'playwright';
export type ToolCapability = 'core' | 'core-tabs' | 'core-install' | 'vision' | 'pdf' | 'testing' | 'tracing';
export type ToolCapability =
'core' |
'core-input' |
'core-navigation' |
'core-tabs' |
'core-install' |
'core-input' |
'vision' |
'pdf' |
'testing' |
'tracing';
export type Config = {
/**
@@ -147,6 +157,11 @@ export type Config = {
*/
outputDir?: string;
/**
* Whether to save snapshots, console messages, network logs and other session logs to a file or to the standard output. Defaults to "stdout".
*/
outputMode?: 'file' | 'stdout';
console?: {
/**
* The level of console messages to return. Each level includes the messages of more severe levels. Defaults to "info".
@@ -193,11 +208,16 @@ export type Config = {
* When taking snapshots for responses, specifies the mode to use.
*/
mode?: 'incremental' | 'full' | 'none';
}
};
/**
* Whether to allow file uploads from anywhere on the file system.
* By default (false), file uploads are restricted to paths within the MCP roots only.
*/
allowUnrestrictedFileAccess?: boolean;
/**
* Specify the language to use for code generation.
*/
codegen?: 'typescript' | 'none';
};

View File

@@ -34,8 +34,8 @@
}
},
"dependencies": {
"playwright": "1.58.0-alpha-2026-01-16",
"playwright-core": "1.58.0-alpha-2026-01-16"
"playwright": "1.59.0-alpha-1769176698000",
"playwright-core": "1.59.0-alpha-1769176698000"
},
"bin": {
"mcp-server-playwright": "cli.js"

View File

@@ -33,7 +33,7 @@ test('browser_click', async ({ client, server }) => {
arguments: { url: server.PREFIX },
})).toHaveResponse({
code: `await page.goto('${server.PREFIX}');`,
pageState: expect.stringContaining(`- button \"Submit\" [ref=e2]`),
snapshot: expect.stringContaining(`- button \"Submit\" [ref=e2]`),
});
expect(await client.callTool({
@@ -44,6 +44,6 @@ test('browser_click', async ({ client, server }) => {
},
})).toHaveResponse({
code: `await page.getByRole('button', { name: 'Submit' }).click();`,
pageState: expect.stringContaining(`button "Submit" [active] [ref=e2]`),
snapshot: expect.stringContaining(`button "Submit" [active] [ref=e2]`),
});
});

View File

@@ -22,11 +22,6 @@ test('browser_navigate', async ({ client, server }) => {
arguments: { url: server.HELLO_WORLD },
})).toHaveResponse({
code: `await page.goto('${server.HELLO_WORLD}');`,
pageState: `- Page URL: ${server.HELLO_WORLD}
- Page Title: Title
- Page Snapshot:
\`\`\`yaml
- generic [active] [ref=e1]: Hello, world!
\`\`\``,
snapshot: expect.stringContaining(`generic [active] [ref=e1]: Hello, world!`),
});
});

View File

@@ -229,7 +229,7 @@ export const expect = baseExpect.extend({
expect(parsed).not.toEqual(expect.objectContaining(object));
else
expect(parsed).toEqual(expect.objectContaining(object));
} catch (e) {
} catch (e: any) {
return {
pass: isNot,
message: () => e.message,
@@ -250,10 +250,12 @@ function parseResponse(response: any) {
const text = response.content[0].text;
const sections = parseSections(text);
const error = sections.get('Error');
const result = sections.get('Result');
const code = sections.get('Ran Playwright code');
const tabs = sections.get('Open tabs');
const pageState = sections.get('Page state');
const snapshot = sections.get('Snapshot');
const consoleMessages = sections.get('New console messages');
const modalState = sections.get('Modal state');
const downloads = sections.get('Downloads');
@@ -262,10 +264,12 @@ function parseResponse(response: any) {
const attachments = response.content.slice(1);
return {
error,
result,
code: codeNoFrame,
tabs,
pageState,
snapshot,
consoleMessages,
modalState,
downloads,

View File

@@ -18,14 +18,15 @@
const fs = require('fs')
const path = require('path')
const { zodToJsonSchema } = require('zod-to-json-schema')
const { execSync } = require('child_process');
const { browserTools } = require('playwright/lib/mcp/browser/tools');
const capabilities = {
'core-navigation': 'Core automation',
'core': 'Core automation',
'core-tabs': 'Tab management',
'core-input': 'Core automation',
'core-install': 'Browser installation',
'vision': 'Coordinate-based (opt-in via --caps=vision)',
'pdf': 'PDF generation (opt-in via --caps=pdf)',
@@ -33,7 +34,15 @@ const capabilities = {
'tracing': 'Tracing (opt-in via --caps=tracing)',
};
const toolsByCapability = Object.fromEntries(Object.entries(capabilities).map(([capability, title]) => [title, browserTools.filter(tool => tool.capability === capability).sort((a, b) => a.schema.name.localeCompare(b.schema.name))]));
/** @type {Record<string, any[]>} */
const toolsByCapability = {};
for (const [capability, title] of Object.entries(capabilities)) {
let tools = browserTools.filter(tool => tool.capability === capability && !tool.skillOnly);
tools = (toolsByCapability[title] || []).concat(tools);
toolsByCapability[title] = tools;
}
for (const [, tools] of Object.entries(toolsByCapability))
tools.sort((a, b) => a.schema.name.localeCompare(b.schema.name));
/**
* @param {any} tool
@@ -47,7 +56,7 @@ function formatToolForReadme(tool) {
lines.push(` - Title: ${tool.title}`);
lines.push(` - Description: ${tool.description}`);
const inputSchema = /** @type {any} */ (zodToJsonSchema(tool.inputSchema || {}));
const inputSchema = /** @type {any} */ (tool.inputSchema ? tool.inputSchema.toJSONSchema() : {});
const requiredParams = inputSchema.required || [];
if (inputSchema.properties && Object.keys(inputSchema.properties).length) {
lines.push(` - Parameters:`);