mysql_query
Execute read-only SQL queries (SELECT/SHOW/DESCRIBE/EXPLAIN) against a local WordPress database for data analysis and debugging.
Instructions
Execute a read-only SQL query against the Local WordPress database
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | Single read-only SQL statement (SELECT/SHOW/DESCRIBE/EXPLAIN). | |
| params | No | Optional parameter values for placeholders (?). |
Implementation Reference
- src/index.ts:175-185 (handler)The handler case for 'mysql_query' in the CallToolRequestSchema handler. It extracts the 'sql' and optional 'params' from arguments, calls mysql.executeReadOnlyQuery(), and returns the result as JSON.
case 'mysql_query': { const sql = String(args.sql); const params = Array.isArray(args.params) ? args.params : undefined; debugLog('Executing mysql_query'); const result = await mysql.executeReadOnlyQuery(sql, params); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) }, ], }; } - src/index.ts:81-99 (schema)Tool registration schema for mysql_query. Defines inputSchema with required 'sql' (string) and optional 'params' (array of strings). Declares the tool as read-only (SELECT/SHOW/DESCRIBE/EXPLAIN).
const tools: Tool[] = [ { name: 'mysql_query', description: 'Execute a read-only SQL query against the Local WordPress database', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: 'Single read-only SQL statement (SELECT/SHOW/DESCRIBE/EXPLAIN).', }, params: { type: 'array', description: 'Optional parameter values for placeholders (?).', items: { type: 'string' }, }, }, required: ['sql'], }, - src/index.ts:81-131 (registration)Tool is registered in the 'tools' array with name 'mysql_query' and its schema, then exposed via ListToolsRequestSchema handler.
const tools: Tool[] = [ { name: 'mysql_query', description: 'Execute a read-only SQL query against the Local WordPress database', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: 'Single read-only SQL statement (SELECT/SHOW/DESCRIBE/EXPLAIN).', }, params: { type: 'array', description: 'Optional parameter values for placeholders (?).', items: { type: 'string' }, }, }, required: ['sql'], }, }, { name: 'mysql_schema', description: 'Inspect database schema. Without args: lists tables. With table: shows columns and indexes.', inputSchema: { type: 'object', properties: { table: { type: 'string', description: 'Optional table name to inspect', }, }, }, }, { name: 'mysql_current_site', description: 'Get information about the currently connected Local WordPress site, including how it was selected', inputSchema: { type: 'object', properties: {}, }, }, { name: 'mysql_list_sites', description: 'List all available Local WordPress sites and their running status', inputSchema: { type: 'object', properties: {}, }, }, ]; - src/mysql-client.ts:46-74 (helper)The executeReadOnlyQuery method on MySQLClient that performs safety checks (no multiple statements, only SELECT/SHOW/DESCRIBE/EXPLAIN allowed) before executing the query.
async executeReadOnlyQuery(sql: string, params?: any[]): Promise<any[]> { const trimmed = sql.trim(); if (!trimmed) { throw new Error('SQL is empty'); } // Disallow multiple statements entirely for safety if (trimmed.includes(';')) { // Allow a trailing semicolon only const statements = trimmed.split(';').filter(s => s.trim().length > 0); if (statements.length > 1) { throw new Error('Multiple statements are not allowed. Submit a single read-only query.'); } } const firstToken = trimmed .replace(/^\/\*[\s\S]*?\*\//g, '') // strip block comments .replace(/^--.*$/gm, '') // strip line comments .trim() .toLowerCase() .split(/\s+/)[0]; const allowed = new Set(['select', 'show', 'describe', 'desc', 'explain']); if (!allowed.has(firstToken)) { throw new Error('Only read-only queries are permitted (SELECT/SHOW/DESCRIBE/EXPLAIN).'); } return await this.query(sql, params); }