mcp-turso-cloud
Version:
MCP server for integrating Turso with LLMs
106 lines (105 loc) • 3.64 kB
JavaScript
/**
* 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);
}
}