Skip to main content
Glama

execute_query

Run SQL queries on Turso databases directly from LLMs using the MCP server. Input the query, optional database name, and parameters to retrieve or modify data efficiently.

Instructions

Executes a SQL query against a database

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
databaseNoDatabase name (optional, uses context if not provided)
paramsNoQuery parameters (optional)
queryYesSQL query to execute

Implementation Reference

  • Core implementation that executes the SQL query against the Turso database client, handling read-only detection, permission selection, parameter conversion, and error wrapping.
    export async function execute_query(
    	database_name: string,
    	query: string,
    	params: Record<string, any> = {},
    ): Promise<ResultSet> {
    	try {
    		// Determine if this is a read-only query
    		const is_read_only = query
    			.trim()
    			.toLowerCase()
    			.startsWith('select');
    		const permission = is_read_only ? 'read-only' : 'full-access';
    
    		const client = await get_database_client(
    			database_name,
    			permission,
    		);
    
    		// Execute the query
    		return await client.execute({
    			sql: query,
    			args: convert_parameters(params),
    		});
    	} catch (error) {
    		throw new TursoApiError(
    			`Failed to execute query for database ${database_name}: ${
    				(error as Error).message
    			}`,
    			500,
    		);
    	}
    }
  • MCP tool registration for 'execute_query', including input schema reference, safety validation to prevent read-only misuse, database context resolution, delegation to core handler, result formatting, and error handling.
    server.tool(
    	{
    		name: 'execute_query',
    		description: `⚠️ DESTRUCTIVE: Execute SQL that can modify/delete data (INSERT, UPDATE, DELETE, DROP, ALTER). Always confirm with user before destructive operations.`,
    		schema: QuerySchema,
    	},
    	async ({ query, params = {}, database }) => {
    		try {
    			// Validate that this is not a read-only query
    			const normalized_query = query.trim().toLowerCase();
    			if (
    				normalized_query.startsWith('select') ||
    				normalized_query.startsWith('pragma')
    			) {
    				throw new Error(
    					'SELECT and PRAGMA queries should use execute_read_only_query',
    				);
    			}
    
    			const database_name = resolve_database_name(database);
    			if (database) set_current_database(database);
    
    			const result = await database_client.execute_query(
    				database_name,
    				query,
    				params,
    			);
    
    			const formatted_result = format_query_result(result);
    			return create_tool_response({
    				database: database_name,
    				query,
    				result: formatted_result,
    			});
    		} catch (error) {
    			return create_tool_error_response(error);
    		}
    	},
    );
  • Zod input schema validation for the execute_query tool parameters.
    const QuerySchema = z.object({
    	query: z.string().describe('SQL query to execute'),
    	params: z.record(z.string(), z.any()).optional().describe('Query parameters (optional) - Use parameterized queries for security'),
    	database: z.string().optional().describe('Database name (optional, uses context if not provided)'),
    });
  • Utility to convert input parameters to libsql client expected format (named object or positional array).
    function convert_parameters(params: Record<string, any>): any {
    	if (!params || Object.keys(params).length === 0) {
    		return {};
    	}
    
    	// Check if parameters are positional (numbered keys like "1", "2", etc.)
    	const keys = Object.keys(params);
    	const is_positional = keys.every((key) => /^\d+$/.test(key));
    
    	if (is_positional) {
    		// Convert to array for positional parameters
    		const max_index = Math.max(...keys.map((k) => parseInt(k)));
    		const param_array: any[] = new Array(max_index);
    
    		for (const [key, value] of Object.entries(params)) {
    			const index = parseInt(key) - 1; // Convert 1-based to 0-based indexing
    			param_array[index] = value;
    		}
    
    		return param_array;
    	}
    
    	// Return as-is for named parameters
    	return params;
    }
  • Formats the libsql ResultSet for JSON-safe tool response, converting BigInt to string.
    function format_query_result(result: ResultSet): any {
    	// Convert BigInt to string to avoid serialization issues
    	const lastInsertRowid =
    		result.lastInsertRowid !== null &&
    		typeof result.lastInsertRowid === 'bigint'
    			? result.lastInsertRowid.toString()
    			: result.lastInsertRowid;
    
    	return {
    		rows: result.rows,
    		rowsAffected: result.rowsAffected,
    		lastInsertRowid: lastInsertRowid,
    		columns: result.columns,
    	};
    }
Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/spences10/mcp-turso-cloud'

If you have feedback or need assistance with the MCP directory API, please join our Discord server