Skip to content

Commit 6aa0d72

Browse files
committed
fix: preserve session creation guidance
1 parent 6c50275 commit 6aa0d72

4 files changed

Lines changed: 45 additions & 18 deletions

File tree

scripts/audit-tool-footprint.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url';
66
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
77
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
88

9-
const MAX_DISCOVERY_CHARS = 40_000;
9+
const MAX_DISCOVERY_CHARS = 42_000;
1010
const ESTIMATED_CHARS_PER_TOKEN = 4;
1111
const LARGEST_TOOL_COUNT = 10;
1212

src/tests/tools/llm-wording.test.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,27 @@ describe('LLM-facing MCP tool wording', () => {
145145
/create.*attach.*detach.*delete.*list.*select/i
146146
);
147147

148-
expect(actionDescription).toMatch(/DEFAULT MODE/i);
148+
expect(actionDescription).toMatch(/DEFAULT\/LOCAL MODE/i);
149149
expect(actionDescription).toMatch(/no separate Appium process is needed/i);
150-
expect(actionDescription).toMatch(/select_device tool FIRST/i);
150+
expect(actionDescription).toMatch(
151+
/select_device first.*explicit target capabilities.*appium:udid/i
152+
);
151153
expect(actionDescription).toMatch(/do NOT pass remoteServerUrl/i);
152154
expect(actionDescription).toMatch(/NEVER invent a localhost URL/i);
153-
expect(actionDescription).toMatch(/prepare_ios_simulator.*before create/i);
155+
expect(actionDescription).toMatch(
156+
/prepare_ios_simulator.*appium_prepare_ios_real_device/i
157+
);
158+
expect(actionDescription).toMatch(
159+
/full returned capabilitiesHint as capabilities/i
160+
);
154161
expect(actionDescription).toMatch(/REMOTE SERVER MODE/i);
155162
expect(actionDescription).toMatch(
156163
/only when the user explicitly provides/i
157164
);
165+
expect(actionDescription).toMatch(/skip select_device/i);
166+
expect(actionDescription).toMatch(
167+
/platform=general.*requires remoteServerUrl/i
168+
);
158169
expect(actionDescription).toMatch(/without taking ownership/i);
159170
expect(actionDescription).toMatch(
160171
/without deleting the real remote session/i
@@ -181,7 +192,10 @@ describe('LLM-facing MCP tool wording', () => {
181192
);
182193
expect(description).toMatch(/NEVER use.*REMOTE.*remoteServerUrl/i);
183194
expect(description).toMatch(
184-
/prepare_ios_simulator.*appium_session_management.*create/i
195+
/prepare_ios_simulator.*appium_prepare_ios_real_device/i
196+
);
197+
expect(description).toMatch(
198+
/full capabilitiesHint.*appium_session_management.*create/i
185199
);
186200
expect(description).toMatch(/Remote devices.*session capabilities/i);
187201

src/tools/session/select-device.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ export default function selectDevice(server: any): void {
8383
description:
8484
'LOCAL servers ONLY; NEVER use for REMOTE/remoteServerUrl. ASK THE USER Android or iOS—do not assume. ' +
8585
'Call without deviceUdid to list: one result auto-selects; for multiple results ask the user, then call again with the chosen deviceUdid. ' +
86-
'For iOS require iosDeviceType and run prepare_ios_simulator before appium_session_management create. ' +
86+
'For iOS require iosDeviceType. After selection run prepare_ios_simulator for a simulator or appium_prepare_ios_real_device for a real device, ' +
87+
'then pass its full capabilitiesHint to appium_session_management create. ' +
8788
'Remote devices are selected through session capabilities.',
8889
parameters: z
8990
.object({
@@ -292,14 +293,18 @@ function selectIOSDevice(
292293
*/
293294
function formatIOSSelectionResponse(
294295
deviceName: string,
295-
deviceUdid: string
296+
deviceUdid: string,
297+
iosDeviceType: 'simulator' | 'real'
296298
): ContentResult {
299+
const prepareTool =
300+
iosDeviceType === 'simulator'
301+
? 'prepare_ios_simulator'
302+
: 'appium_prepare_ios_real_device';
297303
return textResult(
298304
JSON.stringify(
299305
{
300306
message: `✅ Device selected: ${deviceName} (${deviceUdid})`,
301-
instructions:
302-
'🚀 You can now call the prepare_ios_simulator tool to boot and setup WDA on the simulator or the appium_prepare_ios_real_device tool to setup WDA on ios real device.',
307+
instructions: `🚀 Next call ${prepareTool}, then JSON-serialize its full capabilitiesHint as capabilities for appium_session_management with action=create.`,
303308
platform: 'ios',
304309
capabilities: {
305310
'appium:udid': deviceUdid,
@@ -400,7 +405,11 @@ async function handleIOSDeviceSelection(
400405
if (!selected.ok) {
401406
return selected.result;
402407
}
403-
return formatIOSSelectionResponse(selected.device.info.name, deviceUdid);
408+
return formatIOSSelectionResponse(
409+
selected.device.info.name,
410+
deviceUdid,
411+
iosDeviceType!
412+
);
404413
}
405414

406415
// Auto-select when only one device is available
@@ -411,7 +420,8 @@ async function handleIOSDeviceSelection(
411420
}
412421
return formatIOSSelectionResponse(
413422
selected.device.info.name,
414-
devices[0].udid
423+
devices[0].udid,
424+
iosDeviceType!
415425
);
416426
}
417427

src/tools/session/session.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,28 @@ const schema = z.object({
2424
action: z
2525
.enum(SESSION_ACTIONS)
2626
.describe(
27-
'Action. DEFAULT MODE: create without remoteServerUrl uses an embedded driver; no separate Appium process is needed. ' +
28-
'Run select_device tool FIRST, pass platform, do NOT pass remoteServerUrl, and NEVER invent a localhost URL. ' +
29-
'For iOS simulators, run prepare_ios_simulator before create. ' +
30-
'REMOTE SERVER MODE: only when the user explicitly provides a URL; create with that URL/capabilities. ' +
27+
'Action. DEFAULT/LOCAL MODE: create without remoteServerUrl uses an embedded driver; no separate Appium process is needed. ' +
28+
'Normally run select_device first and pass its platform; explicit target capabilities such as appium:udid can be used instead. ' +
29+
'Do NOT pass remoteServerUrl for local create, and NEVER invent a localhost URL. ' +
30+
'For a selected iOS simulator run prepare_ios_simulator; for a selected iOS real device run appium_prepare_ios_real_device. ' +
31+
'Then JSON-serialize the full returned capabilitiesHint as capabilities for create. ' +
32+
'REMOTE SERVER MODE: only when the user explicitly provides a URL; skip select_device and create with that URL/capabilities. ' +
33+
'platform=general is remote-only and requires remoteServerUrl. ' +
3134
'attach requires URL + sessionId (+ platformName capabilities) and connects without taking ownership. ' +
3235
'detach forgets an attached session without deleting the real remote session. delete stops; list shows; select activates.'
3336
),
3437
platform: z
3538
.enum(DRIVER_MODE_PLATFORMS)
3639
.optional()
3740
.describe(
38-
'Required for create; match select_device locally. Use general for other remote drivers.'
41+
'Required for create. For local create, match select_device when used. general is for other remote drivers and requires remoteServerUrl.'
3942
),
4043
capabilities: z
4144
.string()
4245
.optional()
4346
.describe(
44-
'JSON W3C capabilities. create merges iOS/Android defaults or passes general through. ' +
45-
'Serialize full capabilitiesHint values. attach must include platformName.'
47+
'JSON-stringified W3C capabilities. create merges these over iOS/Android defaults or passes general through. ' +
48+
'When using a capabilitiesHint, serialize the full object without dropping boolean or numeric values. attach must include platformName.'
4649
),
4750
remoteServerUrl: z
4851
.string()

0 commit comments

Comments
 (0)