mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-11-04 15:00:11 +00:00
fix: reject JSON arrays as 3p and WebMCP tool params (#2785)
## Summary `execute_3p_developer_tool` and `execute_webmcp_tool` parse a JSON string as params. Arrays pass `typeof parsed === 'object' && parsed !== null`, so `[]` skipped the object check and failed later with a misleading error (`Tool not found` or a Puppeteer private-field TypeError). Reject arrays the same way `wsHeaders` already does. ## Testing - `npm run test tests/tools/thirdPartyDeveloper.test.ts tests/tools/webmcp.test.ts` - `npm run typecheck` - `npm run check-format` AI-assisted (Grok) Co-authored-by: Wolfgang Beyer <wolfi@chromium.org>
This commit is contained in:
1 parent
c0349ce982
commit
c14e616da8
4 files changed
+57
-4
No files matched your search
@@ -85,7 +85,11 @@ export const executeThirdPartyDeveloperTool = definePageTool(() => ({
|
||||
if (request.params.params) {
|
||||
try {
|
||||
const parsed = JSON.parse(request.params.params);
|
||||
if (typeof parsed === 'object' && parsed !== null) {
|
||||
if (
|
||||
typeof parsed === 'object' &&
|
||||
parsed !== null &&
|
||||
!Array.isArray(parsed)
|
||||
) {
|
||||
params = parsed;
|
||||
} else {
|
||||
throw new Error('Parsed params is not an object');
|
||||
|
||||
+5
-1
@@ -47,7 +47,11 @@ export const executeWebMcpTool = definePageTool(() => ({
|
||||
if (request.params.input) {
|
||||
try {
|
||||
const parsed = JSON.parse(request.params.input);
|
||||
if (typeof parsed === 'object' && parsed !== null) {
|
||||
if (
|
||||
typeof parsed === 'object' &&
|
||||
parsed !== null &&
|
||||
!Array.isArray(parsed)
|
||||
) {
|
||||
input = parsed;
|
||||
} else {
|
||||
throw new Error('Parsed input is not an object');
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import assert from 'node:assert';
|
||||
import {describe, it} from 'node:test';
|
||||
import {afterEach, describe, it} from 'node:test';
|
||||
|
||||
import sinon from 'sinon';
|
||||
|
||||
@@ -18,9 +18,14 @@ import {
|
||||
listThirdPartyDeveloperTools,
|
||||
} from '../../src/tools/thirdPartyDeveloper.js';
|
||||
import type {ToolGroups} from '../../src/tools/thirdPartyDeveloper.js';
|
||||
import {createHandlerMocks} from '../mocks.js';
|
||||
import {withMcpContext} from '../utils.js';
|
||||
|
||||
describe('thirdPartyDeveloperTools', () => {
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('list_3p_developer_tools', () => {
|
||||
it('lists tools', async () => {
|
||||
await withMcpContext(
|
||||
@@ -391,6 +396,24 @@ describe('thirdPartyDeveloperTools', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects JSON array params', async () => {
|
||||
const {page, context, response, args} = createHandlerMocks();
|
||||
await assert.rejects(
|
||||
executeThirdPartyDeveloperTool(args).handler(
|
||||
{
|
||||
params: {
|
||||
toolName: 'test-tool',
|
||||
params: '[]',
|
||||
},
|
||||
page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
),
|
||||
{message: /Parsed params is not an object/},
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if parameters are invalid', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context, args) => {
|
||||
|
||||
@@ -5,14 +5,21 @@
|
||||
*/
|
||||
|
||||
import assert from 'node:assert';
|
||||
import {describe, it} from 'node:test';
|
||||
import {afterEach, describe, it} from 'node:test';
|
||||
|
||||
import sinon from 'sinon';
|
||||
|
||||
import type {McpPage} from '../../src/McpPage.js';
|
||||
import {listPages, navigatePage, selectPage} from '../../src/tools/pages.js';
|
||||
import {executeWebMcpTool} from '../../src/tools/webmcp.js';
|
||||
import {createHandlerMocks} from '../mocks.js';
|
||||
import {html, withMcpContext} from '../utils.js';
|
||||
|
||||
describe('webmcp', () => {
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('list_webmcp_tools', () => {
|
||||
it('list webmcp tools in navigate_page response', async () => {
|
||||
await withMcpContext(async (response, context, args) => {
|
||||
@@ -110,6 +117,21 @@ describe('webmcp', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects JSON array input', async () => {
|
||||
const {page, context, response, args} = createHandlerMocks();
|
||||
await assert.rejects(
|
||||
executeWebMcpTool(args).handler(
|
||||
{
|
||||
params: {toolName: 'test_tool', input: '[]'},
|
||||
page,
|
||||
},
|
||||
response,
|
||||
context,
|
||||
),
|
||||
{message: /Parsed input is not an object/},
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if input is invalid', async () => {
|
||||
await withMcpContext(
|
||||
async (response, context, args) => {
|
||||
|
||||
Reference in new issue
Block a user