Skip to main content
Glama

swift_package_run

Execute an executable target from a Swift Package by specifying the package path, executable name, and optional arguments. Supports debug or release configurations, background execution, and custom timeouts.

Instructions

Runs an executable target from a Swift Package with swift run

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
argumentsNoArguments to pass to the executable
backgroundNoRun in background and return immediately (default: false)
configurationNoBuild configuration: 'debug' (default) or 'release'
executableNameNoName of executable to run (defaults to package name)
packagePathYesPath to the Swift package root (Required)
parseAsLibraryNoAdd -parse-as-library flag for @main support (default: false)
timeoutNoTimeout in seconds (default: 30, max: 300)

Implementation Reference

  • The main handler function `swift_package_runLogic` that executes the `swift run` command, supports foreground and background modes, handles timeouts, process tracking, and error cases.
    export async function swift_package_runLogic( params: SwiftPackageRunParams, executor: CommandExecutor, ): Promise<ToolResponse> { const resolvedPath = path.resolve(params.packagePath); const timeout = Math.min(params.timeout ?? 30, 300) * 1000; // Convert to ms, max 5 minutes // Detect test environment to prevent real spawn calls during testing const isTestEnvironment = process.env.VITEST === 'true' || process.env.NODE_ENV === 'test'; const swiftArgs = ['run', '--package-path', resolvedPath]; if (params.configuration && params.configuration.toLowerCase() === 'release') { swiftArgs.push('-c', 'release'); } else if (params.configuration && params.configuration.toLowerCase() !== 'debug') { return createTextResponse("Invalid configuration. Use 'debug' or 'release'.", true); } if (params.parseAsLibrary) { swiftArgs.push('-Xswiftc', '-parse-as-library'); } if (params.executableName) { swiftArgs.push(params.executableName); } // Add double dash before executable arguments if (params.arguments && params.arguments.length > 0) { swiftArgs.push('--'); swiftArgs.push(...params.arguments); } log('info', `Running swift ${swiftArgs.join(' ')}`); try { if (params.background) { // Background mode: Use CommandExecutor but don't wait for completion if (isTestEnvironment) { // In test environment, return mock response without real process const mockPid = 12345; return { content: [ createTextContent( `🚀 Started executable in background (PID: ${mockPid})\n` + `💡 Process is running independently. Use swift_package_stop with PID ${mockPid} to terminate when needed.`, ), ], }; } else { // Production: use CommandExecutor to start the process const command = ['swift', ...swiftArgs]; // Filter out undefined values from process.env const cleanEnv = Object.fromEntries( Object.entries(process.env).filter(([, value]) => value !== undefined), ) as Record<string, string>; const result = await executor( command, 'Swift Package Run (Background)', true, cleanEnv, true, ); // Store the process in active processes system if available if (result.process?.pid) { addProcess(result.process.pid, { process: { kill: (signal?: string) => { // Adapt string signal to NodeJS.Signals if (result.process) { result.process.kill(signal as NodeJS.Signals); } }, on: (event: string, callback: () => void) => { if (result.process) { result.process.on(event, callback); } }, pid: result.process.pid, }, startedAt: new Date(), }); return { content: [ createTextContent( `🚀 Started executable in background (PID: ${result.process.pid})\n` + `💡 Process is running independently. Use swift_package_stop with PID ${result.process.pid} to terminate when needed.`, ), ], }; } else { return { content: [ createTextContent( `🚀 Started executable in background\n` + `💡 Process is running independently. PID not available for this execution.`, ), ], }; } } } else { // Foreground mode: use CommandExecutor but handle long-running processes const command = ['swift', ...swiftArgs]; // Create a promise that will either complete with the command result or timeout const commandPromise = executor(command, 'Swift Package Run', true, undefined); const timeoutPromise = new Promise<{ success: boolean; output: string; error: string; timedOut: boolean; }>((resolve) => { setTimeout(() => { resolve({ success: false, output: '', error: `Process timed out after ${timeout / 1000} seconds`, timedOut: true, }); }, timeout); }); // Race between command completion and timeout const result = await Promise.race([commandPromise, timeoutPromise]); if ('timedOut' in result && result.timedOut) { // For timeout case, the process may still be running - provide timeout response if (isTestEnvironment) { // In test environment, return mock response const mockPid = 12345; return { content: [ createTextContent( `⏱️ Process timed out after ${timeout / 1000} seconds but may continue running.`, ), createTextContent(`PID: ${mockPid} (mock)`), createTextContent( `💡 Process may still be running. Use swift_package_stop with PID ${mockPid} to terminate when needed.`, ), createTextContent(result.output || '(no output so far)'), ], }; } else { // Production: timeout occurred, but we don't start a new process return { content: [ createTextContent(`⏱️ Process timed out after ${timeout / 1000} seconds.`), createTextContent( `💡 Process execution exceeded the timeout limit. Consider using background mode for long-running executables.`, ), createTextContent(result.output || '(no output so far)'), ], }; } } if (result.success) { return { content: [ createTextContent('✅ Swift executable completed successfully.'), createTextContent('💡 Process finished cleanly. Check output for results.'), createTextContent(result.output || '(no output)'), ], }; } else { const content = [ createTextContent('❌ Swift executable failed.'), createTextContent(result.output || '(no output)'), ]; if (result.error) { content.push(createTextContent(`Errors:\n${result.error}`)); } return { content }; } } } catch (error) { const message = error instanceof Error ? error.message : String(error); log('error', `Swift run failed: ${message}`); return createErrorResponse('Failed to execute swift run', message); } }
  • Zod schema defining input parameters for the `swift_package_run` tool, including package path, executable, arguments, config, timeout, background mode, and parse-as-library flag.
    const swiftPackageRunSchema = z.object({ packagePath: z.string().describe('Path to the Swift package root (Required)'), executableName: z .string() .optional() .describe('Name of executable to run (defaults to package name)'), arguments: z.array(z.string()).optional().describe('Arguments to pass to the executable'), configuration: z .enum(['debug', 'release']) .optional() .describe("Build configuration: 'debug' (default) or 'release'"), timeout: z.number().optional().describe('Timeout in seconds (default: 30, max: 300)'), background: z .boolean() .optional() .describe('Run in background and return immediately (default: false)'), parseAsLibrary: z .boolean() .optional() .describe('Add -parse-as-library flag for @main support (default: false)'), });
  • Module export default object registering the tool with name, description, schema, and typed handler created via `createTypedTool`.
    export default { name: 'swift_package_run', description: 'Runs an executable target from a Swift Package with swift run', schema: swiftPackageRunSchema.shape, // MCP SDK compatibility handler: createTypedTool( swiftPackageRunSchema, swift_package_runLogic, getDefaultCommandExecutor, ), };

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