Skip to main content
Glama
index.ts5.57 kB
import { CallToolRequest } from '@modelcontextprotocol/sdk/types.js'; import { MetabaseApiClient } from '../../api.js'; import { ErrorCode, McpError } from '../../types/core.js'; import { validateCardParameters, validatePositiveInteger, validateEnumValue, } from '../../utils/index.js'; import { exportSqlQuery } from './exportQuery.js'; import { exportCard } from './exportCard.js'; import { ExportRequest, SqlExportParams, CardExportParams, ExportResponse } from './types.js'; export async function handleExport( request: CallToolRequest, requestId: string, apiClient: MetabaseApiClient, logDebug: (message: string, data?: unknown) => void, logInfo: (message: string, data?: unknown) => void, logWarn: (message: string, data?: unknown, error?: Error) => void, logError: (message: string, error: unknown) => void ): Promise<ExportResponse> { const args = request.params?.arguments as ExportRequest; const databaseId = args?.database_id; const query = args?.query; const cardId = args?.card_id; const nativeParameters = Array.isArray(args?.native_parameters) ? args.native_parameters : []; const cardParameters = Array.isArray(args?.card_parameters) ? args.card_parameters : []; const format = validateEnumValue( args?.format || 'csv', ['csv', 'json', 'xlsx'] as const, 'format', requestId, logWarn ); const filename = args?.filename; // Validate that either query+database_id or card_id is provided (but not considering 0 as falsy for this check) if (cardId === undefined && databaseId === undefined) { logWarn('Missing required parameters: either card_id or database_id must be provided', { requestId, }); throw new McpError( ErrorCode.InvalidParams, 'Either card_id or database_id parameter is required' ); } if (cardId !== undefined && databaseId !== undefined) { logWarn('Both card_id and database_id provided - only one is allowed', { requestId }); throw new McpError( ErrorCode.InvalidParams, 'Cannot specify both card_id and database_id - choose one export method' ); } // Validate positive integer parameters if (cardId !== undefined) { validatePositiveInteger(cardId, 'card_id', requestId, logWarn); } if (databaseId !== undefined) { validatePositiveInteger(databaseId, 'database_id', requestId, logWarn); } // Strict parameter validation for card export mode if (cardId !== undefined) { // For card export, only card_id, card_parameters, format, and filename are allowed if (query || databaseId !== undefined || (nativeParameters && nativeParameters.length > 0)) { logWarn('Invalid parameters for card export mode', { requestId, invalidParams: { query: query ? 'provided' : 'not provided', database_id: databaseId ? 'provided' : 'not provided', native_parameters: nativeParameters?.length > 0 ? 'provided' : 'not provided', }, }); throw new McpError( ErrorCode.InvalidParams, 'Card export mode only allows card_id, card_parameters, format, and filename parameters' ); } } // Strict parameter validation for SQL export mode if (databaseId !== undefined) { // For SQL export, only database_id, query, native_parameters, format, and filename are allowed if (cardId !== undefined || (cardParameters && cardParameters.length > 0)) { logWarn('Invalid parameters for SQL export mode', { requestId, invalidParams: { card_id: cardId ? 'provided' : 'not provided', card_parameters: cardParameters?.length > 0 ? 'provided' : 'not provided', }, }); throw new McpError( ErrorCode.InvalidParams, 'SQL export mode only allows database_id, query, native_parameters, format, and filename parameters' ); } } // If exporting a card if (cardId !== undefined) { validatePositiveInteger(cardId, 'card_id', requestId, logWarn); // Validate card parameters format if provided if (cardParameters.length > 0) { try { validateCardParameters(cardParameters, requestId, logWarn); } catch (error) { logWarn(`Card parameter validation failed for card ${cardId}`, { error, requestId }); throw new McpError( ErrorCode.InvalidParams, `Invalid card parameters format. If parameter issues persist, consider using export_query with the card's underlying SQL query instead, which provides more reliable parameter handling. Original error: ${error instanceof Error ? error.message : String(error)}` ); } } const cardParams: CardExportParams = { cardId, cardParameters, format: format as 'csv' | 'json' | 'xlsx', filename, }; return await exportCard(cardParams, requestId, apiClient, logDebug, logInfo, logWarn, logError); } // If exporting a SQL query if (!query || typeof query !== 'string') { logWarn('Missing or invalid query parameter in export request', { requestId }); throw new McpError( ErrorCode.InvalidParams, 'SQL query parameter is required and must be a string' ); } validatePositiveInteger(databaseId, 'database_id', requestId, logWarn); const sqlParams: SqlExportParams = { databaseId: databaseId as number, query, nativeParameters, format: format as 'csv' | 'json' | 'xlsx', filename, }; return await exportSqlQuery( sqlParams, requestId, apiClient, logDebug, logInfo, logWarn, logError ); }

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/jerichosequitin/Metabase'

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