Skip to main content
Glama
index.ts10.3 kB
#!/usr/bin/env node import { ConfigManager } from './manager.js'; import { ConnectionManager } from './connection-manager.js'; import { NLPService } from './nlp-service.js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; // 读取 package.json const __dirname = path.dirname(fileURLToPath(import.meta.url)); const packageJsonPath = path.resolve(__dirname, '../package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); const configManager = new ConfigManager(); const connectionManager = new ConnectionManager(); const config = configManager.getConfig(); const nlpService = new NLPService(config.environment.openaiApiKey); const server = new McpServer({ name: 'mcp-server-database-search', version: packageJson.version, }); server.tool( 'query_database', '使用自然语言查询数据库', { query: z.string().describe('自然语言查询描述'), database_id: z.string().optional().describe('数据库连接ID,不指定则使用默认数据库'), target_database: z.string().optional().describe('目标数据库名称,用于查询特定数据库'), raw_sql: z.boolean().optional().default(false).describe('是否直接执行SQL语句'), }, async ({ query, database_id, target_database, raw_sql }) => { try { const dbConfig = database_id ? configManager.getDatabaseConfig(database_id) : configManager.getDefaultDatabaseConfig(); if (!dbConfig) { throw new Error(`数据库连接配置不存在:${database_id}`); } const connection = await connectionManager.getConnection(dbConfig); if (target_database) { await connection.switchDatabase(target_database); } let sql: string; let results: any; // 若给定了执行的SQL语句,则直接执行 if (raw_sql) { sql = query; results = await connection.query(sql); } else { // 获取表结构用于AI转换 const tableStructure = await getTableStructure(connection, dbConfig.type); // 转换自然语言为SQL sql = await nlpService.convertToSQL(query, tableStructure, dbConfig.type); // 执行查询 results = await connection.query(sql); } // 限制结果数量 if (Array.isArray(results) && results.length > config.environment.maxQueryResults) { results = results.slice(0, config.environment.maxQueryResults); } return { content: [ { type: 'text', text: JSON.stringify( { database: dbConfig.name, target_database: target_database || dbConfig.database, sql: sql, results: results, total_rows: Array.isArray(results) ? results.length : 1, message: Array.isArray(results) && results.length === config.environment.maxQueryResults ? `结果已限制为${config.environment.maxQueryResults}条` : undefined, }, null, 2 ), }, ], }; } catch (error) { throw new Error(`查询失败: ${error instanceof Error ? error.message : '未知错误'}`); } } ); // 列出数据库工具 server.tool( 'list_databases', '列出可用的数据库连接和数据库', { database_id: z.string().optional().describe('数据库连接ID,不指定则返回所有连接'), }, async ({ database_id }) => { try { if (database_id) { const dbConfig = configManager.getDatabaseConfig(database_id); if (!dbConfig) { throw new Error(`数据库连接未找到: ${database_id}`); } const connection = await connectionManager.getConnection(dbConfig); const databases = await connection.getDatabases(); return { content: [ { type: 'text', text: JSON.stringify( { connection: { id: dbConfig.id, name: dbConfig.name, type: dbConfig.type, current_database: dbConfig.database, }, available_databases: databases, }, null, 2 ), }, ], }; } else { const allConnections = configManager.getAllDatabases(); const result = []; for (const dbConfig of allConnections) { try { const connection = await connectionManager.getConnection(dbConfig); const databases = await connection.getDatabases(); result.push({ connection: { id: dbConfig.id, name: dbConfig.name, type: dbConfig.type, current_database: dbConfig.database, }, available_databases: databases, }); } catch (error) { result.push({ connection: { id: dbConfig.id, name: dbConfig.name, type: dbConfig.type, current_database: dbConfig.database, }, error: `连接失败: ${error instanceof Error ? error.message : '未知错误'}`, }); } } return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } } catch (error) { throw new Error(`列出数据库失败: ${error instanceof Error ? error.message : '未知错误'}`); } } ); // 获取表结构工具 server.tool( 'get_table_structure', '获取表结构信息', { database_id: z.string().optional().describe('数据库连接ID'), target_database: z.string().optional().describe('目标数据库名称'), table_name: z.string().optional().describe('表名,不指定则返回所有表结构'), }, async ({ database_id, target_database, table_name }) => { try { const dbConfig = database_id ? configManager.getDatabaseConfig(database_id) : configManager.getDefaultDatabaseConfig(); if (!dbConfig) { throw new Error(`数据库连接未找到: ${database_id}`); } const connection = await connectionManager.getConnection(dbConfig); if (target_database) { await connection.switchDatabase(target_database); } const structure = await getTableStructure(connection, dbConfig.type, table_name); return { content: [ { type: 'text', text: JSON.stringify( { database: dbConfig.name, target_database: target_database || dbConfig.database, structure: structure, }, null, 2 ), }, ], }; } catch (error) { throw new Error(`获取表结构失败: ${error instanceof Error ? error.message : '未知错误'}`); } } ); // 执行SQL工具 server.tool( 'execute_sql', '直接执行SQL查询', { sql: z.string().describe('要执行的SQL语句'), database_id: z.string().optional().describe('数据库连接ID'), target_database: z.string().optional().describe('目标数据库名称'), }, async ({ sql, database_id, target_database }) => { try { const dbConfig = database_id ? configManager.getDatabaseConfig(database_id) : configManager.getDefaultDatabaseConfig(); if (!dbConfig) { throw new Error(`数据库连接未找到: ${database_id}`); } const connection = await connectionManager.getConnection(dbConfig); if (target_database) { await connection.switchDatabase(target_database); } const results = await connection.query(sql); return { content: [ { type: 'text', text: JSON.stringify( { database: dbConfig.name, target_database: target_database || dbConfig.database, sql: sql, results: results, }, null, 2 ), }, ], }; } catch (error) { throw new Error(`执行SQL失败: ${error instanceof Error ? error.message : '未知错误'}`); } } ); // 辅助函数:获取表结构 async function getTableStructure(connection: any, dbType: string, tableName?: string) { let sql: string; switch (dbType) { case 'mysql': sql = tableName ? `DESCRIBE \`${tableName}\`` : 'SHOW TABLES'; break; case 'postgresql': sql = tableName ? `SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = '${tableName}'` : `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'`; break; case 'sqlite': sql = tableName ? `PRAGMA table_info(${tableName})` : `SELECT name FROM sqlite_master WHERE type='table'`; break; default: throw new Error(`不支持的数据库类型: ${dbType}`); } return await connection.query(sql); } // 启动服务器 async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); // 监听进程退出,清理连接 process.on('SIGINT', async () => { console.error('收到SIGINT信号,正在关闭连接...'); await connectionManager.closeAll(); process.exit(0); }); process.on('SIGTERM', async () => { console.error('收到SIGTERM信号,正在关闭连接...'); await connectionManager.closeAll(); process.exit(0); }); console.error( `数据库搜索MCP服务器已在stdio上启动 (环境: ${process.env.NODE_ENV || 'development'})` ); } runServer().catch((error) => { console.error('启动服务器时出错:', error); process.exit(1); });

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/CH-122/mcp-server'

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