Skip to main content
Glama

scaffold_ios_project

Generate a modern iOS project with Xcode workspace structure, SPM package for features, and proper iOS configuration, including bundle identifier, deployment target, and device orientation settings.

Instructions

Scaffold a new iOS project from templates. Creates a modern Xcode project with workspace structure, SPM package for features, and proper iOS configuration.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
bundleIdentifierNoBundle identifier (e.g., com.example.myapp). If not provided, will use com.example.projectname
currentProjectVersionNoBuild number (e.g., 1, 42, 100). If not provided, will use 1
customizeNamesNoWhether to customize project names and identifiers. Default is true.
deploymentTargetNoiOS deployment target (e.g., 18.4, 17.0). If not provided, will use 18.4
displayNameNoApp display name (shown on home screen/dock). If not provided, will use projectName
marketingVersionNoMarketing version (e.g., 1.0, 2.1.3). If not provided, will use 1.0
outputPathYesPath where the project should be created
projectNameYesName of the new project
supportedOrientationsNoSupported orientations for iPhone
supportedOrientationsIpadNoSupported orientations for iPad
targetedDeviceFamilyNoTargeted device families

Implementation Reference

  • Zod schema definitions for the tool parameters, including base schema extended for iOS-specific fields.
    // Common base schema for both iOS and macOS
    const BaseScaffoldSchema = z.object({
      projectName: z.string().min(1).describe('Name of the new project'),
      outputPath: z.string().describe('Path where the project should be created'),
      bundleIdentifier: z
        .string()
        .optional()
        .describe(
          'Bundle identifier (e.g., com.example.myapp). If not provided, will use com.example.projectname',
        ),
      displayName: z
        .string()
        .optional()
        .describe(
          'App display name (shown on home screen/dock). If not provided, will use projectName',
        ),
      marketingVersion: z
        .string()
        .optional()
        .describe('Marketing version (e.g., 1.0, 2.1.3). If not provided, will use 1.0'),
      currentProjectVersion: z
        .string()
        .optional()
        .describe('Build number (e.g., 1, 42, 100). If not provided, will use 1'),
      customizeNames: z
        .boolean()
        .default(true)
        .describe('Whether to customize project names and identifiers. Default is true.'),
    });
    
    // iOS-specific schema
    const ScaffoldiOSProjectSchema = BaseScaffoldSchema.extend({
      deploymentTarget: z
        .string()
        .optional()
        .describe('iOS deployment target (e.g., 18.4, 17.0). If not provided, will use 18.4'),
      targetedDeviceFamily: z
        .array(z.enum(['iphone', 'ipad', 'universal']))
        .optional()
        .describe('Targeted device families'),
      supportedOrientations: z
        .array(z.enum(['portrait', 'landscape-left', 'landscape-right', 'portrait-upside-down']))
        .optional()
        .describe('Supported orientations for iPhone'),
      supportedOrientationsIpad: z
        .array(z.enum(['portrait', 'landscape-left', 'landscape-right', 'portrait-upside-down']))
        .optional()
        .describe('Supported orientations for iPad'),
    });
  • Core handler function that orchestrates iOS project scaffolding, handles errors, and returns the response.
    export async function scaffold_ios_projectLogic(
      params: ScaffoldIOSProjectParams,
      commandExecutor: CommandExecutor,
      fileSystemExecutor: FileSystemExecutor,
    ): Promise<ToolResponse> {
      try {
        const projectParams = { ...params, platform: 'iOS' };
        const projectPath = await scaffoldProject(projectParams, commandExecutor, fileSystemExecutor);
    
        const response = {
          success: true,
          projectPath,
          platform: 'iOS',
          message: `Successfully scaffolded iOS project "${params.projectName}" in ${projectPath}`,
          nextSteps: [
            `Important: Before working on the project make sure to read the README.md file in the workspace root directory.`,
            `Build for simulator: build_sim({ workspacePath: "${projectPath}/${params.customizeNames ? params.projectName : 'MyProject'}.xcworkspace", scheme: "${params.customizeNames ? params.projectName : 'MyProject'}", simulatorName: "iPhone 16" })`,
            `Build and run on simulator: build_run_sim({ workspacePath: "${projectPath}/${params.customizeNames ? params.projectName : 'MyProject'}.xcworkspace", scheme: "${params.customizeNames ? params.projectName : 'MyProject'}", simulatorName: "iPhone 16" })`,
          ],
        };
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(response, null, 2),
            },
          ],
        };
      } catch (error) {
        log(
          'error',
          `Failed to scaffold iOS project: ${error instanceof Error ? error.message : String(error)}`,
        );
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(
                {
                  success: false,
                  error: error instanceof Error ? error.message : 'Unknown error occurred',
                },
                null,
                2,
              ),
            },
          ],
          isError: true,
        };
      }
    }
  • Tool registration exporting the tool object with name, description, schema, and a thin handler that parses args and calls the core logic.
    export default {
      name: 'scaffold_ios_project',
      description:
        'Scaffold a new iOS project from templates. Creates a modern Xcode project with workspace structure, SPM package for features, and proper iOS configuration.',
      schema: ScaffoldiOSProjectSchema.shape,
      async handler(args: Record<string, unknown>): Promise<ToolResponse> {
        const params = ScaffoldiOSProjectSchema.parse(args);
        return scaffold_ios_projectLogic(
          params,
          getDefaultCommandExecutor(),
          getDefaultFileSystemExecutor(),
        );
      },
    };
  • Key helper function that handles template retrieval, project validation, and recursive directory processing for scaffolding.
    async function scaffoldProject(
      params: Record<string, unknown>,
      commandExecutor?: CommandExecutor,
      fileSystemExecutor: FileSystemExecutor = getDefaultFileSystemExecutor(),
    ): Promise<string> {
      const projectName = params.projectName as string;
      const outputPath = params.outputPath as string;
      const platform = params.platform as 'iOS' | 'macOS';
      const customizeNames = (params.customizeNames as boolean | undefined) ?? true;
    
      log('info', `Scaffolding project: ${projectName} (${platform}) at ${outputPath}`);
    
      // Validate project name
      if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(projectName)) {
        throw new ValidationError(
          'Project name must start with a letter and contain only letters, numbers, and underscores',
        );
      }
    
      // Get template path from TemplateManager
      let templatePath;
      try {
        // Use the default command executor if not provided
        commandExecutor ??= getDefaultCommandExecutor();
    
        templatePath = await TemplateManager.getTemplatePath(
          platform,
          commandExecutor,
          fileSystemExecutor,
        );
      } catch (error) {
        throw new ValidationError(
          `Failed to get template for ${platform}: ${error instanceof Error ? error.message : String(error)}`,
        );
      }
    
      // Use outputPath directly as the destination
      const projectPath = outputPath;
    
      // Check if the output directory already has Xcode project files
      const xcworkspaceExists = fileSystemExecutor.existsSync(
        join(projectPath, `${customizeNames ? projectName : 'MyProject'}.xcworkspace`),
      );
      const xcodeprojExists = fileSystemExecutor.existsSync(
        join(projectPath, `${customizeNames ? projectName : 'MyProject'}.xcodeproj`),
      );
    
      if (xcworkspaceExists || xcodeprojExists) {
        throw new ValidationError(`Xcode project files already exist in ${projectPath}`);
      }
    
      try {
        // Process the template directly into the output path
        await processDirectory(templatePath, projectPath, params, fileSystemExecutor);
    
        return projectPath;
      } finally {
        // Clean up downloaded template if needed
        await TemplateManager.cleanup(templatePath, fileSystemExecutor);
      }
    }
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It states the tool 'creates' a project, implying a write operation, but doesn't address permissions, side effects, error handling, or what happens if the output path exists. For a creation tool with 11 parameters and no annotation coverage, this is insufficient.

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, well-structured sentence that efficiently conveys the core purpose and key features without redundancy. Every word contributes to understanding what the tool does.

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

Completeness2/5

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

For a complex creation tool with 11 parameters and no annotations or output schema, the description is incomplete. It doesn't explain what 'scaffold' entails beyond high-level features, doesn't describe the output structure or files created, and provides no behavioral context for a tool that likely modifies the filesystem.

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 100%, so the schema fully documents all 11 parameters with descriptions and defaults. The description adds no parameter-specific information beyond what's in the schema, meeting the baseline for high coverage but not providing additional value.

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 action ('scaffold'), resource ('new iOS project'), and specific outcomes ('modern Xcode project with workspace structure, SPM package for features, and proper iOS configuration'). It distinguishes from the sibling 'scaffold_macos_project' by specifying iOS rather than macOS.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like 'scaffold_macos_project' or other project creation tools. It doesn't mention prerequisites, typical scenarios, or exclusions, leaving the agent to infer usage from the tool name alone.

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