Skip to content

Commit 9e0fa8b

Browse files
committed
bug mcp normalise stdin and http for standlone npx
1 parent d8f83d8 commit 9e0fa8b

3 files changed

Lines changed: 77 additions & 4 deletions

File tree

src/mcp/commandNormalization.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,59 @@ function hasNpxYesFlag(args: string[] | undefined): boolean {
2121
return args.some(arg => arg === '-y' || arg === '--yes');
2222
}
2323

24+
function hasFlag(args: string[], flag: string): boolean {
25+
return args.some(arg => arg === flag || arg.startsWith(`${flag}=`));
26+
}
27+
28+
function findNpxCommandIndex(args: string[]): number | null {
29+
for (let i = 0; i < args.length; i++) {
30+
const token = args[i];
31+
32+
if (token === '--') {
33+
return i + 1 < args.length ? i + 1 : null;
34+
}
35+
36+
if (!token.startsWith('-') || token === '-') {
37+
return i;
38+
}
39+
40+
const consumesNextValue = token === '-p'
41+
|| token === '--package'
42+
|| token === '-c'
43+
|| token === '--call';
44+
if (consumesNextValue) {
45+
i++;
46+
}
47+
}
48+
49+
return null;
50+
}
51+
52+
function isChromeDevtoolsMcpPackage(spec: string): boolean {
53+
const normalized = spec.toLowerCase();
54+
return normalized === 'chrome-devtools-mcp' || normalized.startsWith('chrome-devtools-mcp@');
55+
}
56+
57+
function addKnownNonInteractiveServerFlags(args: string[]): string[] {
58+
const normalizedArgs = [...args];
59+
const commandIndex = findNpxCommandIndex(normalizedArgs);
60+
if (commandIndex === null || commandIndex >= normalizedArgs.length) {
61+
return normalizedArgs;
62+
}
63+
64+
const packageSpec = normalizedArgs[commandIndex];
65+
if (!isChromeDevtoolsMcpPackage(packageSpec)) {
66+
return normalizedArgs;
67+
}
68+
69+
// Prevent startup prompts that block MCP initialize handshake.
70+
if (!hasFlag(normalizedArgs, '--no-usage-stats')) {
71+
normalizedArgs.push('--no-usage-stats');
72+
}
73+
74+
return normalizedArgs;
75+
}
76+
2477
function sanitizePathSegment(value: string): string {
2578
const sanitized = value
2679
.toLowerCase()
@@ -87,10 +140,11 @@ export function normalizeMcpCommandForSpawn(
87140
if (!hasNpxYesFlag(normalizedArgs)) {
88141
normalizedArgs.unshift('-y');
89142
}
143+
const spawnSafeArgs = addKnownNonInteractiveServerFlags(normalizedArgs);
90144

91145
return {
92146
command,
93-
args: normalizedArgs.length > 0 ? normalizedArgs : undefined,
147+
args: spawnSafeArgs.length > 0 ? spawnSafeArgs : undefined,
94148
};
95149
}
96150

tests/mcpCliCommands.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ describe('MCP CLI subcommands', () => {
168168
name: 'chrome-devtools',
169169
transport: 'stdio',
170170
command: 'npx',
171-
args: ['-y', 'chrome-devtools-mcp@latest'],
171+
args: ['-y', 'chrome-devtools-mcp@latest', '--no-usage-stats'],
172172
});
173173
});
174174

tests/mcpCommandNormalization.spec.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,26 @@ describe('MCP command normalization', () => {
1717
const normalized = normalizeMcpCommandForSpawn('npx', ['chrome-devtools-mcp@latest']);
1818
expect(normalized).toEqual({
1919
command: 'npx',
20-
args: ['-y', 'chrome-devtools-mcp@latest'],
20+
args: ['-y', 'chrome-devtools-mcp@latest', '--no-usage-stats'],
2121
});
2222
});
2323

2424
it('does not duplicate existing -y flag', () => {
2525
const normalized = normalizeMcpCommandForSpawn('npx', ['-y', 'chrome-devtools-mcp@latest']);
2626
expect(normalized).toEqual({
2727
command: 'npx',
28-
args: ['-y', 'chrome-devtools-mcp@latest'],
28+
args: ['-y', 'chrome-devtools-mcp@latest', '--no-usage-stats'],
29+
});
30+
});
31+
32+
it('does not duplicate chrome-devtools non-interactive flag', () => {
33+
const normalized = normalizeMcpCommandForSpawn(
34+
'npx',
35+
['-y', 'chrome-devtools-mcp@latest', '--no-usage-stats']
36+
);
37+
expect(normalized).toEqual({
38+
command: 'npx',
39+
args: ['-y', 'chrome-devtools-mcp@latest', '--no-usage-stats'],
2940
});
3041
});
3142

@@ -53,6 +64,14 @@ describe('MCP command normalization', () => {
5364
});
5465
});
5566

67+
it('adds chrome-devtools non-interactive flag for config normalization', () => {
68+
const normalized = normalizeMcpCommandForConfig('npx', ['chrome-devtools-mcp@latest']);
69+
expect(normalized).toEqual({
70+
command: 'npx',
71+
args: ['-y', 'chrome-devtools-mcp@latest', '--no-usage-stats'],
72+
});
73+
});
74+
5675
it('detects npx command names across platforms', () => {
5776
expect(isNpxCommand('npx')).toBe(true);
5877
expect(isNpxCommand('npx.cmd')).toBe(true);

0 commit comments

Comments
 (0)