Skip to content

Commit 6f95e41

Browse files
Refactor tool interfaces, improve error handling, and update tool references
Co-authored-by: web <web@cameroncooke.com>
1 parent cfb0d02 commit 6f95e41

7 files changed

Lines changed: 41 additions & 34 deletions

File tree

src/mcp/tools/device/test_device.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ async function parseXcresultBundle(
6969
if (!result.success) {
7070
throw new Error(result.error ?? 'Failed to execute xcresulttool');
7171
}
72+
if (!result.output || result.output.trim().length === 0) {
73+
throw new Error('xcresulttool returned no output');
74+
}
7275

7376
// Parse JSON response and format as human-readable
7477
const summaryData = JSON.parse(result.output) as Record<string, unknown>;
@@ -163,9 +166,19 @@ export async function testDeviceLogic(
163166
`Starting test run for scheme ${params.scheme} on platform ${params.platform ?? 'iOS'} (internal)`,
164167
);
165168

169+
let tempDir: string | undefined;
170+
const cleanup = async (): Promise<void> => {
171+
if (!tempDir) return;
172+
try {
173+
await fileSystemExecutor.rm(tempDir, { recursive: true, force: true });
174+
} catch (cleanupError) {
175+
log('warn', `Failed to clean up temporary directory: ${cleanupError}`);
176+
}
177+
};
178+
166179
try {
167180
// Create temporary directory for xcresult bundle
168-
const tempDir = await fileSystemExecutor.mkdtemp(
181+
tempDir = await fileSystemExecutor.mkdtemp(
169182
join(fileSystemExecutor.tmpdir(), 'xcodebuild-test-'),
170183
);
171184
const resultBundlePath = join(tempDir, 'TestResults.xcresult');
@@ -214,7 +227,7 @@ export async function testDeviceLogic(
214227
log('info', 'Successfully parsed xcresult bundle');
215228

216229
// Clean up temporary directory
217-
await fileSystemExecutor.rm(tempDir, { recursive: true, force: true });
230+
await cleanup();
218231

219232
// Return combined result - preserve isError from testResult (test failures should be marked as errors)
220233
return {
@@ -231,19 +244,16 @@ export async function testDeviceLogic(
231244
// If parsing fails, return original test result
232245
log('warn', `Failed to parse xcresult bundle: ${parseError}`);
233246

234-
// Clean up temporary directory even if parsing fails
235-
try {
236-
await fileSystemExecutor.rm(tempDir, { recursive: true, force: true });
237-
} catch (cleanupError) {
238-
log('warn', `Failed to clean up temporary directory: ${cleanupError}`);
239-
}
247+
await cleanup();
240248

241249
return testResult;
242250
}
243251
} catch (error) {
244252
const errorMessage = error instanceof Error ? error.message : String(error);
245253
log('error', `Error during test run: ${errorMessage}`);
246254
return createTextResponse(`Error during test run: ${errorMessage}`, true);
255+
} finally {
256+
await cleanup();
247257
}
248258
}
249259

@@ -254,13 +264,13 @@ export default {
254264
schema: baseSchemaObject.shape,
255265
handler: createTypedTool<TestDeviceParams>(
256266
testDeviceSchema as z.ZodType<TestDeviceParams>,
257-
(params: TestDeviceParams) => {
267+
(params: TestDeviceParams, executor: CommandExecutor) => {
258268
return testDeviceLogic(
259269
{
260270
...params,
261271
platform: params.platform ?? 'iOS',
262272
},
263-
getDefaultCommandExecutor(),
273+
executor,
264274
getDefaultFileSystemExecutor(),
265275
);
266276
},

src/mcp/tools/macos/build_run_macos.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export type BuildRunMacOSParams = z.infer<typeof buildRunMacOSSchema>;
5252
*/
5353
async function _handleMacOSBuildLogic(
5454
params: BuildRunMacOSParams,
55-
executor: CommandExecutor = getDefaultCommandExecutor(),
55+
executor: CommandExecutor,
5656
): Promise<ToolResponse> {
5757
log('info', `Starting macOS build for scheme ${params.scheme} (internal)`);
5858

@@ -66,16 +66,16 @@ async function _handleMacOSBuildLogic(
6666
arch: params.arch,
6767
logPrefix: 'macOS Build',
6868
},
69-
params.preferXcodebuild,
69+
params.preferXcodebuild ?? false,
7070
'build',
7171
executor,
7272
);
7373
}
7474

7575
async function _getAppPathFromBuildSettings(
7676
params: BuildRunMacOSParams,
77-
executor: CommandExecutor = getDefaultCommandExecutor(),
78-
): Promise<{ success: boolean; appPath?: string; error?: string }> {
77+
executor: CommandExecutor,
78+
): Promise<{ success: true; appPath: string } | { success: false; error: string }> {
7979
try {
8080
// Create the command array for xcodebuild
8181
const command = ['xcodebuild', '-showBuildSettings'];
@@ -163,11 +163,11 @@ export async function buildRunMacOSLogic(
163163
return response;
164164
}
165165

166-
const appPath = appPathResult.appPath; // We know this is a valid string now
166+
const appPath = appPathResult.appPath; // success === true narrows to string
167167
log('info', `App path determined as: ${appPath}`);
168168

169169
// 4. Launch the app using CommandExecutor
170-
const launchResult = await executor(['open', appPath!], 'Launch macOS App', true);
170+
const launchResult = await executor(['open', appPath], 'Launch macOS App', true);
171171

172172
if (!launchResult.success) {
173173
log('error', `Build succeeded, but failed to launch app ${appPath}: ${launchResult.error}`);
@@ -211,14 +211,14 @@ export default {
211211
schema: baseSchemaObject.shape, // MCP SDK compatibility
212212
handler: createTypedTool<BuildRunMacOSParams>(
213213
buildRunMacOSSchema as z.ZodType<BuildRunMacOSParams>,
214-
(params: BuildRunMacOSParams) =>
214+
(params: BuildRunMacOSParams, executor) =>
215215
buildRunMacOSLogic(
216216
{
217217
...params,
218218
configuration: params.configuration ?? 'Debug',
219219
preferXcodebuild: params.preferXcodebuild ?? false,
220220
},
221-
getDefaultCommandExecutor(),
221+
executor,
222222
),
223223
getDefaultCommandExecutor,
224224
),

src/mcp/tools/macos/get_macos_app_path.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,19 @@ export async function get_macos_app_pathLogic(
8181
command.push('-scheme', params.scheme);
8282
command.push('-configuration', configuration);
8383

84-
// Add optional derived data path (only for projects)
85-
if (params.derivedDataPath && params.projectPath) {
84+
// Add optional derived data path
85+
if (params.derivedDataPath) {
8686
command.push('-derivedDataPath', params.derivedDataPath);
8787
}
8888

89-
// Handle destination for macOS (only for workspaces)
90-
if (params.workspacePath) {
91-
let destinationString = 'platform=macOS';
92-
if (params.arch) {
93-
destinationString += `,arch=${params.arch}`;
94-
}
89+
// Handle destination for macOS when arch is specified
90+
if (params.arch) {
91+
const destinationString = `platform=macOS,arch=${params.arch}`;
9592
command.push('-destination', destinationString);
9693
}
9794

98-
// Add extra arguments if provided (only for projects)
99-
if (params.extraArgs && Array.isArray(params.extraArgs) && params.projectPath) {
95+
// Add extra arguments if provided
96+
if (params.extraArgs && Array.isArray(params.extraArgs)) {
10097
command.push(...params.extraArgs);
10198
}
10299

src/mcp/tools/project-discovery/__tests__/list_schemes.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('list_schemes plugin', () => {
7878
type: 'text',
7979
text: `Next Steps:
8080
1. Build the app: build_macos({ projectPath: "/path/to/MyProject.xcodeproj", scheme: "MyProject" })
81-
or for iOS: build_simulator_name({ projectPath: "/path/to/MyProject.xcodeproj", scheme: "MyProject", simulatorName: "iPhone 16" })
81+
or for iOS: build_simulator({ projectPath: "/path/to/MyProject.xcodeproj", scheme: "MyProject", simulatorName: "iPhone 16" })
8282
2. Show build settings: show_build_settings({ projectPath: "/path/to/MyProject.xcodeproj", scheme: "MyProject" })`,
8383
},
8484
],
@@ -295,7 +295,7 @@ describe('list_schemes plugin', () => {
295295
type: 'text',
296296
text: `Next Steps:
297297
1. Build the app: build_macos({ workspacePath: "/path/to/MyProject.xcworkspace", scheme: "MyApp" })
298-
or for iOS: build_simulator_name({ workspacePath: "/path/to/MyProject.xcworkspace", scheme: "MyApp", simulatorName: "iPhone 16" })
298+
or for iOS: build_simulator({ workspacePath: "/path/to/MyProject.xcworkspace", scheme: "MyApp", simulatorName: "iPhone 16" })
299299
2. Show build settings: show_build_settings({ workspacePath: "/path/to/MyProject.xcworkspace", scheme: "MyApp" })`,
300300
},
301301
],

src/mcp/tools/project-discovery/list_schemes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export async function listSchemesLogic(
8080
// Note: After Phase 2, these will be unified tool names too
8181
nextStepsText = `Next Steps:
8282
1. Build the app: build_macos({ ${projectOrWorkspace}Path: "${path}", scheme: "${firstScheme}" })
83-
or for iOS: build_simulator_name({ ${projectOrWorkspace}Path: "${path}", scheme: "${firstScheme}", simulatorName: "iPhone 16" })
83+
or for iOS: build_simulator({ ${projectOrWorkspace}Path: "${path}", scheme: "${firstScheme}", simulatorName: "iPhone 16" })
8484
2. Show build settings: show_build_settings({ ${projectOrWorkspace}Path: "${path}", scheme: "${firstScheme}" })`;
8585
}
8686

src/mcp/tools/project-scaffolding/__tests__/scaffold_macos_project.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ describe('scaffold_macos_project plugin', () => {
249249
nextSteps: [
250250
'Important: Before working on the project make sure to read the README.md file in the workspace root directory.',
251251
'Build for macOS: build_macos({ workspacePath: "/tmp/test-projects/MyProject.xcworkspace", scheme: "MyProject" })',
252-
'Run and run on macOS: build_run_mac_ws --workspace-path "/tmp/test-projects/MyProject.xcworkspace" --scheme "MyProject"',
252+
'Build & Run on macOS: build_run_macos({ workspacePath: "/tmp/test-projects/MyProject.xcworkspace", scheme: "MyProject" })',
253253
],
254254
},
255255
null,
@@ -289,7 +289,7 @@ describe('scaffold_macos_project plugin', () => {
289289
nextSteps: [
290290
'Important: Before working on the project make sure to read the README.md file in the workspace root directory.',
291291
'Build for macOS: build_macos({ workspacePath: "/tmp/test-projects/MyProject.xcworkspace", scheme: "MyProject" })',
292-
'Run and run on macOS: build_run_mac_ws --workspace-path "/tmp/test-projects/MyProject.xcworkspace" --scheme "MyProject"',
292+
'Build & Run on macOS: build_run_macos({ workspacePath: "/tmp/test-projects/MyProject.xcworkspace", scheme: "MyProject" })',
293293
],
294294
},
295295
null,

src/mcp/tools/project-scaffolding/scaffold_macos_project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ export async function scaffold_macos_projectLogic(
365365
nextSteps: [
366366
`Important: Before working on the project make sure to read the README.md file in the workspace root directory.`,
367367
`Build for macOS: build_macos({ workspacePath: "${projectPath}/${params.customizeNames ? params.projectName : 'MyProject'}.xcworkspace", scheme: "${params.customizeNames ? params.projectName : 'MyProject'}" })`,
368-
`Run and run on macOS: build_run_mac_ws --workspace-path "${projectPath}/${params.customizeNames ? params.projectName : 'MyProject'}.xcworkspace" --scheme "${params.customizeNames ? params.projectName : 'MyProject'}"`,
368+
`Build & Run on macOS: build_run_macos({ workspacePath: "${projectPath}/${params.customizeNames ? params.projectName : 'MyProject'}.xcworkspace", scheme: "${params.customizeNames ? params.projectName : 'MyProject'}" })`,
369369
],
370370
};
371371

0 commit comments

Comments
 (0)