Skip to content

Commit 75505b4

Browse files
committed
fix: address critical Cursor review comments
- Fix missing null check in discover_tools.ts for server.server access - Fix race condition in command.ts for detached processes by using resolved flag - Remove duplicate validation in UI testing tools (key_sequence, long_press) since createTypedTool already validates via Zod schemas - Clean up unused imports
1 parent 7414c97 commit 75505b4

4 files changed

Lines changed: 50 additions & 46 deletions

File tree

src/mcp/tools/discovery/discover_tools.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export async function discover_toolsLogic(
5858
}
5959

6060
// 1. Check for sampling capability
61-
if (!server.server.getClientCapabilities()?.sampling) {
61+
const clientCapabilities = server.server?.getClientCapabilities?.();
62+
if (!clientCapabilities?.sampling) {
6263
log('warn', 'Client does not support sampling capability');
6364
return createTextResponse(
6465
'Your client does not support the sampling feature required for dynamic tool discovery. ' +
@@ -99,6 +100,9 @@ Each workflow contains ALL tools needed for its complete development workflow -
99100

100101
// 4. Send sampling request
101102
log('debug', 'Sending sampling request to client LLM');
103+
if (!server.server?.createMessage) {
104+
throw new Error('Server does not support message creation');
105+
}
102106
const samplingResult = await server.server.createMessage({
103107
messages: [{ role: 'user', content: { type: 'text', text: userPrompt } }],
104108
maxTokens: 200,

src/mcp/tools/ui-testing/key_sequence.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { z } from 'zod';
88
import { ToolResponse } from '../../../types/common.js';
99
import { log } from '../../../utils/index.js';
10-
import { validateRequiredParam, createTextResponse } from '../../../utils/index.js';
10+
import { createTextResponse } from '../../../utils/index.js';
1111
import {
1212
DependencyError,
1313
AxeError,
@@ -50,11 +50,6 @@ export async function key_sequenceLogic(
5050
},
5151
): Promise<ToolResponse> {
5252
const toolName = 'key_sequence';
53-
const simUuidValidation = validateRequiredParam('simulatorUuid', params.simulatorUuid);
54-
if (!simUuidValidation.isValid) return simUuidValidation.errorResponse!;
55-
const keyCodesValidation = validateRequiredParam('keyCodes', params.keyCodes);
56-
if (!keyCodesValidation.isValid) return keyCodesValidation.errorResponse!;
57-
5853
const { simulatorUuid, keyCodes, delay } = params;
5954
const commandArgs = ['key-sequence', '--keycodes', keyCodes.join(',')];
6055
if (delay !== undefined) {

src/mcp/tools/ui-testing/long_press.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import { z } from 'zod';
99
import { ToolResponse } from '../../../types/common.js';
1010
import { log } from '../../../utils/index.js';
11-
import { validateRequiredParam, createTextResponse } from '../../../utils/index.js';
11+
import { createTextResponse } from '../../../utils/index.js';
1212
import {
1313
DependencyError,
1414
AxeError,
@@ -52,15 +52,6 @@ export async function long_pressLogic(
5252
},
5353
): Promise<ToolResponse> {
5454
const toolName = 'long_press';
55-
const simUuidValidation = validateRequiredParam('simulatorUuid', params.simulatorUuid);
56-
if (!simUuidValidation.isValid) return simUuidValidation.errorResponse!;
57-
const xValidation = validateRequiredParam('x', params.x);
58-
if (!xValidation.isValid) return xValidation.errorResponse!;
59-
const yValidation = validateRequiredParam('y', params.y);
60-
if (!yValidation.isValid) return yValidation.errorResponse!;
61-
const durationValidation = validateRequiredParam('duration', params.duration);
62-
if (!durationValidation.isValid) return durationValidation.errorResponse!;
63-
6455
const { simulatorUuid, x, y, duration } = params;
6556
// AXe uses touch command with --down, --up, and --delay for long press
6657
const delayInSeconds = Number(duration) / 1000; // Convert ms to seconds

src/utils/command.ts

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -117,41 +117,55 @@ async function defaultExecutor(
117117
stderr += data.toString();
118118
});
119119

120-
childProcess.on('close', (code) => {
121-
const success = code === 0;
122-
const response: CommandResponse = {
123-
success,
124-
output: stdout,
125-
error: success ? undefined : stderr,
126-
process: childProcess,
127-
};
128-
129-
resolve(response);
130-
});
120+
// For detached processes, handle differently to avoid race conditions
121+
if (detached) {
122+
// For detached processes, only wait for spawn success/failure
123+
let resolved = false;
131124

132-
childProcess.on('error', (err) => {
133-
reject(err);
134-
});
125+
childProcess.on('error', (err) => {
126+
if (!resolved) {
127+
resolved = true;
128+
reject(err);
129+
}
130+
});
135131

136-
// For detached processes, resolve immediately after successful spawn
137-
if (detached) {
138132
// Give a small delay to ensure the process starts successfully
139133
setTimeout(() => {
140-
if (childProcess.pid) {
141-
resolve({
142-
success: true,
143-
output: '', // No output yet for detached processes
144-
process: childProcess,
145-
});
146-
} else {
147-
resolve({
148-
success: false,
149-
output: '',
150-
error: 'Failed to start detached process',
151-
process: childProcess,
152-
});
134+
if (!resolved) {
135+
resolved = true;
136+
if (childProcess.pid) {
137+
resolve({
138+
success: true,
139+
output: '', // No output for detached processes
140+
process: childProcess,
141+
});
142+
} else {
143+
resolve({
144+
success: false,
145+
output: '',
146+
error: 'Failed to start detached process',
147+
process: childProcess,
148+
});
149+
}
153150
}
154151
}, 100);
152+
} else {
153+
// For non-detached processes, handle normally
154+
childProcess.on('close', (code) => {
155+
const success = code === 0;
156+
const response: CommandResponse = {
157+
success,
158+
output: stdout,
159+
error: success ? undefined : stderr,
160+
process: childProcess,
161+
};
162+
163+
resolve(response);
164+
});
165+
166+
childProcess.on('error', (err) => {
167+
reject(err);
168+
});
155169
}
156170
});
157171
}

0 commit comments

Comments
 (0)