Skip to main content
Glama

gesture

Execute preset gestures like scroll, swipe, or edge swipes on iOS simulators for testing and automation. Configure screen dimensions, duration, and delays for precise control.

Instructions

Perform gesture on iOS simulator using preset gestures: scroll-up, scroll-down, scroll-left, scroll-right, swipe-from-left-edge, swipe-from-right-edge, swipe-from-top-edge, swipe-from-bottom-edge

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
deltaNoOptional: Distance to move in pixels.
durationNoOptional: Duration of the gesture in seconds.
postDelayNoOptional: Delay after completing the gesture in seconds.
preDelayNoOptional: Delay before starting the gesture in seconds.
presetYesThe gesture preset to perform. Must be one of: scroll-up, scroll-down, scroll-left, scroll-right, swipe-from-left-edge, swipe-from-right-edge, swipe-from-top-edge, swipe-from-bottom-edge.
screenHeightNoOptional: Screen height in pixels. Used for gesture calculations. Auto-detected if not provided.
screenWidthNoOptional: Screen width in pixels. Used for gesture calculations. Auto-detected if not provided.
simulatorUuidYes

Implementation Reference

  • Core handler function that constructs the AXe command arguments from parameters and executes the gesture on the iOS simulator, handling errors and responses.
    export async function gestureLogic( params: GestureParams, executor: CommandExecutor, axeHelpers: AxeHelpers = { getAxePath, getBundledAxeEnvironment, createAxeNotAvailableResponse, }, ): Promise<ToolResponse> { const toolName = 'gesture'; const { simulatorId, preset, screenWidth, screenHeight, duration, delta, preDelay, postDelay } = params; const commandArgs = ['gesture', preset]; if (screenWidth !== undefined) { commandArgs.push('--screen-width', String(screenWidth)); } if (screenHeight !== undefined) { commandArgs.push('--screen-height', String(screenHeight)); } if (duration !== undefined) { commandArgs.push('--duration', String(duration)); } if (delta !== undefined) { commandArgs.push('--delta', String(delta)); } if (preDelay !== undefined) { commandArgs.push('--pre-delay', String(preDelay)); } if (postDelay !== undefined) { commandArgs.push('--post-delay', String(postDelay)); } log('info', `${LOG_PREFIX}/${toolName}: Starting gesture '${preset}' on ${simulatorId}`); try { await executeAxeCommand(commandArgs, simulatorId, 'gesture', executor, axeHelpers); log('info', `${LOG_PREFIX}/${toolName}: Success for ${simulatorId}`); return createTextResponse(`Gesture '${preset}' executed successfully.`); } catch (error) { log('error', `${LOG_PREFIX}/${toolName}: Failed - ${error}`); if (error instanceof DependencyError) { return axeHelpers.createAxeNotAvailableResponse(); } else if (error instanceof AxeError) { return createErrorResponse( `Failed to execute gesture '${preset}': ${error.message}`, error.axeOutput, ); } else if (error instanceof SystemError) { return createErrorResponse( `System error executing axe: ${error.message}`, error.originalError?.stack, ); } return createErrorResponse( `An unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`, ); } }
  • Zod schema defining input parameters for the gesture tool, including required simulatorId and preset, and optional screen dimensions, duration, delta, delays.
    const gestureSchema = z.object({ simulatorId: z.string().uuid('Invalid Simulator UUID format'), preset: z .enum([ 'scroll-up', 'scroll-down', 'scroll-left', 'scroll-right', 'swipe-from-left-edge', 'swipe-from-right-edge', 'swipe-from-top-edge', 'swipe-from-bottom-edge', ]) .describe( 'The gesture preset to perform. Must be one of: scroll-up, scroll-down, scroll-left, scroll-right, swipe-from-left-edge, swipe-from-right-edge, swipe-from-top-edge, swipe-from-bottom-edge.', ), screenWidth: z .number() .int() .min(1) .optional() .describe( 'Optional: Screen width in pixels. Used for gesture calculations. Auto-detected if not provided.', ), screenHeight: z .number() .int() .min(1) .optional() .describe( 'Optional: Screen height in pixels. Used for gesture calculations. Auto-detected if not provided.', ), duration: z .number() .min(0, 'Duration must be non-negative') .optional() .describe('Optional: Duration of the gesture in seconds.'), delta: z .number() .min(0, 'Delta must be non-negative') .optional() .describe('Optional: Distance to move in pixels.'), preDelay: z .number() .min(0, 'Pre-delay must be non-negative') .optional() .describe('Optional: Delay before starting the gesture in seconds.'), postDelay: z .number() .min(0, 'Post-delay must be non-negative') .optional() .describe('Optional: Delay after completing the gesture in seconds.'), });
  • Default export registering the 'gesture' tool with name, description, schema (public version omitting simulatorId), and handler created by createSessionAwareTool wrapping gestureLogic.
    export default { name: 'gesture', description: 'Perform gesture on iOS simulator using preset gestures: scroll-up, scroll-down, scroll-left, scroll-right, swipe-from-left-edge, swipe-from-right-edge, swipe-from-top-edge, swipe-from-bottom-edge', schema: publicSchemaObject.shape, // MCP SDK compatibility handler: createSessionAwareTool<GestureParams>({ internalSchema: gestureSchema as unknown as z.ZodType<GestureParams>, logicFunction: (params: GestureParams, executor: CommandExecutor) => gestureLogic(params, executor, { getAxePath, getBundledAxeEnvironment, createAxeNotAvailableResponse, }), getExecutor: getDefaultCommandExecutor, requirements: [{ allOf: ['simulatorId'], message: 'simulatorId is required' }], }), };
  • Helper function to execute AXe commands on the simulator, handling binary path, UDID, environment, execution, and error wrapping.
    async function executeAxeCommand( commandArgs: string[], simulatorId: string, commandName: string, executor: CommandExecutor = getDefaultCommandExecutor(), axeHelpers: AxeHelpers = { getAxePath, getBundledAxeEnvironment, createAxeNotAvailableResponse }, ): Promise<void> { // Get the appropriate axe binary path const axeBinary = axeHelpers.getAxePath(); if (!axeBinary) { throw new DependencyError('AXe binary not found'); } // Add --udid parameter to all commands const fullArgs = [...commandArgs, '--udid', simulatorId]; // Construct the full command array with the axe binary as the first element const fullCommand = [axeBinary, ...fullArgs]; try { // Determine environment variables for bundled AXe const axeEnv = axeBinary !== 'axe' ? axeHelpers.getBundledAxeEnvironment() : undefined; const result = await executor(fullCommand, `${LOG_PREFIX}: ${commandName}`, false, axeEnv); if (!result.success) { throw new AxeError( `axe command '${commandName}' failed.`, commandName, result.error ?? result.output, simulatorId, ); } // Check for stderr output in successful commands if (result.error) { log( 'warn', `${LOG_PREFIX}: Command '${commandName}' produced stderr output but exited successfully. Output: ${result.error}`, ); } // Function now returns void - the calling code creates its own response } catch (error) { if (error instanceof Error) { if (error instanceof AxeError) { throw error; } // Otherwise wrap it in a SystemError throw new SystemError(`Failed to execute axe command: ${error.message}`, error); } // For any other type of error throw new SystemError(`Failed to execute axe command: ${String(error)}`); } }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cameroncooke/XcodeBuildMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server