MCP-Turso

by nbbaier
Verified
  • src
#!/usr/bin/env node import { type Client, createClient } from "@libsql/client"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import createLogger from "./logger.js"; import { content, dbSchema, describeTable, getLogFile, listTables, query, } from "./utils.js"; const server = new McpServer({ name: "Turso MCP Server", version: "0.1.0", }); const dbUrl = process.env.TURSO_DATABASE_URL; const authToken = process.env.TURSO_AUTH_TOKEN; const logFile = getLogFile(); const logger = createLogger(logFile); if (!dbUrl) { logger.error("TURSO_DATABASE_URL environment variable is required"); process.exit(1); } if (!authToken) { logger.error("TURSO_AUTH_TOKEN environment variable is required"); process.exit(1); } let db: Client; try { db = createClient({ url: dbUrl, authToken }); logger.info("Successfully connected to Turso database"); } catch (error) { logger.error("Failed to connect to Turso database", error); process.exit(1); } /** * MCP tool handler that lists all tables in the Turso database. */ server.tool("list_tables", "List all tables in the database", {}, async () => { try { logger.info("Executing list_tables"); const tables = await listTables(db); return content(JSON.stringify({ tables }, null, 2)); } catch (error) { logger.error("Failed to list tables", error); return content( `Error listing tables: ${error instanceof Error ? error.message : String(error)}`, true, ); } }); /** * MCP tool handler that retrieves the schema for all tables in the database. */ server.tool( "get_db_schema", "Get the schema for all tables in the database", {}, async () => { try { const schema = await dbSchema(db); return content(JSON.stringify({ schema }, null, 2)); } catch (error) { return content( `Error getting schema: ${error instanceof Error ? error.message : String(error)}`, true, ); } }, ); /** * MCP tool handler that retrieves detailed schema information for a specific table. * * @param table_name - The name of the table to describe */ server.tool( "describe_table", "View schema information for a specific table", { table_name: z .string() .describe("Name of the table to describe") .min(1, "Table name is required"), }, async ({ table_name }) => { try { logger.info(`Executing describe_table for table: ${table_name}`); const schema = await describeTable(table_name, db); return content(JSON.stringify({ schema }, null, 2)); } catch (error) { logger.error(`Failed to describe table ${table_name}`, error); return content( `Error describing table: ${error instanceof Error ? error.message : String(error)}`, true, ); } }, ); /** * MCP tool handler that executes a SELECT query against the database. * * @param sql - The SQL query to execute (must be a SELECT query) */ server.tool( "query", "Execute a SELECT query to read data from the database", { sql: z .string() .describe("SELECT SQL query to execute") .min(1, "SQL query is required"), }, async ({ sql }) => { try { logger.info(`Executing query: ${sql}`); const result = await query(sql, db); return content(JSON.stringify(result, null, 2)); } catch (error) { logger.error("Failed to execute query", error); return content( `Error executing query: ${error instanceof Error ? error.message : String(error)}`, true, ); } }, ); process.on("uncaughtException", (error) => { logger.error("Uncaught exception", error); }); process.on("unhandledRejection", (reason) => { logger.error("Unhandled rejection", reason); }); console.error(`[INFO] Additional logs available at: ${logger.logFile}`); logger.info("Connecting to transport..."); const transport = new StdioServerTransport(); await server.connect(transport); logger.info("Turso MCP server running"); process.on("exit", (code) => { logger.info("Turso MCP server closed", code); });