mcp.ts 4.1 KB

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