read-adb-logcat
Dump Android logcat output filtered by package, process ID, or tag with tail and timeout controls for debugging.
Instructions
Dump recent adb logcat output scoped by package, pid, or tag with tail and timeout controls.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| 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 when tag is provided (e.g., D for debug) | V |
| maxLines | No | Tail line count via logcat -t | |
| timeoutMs | No | Timeout per adb call in milliseconds |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"maxLines": {
"default": 200,
"description": "Tail line count via logcat -t",
"maximum": 2000,
"minimum": 1,
"type": "integer"
},
"packageName": {
"description": "Android package name; resolves pid via adb shell pidof",
"minLength": 1,
"type": "string"
},
"pid": {
"description": "Explicit process id for logcat --pid",
"minLength": 1,
"type": "string"
},
"priority": {
"default": "V",
"description": "Minimum priority when tag is provided (e.g., D for debug)",
"enum": [
"V",
"D",
"I",
"W",
"E",
"F",
"S"
],
"type": "string"
},
"tag": {
"description": "Logcat tag to include (uses -s tag)",
"minLength": 1,
"type": "string"
},
"timeoutMs": {
"default": 5000,
"description": "Timeout per adb call in milliseconds",
"maximum": 15000,
"minimum": 1000,
"type": "integer"
}
},
"type": "object"
}
Implementation Reference
- src/tools/logcatTool.js:165-197 (handler)The handler function for 'read-adb-logcat' that resolves PID from package if provided, constructs logcat arguments, executes the adb logcat command, logs timing info, and returns the output.async (params, extra) => { const timeoutMs = params.timeoutMs; const pid = params.pid || (params.packageName ? await resolvePid(params.packageName, timeoutMs) : null); const args = buildLogcatArgs(params, pid); const startTime = process.hrtime.bigint(); const output = await runAdbCommand(args, timeoutMs); const elapsedMs = Number(process.hrtime.bigint() - startTime) / 1_000_000; if (extra && typeof extra.sessionId === 'string') { server .sendLoggingMessage( { level: 'info', data: `Read logcat (${params.maxLines} lines` + (pid ? `, pid=${pid}` : '') + (params.tag ? `, tag=${params.tag}:${params.priority}` : '') + `) in ${elapsedMs.toFixed(2)}ms` }, extra.sessionId ) .catch(() => { /* best-effort logging */ }); } if (!output) { return { content: [{ type: 'text', text: 'Logcat returned no lines.' }] }; } return { content: [{ type: 'text', text: output }] }; }
- src/tools/logcatTool.js:16-46 (schema)Zod input schema for 'read-adb-logcat' defining parameters like packageName, pid, tag, priority, maxLines, and timeoutMs with validation and descriptions.const logcatInputSchema = z .object({ 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 when tag is provided (e.g., D for debug)'), maxLines: z .number() .int() .min(1) .max(2000) .default(200) .describe('Tail line count via logcat -t'), timeoutMs: z .number() .int() .min(1000) .max(15000) .default(5000) .describe('Timeout per adb call in milliseconds') }) .refine(data => data.packageName || data.pid || data.tag, { message: 'Provide packageName, pid, or tag to avoid unfiltered logs' });
- src/tools/logcatTool.js:157-198 (registration)Registration of the 'read-adb-logcat' tool via server.registerTool within the registerLogcatTool function, specifying title, description, inputSchema, and handler.server.registerTool( 'read-adb-logcat', { title: 'Read adb logcat', description: 'Dump recent adb logcat output scoped by package, pid, or tag with tail and timeout controls.', inputSchema: logcatInputSchema }, async (params, extra) => { const timeoutMs = params.timeoutMs; const pid = params.pid || (params.packageName ? await resolvePid(params.packageName, timeoutMs) : null); const args = buildLogcatArgs(params, pid); const startTime = process.hrtime.bigint(); const output = await runAdbCommand(args, timeoutMs); const elapsedMs = Number(process.hrtime.bigint() - startTime) / 1_000_000; if (extra && typeof extra.sessionId === 'string') { server .sendLoggingMessage( { level: 'info', data: `Read logcat (${params.maxLines} lines` + (pid ? `, pid=${pid}` : '') + (params.tag ? `, tag=${params.tag}:${params.priority}` : '') + `) in ${elapsedMs.toFixed(2)}ms` }, extra.sessionId ) .catch(() => { /* best-effort logging */ }); } if (!output) { return { content: [{ type: 'text', text: 'Logcat returned no lines.' }] }; } return { content: [{ type: 'text', text: output }] }; } );
- src/tools/logcatTool.js:118-133 (helper)Helper function to execute adb commands asynchronously with timeout and error handling, used by the logcat 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); } }
- src/tools/logcatTool.js:135-142 (helper)Helper function to resolve process ID (PID) from package name using adb shell pidof, called by the handler when packageName is provided.async function resolvePid(packageName, timeoutMs) { const output = await runAdbCommand(['shell', 'pidof', '-s', packageName], timeoutMs); const pid = output.split(/\s+/).find(Boolean); if (!pid) { throw new Error(`Could not resolve pid for package ${packageName}`); } return pid; }