execute
Execute data modification SQL statements (INSERT, UPDATE, DELETE, DDL). Validate without executing by setting dryRun=true; confirm destructive operations like DROP or TRUNCATE before execution.
Instructions
Execute a data modification SQL statement (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, etc.). Set dryRun=true to validate without executing — uses EXPLAIN for DML, or previews the SQL for DDL. Always confirm destructive operations (DROP, TRUNCATE, DELETE without WHERE) with the user before executing. Not available in read-only mode.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | The SQL statement to execute. SELECT statements are not allowed here; use the "query" tool instead. | |
| dryRun | No | If true, validates the statement via EXPLAIN without executing it. Defaults to false. |
Implementation Reference
- src/tools/execute.ts:26-109 (handler)The main handler function for the 'execute' tool. It checks read-only mode, validates SQL input, rejects SELECT/WITH statements, supports dry-run (EXPLAIN for DML, preview for DDL), and runs the actual SQL returning affectedRows/changedRows.
export function createExecuteHandler(runner: QueryRunner, isReadonly: boolean) { return async ({ sql, dryRun }: { sql: string; dryRun?: boolean }) => { if (isReadonly) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Error: Server is in read-only mode. Data modification is not allowed.', }, ], }; } const validation = validateSql(sql); if (!validation.valid) { return { isError: true as const, content: [{ type: 'text' as const, text: validation.message! }], }; } const normalized = sql.trim().toUpperCase(); if (normalized.startsWith('SELECT') || normalized.startsWith('WITH')) { return { isError: true as const, content: [ { type: 'text' as const, text: 'Error: Use the "query" tool for SELECT statements.', }, ], }; } if (dryRun) { const DDL_PREFIXES = ['CREATE', 'DROP', 'ALTER', 'TRUNCATE', 'RENAME']; const isDdl = DDL_PREFIXES.some((p) => normalized.startsWith(p)); if (isDdl) { return { content: [ { type: 'text' as const, text: `[dry-run] SQL preview (DDL cannot be validated via EXPLAIN):\n${sql}`, }, ], }; } try { const [rows] = await runner.query(`EXPLAIN ${sql}`); return { content: [ { type: 'text' as const, text: `[dry-run] Statement validated via EXPLAIN:\n${JSON.stringify(rows, null, 2)}`, }, ], }; } catch (error) { return { isError: true as const, content: [{ type: 'text' as const, text: `[dry-run] Validation failed: ${formatError(error)}` }], }; } } try { const [result] = await runner.query(sql); const r = result as unknown as Record<string, unknown>; return { content: [ { type: 'text' as const, text: `affectedRows: ${r.affectedRows}, changedRows: ${r.changedRows ?? 0}` }, ], }; } catch (error) { return { isError: true as const, content: [{ type: 'text' as const, text: formatError(error) }], }; } }; } - src/tools/execute.ts:6-24 (schema)Tool name ('execute'), description, and Zod-based input schema (sql string, dryRun optional boolean).
export const executeToolName = 'execute'; export const executeToolConfig = { title: 'Execute', description: 'Execute a data modification SQL statement (INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, etc.). ' + 'Set dryRun=true to validate without executing — uses EXPLAIN for DML, or previews the SQL for DDL. ' + 'Always confirm destructive operations (DROP, TRUNCATE, DELETE without WHERE) with the user before executing. ' + 'Not available in read-only mode.', inputSchema: { sql: z .string() .describe('The SQL statement to execute. SELECT statements are not allowed here; use the "query" tool instead.'), dryRun: z .boolean() .optional() .describe('If true, validates the statement via EXPLAIN without executing it. Defaults to false.'), }, }; - src/tools/index.ts:22-27 (registration)Registers the 'execute' tool on the MCP server with its name, description, input schema, and handler.
server.tool( executeToolName, executeToolConfig.description, executeToolConfig.inputSchema, createExecuteHandler(runner, readonly), ); - src/tools/validate-input.ts:31-39 (helper)Validates SQL input for control characters before execution.
export function validateSql(sql: string): ValidationResult { if (hasControlChars(sql)) { return { valid: false, message: 'Error: SQL contains control characters. Remove non-printable characters (tab and newline are allowed).', }; } return { valid: true }; } - src/tools/error-hint.ts:11-15 (helper)Formats error messages with contextual hints for common MySQL errors.
export function formatError(error: unknown): string { const message = error instanceof Error ? error.message : String(error); const hint = HINTS.find(([pattern]) => pattern.test(message)); return hint ? `Error: ${message}\n${hint[1]}` : `Error: ${message}`; }