mcp.ts157 lines · main
1import {
2 ApiKey,
3 ApiKeyType,
4 ApplyMigrationOptions,
5 DatabaseOperations,
6 DebuggingOperations,
7 DevelopmentOperations,
8 ExecuteSqlOptions,
9 GetLogsOptions,
10} from '@supabase/mcp-server-supabase/platform'
11
12import { DEFAULT_EXPOSED_SCHEMAS } from './constants'
13import { generateTypescriptTypes } from './generate-types'
14import { getLints } from './lints'
15import { getLogQuery, retrieveAnalyticsData } from './logs'
16import { applyAndTrackMigrations, listMigrationVersions } from './migrations'
17import { executeQuery } from './query'
18import { getProjectSettings } from './settings'
19import { ResponseError } from '@/types'
20
21export type GetDatabaseOperationsOptions = {
22 headers?: HeadersInit
23}
24
25export type GetDevelopmentOperationsOptions = {
26 headers?: HeadersInit
27}
28
29export type GetDebuggingOperationsOptions = {
30 headers?: HeadersInit
31}
32
33export function getDatabaseOperations({
34 headers,
35}: GetDatabaseOperationsOptions): DatabaseOperations {
36 return {
37 async executeSql<T>(_projectRef: string, options: ExecuteSqlOptions) {
38 const { query, parameters, read_only: readOnly } = options
39
40 const { data, error } = await executeQuery<T>({ query, parameters, headers, readOnly })
41
42 if (error) {
43 throw error
44 }
45
46 return data
47 },
48 async listMigrations() {
49 const { data, error } = await listMigrationVersions({ headers })
50
51 if (error) {
52 throw error
53 }
54
55 return data
56 },
57 async applyMigration(_projectRef: string, options: ApplyMigrationOptions) {
58 const { query, name } = options
59 const { error } = await applyAndTrackMigrations({ query, name, headers })
60
61 if (error) {
62 throw error
63 }
64 },
65 }
66}
67
68export function getDevelopmentOperations({
69 headers,
70}: GetDevelopmentOperationsOptions): DevelopmentOperations {
71 return {
72 async getProjectUrl(_projectRef) {
73 const settings = getProjectSettings()
74 return `${settings.app_config.protocol}://${settings.app_config.endpoint}`
75 },
76 async getPublishableKeys(_projectRef) {
77 const settings = getProjectSettings()
78 const anonKey = settings.service_api_keys.find((key) => key.name === 'anon key')
79
80 if (!anonKey) {
81 throw new Error('Anon key not found in project settings')
82 }
83
84 // For self-hosted, only the legacy anon key is available and returned here.
85 // There is currently no publishable key variable in self-hosted configuration,
86 // and the migration to new publishable keys requires additional Auth and service setup.
87 const publishableKeysArray: ApiKey[] = [
88 {
89 api_key: anonKey.api_key,
90 name: anonKey.name,
91 type: 'anon' as ApiKeyType,
92 },
93 ]
94
95 return publishableKeysArray
96 },
97 async generateTypescriptTypes(_projectRef) {
98 const response = await generateTypescriptTypes({ headers })
99
100 if (response instanceof ResponseError) {
101 throw response
102 }
103
104 return response
105 },
106 }
107}
108
109export function getDebuggingOperations({
110 headers,
111}: GetDebuggingOperationsOptions): DebuggingOperations {
112 return {
113 async getLogs(projectRef: string, options: GetLogsOptions) {
114 const sql = getLogQuery(options.service)
115
116 const { data, error } = await retrieveAnalyticsData({
117 name: 'logs.all',
118 projectRef,
119 params: {
120 sql,
121 iso_timestamp_start: options.iso_timestamp_start,
122 iso_timestamp_end: options.iso_timestamp_end,
123 },
124 })
125
126 if (error) {
127 throw error
128 }
129
130 return data
131 },
132 async getSecurityAdvisors(_projectRef) {
133 const { data, error } = await getLints({
134 headers,
135 exposedSchemas: DEFAULT_EXPOSED_SCHEMAS,
136 })
137
138 if (error) {
139 throw error
140 }
141
142 return data.filter((lint) => lint.categories.includes('SECURITY'))
143 },
144 async getPerformanceAdvisors(_projectRef) {
145 const { data, error } = await getLints({
146 headers,
147 exposedSchemas: DEFAULT_EXPOSED_SCHEMAS,
148 })
149
150 if (error) {
151 throw error
152 }
153
154 return data.filter((lint) => lint.categories.includes('PERFORMANCE'))
155 },
156 }
157}