inspect_app_state
Inspect mobile app preferences and databases to debug and analyze stored data on Android and iOS platforms.
Instructions
Inspect app preferences (SharedPreferences/UserDefaults) and SQLite databases. Can list all preferences, inspect specific databases, or run SQL queries.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| appId | Yes | App package name (Android) or bundle ID (iOS) | |
| platform | Yes | Target platform | |
| deviceId | No | Device ID (optional, uses first available) | |
| includePreferences | No | Include preferences in inspection (default: true) | |
| includeDatabases | No | Include databases in inspection (default: true) | |
| preferencesFile | No | Specific preferences file to inspect | |
| databaseName | No | Specific database name to inspect or query | |
| sqlQuery | No | SQL query to execute (requires databaseName) | |
| maxRows | No | Maximum rows to return from query (default: 100) | |
| timeoutMs | No | Timeout in milliseconds (default: 30000) |
Implementation Reference
- Core handler function that performs app state inspection: validates arguments, handles SQL queries or full state collection (preferences/databases), and returns structured results.export async function inspectAppState(args: InspectAppStateArgs): Promise<AppStateResult> { const { appId, platform, deviceId, includePreferences = true, includeDatabases = true, preferencesFile, databaseName, sqlQuery, maxRows = 100, timeoutMs = 30000, } = args; const startTime = Date.now(); // Validate platform if (!isPlatform(platform)) { throw Errors.invalidArguments(`Invalid platform: ${platform}. Must be 'android' or 'ios'`); } // Validate app ID if (!appId || appId.trim().length === 0) { throw Errors.invalidArguments('App ID is required'); } try { // If SQL query is provided, execute it directly if (sqlQuery && databaseName) { const queryResult = await executeSqlQuery( appId, platform, databaseName, sqlQuery, { deviceId, maxRows, timeoutMs } ); return { success: true, queryResult, durationMs: Date.now() - startTime, }; } // Collect app state const state = await collectAppState(appId, platform, { deviceId, includePreferences, includeDatabases, preferencesFile, databaseName, timeoutMs, }); return { success: true, state, durationMs: Date.now() - startTime, }; } catch (error) { return { success: false, error: String(error), durationMs: Date.now() - startTime, }; } }
- TypeScript interface defining the input parameters for the inspect_app_state tool.export interface InspectAppStateArgs { /** App package/bundle ID */ appId: string; /** Target platform */ platform: string; /** Device ID */ deviceId?: string; /** Include preferences */ includePreferences?: boolean; /** Include databases */ includeDatabases?: boolean; /** Specific preferences file name */ preferencesFile?: string; /** Specific database name */ databaseName?: string; /** SQL query to run */ sqlQuery?: string; /** Maximum rows to return */ maxRows?: number; /** Timeout in milliseconds */ timeoutMs?: number; }
- src/tools/observability/inspect-app-state.ts:279-341 (registration)Registers the inspect_app_state tool with the MCP tool registry, including detailed input schema and a wrapper handler that calls the core inspectAppState function and adds formatted output.export function registerInspectAppStateTool(): void { getToolRegistry().register( 'inspect_app_state', { description: 'Inspect app preferences (SharedPreferences/UserDefaults) and SQLite databases. ' + 'Can list all preferences, inspect specific databases, or run SQL queries.', inputSchema: createInputSchema( { appId: { type: 'string', description: 'App package name (Android) or bundle ID (iOS)', }, platform: { type: 'string', enum: ['android', 'ios'], description: 'Target platform', }, deviceId: { type: 'string', description: 'Device ID (optional, uses first available)', }, includePreferences: { type: 'boolean', description: 'Include preferences in inspection (default: true)', }, includeDatabases: { type: 'boolean', description: 'Include databases in inspection (default: true)', }, preferencesFile: { type: 'string', description: 'Specific preferences file to inspect', }, databaseName: { type: 'string', description: 'Specific database name to inspect or query', }, sqlQuery: { type: 'string', description: 'SQL query to execute (requires databaseName)', }, maxRows: { type: 'number', description: 'Maximum rows to return from query (default: 100)', }, timeoutMs: { type: 'number', description: 'Timeout in milliseconds (default: 30000)', }, }, ['appId', 'platform'] ), }, async (args) => { const result = await inspectAppState(args as unknown as InspectAppStateArgs); return { ...result, formattedOutput: formatInspectionResult(result), }; } ); }
- Helper function to format inspection results into readable markdown for AI consumption, handling both query results and full app state summaries.export function formatInspectionResult(result: AppStateResult): string { const lines: string[] = []; if (!result.success) { lines.push(`## App State Inspection: Failed`); lines.push(``); lines.push(`**Error**: ${result.error}`); return lines.join('\n'); } if (result.queryResult) { lines.push(`## SQL Query Result`); lines.push(``); lines.push(`**Rows**: ${result.queryResult.rowCount}`); lines.push(`**Columns**: ${result.queryResult.columns.join(', ')}`); lines.push(``); if (result.queryResult.rows.length > 0) { lines.push(`### Data`); lines.push(``); // Format as markdown table lines.push(`| ${result.queryResult.columns.join(' | ')} |`); lines.push(`| ${result.queryResult.columns.map(() => '---').join(' | ')} |`); for (const row of result.queryResult.rows.slice(0, 20)) { const values = result.queryResult.columns.map((col) => { const value = row[col]; if (value === null) return 'NULL'; if (typeof value === 'string' && value.length > 30) { return value.slice(0, 30) + '...'; } return String(value); }); lines.push(`| ${values.join(' | ')} |`); } if (result.queryResult.rows.length > 20) { lines.push(``); lines.push(`*Showing 20 of ${result.queryResult.rows.length} rows*`); } } return lines.join('\n'); } if (result.state) { return generateAppStateSummary(result.state); } return 'No data available'; }
- src/tools/register.ts:166-170 (registration)Central tool registration during server startup: imports and invokes the tool's registration function.const { registerInspectAppStateTool } = await import('./observability/inspect-app-state.js'); const { registerInspectLogsTool } = await import('./observability/inspect-logs.js'); registerInspectAppStateTool(); registerInspectLogsTool();