Skip to main content
Glama

MCP Firebird

database.ts6.93 kB
// src/resources/database.ts import { z } from 'zod'; import { createLogger } from '../utils/logger.js'; import { listTables, describeTable, executeQuery } from '../db/queries.js'; import { getTableSchema } from '../db/schema.js'; const logger = createLogger('database'); // Provide string argument /** * Interfaz para definir un Recurso MCP. */ export interface ResourceDefinition { title?: string; // Título del recurso description: string; // Descripción del recurso mimeType?: string; // Tipo MIME del contenido handler: (params: Record<string, string>) => Promise<object>; // Handler recibe parámetros de la URI } /** * Configura los recursos relacionados con la base de datos y devuelve un mapa de definiciones. * @returns {Map<string, ResourceDefinition>} Mapa con las definiciones de recursos (clave puede ser nombre o URI template). */ export const setupDatabaseResources = (): Map<string, ResourceDefinition> => { const resources = new Map<string, ResourceDefinition>(); // --- Definición del Recurso: Lista de Tablas --- (URI: /tables) const listTablesResource: ResourceDefinition = { description: "Recurso que representa la lista de todas las tablas en la base de datos.", handler: async () => { logger.info("Accediendo al recurso /tables"); try { const tables = await listTables(); return { tables }; } catch (error: any) { logger.error(`Error al obtener la lista de tablas para el recurso /tables: ${error.message || error}`); return { contents: [], error: "Error interno al listar tablas", details: error.message || String(error) }; } } }; resources.set("/tables", listTablesResource); // Usar URI como clave // --- Definición del Recurso: Esquema de Tabla --- (URI: /tables/{tableName}/schema) const tableSchemaResource: ResourceDefinition = { description: "Recurso que representa el esquema de una tabla específica.", handler: async (params) => { const tableName = params.tableName; if (!tableName) { logger.warn("Intento de acceso a /tables/{tableName}/schema sin tableName"); return { contents: [], error: "Falta el nombre de la tabla en la URI" }; } logger.info(`Accediendo al recurso /tables/${tableName}/schema`); try { const schema = await getTableSchema(tableName); return schema; } catch (error: any) { logger.error(`Error al obtener el esquema para el recurso /tables/${tableName}/schema: ${error.message || error}`); return { contents: [], error: `Error interno al obtener esquema para ${tableName}`, details: error.message || String(error) }; } } }; // La clave podría ser la plantilla URI para que el handler en index.ts pueda hacer matching resources.set("/tables/{tableName}/schema", tableSchemaResource); // --- Definición del Recurso: Descripción de Tabla (describeTable) --- (URI: /tables/{tableName}/description) const tableDescriptionResource: ResourceDefinition = { description: "Recurso que representa la descripción detallada (columnas, tipos, etc.) de una tabla específica.", handler: async (params) => { const tableName = params.tableName; if (!tableName) { logger.warn("Intento de acceso a /tables/{tableName}/description sin tableName"); return { contents: [], error: "Falta el nombre de la tabla en la URI" }; } logger.info(`Accediendo al recurso /tables/${tableName}/description`); try { // Asumiendo que describeTable devuelve un objeto adecuado const description = await describeTable(tableName); return description; } catch (error: any) { logger.error(`Error al obtener la descripción para el recurso /tables/${tableName}/description: ${error.message || error}`); return { contents: [], error: `Error interno al obtener descripción para ${tableName}`, details: error.message || String(error) }; } } }; resources.set("/tables/{tableName}/description", tableDescriptionResource); // --- Definición del Recurso: Datos de Tabla (con paginación simple) --- (URI: /tables/{tableName}/data?first=N&skip=M) // Nota: Esto es un ejemplo simple, la paginación real puede ser más compleja. const tableDataResource: ResourceDefinition = { description: "Recurso que representa los datos de una tabla, con paginación básica (FIRST/SKIP).", handler: async (params) => { const tableName = params.tableName; const first = params.first ? parseInt(params.first, 10) : undefined; const skip = params.skip ? parseInt(params.skip, 10) : 0; // Default skip to 0 if (!tableName) { logger.warn("Intento de acceso a /tables/{tableName}/data sin tableName"); return { contents: [], error: "Falta el nombre de la tabla en la URI" }; } if (params.first && (isNaN(first as number) || (first as number) <= 0)) { return { contents: [], error: "Parámetro 'first' debe ser un número positivo" }; } if (params.skip && (isNaN(skip as number) || (skip as number) < 0)) { return { contents: [], error: "Parámetro 'skip' debe ser un número no negativo" }; } logger.info(`Accediendo al recurso /tables/${tableName}/data (first: ${first}, skip: ${skip})`); try { // Construir la consulta base let sql = `SELECT * FROM "${tableName}"`; // Asegurar comillas por si acaso // Firebird usa FIRST y SKIP if (first !== undefined) { sql += ` FIRST ${first}`; } if (skip > 0) { sql += ` SKIP ${skip}`; } const results = await executeQuery(sql); return { data: results }; } catch (error: any) { logger.error(`Error al obtener datos para el recurso /tables/${tableName}/data: ${error.message || error}`); return { contents: [], error: `Error interno al obtener datos para ${tableName}`, details: error.message || String(error) }; } } }; // URI puede incluir placeholders para query params, pero el matching debe hacerse en el handler de index.ts resources.set("/tables/{tableName}/data", tableDataResource); // Clave base sin query params // Añadir más recursos aquí... logger.info(`Definidos ${resources.size} recursos de base de datos.`); return resources; };

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/PuroDelphi/mcpFirebird'

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