Skip to main content
Glama
by MikelA92
cardHandlers.js•6.38 kB
import { Validators } from '../../shared/utils/validators.js'; import { logger } from '../../shared/utils/logger.js'; /** * Handlers for card-related operations */ export class CardHandlers { constructor(apiClient) { this.apiClient = apiClient; this.logger = logger.child('CardHandlers'); } /** * Get a card by ID */ async getCard(cardId) { Validators.validateCardId(cardId); this.logger.debug('Getting card', { cardId }); const card = await this.apiClient.makeRequest(`/api/card/${cardId}`); const sqlQuery = card.dataset_query?.native?.query || 'No native SQL query found'; const queryBuilder = card.dataset_query?.query ? JSON.stringify(card.dataset_query.query, null, 2) : null; const cardInfo = { id: card.id, name: card.name, description: card.description, sqlQuery: sqlQuery, databaseId: card.dataset_query?.database, queryType: card.dataset_query?.type, createdAt: card.created_at, updatedAt: card.updated_at, }; let queryDetails = ''; if (card.dataset_query?.type === 'native') { queryDetails = `SQL Query:\n${sqlQuery}`; } else if (card.dataset_query?.type === 'query' && queryBuilder) { queryDetails = `Query Builder Structure:\n${queryBuilder}`; } else { queryDetails = 'No query information available'; } return { content: [ { type: 'text', text: `Card Information: ID: ${cardInfo.id} Name: ${cardInfo.name} Description: ${cardInfo.description || 'No description'} Database ID: ${cardInfo.databaseId} Query Type: ${cardInfo.queryType} Created: ${cardInfo.createdAt} Updated: ${cardInfo.updatedAt} ${queryDetails}`, }, ], }; } /** * List cards with optional filtering */ async listCards(filter = 'all', modelId = null) { this.logger.debug('Listing cards', { filter, modelId }); const params = new URLSearchParams({ f: filter }); if (modelId) { params.append('model_id', modelId); } const response = await this.apiClient.makeRequest(`/api/card/?${params}`); const cards = Array.isArray(response) ? response : response.data || []; const cardList = cards.map(card => ({ id: card.id, name: card.name, description: card.description, databaseId: card.dataset_query?.database, queryType: card.dataset_query?.type, createdAt: card.created_at, })); return { content: [ { type: 'text', text: `Found ${cardList.length} cards (filter: ${filter}): ${cardList.slice(0, 50).map(card => `- ID: ${card.id} | Name: ${card.name} | DB: ${card.databaseId} | Type: ${card.queryType}` ).join('\n')}${cardList.length > 50 ? `\n... and ${cardList.length - 50} more cards` : ''}`, }, ], }; } /** * Execute a card query */ async executeCardQuery(cardId, parameters = {}) { Validators.validateCardId(cardId); this.logger.debug('Executing card query', { cardId, parameters }); const queryParams = new URLSearchParams(); Object.entries(parameters).forEach(([key, value]) => { queryParams.append(key, value); }); const results = await this.apiClient.makeRequest(`/api/card/${cardId}/query?${queryParams}`, { method: 'POST', }); return { content: [ { type: 'text', text: `Query Results for Card ${cardId}: ${JSON.stringify(results, null, 2)}`, }, ], }; } /** * Execute a query builder card with specific parameters */ async executeQueryBuilderCard(cardId, parameters) { Validators.validateCardId(cardId); this.logger.debug('Executing query builder card', { cardId, parameters }); // First, get the base card to understand its structure const baseCard = await this.apiClient.makeRequest(`/api/card/${cardId}`); if (baseCard.dataset_query.type !== 'query') { throw new Error('Card is not a query-builder card'); } // Create a modified dataset query with the provided parameters const modifiedQuery = { ...baseCard.dataset_query, query: { ...baseCard.dataset_query.query, ...parameters, }, }; // Execute the query using the dataset endpoint const body = { database: baseCard.dataset_query.database, type: 'query', query: modifiedQuery.query, }; const results = await this.apiClient.makeRequest('/api/dataset', { method: 'POST', body: JSON.stringify(body), }); return { content: [ { type: 'text', text: `Query Builder Card Execution Results: Card ID: ${cardId} Parameters Applied: ${JSON.stringify(parameters, null, 2)} Results: ${JSON.stringify(results, null, 2)}`, }, ], }; } /** * Get generated SQL for a query builder card with parameters */ async getGeneratedSQL(cardId, parameters) { Validators.validateCardId(cardId); this.logger.debug('Getting generated SQL', { cardId, parameters }); // Get the base card const baseCard = await this.apiClient.makeRequest(`/api/card/${cardId}`); if (baseCard.dataset_query.type !== 'query') { throw new Error('Card is not a query-builder card'); } // Create a modified dataset query with the provided parameters const modifiedQuery = { ...baseCard.dataset_query, query: { ...baseCard.dataset_query.query, ...parameters, }, }; // Use the query endpoint to get the generated SQL const body = { database: baseCard.dataset_query.database, type: 'query', query: modifiedQuery.query, }; const results = await this.apiClient.makeRequest('/api/dataset', { method: 'POST', body: JSON.stringify(body), }); // Extract SQL if available const sql = results.query || results.native?.query || 'SQL not available in response'; return { content: [ { type: 'text', text: `Generated SQL for Query Builder Card: Card ID: ${cardId} Card Name: ${baseCard.name} Parameters Applied: ${JSON.stringify(parameters, null, 2)} Generated SQL: ${sql} Full Query Response: ${JSON.stringify(results, null, 2)}`, }, ], }; } }

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/MikelA92/metabase-mcp-mab'

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