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)}`);
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It mentions the action ('perform gesture') but doesn't disclose behavioral traits like whether this requires a running simulator, what happens if the gesture fails, or if there are side effects. The description is minimal and doesn't provide context about execution environment or error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that front-loads the core action ('perform gesture') and lists all preset options without unnecessary words. Every element earns its place by specifying the target (iOS simulator) and available gestures.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 parameters, no output schema, no annotations), the description is adequate but minimal. It covers the preset options and target environment, but lacks details on behavioral context, error handling, or integration with sibling tools, leaving gaps for an agent to infer usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is high (88%), so the baseline is 3. The description lists the preset gesture options, which matches the 'preset' parameter's enum values in the schema, but doesn't add meaning beyond what the schema already provides for other parameters like 'delta', 'duration', or 'simulatorUuid'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('perform') and resource ('gesture on iOS simulator') with specific scope ('using preset gestures'). It distinguishes from sibling tools like 'swipe' and 'tap' by specifying it uses preset gestures rather than custom coordinates or durations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context (iOS simulator testing) but doesn't explicitly state when to use this tool versus alternatives like 'swipe' or 'tap'. It lists the available preset gestures, which suggests usage for standardized gestures, but lacks explicit guidance on prerequisites or when-not-to-use scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

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/getsentry/XcodeBuildMCP'

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