stop_device_log_cap
Terminates an active Apple device log capture session and retrieves the collected logs using the specified session ID in XcodeBuildMCP.
Instructions
Stops an active Apple device log capture session and returns the captured logs.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| logSessionId | Yes | The session ID returned by start_device_log_cap. |
Implementation Reference
- src/mcp/tools/logging/stop_device_log_cap.ts:311-322 (registration)MCP tool registration object exported as default, including name, description, schema, and handler that delegates to the main logic function.export default { name: 'stop_device_log_cap', description: 'Stops an active Apple device log capture session and returns the captured logs.', schema: stopDeviceLogCapSchema.shape, // MCP SDK compatibility handler: createTypedTool( stopDeviceLogCapSchema, (params: StopDeviceLogCapParams) => { return stop_device_log_capLogic(params, getDefaultFileSystemExecutor()); }, getDefaultCommandExecutor, ), };
- Zod schema for the tool input parameters, requiring logSessionId.const stopDeviceLogCapSchema = z.object({ logSessionId: z.string().describe('The session ID returned by start_device_log_cap.'), });
- Core handler function that stops the log capture process, reads the log file, removes the session, and returns the captured logs or error.export async function stop_device_log_capLogic( params: StopDeviceLogCapParams, fileSystemExecutor: FileSystemExecutor, ): Promise<ToolResponse> { const { logSessionId } = params; const session = activeDeviceLogSessions.get(logSessionId); if (!session) { log('warning', `Device log session not found: ${logSessionId}`); return { content: [ { type: 'text', text: `Failed to stop device log capture session ${logSessionId}: Device log capture session not found: ${logSessionId}`, }, ], isError: true, }; } try { log('info', `Attempting to stop device log capture session: ${logSessionId}`); const shouldSignalStop = !(session.hasEnded ?? false) && session.process.killed !== true && session.process.exitCode == null; if (shouldSignalStop) { session.process.kill?.('SIGTERM'); } await waitForSessionToFinish(session); if (session.logStream) { await ensureStreamClosed(session.logStream); } const logFilePath = session.logFilePath; activeDeviceLogSessions.delete(logSessionId); // Check file access if (!fileSystemExecutor.existsSync(logFilePath)) { throw new Error(`Log file not found: ${logFilePath}`); } const fileContent = await fileSystemExecutor.readFile(logFilePath, 'utf-8'); log('info', `Successfully read device log content from ${logFilePath}`); log( 'info', `Device log capture session ${logSessionId} stopped. Log file retained at: ${logFilePath}`, ); return { content: [ { type: 'text', text: `✅ Device log capture session stopped successfully\n\nSession ID: ${logSessionId}\n\n--- Captured Logs ---\n${fileContent}`, }, ], }; } catch (error) { const message = error instanceof Error ? error.message : String(error); log('error', `Failed to stop device log capture session ${logSessionId}: ${message}`); return { content: [ { type: 'text', text: `Failed to stop device log capture session ${logSessionId}: ${message}`, }, ], isError: true, }; } }
- Helper function to wait for the log capture process to finish, using event listeners or polling.async function waitForSessionToFinish(session: DeviceLogSession): Promise<void> { if (session.hasEnded) { return; } if (session.process.exitCode != null) { session.hasEnded = true; return; } if (typeof session.process.once === 'function') { await new Promise<void>((resolve) => { const onClose = (): void => { clearTimeout(timeout); session.hasEnded = true; resolve(); }; const timeout = setTimeout(() => { session.process.removeListener?.('close', onClose); session.hasEnded = true; resolve(); }, 1000); session.process.once('close', onClose); if (session.hasEnded || session.process.exitCode != null) { session.process.removeListener?.('close', onClose); onClose(); } }); return; } // Fallback polling for minimal mock processes (primarily in tests) for (let i = 0; i < 20; i += 1) { if (session.hasEnded || session.process.exitCode != null) { session.hasEnded = true; break; } await new Promise((resolve) => setTimeout(resolve, 50)); } }
- src/mcp/tools/device/stop_device_log_cap.ts:1-2 (registration)Re-export of the main tool implementation from logging directory for device tools organization.// Re-export from logging to complete workflow export { default } from '../logging/stop_device_log_cap.ts';