UNPKG

mcp-turso-cloud

Version:

MCP server for integrating Turso with LLMs

106 lines (105 loc) 3.64 kB
/** * Turso Database HTTP API client for database-level operations */ import { createClient } from '@libsql/client'; import { TursoApiError } from '../common/errors.js'; import { get_config } from '../config.js'; import { get_database_token } from './token-manager.js'; // Cache of database clients const client_cache = {}; /** * Get a client for a specific database, creating one if necessary */ export async function get_database_client(database_name, permission = 'full-access') { // Check if we have a cached client const cache_key = `${database_name}:${permission}`; if (client_cache[cache_key]) { return client_cache[cache_key]; } try { // Get a token for the database const token = await get_database_token(database_name, permission); // Get the organization name from config const config = get_config(); const organization = config.TURSO_ORGANIZATION; // Create a new client with the correct hostname format const client = createClient({ url: `https://${database_name}-${organization}.turso.io`, authToken: token, }); // Cache the client client_cache[cache_key] = client; return client; } catch (error) { if (error instanceof TursoApiError) { throw error; } throw new TursoApiError(`Failed to create client for database ${database_name}: ${error.message}`, 500); } } /** * List all tables in a database */ export async function list_tables(database_name) { try { const client = await get_database_client(database_name, 'read-only'); // Query the sqlite_schema table to get all tables const result = await client.execute({ sql: `SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`, }); // Extract table names from the result return result.rows.map((row) => row.name); } catch (error) { throw new TursoApiError(`Failed to list tables for database ${database_name}: ${error.message}`, 500); } } /** * Execute a SQL query against a database */ export async function execute_query(database_name, query, params = {}) { try { // Determine if this is a read-only query const is_read_only = query .trim() .toLowerCase() .startsWith('select'); const permission = is_read_only ? 'read-only' : 'full-access'; const client = await get_database_client(database_name, permission); // Execute the query return await client.execute({ sql: query, args: params, }); } catch (error) { throw new TursoApiError(`Failed to execute query for database ${database_name}: ${error.message}`, 500); } } /** * Get schema information for a table */ export async function describe_table(database_name, table_name) { try { const client = await get_database_client(database_name, 'read-only'); // Query the table info const result = await client.execute({ sql: `PRAGMA table_info(${table_name})`, }); // Return the column definitions return result.rows.map((row) => ({ name: row.name, type: row.type, notnull: row.notnull, dflt_value: row.dflt_value, pk: row.pk, })); } catch (error) { throw new TursoApiError(`Failed to describe table ${table_name} for database ${database_name}: ${error.message}`, 500); } }