manage-logcat
Read Android device logs, capture crash buffers, check ANR reports, and clear log buffers through unified ADB logcat commands for debugging and monitoring.
Instructions
Unified tool to read logs, capture crashes, check ANRs, and clear buffers.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | Action to perform: read logs, get crash buffer, check ANR, or clear buffer. | read |
| packageName | No | Android package name; resolves pid via adb shell pidof | |
| pid | No | Explicit process id for logcat --pid | |
| tag | No | Logcat tag to include (uses -s tag) | |
| priority | No | Minimum priority (e.g. D for debug). | V |
| maxLines | No | Tail line count (logcat -t). | |
| timeoutMs | No | Timeout per adb call in milliseconds |
Implementation Reference
- src/tools/logcatTool.js:61-109 (handler)The core handler function that implements the logic for the 'manage-logcat' tool, dispatching to different ADB logcat commands based on the 'action' parameter (read, crash, anr, clear).async (params) => { const { action, timeoutMs } = params; if (action === 'clear') { await runAdbCommand(['logcat', '-c'], timeoutMs); return { content: [{ type: 'text', text: 'Cleared logcat buffers.' }] }; } // Resolve PID if packageName is provided let pid = params.pid; if (!pid && params.packageName) { pid = await resolvePid(params.packageName, timeoutMs); } // 1. ANR Check if (action === 'anr') { const sections = []; try { const logArgs = ['logcat', '-d', '-t', String(params.maxLines), 'ActivityManager:E', '*:S']; const amLogs = await runAdbCommand(logArgs, timeoutMs); sections.push('ActivityManager (recent):\n' + (amLogs || 'No entries.')); } catch (e) { sections.push('ActivityManager error: ' + e.message); } try { const tail = await runAdbCommand(['shell', 'tail', '-n', '200', '/data/anr/traces.txt'], timeoutMs); sections.push('traces.txt tail (200 lines):\n' + (tail || 'Empty.')); } catch (e) { sections.push('traces.txt error: ' + e.message); } return { content: [{ type: 'text', text: sections.join('\n\n') }] }; } // 2. Crash Buffer if (action === 'crash') { const args = ['logcat', '-b', 'crash', '-d', '-t', String(params.maxLines)]; if (pid) args.push(`--pid=${pid}`); const output = await runAdbCommand(args, timeoutMs); return { content: [{ type: 'text', text: output || 'No crash entries found.' }] }; } // 3. Normal Read (Default) const args = ['logcat', '-d', '-t', String(params.maxLines)]; if (pid) args.push(`--pid=${pid}`); if (params.tag) { args.push('-s', `${params.tag}:${params.priority}`); } const output = await runAdbCommand(args, timeoutMs); return { content: [{ type: 'text', text: output || 'Logcat returned no lines.' }] }; }
- src/tools/logcatTool.js:12-20 (schema)Zod schema defining the input parameters and validation for the manage-logcat tool.const manageLogcatSchema = z.object({ action: z.enum(['read', 'crash', 'anr', 'clear']).default('read').describe('Action to perform: read logs, get crash buffer, check ANR, or clear buffer.'), packageName: z.string().min(1).describe('Android package name; resolves pid via adb shell pidof').optional(), pid: z.string().min(1).describe('Explicit process id for logcat --pid').optional(), tag: z.string().min(1).describe('Logcat tag to include (uses -s tag)').optional(), priority: z.enum(['V', 'D', 'I', 'W', 'E', 'F', 'S']).default('V').describe('Minimum priority (e.g. D for debug).'), maxLines: z.number().int().min(1).max(2000).default(200).describe('Tail line count (logcat -t).'), timeoutMs: z.number().int().min(1000).max(15000).default(5000).describe('Timeout per adb call in milliseconds') });
- src/tools/logcatTool.js:54-110 (registration)Direct registration of the 'manage-logcat' tool with the MCP server, specifying name, metadata, schema, and inline handler.server.registerTool( 'manage-logcat', { title: 'Manage ADB Logcat', description: 'Unified tool to read logs, capture crashes, check ANRs, and clear buffers.', inputSchema: manageLogcatSchema }, async (params) => { const { action, timeoutMs } = params; if (action === 'clear') { await runAdbCommand(['logcat', '-c'], timeoutMs); return { content: [{ type: 'text', text: 'Cleared logcat buffers.' }] }; } // Resolve PID if packageName is provided let pid = params.pid; if (!pid && params.packageName) { pid = await resolvePid(params.packageName, timeoutMs); } // 1. ANR Check if (action === 'anr') { const sections = []; try { const logArgs = ['logcat', '-d', '-t', String(params.maxLines), 'ActivityManager:E', '*:S']; const amLogs = await runAdbCommand(logArgs, timeoutMs); sections.push('ActivityManager (recent):\n' + (amLogs || 'No entries.')); } catch (e) { sections.push('ActivityManager error: ' + e.message); } try { const tail = await runAdbCommand(['shell', 'tail', '-n', '200', '/data/anr/traces.txt'], timeoutMs); sections.push('traces.txt tail (200 lines):\n' + (tail || 'Empty.')); } catch (e) { sections.push('traces.txt error: ' + e.message); } return { content: [{ type: 'text', text: sections.join('\n\n') }] }; } // 2. Crash Buffer if (action === 'crash') { const args = ['logcat', '-b', 'crash', '-d', '-t', String(params.maxLines)]; if (pid) args.push(`--pid=${pid}`); const output = await runAdbCommand(args, timeoutMs); return { content: [{ type: 'text', text: output || 'No crash entries found.' }] }; } // 3. Normal Read (Default) const args = ['logcat', '-d', '-t', String(params.maxLines)]; if (pid) args.push(`--pid=${pid}`); if (params.tag) { args.push('-s', `${params.tag}:${params.priority}`); } const output = await runAdbCommand(args, timeoutMs); return { content: [{ type: 'text', text: output || 'Logcat returned no lines.' }] }; } );
- src/index.js:28-28 (registration)Invocation of registerLogcatTool which performs the server.registerTool for manage-logcat (and get-current-activity).registerLogcatTool(server);
- src/tools/logcatTool.js:26-41 (helper)Helper function to execute ADB shell commands with timeout handling and comprehensive error reporting, used extensively in the handler.async function runAdbCommand(args, timeoutMs) { try { const { stdout } = await execFileAsync('adb', args, { timeout: timeoutMs, maxBuffer: 5 * 1024 * 1024 }); return stdout.trimEnd(); } catch (error) { const stderr = error && typeof error.stderr === 'string' ? error.stderr.trim() : ''; const message = [`adb ${args.join(' ')} failed`, error.message].filter(Boolean).join(': '); if (stderr) { throw new Error(`${message} | stderr: ${stderr}`); } throw new Error(message); } }