Skip to main content
Glama
jasonsmithj

Redash MCP Server

by jasonsmithj

execute_query_and_wait

Execute SQL queries on Redash data sources and wait for results, supporting cached results with configurable maximum age.

Instructions

Execute a SQL query and wait for the result

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesThe SQL query to execute
data_source_idYesThe ID of the data source to query
max_ageNoMaximum age of cached results in seconds

Implementation Reference

  • Handler function that validates input parameters, constructs the query execution request, calls the Redash client's executeQueryAndWait method, and returns the result as formatted JSON or an error message.
    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,
        };
      }
    },
  • Input schema defining the parameters for the tool: 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:59-59 (registration)
    Registration of the executeQueryAndWaitTool in the central tools array used for list_tools and call_tool request handling.
    const tools = [listDataSourcesTool, getDataSourceTool, executeQueryAndWaitTool, listQueriesTool];
  • src/index.ts:17-17 (registration)
    Import statement bringing the executeQueryAndWaitTool into the main index file for registration.
    import { executeQueryAndWaitTool, listQueriesTool } from './tools/query.js';
  • Supporting method in RedashClient that executes the query via API, handles cached results or polls the job status until completion or failure/timeout.
    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`);
    }

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/jasonsmithj/redash-mcp'

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