Skip to content

Commit b8c3fd2

Browse files
committed
feat: support rollback via down migration
1 parent 15598dd commit b8c3fd2

File tree

4 files changed

+71
-9
lines changed

4 files changed

+71
-9
lines changed

packages/mcp-server-supabase/src/platform/api-platform.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import {
4141
type StorageConfig,
4242
type StorageOperations,
4343
type SupabasePlatform,
44+
type RollbackMigrationOptions,
45+
rollbackMigrationOptionsSchema,
4446
} from './index.js';
4547

4648
const { version } = packageJson;
@@ -235,6 +237,27 @@ export function createSupabaseApiPlatform(
235237
// to avoid prompt injection attacks. If the migration failed,
236238
// it will throw an error.
237239
},
240+
async rollbackMigration(projectId: string, options: RollbackMigrationOptions) {
241+
const { version } = rollbackMigrationOptionsSchema.parse(options);
242+
243+
const response = await managementApiClient.DELETE(
244+
'/v1/projects/{ref}/database/migrations',
245+
{
246+
params: {
247+
path: {
248+
ref: projectId,
249+
},
250+
query: {
251+
gte: version
252+
}
253+
},
254+
}
255+
);
256+
257+
assertSuccess(response, 'Failed to rollback migration');
258+
259+
return response.data;
260+
},
238261
};
239262

240263
const debugging: DebuggingOperations = {

packages/mcp-server-supabase/src/platform/types.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ export const executeSqlOptionsSchema = z.object({
121121
export const applyMigrationOptionsSchema = z.object({
122122
name: z.string(),
123123
query: z.string(),
124+
rollback: z.string(),
125+
});
126+
127+
export const rollbackMigrationOptionsSchema = z.object({
128+
version: z.string(),
124129
});
125130

126131
export const migrationSchema = z.object({
@@ -163,6 +168,7 @@ export type DeployEdgeFunctionOptions = z.infer<
163168

164169
export type ExecuteSqlOptions = z.infer<typeof executeSqlOptionsSchema>;
165170
export type ApplyMigrationOptions = z.infer<typeof applyMigrationOptionsSchema>;
171+
export type RollbackMigrationOptions = z.infer<typeof rollbackMigrationOptionsSchema>;
166172
export type Migration = z.infer<typeof migrationSchema>;
167173
export type ListMigrationsResult = z.infer<typeof migrationSchema>;
168174

@@ -182,6 +188,10 @@ export type DatabaseOperations = {
182188
projectId: string,
183189
options: ApplyMigrationOptions
184190
): Promise<void>;
191+
rollbackMigration(
192+
projectId: string,
193+
options: RollbackMigrationOptions
194+
): Promise<void>;
185195
};
186196

187197
export type AccountOperations = {
@@ -234,10 +244,7 @@ export type DevelopmentOperations = {
234244

235245
export type StorageOperations = {
236246
getStorageConfig(projectId: string): Promise<StorageConfig>;
237-
updateStorageConfig(
238-
projectId: string,
239-
config: StorageConfig
240-
): Promise<void>;
247+
updateStorageConfig(projectId: string, config: StorageConfig): Promise<void>;
241248
listAllBuckets(projectId: string): Promise<StorageBucket[]>;
242249
};
243250

@@ -249,10 +256,7 @@ export type BranchingOperations = {
249256
): Promise<Branch>;
250257
deleteBranch(branchId: string): Promise<void>;
251258
mergeBranch(branchId: string): Promise<void>;
252-
resetBranch(
253-
branchId: string,
254-
options: ResetBranchOptions
255-
): Promise<void>;
259+
resetBranch(branchId: string, options: ResetBranchOptions): Promise<void>;
256260
rebaseBranch(branchId: string): Promise<void>;
257261
};
258262

packages/mcp-server-supabase/src/server.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,9 @@ describe('feature groups', () => {
27342734
applyMigration() {
27352735
throw new Error('Not implemented');
27362736
},
2737+
rollbackMigration() {
2738+
throw new Error('Not implemented');
2739+
},
27372740
},
27382741
};
27392742

@@ -2763,6 +2766,9 @@ describe('feature groups', () => {
27632766
applyMigration() {
27642767
throw new Error('Not implemented');
27652768
},
2769+
rollbackMigration() {
2770+
throw new Error('Not implemented');
2771+
},
27662772
},
27672773
};
27682774

packages/mcp-server-supabase/src/tools/database-operation-tools.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,45 @@ export function getDatabaseTools({
208208
project_id: z.string(),
209209
name: z.string().describe('The name of the migration in snake_case'),
210210
query: z.string().describe('The SQL query to apply'),
211+
rollback: z.string().describe('The SQL query to rollback'),
211212
}),
212213
inject: { project_id },
213-
execute: async ({ project_id, name, query }) => {
214+
execute: async ({ project_id, name, query, rollback }) => {
214215
if (readOnly) {
215216
throw new Error('Cannot apply migration in read-only mode.');
216217
}
217218

218219
await database.applyMigration(project_id, {
219220
name,
220221
query,
222+
rollback,
223+
});
224+
225+
return SUCCESS_RESPONSE;
226+
},
227+
}),
228+
rollback_migration: injectableTool({
229+
description:
230+
'Rollback database migrations greater or equal to the specified version.',
231+
annotations: {
232+
title: 'Rollback migration',
233+
readOnlyHint: false,
234+
destructiveHint: true,
235+
idempotentHint: false,
236+
openWorldHint: true,
237+
},
238+
parameters: z.object({
239+
project_id: z.string(),
240+
version: z.string().describe('The target migration version to rollback'),
241+
}),
242+
inject: { project_id },
243+
execute: async ({ project_id, version }) => {
244+
if (readOnly) {
245+
throw new Error('Cannot apply migration in read-only mode.');
246+
}
247+
248+
await database.rollbackMigration(project_id, {
249+
version,
221250
});
222251

223252
return SUCCESS_RESPONSE;

0 commit comments

Comments
 (0)