execute_query_and_wait
Execute SQL queries on Redash data sources and retrieve results by specifying query text, data source ID, and optional cache settings.
Instructions
Execute a SQL query and wait for the result
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | The SQL query to execute | |
| data_source_id | Yes | The ID of the data source to query | |
| max_age | No | Maximum age of cached results in seconds |
Implementation Reference
- src/tools/query.ts:36-91 (handler)Handler function implementing the tool logic: validates query and data_source_id, optionally includes max_age, calls Redash client's executeQueryAndWait, returns JSON result or error.handler: async (args, client) => { try { const { query, data_source_id, max_age } = args; if (typeof query !== 'string') { return { content: [ { type: 'text', text: 'Error: query is required and must be a string', } as TextContent, ], isError: true, }; } if (typeof data_source_id !== 'number') { return { content: [ { type: 'text', text: 'Error: data_source_id is required and must be a number', } as TextContent, ], isError: true, }; } const request = { query, data_source_id, ...(typeof max_age === 'number' ? { max_age } : {}), }; const result = await client.executeQueryAndWait(request); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), } as TextContent, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error executing query: ${error instanceof Error ? error.message : String(error)}`, } as TextContent, ], isError: true, }; } },
- src/tools/query.ts:14-35 (schema)Input schema for the tool defining required 'query' (string) and 'data_source_id' (number), optional 'max_age' (number).inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'The SQL query to execute', minLength: 1, }, data_source_id: { type: 'number', description: 'The ID of the data source to query', minimum: 1, }, max_age: { type: 'number', description: 'Maximum age of cached results in seconds', minimum: 0, }, }, required: ['query', 'data_source_id'], additionalProperties: false, },
- src/index.ts:58-60 (registration)Registration of the executeQueryAndWaitTool in the main tools array used by MCP server's list_tools and call_tool handlers.*/ const tools = [listDataSourcesTool, getDataSourceTool, executeQueryAndWaitTool, listQueriesTool];
- src/redash-client.ts:152-199 (helper)Supporting method in RedashClient that executes the query via API, handles cached results or polls job status until completion or failure/timeout, used by the tool handler.async executeQueryAndWait( request: QueryExecutionRequest, pollInterval = 1000, maxAttempts = 60 ): Promise<QueryResult> { // Execute query const response = await this.executeQuery(request); // Check if we got a cached result directly if ('query_result' in response) { return (response as unknown as { query_result: QueryResult }).query_result; } // Otherwise, poll for job completion const { job } = response; if (!job) { throw new Error('Invalid response: neither job nor query_result found'); } // Poll for completion let attempts = 0; while (attempts < maxAttempts) { const { job: currentJob } = await this.getJob(job.id); // Status: 3 = success if (currentJob.status === 3) { if (!currentJob.query_result_id) { throw new Error('Query completed but no result ID found'); } return this.getQueryResult(currentJob.query_result_id); } // Status: 4 = failure if (currentJob.status === 4) { const error: RedashApiError = { message: currentJob.error ?? 'Query execution failed', job: currentJob, }; throw error; } // Wait before polling again await new Promise((resolve) => setTimeout(resolve, pollInterval)); attempts++; } throw new Error(`Query execution timeout after ${maxAttempts} attempts`); }