Skip to content

Commit 5c784fa

Browse files
committed
feat: consolidate get_simulator_app_path_id/name into unified get_simulator_app_path
- Unified tool accepts both simulatorId and simulatorName (XOR) - Added warning for useLatestOS with simulatorId - Reduces MCP context usage with single tool interface
1 parent af2473d commit 5c784fa

2 files changed

Lines changed: 38 additions & 223 deletions

File tree

src/mcp/tools/simulator/get_simulator_app_path.ts

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/**
2-
* Unified implementation of get_simulator_app_path_name tool
3-
* Gets the app bundle path for a simulator by name using either a project or workspace file
4-
* Supports both .xcodeproj and .xcworkspace files with XOR validation
2+
* Simulator Get App Path Plugin: Get Simulator App Path (Unified)
3+
*
4+
* Gets the app bundle path for a simulator by UUID or name using either a project or workspace file.
5+
* Accepts mutually exclusive `projectPath` or `workspacePath`.
6+
* Accepts mutually exclusive `simulatorId` or `simulatorName`.
57
*/
68

79
import { z } from 'zod';
@@ -88,56 +90,73 @@ function nullifyEmptyStrings(value: unknown): unknown {
8890
}
8991

9092
// Define base schema
91-
const baseGetSimulatorAppPathNameSchema = z.object({
93+
const baseGetSimulatorAppPathSchema = z.object({
9294
projectPath: z.string().optional().describe('Path to the .xcodeproj file'),
9395
workspacePath: z.string().optional().describe('Path to the .xcworkspace file'),
9496
scheme: z.string().describe('The scheme to use (Required)'),
9597
platform: z
9698
.enum(['iOS Simulator', 'watchOS Simulator', 'tvOS Simulator', 'visionOS Simulator'])
9799
.describe('Target simulator platform (Required)'),
98-
simulatorName: z.string().describe("Name of the simulator to use (e.g., 'iPhone 16') (Required)"),
100+
simulatorId: z
101+
.string()
102+
.optional()
103+
.describe('UUID of the simulator to use (obtained from listSimulators)'),
104+
simulatorName: z.string().optional().describe("Name of the simulator to use (e.g., 'iPhone 16')"),
99105
configuration: z.string().optional().describe('Build configuration (Debug, Release, etc.)'),
100106
useLatestOS: z
101107
.boolean()
102108
.optional()
103109
.describe('Whether to use the latest OS version for the named simulator'),
104-
simulatorId: z.string().optional().describe('Optional simulator UUID'),
105110
arch: z.string().optional().describe('Optional architecture'),
106111
});
107112

108113
// Add XOR validation with preprocessing
109-
const getSimulatorAppPathNameSchema = z.preprocess(
114+
const getSimulatorAppPathSchema = z.preprocess(
110115
nullifyEmptyStrings,
111-
baseGetSimulatorAppPathNameSchema
116+
baseGetSimulatorAppPathSchema
112117
.refine((val) => val.projectPath !== undefined || val.workspacePath !== undefined, {
113118
message: 'Either projectPath or workspacePath is required.',
114119
})
115120
.refine((val) => !(val.projectPath !== undefined && val.workspacePath !== undefined), {
116121
message: 'projectPath and workspacePath are mutually exclusive. Provide only one.',
122+
})
123+
.refine((val) => val.simulatorId !== undefined || val.simulatorName !== undefined, {
124+
message: 'Either simulatorId or simulatorName is required.',
125+
})
126+
.refine((val) => !(val.simulatorId !== undefined && val.simulatorName !== undefined), {
127+
message: 'simulatorId and simulatorName are mutually exclusive. Provide only one.',
117128
}),
118129
);
119130

120131
// Use z.infer for type safety
121-
type GetSimulatorAppPathNameParams = z.infer<typeof getSimulatorAppPathNameSchema>;
132+
type GetSimulatorAppPathParams = z.infer<typeof getSimulatorAppPathSchema>;
122133

123134
/**
124135
* Exported business logic function for getting app path
125136
*/
126-
export async function get_simulator_app_path_nameLogic(
127-
params: GetSimulatorAppPathNameParams,
137+
export async function get_simulator_app_pathLogic(
138+
params: GetSimulatorAppPathParams,
128139
executor: CommandExecutor,
129140
): Promise<ToolResponse> {
130141
// Set defaults - Zod validation already ensures required params are present
131142
const projectPath = params.projectPath;
132143
const workspacePath = params.workspacePath;
133144
const scheme = params.scheme;
134145
const platform = params.platform;
146+
const simulatorId = params.simulatorId;
135147
const simulatorName = params.simulatorName;
136148
const configuration = params.configuration ?? 'Debug';
137149
const useLatestOS = params.useLatestOS ?? true;
138-
const simulatorId = params.simulatorId;
139150
const arch = params.arch;
140151

152+
// Log warning if useLatestOS is provided with simulatorId
153+
if (simulatorId && params.useLatestOS !== undefined) {
154+
log(
155+
'warning',
156+
`useLatestOS parameter is ignored when using simulatorId (UUID implies exact device/OS)`,
157+
);
158+
}
159+
141160
log('info', `Getting app path for scheme ${scheme} on platform ${platform}`);
142161

143162
try {
@@ -169,7 +188,7 @@ export async function get_simulator_app_path_nameLogic(
169188
if (simulatorId) {
170189
destinationString = `platform=${platform},id=${simulatorId}`;
171190
} else if (simulatorName) {
172-
destinationString = `platform=${platform},name=${simulatorName}${useLatestOS ? ',OS=latest' : ''}`;
191+
destinationString = `platform=${platform},name=${simulatorName}${(simulatorId ? false : useLatestOS) ? ',OS=latest' : ''}`;
173192
} else {
174193
return createTextResponse(
175194
`For ${platform} platform, either simulatorId or simulatorName must be provided`,
@@ -269,13 +288,13 @@ export async function get_simulator_app_path_nameLogic(
269288
}
270289

271290
export default {
272-
name: 'get_simulator_app_path_name',
291+
name: 'get_simulator_app_path',
273292
description:
274-
"Gets the app bundle path for a simulator by name using either a project or workspace file. IMPORTANT: Requires either projectPath OR workspacePath (not both), plus scheme, platform, and simulatorName. Example: get_simulator_app_path_name({ projectPath: '/path/to/project.xcodeproj', scheme: 'MyScheme', platform: 'iOS Simulator', simulatorName: 'iPhone 16' })",
275-
schema: baseGetSimulatorAppPathNameSchema.shape, // MCP SDK compatibility
276-
handler: createTypedTool<GetSimulatorAppPathNameParams>(
277-
getSimulatorAppPathNameSchema as unknown as z.ZodType<GetSimulatorAppPathNameParams>,
278-
get_simulator_app_path_nameLogic,
293+
"Gets the app bundle path for a simulator by UUID or name using either a project or workspace file. IMPORTANT: Requires either projectPath OR workspacePath (not both), plus scheme, platform, and either simulatorId OR simulatorName (not both). Example: get_simulator_app_path({ projectPath: '/path/to/project.xcodeproj', scheme: 'MyScheme', platform: 'iOS Simulator', simulatorName: 'iPhone 16' })",
294+
schema: baseGetSimulatorAppPathSchema.shape, // MCP SDK compatibility
295+
handler: createTypedTool<GetSimulatorAppPathParams>(
296+
getSimulatorAppPathSchema as unknown as z.ZodType<GetSimulatorAppPathParams>,
297+
get_simulator_app_pathLogic,
279298
getDefaultCommandExecutor,
280299
),
281300
};

src/mcp/tools/simulator/get_simulator_app_path_id.ts

Lines changed: 0 additions & 204 deletions
This file was deleted.

0 commit comments

Comments
 (0)