Skip to content

Commit ebc5843

Browse files
committed
elicitation support ot create_branch
1 parent 9d0ff02 commit ebc5843

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed

packages/mcp-server-supabase/src/tools/branching-tools.ts

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,73 @@ export function getBranchingTools({
3737
.string()
3838
.default('develop')
3939
.describe('Name of the branch to create'),
40+
// When the client supports elicitation, we will ask the user to confirm the
41+
// branch cost interactively and this parameter is not required. For clients
42+
// without elicitation support, this confirmation ID is required.
4043
confirm_cost_id: z
41-
.string({
42-
required_error:
43-
'User must confirm understanding of costs before creating a branch.',
44-
})
45-
.describe('The cost confirmation ID. Call `confirm_cost` first.'),
44+
.string()
45+
.optional()
46+
.describe(
47+
'The cost confirmation ID. Call `confirm_cost` first if elicitation is not supported.'
48+
),
4649
}),
4750
inject: { project_id },
48-
execute: async ({ project_id, name, confirm_cost_id }) => {
51+
execute: async ({ project_id, name, confirm_cost_id }, context) => {
4952
if (readOnly) {
5053
throw new Error('Cannot create a branch in read-only mode.');
5154
}
5255

5356
const cost = getBranchCost();
54-
const costHash = await hashObject(cost);
55-
if (costHash !== confirm_cost_id) {
56-
throw new Error(
57-
'Cost confirmation ID does not match the expected cost of creating a branch.'
58-
);
57+
58+
// If the server and client support elicitation, request explicit confirmation
59+
const caps = context?.server?.getClientCapabilities?.();
60+
const supportsElicitation = Boolean(caps && (caps as any).elicitation);
61+
62+
if (
63+
cost.amount > 0 &&
64+
supportsElicitation &&
65+
context?.server?.elicitInput
66+
) {
67+
const costMessage = `$${cost.amount} per ${cost.recurrence}`;
68+
69+
const result = await context.server.elicitInput({
70+
message: `You are about to create branch "${name}" on project ${project_id}.\n\n💰 Cost: ${costMessage}\n\nDo you want to proceed with this billable branch?`,
71+
requestedSchema: {
72+
type: 'object',
73+
properties: {
74+
confirm: {
75+
type: 'boolean',
76+
title: 'Confirm billable branch creation',
77+
description: `I understand this will cost ${costMessage} and want to proceed`,
78+
},
79+
},
80+
required: ['confirm'],
81+
},
82+
});
83+
84+
if (result.action === 'decline' || result.action === 'cancel') {
85+
throw new Error('Branch creation cancelled by user.');
86+
}
87+
88+
if (result.action === 'accept' && !result.content?.confirm) {
89+
throw new Error(
90+
'You must confirm understanding of the cost to create a billable branch.'
91+
);
92+
}
93+
} else {
94+
// Fallback path (no elicitation support): require confirm_cost_id
95+
if (!confirm_cost_id) {
96+
throw new Error(
97+
'User must confirm understanding of costs before creating a branch.'
98+
);
99+
}
100+
101+
const costHash = await hashObject(cost);
102+
if (costHash !== confirm_cost_id) {
103+
throw new Error(
104+
'Cost confirmation ID does not match the expected cost of creating a branch.'
105+
);
106+
}
59107
}
60108
return await branching.createBranch(project_id, { name });
61109
},

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ export function getDatabaseTools({
232232
confirm: {
233233
type: 'boolean',
234234
title: 'Confirm Migration',
235-
description: 'I have reviewed the SQL and approve this migration',
235+
description:
236+
'I have reviewed the SQL and approve this migration',
236237
},
237238
},
238239
required: ['confirm'],

packages/mcp-server-supabase/src/tools/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ export function injectableTool<
6464
description,
6565
annotations,
6666
parameters: parameters.omit(mask),
67-
execute: (args) => execute({ ...args, ...inject }),
67+
execute: (args, context) => execute({ ...args, ...inject }, context),
6868
}) as Tool<z.ZodObject<any, any, any, CleanParams>, Result>;
6969
}

0 commit comments

Comments
 (0)