Files
supabase/apps/studio/lib/api/self-hosted/mcp.ts

165 lines
4.1 KiB
TypeScript

import {
ApiKey,
ApiKeyType,
ApplyMigrationOptions,
DatabaseOperations,
DebuggingOperations,
DevelopmentOperations,
ExecuteSqlOptions,
GetLogsOptions,
} from '@supabase/mcp-server-supabase/platform'
import { DEFAULT_EXPOSED_SCHEMAS } from './constants'
import { generateTypescriptTypes } from './generate-types'
import { getLints } from './lints'
import { getLogQuery, retrieveAnalyticsData } from './logs'
import { applyAndTrackMigrations, listMigrationVersions } from './migrations'
import { executeQuery } from './query'
import { getProjectSettings } from './settings'
import { ResponseError } from '@/types'
export type GetDatabaseOperationsOptions = {
headers?: HeadersInit
}
export type GetDevelopmentOperationsOptions = {
headers?: HeadersInit
}
export type GetDebuggingOperationsOptions = {
headers?: HeadersInit
}
export function getDatabaseOperations({
headers,
}: GetDatabaseOperationsOptions): DatabaseOperations {
return {
async executeSql<T>(_projectRef: string, options: ExecuteSqlOptions) {
const { query, parameters, read_only: readOnly } = options
const { data, error } = await executeQuery<T>({ query, parameters, headers, readOnly })
if (error) {
throw error
}
return data
},
async listMigrations() {
const { data, error } = await listMigrationVersions({ headers })
if (error) {
throw error
}
return data
},
async applyMigration(_projectRef: string, options: ApplyMigrationOptions) {
const { query, name } = options
const { error } = await applyAndTrackMigrations({ query, name, headers })
if (error) {
throw error
}
},
}
}
export function getDevelopmentOperations({
headers,
}: GetDevelopmentOperationsOptions): DevelopmentOperations {
return {
async getProjectUrl(_projectRef) {
const settings = getProjectSettings()
return `${settings.app_config.protocol}://${settings.app_config.endpoint}`
},
async getPublishableKeys(_projectRef) {
if (process.env.SUPABASE_PUBLISHABLE_KEY) {
const publishableKeysArray: ApiKey[] = [
{
api_key: process.env.SUPABASE_PUBLISHABLE_KEY,
name: 'publishable',
type: 'publishable' as ApiKeyType,
},
]
return publishableKeysArray
}
const settings = getProjectSettings()
const anonKey = settings.service_api_keys.find((key) => key.name === 'anon key')
if (!anonKey) {
throw new Error('Anon key not found in project settings')
}
const publishableKeysArray: ApiKey[] = [
{
api_key: anonKey.api_key,
name: anonKey.name,
type: 'legacy' as ApiKeyType,
},
]
return publishableKeysArray
},
async generateTypescriptTypes(_projectRef) {
const response = await generateTypescriptTypes({ headers })
if (response instanceof ResponseError) {
throw response
}
return response
},
}
}
export function getDebuggingOperations({
headers,
}: GetDebuggingOperationsOptions): DebuggingOperations {
return {
async getLogs(projectRef: string, options: GetLogsOptions) {
const sql = getLogQuery(options.service)
const { data, error } = await retrieveAnalyticsData({
name: 'logs.all',
projectRef,
params: {
sql,
iso_timestamp_start: options.iso_timestamp_start,
iso_timestamp_end: options.iso_timestamp_end,
},
})
if (error) {
throw error
}
return data
},
async getSecurityAdvisors(_projectRef) {
const { data, error } = await getLints({
headers,
exposedSchemas: DEFAULT_EXPOSED_SCHEMAS,
})
if (error) {
throw error
}
return data.filter((lint) => lint.categories.includes('SECURITY'))
},
async getPerformanceAdvisors(_projectRef) {
const { data, error } = await getLints({
headers,
exposedSchemas: DEFAULT_EXPOSED_SCHEMAS,
})
if (error) {
throw error
}
return data.filter((lint) => lint.categories.includes('PERFORMANCE'))
},
}
}