Skip to main content
Glama

mcp-metabase-server P

by easecloudio
metabase-client.ts10.1 kB
/** * Metabase API Client * Handles all API interactions with Metabase */ import axios, { AxiosInstance } from "axios"; import { ErrorCode, McpError } from "../types/errors.js"; import { MetabaseConfig, Dashboard, Card, Database, Collection, User, Table, Field, PermissionGroup, QueryResult, } from "../types/metabase.js"; export class MetabaseClient { private axiosInstance: AxiosInstance; private sessionToken: string | null = null; private config: MetabaseConfig; constructor(config: MetabaseConfig) { this.config = config; this.axiosInstance = axios.create({ baseURL: config.url, headers: { "Content-Type": "application/json", }, }); if (config.apiKey) { this.logInfo("Using Metabase API Key for authentication."); this.axiosInstance.defaults.headers.common["X-API-Key"] = config.apiKey; this.sessionToken = "api_key_used"; } else if (config.username && config.password) { this.logInfo("Using Metabase username/password for authentication."); } else { this.logError( "Metabase authentication credentials not configured properly.", {} ); throw new Error( "Metabase authentication credentials not provided or incomplete." ); } } private logInfo(message: string, data?: unknown) { const logMessage = { timestamp: new Date().toISOString(), level: "info", message, data, }; console.error(JSON.stringify(logMessage)); console.error(`INFO: ${message}`); } private logError(message: string, error: unknown) { const errorObj = error as Error; const logMessage = { timestamp: new Date().toISOString(), level: "error", message, error: errorObj.message || "Unknown error", stack: errorObj.stack, }; console.error(JSON.stringify(logMessage)); console.error(`ERROR: ${message} - ${errorObj.message || "Unknown error"}`); } /** * Get Metabase session token for username/password authentication */ private async getSessionToken(): Promise<string> { if (this.sessionToken) { return this.sessionToken; } this.logInfo("Authenticating with Metabase using username/password..."); try { const response = await this.axiosInstance.post("/api/session", { username: this.config.username, password: this.config.password, }); this.sessionToken = response.data.id; // Set default request headers this.axiosInstance.defaults.headers.common["X-Metabase-Session"] = this.sessionToken; this.logInfo("Successfully authenticated with Metabase"); return this.sessionToken as string; } catch (error) { this.logError("Authentication failed", error); throw new McpError( ErrorCode.InternalError, "Failed to authenticate with Metabase" ); } } /** * Ensure authentication is ready */ private async ensureAuthenticated(): Promise<void> { if (!this.config.apiKey) { await this.getSessionToken(); } } // Dashboard operations async getDashboards(): Promise<Dashboard[]> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get("/api/dashboard"); return response.data; } async getDashboard(id: number): Promise<Dashboard> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get(`/api/dashboard/${id}`); return response.data; } async createDashboard(dashboard: Partial<Dashboard>): Promise<Dashboard> { await this.ensureAuthenticated(); const response = await this.axiosInstance.post("/api/dashboard", dashboard); return response.data; } async updateDashboard( id: number, updates: Partial<Dashboard> ): Promise<Dashboard> { await this.ensureAuthenticated(); const response = await this.axiosInstance.put( `/api/dashboard/${id}`, updates ); return response.data; } async deleteDashboard( id: number, hardDelete: boolean = false ): Promise<void> { await this.ensureAuthenticated(); if (hardDelete) { await this.axiosInstance.delete(`/api/dashboard/${id}`); } else { await this.axiosInstance.put(`/api/dashboard/${id}`, { archived: true }); } } // Card operations async getCards(): Promise<Card[]> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get("/api/card"); return response.data; } async getCard(id: number): Promise<Card> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get(`/api/card/${id}`); return response.data; } async createCard(card: Partial<Card>): Promise<Card> { await this.ensureAuthenticated(); const response = await this.axiosInstance.post("/api/card", card); return response.data; } async updateCard(id: number, updates: Partial<Card>): Promise<Card> { await this.ensureAuthenticated(); const response = await this.axiosInstance.put(`/api/card/${id}`, updates); return response.data; } async deleteCard(id: number, hardDelete: boolean = false): Promise<void> { await this.ensureAuthenticated(); if (hardDelete) { await this.axiosInstance.delete(`/api/card/${id}`); } else { await this.axiosInstance.put(`/api/card/${id}`, { archived: true }); } } async executeCard(id: number, parameters: any = {}): Promise<QueryResult> { await this.ensureAuthenticated(); const response = await this.axiosInstance.post(`/api/card/${id}/query`, { parameters, }); return response.data; } // Database operations async getDatabases(): Promise<Database[]> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get("/api/database"); return response.data; } async getDatabase(id: number): Promise<Database> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get(`/api/database/${id}`); return response.data; } async executeQuery( databaseId: number, query: string, parameters: any[] = [] ): Promise<QueryResult> { await this.ensureAuthenticated(); const queryData = { type: "native", native: { query: query, template_tags: {}, }, parameters: parameters, database: databaseId, }; const response = await this.axiosInstance.post("/api/dataset", queryData); return response.data; } // Collection operations async getCollections(archived: boolean = false): Promise<Collection[]> { await this.ensureAuthenticated(); const params = archived ? { archived: true } : {}; const response = await this.axiosInstance.get("/api/collection", { params, }); return response.data; } async getCollection(id: number): Promise<Collection> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get(`/api/collection/${id}`); return response.data; } async createCollection(collection: Partial<Collection>): Promise<Collection> { await this.ensureAuthenticated(); const response = await this.axiosInstance.post( "/api/collection", collection ); return response.data; } async updateCollection( id: number, updates: Partial<Collection> ): Promise<Collection> { await this.ensureAuthenticated(); const response = await this.axiosInstance.put( `/api/collection/${id}`, updates ); return response.data; } async deleteCollection(id: number): Promise<void> { await this.ensureAuthenticated(); await this.axiosInstance.delete(`/api/collection/${id}`); } // User operations async getUsers(includeDeactivated: boolean = false): Promise<User[]> { await this.ensureAuthenticated(); const params = includeDeactivated ? { include_deactivated: true } : {}; const response = await this.axiosInstance.get("/api/user", { params }); return response.data; } async getUser(id: number): Promise<User> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get(`/api/user/${id}`); return response.data; } async createUser(user: Partial<User>): Promise<User> { await this.ensureAuthenticated(); const response = await this.axiosInstance.post("/api/user", user); return response.data; } async updateUser(id: number, updates: Partial<User>): Promise<User> { await this.ensureAuthenticated(); const response = await this.axiosInstance.put(`/api/user/${id}`, updates); return response.data; } async deleteUser(id: number): Promise<void> { await this.ensureAuthenticated(); await this.axiosInstance.delete(`/api/user/${id}`); } // Permission operations async getPermissionGroups(): Promise<PermissionGroup[]> { await this.ensureAuthenticated(); const response = await this.axiosInstance.get("/api/permissions/group"); return response.data; } async createPermissionGroup(name: string): Promise<PermissionGroup> { await this.ensureAuthenticated(); const response = await this.axiosInstance.post("/api/permissions/group", { name, }); return response.data; } async updatePermissionGroup( id: number, name: string ): Promise<PermissionGroup> { await this.ensureAuthenticated(); const response = await this.axiosInstance.put( `/api/permissions/group/${id}`, { name } ); return response.data; } async deletePermissionGroup(id: number): Promise<void> { await this.ensureAuthenticated(); await this.axiosInstance.delete(`/api/permissions/group/${id}`); } // Generic API method for other operations async apiCall( method: "GET" | "POST" | "PUT" | "DELETE", endpoint: string, data?: any ): Promise<any> { await this.ensureAuthenticated(); const response = await this.axiosInstance.request({ method, url: endpoint, data, }); return response.data; } }

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/easecloudio/mcp-metabase-server'

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