Skip to main content
Glama

record_video

Capture videos of iOS Simulator activity using simctl. Customize output path, codec, display, and mask settings for precise recording needs.

Instructions

Records a video of the iOS Simulator using simctl directly

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codecNoSpecifies the codec type: "h264" or "hevc". Default is "hevc".
displayNoDisplay to capture: "internal" or "external". Default depends on device type.
forceNoForce the output file to be written to, even if the file already exists.
maskNoFor non-rectangular displays, handle the mask by policy: "ignored", "alpha", or "black".
output_pathNoOptional output path. If not provided, a default name will be used. The file will be saved in the directory specified by `IOS_SIMULATOR_MCP_DEFAULT_OUTPUT_DIR` or in `~/Downloads` if the environment variable is not set.

Implementation Reference

  • Handler function that starts video recording using xcrun simctl io booted recordVideo, handles parameters like codec, display, mask, force, and spawns the process while waiting for confirmation.
    async ({ output_path, codec, display, mask, force }) => { try { const defaultFileName = `simulator_recording_${Date.now()}.mp4`; const outputFile = ensureAbsolutePath(output_path ?? defaultFileName); // Start the recording process const recordingProcess = spawn("xcrun", [ "simctl", "io", "booted", "recordVideo", ...(codec ? [`--codec=${codec}`] : []), ...(display ? [`--display=${display}`] : []), ...(mask ? [`--mask=${mask}`] : []), ...(force ? ["--force"] : []), // When passing user-provided values to a command, it's crucial to use `--` // to separate the command's options from positional arguments. // This prevents the shell from misinterpreting the arguments as options. "--", outputFile, ]); // Wait for recording to start await new Promise((resolve, reject) => { let errorOutput = ""; recordingProcess.stderr.on("data", (data) => { const message = data.toString(); if (message.includes("Recording started")) { resolve(true); } else { errorOutput += message; } }); // Set timeout for start verification setTimeout(() => { if (recordingProcess.killed) { reject(new Error("Recording process terminated unexpectedly")); } else { resolve(true); } }, 3000); }); return { isError: false, content: [ { type: "text", text: `Recording started. The video will be saved to: ${outputFile}\nTo stop recording, use the stop_recording command.`, }, ], }; } catch (error) { return { isError: true, content: [ { type: "text", text: errorWithTroubleshooting( `Error starting recording: ${toError(error).message}` ), }, ], }; } }
  • Zod input schema defining optional parameters for the record_video tool: output_path, codec (h264/hevc), display (internal/external), mask (ignored/alpha/black), force (boolean).
    { output_path: z .string() .max(1024) .optional() .describe( `Optional output path. If not provided, a default name will be used. The file will be saved in the directory specified by \`IOS_SIMULATOR_MCP_DEFAULT_OUTPUT_DIR\` or in \`~/Downloads\` if the environment variable is not set.` ), codec: z .enum(["h264", "hevc"]) .optional() .describe( 'Specifies the codec type: "h264" or "hevc". Default is "hevc".' ), display: z .enum(["internal", "external"]) .optional() .describe( 'Display to capture: "internal" or "external". Default depends on device type.' ), mask: z .enum(["ignored", "alpha", "black"]) .optional() .describe( 'For non-rectangular displays, handle the mask by policy: "ignored", "alpha", or "black".' ), force: z .boolean() .optional() .describe( "Force the output file to be written to, even if the file already exists." ), },
  • src/index.ts:729-835 (registration)
    Conditional registration of the 'record_video' tool using server.tool, including description, schema, and handler, skipped if filtered.
    if (!isToolFiltered("record_video")) { server.tool( "record_video", "Records a video of the iOS Simulator using simctl directly", { output_path: z .string() .max(1024) .optional() .describe( `Optional output path. If not provided, a default name will be used. The file will be saved in the directory specified by \`IOS_SIMULATOR_MCP_DEFAULT_OUTPUT_DIR\` or in \`~/Downloads\` if the environment variable is not set.` ), codec: z .enum(["h264", "hevc"]) .optional() .describe( 'Specifies the codec type: "h264" or "hevc". Default is "hevc".' ), display: z .enum(["internal", "external"]) .optional() .describe( 'Display to capture: "internal" or "external". Default depends on device type.' ), mask: z .enum(["ignored", "alpha", "black"]) .optional() .describe( 'For non-rectangular displays, handle the mask by policy: "ignored", "alpha", or "black".' ), force: z .boolean() .optional() .describe( "Force the output file to be written to, even if the file already exists." ), }, async ({ output_path, codec, display, mask, force }) => { try { const defaultFileName = `simulator_recording_${Date.now()}.mp4`; const outputFile = ensureAbsolutePath(output_path ?? defaultFileName); // Start the recording process const recordingProcess = spawn("xcrun", [ "simctl", "io", "booted", "recordVideo", ...(codec ? [`--codec=${codec}`] : []), ...(display ? [`--display=${display}`] : []), ...(mask ? [`--mask=${mask}`] : []), ...(force ? ["--force"] : []), // When passing user-provided values to a command, it's crucial to use `--` // to separate the command's options from positional arguments. // This prevents the shell from misinterpreting the arguments as options. "--", outputFile, ]); // Wait for recording to start await new Promise((resolve, reject) => { let errorOutput = ""; recordingProcess.stderr.on("data", (data) => { const message = data.toString(); if (message.includes("Recording started")) { resolve(true); } else { errorOutput += message; } }); // Set timeout for start verification setTimeout(() => { if (recordingProcess.killed) { reject(new Error("Recording process terminated unexpectedly")); } else { resolve(true); } }, 3000); }); return { isError: false, content: [ { type: "text", text: `Recording started. The video will be saved to: ${outputFile}\nTo stop recording, use the stop_recording command.`, }, ], }; } catch (error) { return { isError: true, content: [ { type: "text", text: errorWithTroubleshooting( `Error starting recording: ${toError(error).message}` ), }, ], }; } } ); }

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/joshuayoes/ios-simulator-mcp'

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