docs: document MCP cost confirmation via elicitations (#50017)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update for the MCP cost confirmation launch
([AI-1161](https://linear.app/supabase/issue/AI-1161/write-the-docs)).

## What is the current behavior?

The MCP server guide lists `get_cost` / `confirm_cost` but doesn't
describe the elicitation-based cost confirmation flow that
`@supabase/mcp-server-supabase` 0.12.0 introduces for `create_project`
and `create_branch` on form-capable clients.

## What is the new behavior?

- New **Cost confirmation** section in the MCP server guide: how the
elicitation flow works (accept / decline / expiry / rate-change
outcomes, all side-effect-free except accept), the zero-cost skip,
client support, and how to tell which cost flow a connection uses.
- New troubleshooting entry: "Cost confirmations do not appear in your
MCP client".
- Three `supa-mdx-lint` dictionary additions the new prose needs
(`elicitation(s)`, `dialogs`, `pauses`).

## Additional context

**Draft — hold until launch.** Merge gates before publishing:

1. The feature is enabled for hosted connections.
2. The client support table is re-verified against launch verification
results (there's a matching `{/* ... */}` reviewer note above the
table). Client support moves quickly; the table reflects verification as
of 2026-09-04.

Needs review:

- **Rate-change behavior follows the shipped code, not the spec docs**:
on any change to the computed cost between confirmation and creation
(including a decrease), the server reissues a fresh confirmation rather
than proceeding (`account-tools.ts` redemption path in supabase/mcp).
Flagging in case the intent was lower-or-equal proceeds.
- No exact confirmation expiry is stated because the TTL is
deployment-configured (`ttlSeconds`).
- Wording deliberately says "client-mediated" style confirmation and
avoids claiming a person approved each action, since clients can answer
elicitations via hooks.

Test plan: `supa-mdx-lint` clean on both files; Prettier (repo config)
clean. No runnable snippets, so no sandbox verification needed. Vercel
preview link will appear below.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added advanced options to hosted MCP connections for skipping selected
cost or destructive-SQL confirmations when supported. Available options
depend on connection scope, enabled features, and read-only settings.
* The configuration panel explains when skip selections are unavailable
or ignored by certain client configurations.

* **Documentation**
* Added guidance on cost and SQL confirmation prompts, Edge Function
secret entry, and troubleshooting missing prompts or unavailable secret
collection. This includes client requirements, fallback behavior, and
relevant security considerations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Barry Roodt <barry.roodt@supabase.io>
This commit is contained in:
authored and GitHub committed 2026-10-02 08:58:34 +02:00
1 parent ffd2754c7a
commit 531431cd77
9 files changed
+454 -10

No files matched your search

+87 -7
View File
@@ -70,6 +70,7 @@ The Supabase MCP server provides tools organized into feature groups. All groups
- `list_edge_functions` - List all Edge Functions
- `get_edge_function` - Get a specific Edge Function
- `deploy_edge_function` - Deploy an Edge Function
- `create_edge_function_secret` - When available, request secret entry in the Supabase Dashboard. See [Edge Function secrets](#edge-function-secrets) for requirements.
### Account management
@@ -82,7 +83,7 @@ Disabled when using project-scoped mode (`project_ref` parameter).
- `list_projects` / `get_project` - List or get project details
- `create_project` / `pause_project` / `restore_project` - Manage projects
- `list_organizations` / `get_organization` - Organization management
- `get_cost` / `confirm_cost` - Cost information
- `get_cost` / `confirm_cost` - Cost information for tools that use the [legacy cost confirmation workflow](#cost-confirmation)
### Docs
@@ -104,15 +105,79 @@ Requires a paid plan.
- `list_storage_buckets` - List storage buckets
- `get_storage_config` / `update_storage_config` - Storage configuration
## Elicitations
[Elicitation](https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation) lets an MCP server pause a tool call to ask you for input or confirmation. These flows require both server availability and an MCP client that supports the appropriate elicitation mode: forms for [cost confirmation](#cost-confirmation) and [SQL confirmations](#destructive-sql-confirmations), or URLs for [secret entry](#edge-function-secrets).
Server elicitation is separate from your MCP client's own approval of tool calls. It does not replace manual approval or the [security recommendations](#recommendations).
Treat elicitations as a guardrail, not a guarantee of human review or approval. Some clients support hooks or rules that answer elicitations automatically.
### Client support
Elicitations require your MCP client to support the corresponding mode for the request.
| Mode | Supabase use |
| ---- | ----------------------------------------------------------------------------------------------------------- |
| Form | [Cost confirmation](#cost-confirmation) and [destructive SQL confirmations](#destructive-sql-confirmations) |
| URL | [Edge Function secret entry](#edge-function-secrets) in the Supabase Dashboard |
Support for one mode does not imply support for the other. Check your client's documentation for the modes it supports. The MCP specification revision alone does not determine which flows your connection uses.
### Cost confirmation
When your connection uses form-based cost confirmation, your MCP client shows the expected cost before your agent takes an action that incurs additional charges. The action proceeds only on explicit approval.
Cost confirmation applies to `create_project` and `create_branch`. When your agent calls one of these tools, the tool call pauses and your client displays the resource, the standard rate, and the billing interval, along with controls to accept or decline. The exact labels vary by client.
- Accepting resumes the same tool call to create the resource.
- Declining or dismissing the confirmation creates nothing, and the agent receives a result that it can relay to you.
- Confirmations are valid for a short time. If one expires, nothing is created. The agent can call the tool again to request a fresh confirmation.
- The cost is checked again immediately before creation. If it has changed to a different nonzero amount since you confirmed, you receive a fresh confirmation that shows the updated cost.
Project creation with a zero-cost quote does not trigger a cost confirmation prompt. When branch creation uses form-based cost confirmation, it asks you to confirm the standard rate before any allowances or exemptions are applied.
If form-based cost confirmation is unavailable, unsupported by your client, or [skipped for the tool](#skip-form-confirmations), the legacy cost confirmation workflow applies: the agent quotes the cost in chat, uses `get_cost` and `confirm_cost`, and passes the returned `confirm_cost_id` to `create_project` or `create_branch`. These helpers are account tools and are not exposed in project-scoped connections. Skipping the form does not approve the cost or avoid charges.
To check which flow a creation tool uses, ask your client to list the available Supabase tools and the resource types accepted by `get_cost` and `confirm_cost`. The resource types accepted by these helpers use the legacy cost confirmation workflow; another resource type can use form-based cost confirmation on the same connection. Their absence does not prove that form-based cost confirmation is active: project scoping, account feature settings, or server availability can also hide them.
Your MCP client controls how the confirmation is collected. Some clients support hooks or rules that answer elicitations automatically, so treat cost confirmation as a guardrail rather than proof that a person approved each action.
Troubleshooting: If you expect a dialog and don't see one, see [Cost confirmations do not appear in your MCP client](/docs/guides/troubleshooting/cost-confirmations-do-not-appear-in-your-mcp-client-mVq3Lp).
### Destructive SQL confirmations
When SQL elicitation is available and your client supports forms, `execute_sql` and `apply_migration` ask for confirmation when they detect destructive SQL. The `execute_sql` confirmation applies only outside read-only mode. SQL not classified as destructive proceeds without this additional warning. Treat this elicitation as a guardrail - it may not catch every destructive operation and is not a security guarantee.
If SQL elicitation is unavailable, unsupported by your client, or skipped with [`skip_elicitations`](#skip-form-confirmations), SQL follows the existing execution path without an additional MCP confirmation. Read-only restrictions and permissions still apply. Keep the [security recommendations](#recommendations) in place.
Troubleshooting: If you expect a dialog and don't see one, see [SQL confirmations do not appear in your MCP client](/docs/guides/troubleshooting/sql-confirmations-do-not-appear-in-your-mcp-client-sQf7Kp).
### Edge Function secrets
`create_edge_function_secret` is available only when the server offers it, your client supports URL elicitation, Edge Functions tools are enabled, and the connection is not read-only. You also need permission to read and write Edge Function secrets for the project.
Enter secret values only in the Supabase Dashboard, never in chat, model input, or MCP tool arguments. The tool requests the secret name and project, not the secret value.
1. Ask your AI assistant to add an Edge Function secret, specifying the project and secret name without providing the value.
2. Open the Supabase Dashboard URL presented by your MCP client.
3. Enter and save the secret value in the Dashboard.
4. Return to your MCP client and confirm that you saved it.
Save the secret in the Dashboard before confirming in your MCP client. If you cancel the request, this does not undo a secret you already saved in the Dashboard.
Troubleshooting: If the tool is unavailable or the Dashboard flow is incomplete, see [Edge Function secret collection is unavailable or incomplete](/docs/guides/troubleshooting/edge-function-secret-collection-is-unavailable-or-incomplete-eFs4Nx).
## Configuration options
The [configuration panel above](#configure-your-ai-tool) can set these options for you. If you prefer to configure manually, the following URL query parameters are available:
The [configuration panel](#configure-your-ai-tool) can set project scope, read-only mode, and feature groups. For hosted connections, you can also set `skip_elicitations` in the panel or edit your MCP server URL manually. The following URL query parameters are available:
| Parameter | Description | Example |
| ------------------- | ---------------------------------------------------- | ------------------------- |
| `read_only=true` | Execute all queries as a read-only Postgres user | `?read_only=true` |
| `project_ref=<id>` | Scope to a specific project (disables account tools) | `?project_ref=abc123` |
| `features=<groups>` | Enable only specific tool groups (comma-separated) | `?features=database,docs` |
| Parameter | Description | Example |
| --------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `read_only=true` | Execute all queries as a read-only Postgres user | `?read_only=true` |
| `project_ref=<id>` | Scope to a specific project (disables account tools) | `?project_ref=abc123` |
| `features=<groups>` | Enable only specific tool groups (comma-separated) | `?features=database,docs` |
| `skip_elicitations=<tools>` | Skip form confirmations for the named tools. See [Skip form confirmations](#skip-form-confirmations). | `?skip_elicitations=execute_sql,apply_migration` |
Parameters can be combined: <code><CustomContent data="mcp:servers">remote</CustomContent>?project_ref=abc123&read_only=true</code>
@@ -122,6 +187,20 @@ When using [Supabase CLI](/docs/guides/local-development) for local development,
</Admonition>
### Skip form confirmations
Use one `skip_elicitations` parameter with a comma-separated list of tool names: `create_project`, `create_branch`, `execute_sql`, or `apply_migration`.
Names are case-sensitive. Omit the parameter or leave it empty to skip none; this does not enable confirmations that the server does not offer. Invalid names are rejected. There is no boolean or `all` switch, and `create_edge_function_secret` is not supported by this parameter.
In the panel, skip choices are hidden for read-only and local connections. Cost confirmation choices require a connection not scoped to a project with account helpers enabled; `create_branch` also requires branching. SQL-confirmation choices require the database feature group. These limits apply to the panel, not to manually supplied URL parameters.
Skip cost confirmation: <code><CustomContent data="mcp:servers">remote</CustomContent>?skip_elicitations=create_project,create_branch</code>
Skip SQL confirmations: <code><CustomContent data="mcp:servers">remote</CustomContent>?skip_elicitations=execute_sql,apply_migration</code>
Skipping cost confirmations retains the [legacy cost confirmation workflow](#cost-confirmation). Skipping SQL confirmations uses the existing SQL execution path without an additional MCP confirmation. Neither option bypasses authentication, permissions, read-only restrictions, or charges.
## Manual authentication
By default the hosted Supabase MCP server uses [dynamic client registration](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#dynamic-client-registration) to authenticate with your Supabase org. This means that you don't need to manually create a personal access token (PAT) or OAuth app to use the server.
@@ -193,6 +272,7 @@ We recommend the following best practices to mitigate security risks when using
- **Read-only mode**: Set unattended monitoring and diagnostic routines to [read-only](#configuration-options) mode, which executes SQL queries as a read-only Postgres user.
- **Project scoping**: Scope your MCP server to a [specific project](#configuration-options), limiting access to only that project's resources. This prevents LLMs from accessing data from other projects in your Supabase account.
- **Branching**: Use Supabase's [branching feature](/docs/guides/deployment/branching) to create a development branch for your database. This allows you to test changes in a safe environment before merging them to production.
- **Cost confirmation**: When your connection uses cost confirmation dialogs, the server asks for [confirmation through your client](#cost-confirmation) before it creates resources that incur charges. This is a guardrail on top of authentication and authorization, not a replacement for them.
- **Feature groups**: Restrict which [tool groups](#available-tools) are available using the `features` [configuration option](#configuration-options). This helps reduce the attack surface and limits the actions that LLMs can perform to only those that you need.
## On GitHub
@@ -0,0 +1,38 @@
---
title = "Cost confirmations do not appear in your MCP client"
topics = [ "ai" ]
keywords = [
"mcp",
"elicitation",
"cost",
"confirmation",
"get_cost",
"confirm_cost",
"create_project",
"create_branch",
]
---
When your connection uses cost confirmation dialogs, the Supabase MCP server asks for [confirmation through your MCP client](/docs/guides/ai-tools/mcp#cost-confirmation) before `create_project` or `create_branch` creates a resource that incurs charges. If you expect a confirmation dialog and don't see one, work through these checks.
## Your client uses the `get_cost` and `confirm_cost` flow
Cost confirmation dialogs appear when the server offers form-based cost confirmation for the tool and your client supports form elicitations for the request. The specification revision alone does not determine which flow your connection uses. If form-based cost confirmation is unavailable or unsupported, the tool uses the legacy cost confirmation workflow instead. In that workflow, the agent quotes the cost in chat and asks you before creating the resource. No dialog appears, and this is the expected behavior.
To check which flow a creation tool uses, ask your client to list the available Supabase tools and the resource types accepted by `get_cost` and `confirm_cost`. The resource types accepted by these helpers use the legacy cost confirmation workflow; another resource type can use form-based cost confirmation on the same connection. Their absence does not prove that form-based cost confirmation is active: project scoping, account feature settings, or server availability can also hide them.
## Cost confirmations are skipped for the tool
Check your MCP server URL for `skip_elicitations`. If it includes `create_project` or `create_branch`, that tool uses the legacy cost confirmation workflow instead of a confirmation dialog. Skipping the form does not approve the cost or avoid charges. See [Skip form confirmations](/docs/guides/ai-tools/mcp#skip-form-confirmations).
## The project creation is quoted at zero cost
When a new project creation request uses form-based cost confirmation and is quoted at zero cost, no confirmation is requested and the project is created directly. This exception does not apply to branch creation: when it uses form-based cost confirmation, it asks you to confirm the standard rate before any allowances or exemptions are applied.
## Your client answers elicitations automatically
Some clients support hooks or rules that respond to elicitations without showing a dialog. If resources are created without a visible confirmation on a client that supports the dialog, check your client's elicitation or hook configuration.
## Still stuck?
If none of these explain what you're seeing, open an issue on the [Supabase MCP repository](https://github.com/supabase/mcp) with your client name and version.
@@ -0,0 +1,39 @@
---
title = "Edge Function secret collection is unavailable or incomplete"
topics = [ "ai", "functions" ]
keywords = [
"mcp",
"elicitation",
"secrets",
"create_edge_function_secret",
"Dashboard",
]
---
The `create_edge_function_secret` tool uses a [Dashboard flow to collect an Edge Function secret](/docs/guides/ai-tools/mcp#edge-function-secrets). If the tool is unavailable or the flow is incomplete, work through these checks.
## Your connection does not support URL elicitation
The tool requires the server to offer secret collection and your client to support URL elicitations. Support for form elicitations does not imply support for URL elicitations. Check [Client support](/docs/guides/ai-tools/mcp#client-support) for your connection.
## The tool is unavailable for your project
Check that Edge Functions tools are enabled, your connection is not read-only, and you have read and write permissions for project secrets. These are required for `create_edge_function_secret` to be available.
`skip_elicitations` cannot include `create_edge_function_secret` and does not enable this flow.
## The secret has not been saved in the Dashboard
The tool takes the secret name and project information, not the secret value. Never put the secret value in chat, send it to the model, or include it in tool arguments.
To complete the flow:
1. Open the Dashboard URL provided by the tool.
2. Enter and save the secret value in the Supabase Dashboard.
3. Return to your MCP client and confirm completion.
Confirming in your client does not replace saving the value in the Dashboard.
## You cancel after saving the secret
If you cancel the elicitation, this does not undo a secret already saved in the Dashboard. Check the secret in the Dashboard rather than assuming cancellation removed it.
@@ -0,0 +1,41 @@
---
title = "SQL confirmations do not appear in your MCP client"
topics = [ "ai", "database" ]
keywords = [
"mcp",
"elicitation",
"confirmation",
"destructive SQL",
"execute_sql",
"apply_migration",
"skip_elicitations",
]
---
The Supabase MCP server can ask for [confirmation before running detected destructive SQL](/docs/guides/ai-tools/mcp#destructive-sql-confirmations) through `execute_sql` or `apply_migration`. If you expect a confirmation dialog and don't see one, work through these checks.
## Form-based SQL confirmation is unavailable or unsupported
SQL confirmation dialogs require your client to support form elicitations for the request. Check your connection against [Client support](/docs/guides/ai-tools/mcp#client-support).
If form-based SQL confirmation is unavailable or unsupported, the tools follow their existing SQL execution behavior without an additional MCP confirmation prompt. Permissions and read-only restrictions still apply. There is no legacy cost-style confirmation workflow for SQL.
## The SQL does not trigger detection
The tools only request confirmation for SQL detected as destructive. Detection does not catch every destructive statement. A missing prompt does not prove that SQL is safe.
Review the SQL itself rather than relying on a confirmation dialog. Do not run destructive SQL to test whether a prompt appears.
## Your connection is read-only
`execute_sql` only requests destructive SQL confirmation outside read-only mode. Keep read-only mode enabled when you do not need write access; do not disable it to get a confirmation prompt.
## SQL confirmations are skipped for the tool
Check your MCP server URL for `skip_elicitations`. If it includes `execute_sql` or `apply_migration`, that tool follows its existing SQL execution behavior without the additional MCP confirmation prompt. Permissions and read-only restrictions still apply.
To receive supported confirmations, remove the affected tool from `skip_elicitations`. See [Skip form confirmations](/docs/guides/ai-tools/mcp#skip-form-confirmations).
## Your client answers elicitations automatically
Some clients support hooks or rules that respond to elicitations without showing a dialog. If your client supports form elicitations but no dialog appears, check its elicitation or hook configuration.
@@ -131,7 +131,10 @@ export function McpConfigPanel() {
Find your client below and add the configuration shown. You can scope the server by
appending URL query parameters: <inlineCode value="?project_ref=<id>" /> to limit it to a
single project, <inlineCode value="?read_only=true" /> to allow only read queries, and{' '}
<inlineCode value="?features=database,docs" /> to enable specific tool groups.
<inlineCode value="?features=database,docs" /> to enable specific tool groups. For hosted
connections, the optional <inlineCode value="skip_elicitations" /> parameter selects which{' '}
<link url="/docs/guides/ai-tools/mcp#skip-form-confirmations">form confirmations</link> to
skip when elicitation is available.
</paragraph>
{MCP_CLIENT_GROUPS.map((group) => (
@@ -0,0 +1,80 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { TooltipProvider } from 'ui'
import { describe, expect, it } from 'vitest'
import { McpConfigPanel } from './McpConfigPanel'
const props = {
isPlatform: true,
platformUrl: 'https://mcp.supabase.com/mcp',
nonPlatformUrl: 'http://localhost:54321/mcp',
onCopyCallback: () => {},
}
function selectOptOut(tool: string) {
fireEvent.click(screen.getByRole('button', { name: 'Advanced' }))
fireEvent.click(screen.getByRole('combobox', { name: 'Skip confirmations for' }))
fireEvent.click(screen.getByRole('option', { name: tool }))
fireEvent.keyDown(screen.getByRole('combobox', { name: 'Skip confirmations for' }), {
key: 'Escape',
})
}
describe('McpConfigPanel opt-out transitions', () => {
it('permanently clears cost opt-outs when a connection becomes project scoped', () => {
const { container, rerender } = render(<McpConfigPanel {...props} />, {
wrapper: TooltipProvider,
})
selectOptOut('create_branch')
expect(container.textContent).toContain('skip_elicitations=create_branch')
rerender(<McpConfigPanel {...props} projectRef="test-project" />)
expect(container.textContent).not.toContain('skip_elicitations=')
rerender(<McpConfigPanel {...props} />)
expect(container.textContent).not.toContain('skip_elicitations=')
})
it('permanently clears SQL opt-outs across a non-platform connection', () => {
const { container, rerender } = render(<McpConfigPanel {...props} />, {
wrapper: TooltipProvider,
})
selectOptOut('execute_sql')
expect(container.textContent).toContain('skip_elicitations=execute_sql')
rerender(<McpConfigPanel {...props} isPlatform={false} />)
expect(container.textContent).not.toContain('skip_elicitations=')
rerender(<McpConfigPanel {...props} />)
expect(container.textContent).not.toContain('skip_elicitations=')
})
it('does not restore SQL opt-outs after read-only mode is turned off', () => {
const { container } = render(<McpConfigPanel {...props} />, { wrapper: TooltipProvider })
selectOptOut('execute_sql')
expect(container.textContent).toContain('skip_elicitations=execute_sql')
fireEvent.click(screen.getByRole('switch', { name: 'Read-only' }))
expect(container.textContent).not.toContain('skip_elicitations=')
fireEvent.click(screen.getByRole('switch', { name: 'Read-only' }))
expect(container.textContent).not.toContain('skip_elicitations=')
})
it.each([
{ feature: 'Database', tool: 'execute_sql' },
{ feature: 'Account', tool: 'create_branch' },
{ feature: 'Branching', tool: 'create_branch' },
])('does not restore $tool after removing and readding $feature', ({ feature, tool }) => {
const { container } = render(<McpConfigPanel {...props} />, { wrapper: TooltipProvider })
selectOptOut(tool)
expect(container.textContent).toContain(`skip_elicitations=${tool}`)
fireEvent.click(screen.getByRole('combobox', { name: 'Select features' }))
fireEvent.click(screen.getByRole('option', { name: new RegExp(`^${feature}`) }))
expect(container.textContent).not.toContain('skip_elicitations=')
fireEvent.click(screen.getByRole('option', { name: new RegExp(`^${feature}`) }))
expect(container.textContent).not.toContain('skip_elicitations=')
})
})
@@ -1,10 +1,18 @@
'use client'
import { ChevronRight } from 'lucide-react'
import React, { useMemo, useState } from 'react'
import { cn, Separator } from 'ui'
import { cn, Collapsible, CollapsibleContent, CollapsibleTrigger, Label, Separator } from 'ui'
import { CodeBlock } from 'ui-patterns/CodeBlock'
import { InfoTooltip } from '../info-tooltip'
import {
MultiSelector,
MultiSelectorContent,
MultiSelectorItem,
MultiSelectorList,
MultiSelectorTrigger,
} from '../multi-select'
import {
FEATURE_GROUPS_NON_PLATFORM,
FEATURE_GROUPS_PLATFORM,
@@ -15,7 +23,7 @@ import { McpConfigurationDisplay } from './components/McpConfigurationDisplay'
import { McpConfigurationOptions } from './components/McpConfigurationOptions'
import { MCP_CLIENTS } from './mcpClients'
import type { McpClient, McpOnCopyCallback } from './types'
import { getMcpUrl } from './utils/getMcpUrl'
import { getMcpUrl, type McpSkipElicitation } from './utils/getMcpUrl'
const CLIENT_GROUPS = MCP_CLIENT_GROUPS.map((group) => ({
heading: group.heading,
@@ -59,6 +67,7 @@ export function McpConfigPanel({
supportedFeatures.filter((group) => group.id !== 'storage').map((group) => group.id)
)
const [selectedClient, setSelectedClient] = useState(initialSelectedClient ?? MCP_CLIENTS[0])
const [skipElicitations, setSkipElicitations] = useState<McpSkipElicitation[]>([])
const selectedFeaturesSupported = useMemo(() => {
return selectedFeatures.filter((feature) =>
@@ -66,6 +75,26 @@ export function McpConfigPanel({
)
}, [selectedFeatures, supportedFeatures])
const eligibleSkipElicitations: McpSkipElicitation[] = []
if (isPlatform && !readonly) {
if (selectedFeaturesSupported.includes('database')) {
eligibleSkipElicitations.push('execute_sql', 'apply_migration')
}
if (!projectRef && selectedFeaturesSupported.includes('account')) {
eligibleSkipElicitations.push('create_project')
if (selectedFeaturesSupported.includes('branching')) {
eligibleSkipElicitations.push('create_branch')
}
}
}
const validSkipElicitations = skipElicitations.filter((tool) =>
eligibleSkipElicitations.includes(tool)
)
// Prune during render so changed props cannot commit stale opt-outs or restore them later.
if (validSkipElicitations.length !== skipElicitations.length) {
setSkipElicitations(validSkipElicitations)
}
const { mcpUrl, clientConfig } = getMcpUrl({
projectRef,
isPlatform,
@@ -74,6 +103,7 @@ export function McpConfigPanel({
nonPlatformUrl,
readonly,
features: selectedFeaturesSupported,
skipElicitations: validSkipElicitations,
selectedClient,
})
@@ -102,6 +132,73 @@ export function McpConfigPanel({
onFeaturesChange={setSelectedFeatures}
featureGroups={isPlatform ? FEATURE_GROUPS_PLATFORM : FEATURE_GROUPS_NON_PLATFORM}
/>
{isPlatform && !readonly && (
<Collapsible className={innerPanelSpacing}>
<CollapsibleTrigger className="group flex items-center gap-2 text-sm">
<ChevronRight
size={16}
className="transition-transform group-data-[state=open]:rotate-90"
/>
Advanced
</CollapsibleTrigger>
<CollapsibleContent className="space-y-3 pt-3">
<div className="flex items-center gap-2">
<Label className="text-sm">Skip confirmations for selected tools</Label>
<InfoTooltip>
Select the tools whose confirmation prompts you want to skip. Leave empty to keep
the default behavior.
</InfoTooltip>
</div>
{eligibleSkipElicitations.length > 0 ? (
<MultiSelector
values={validSkipElicitations}
onValuesChange={(values) =>
setSkipElicitations(
eligibleSkipElicitations.filter((tool) => values.includes(tool))
)
}
>
<MultiSelectorTrigger
className="w-full"
label="None selected"
aria-label="Skip confirmations for"
badgeLimit="wrap"
showIcon={true}
/>
<MultiSelectorContent>
<MultiSelectorList>
{eligibleSkipElicitations.map((tool) => (
<MultiSelectorItem key={tool} value={tool}>
<code>{tool}</code>
</MultiSelectorItem>
))}
</MultiSelectorList>
</MultiSelectorContent>
</MultiSelector>
) : (
<p className="text-xs text-foreground-light">
No eligible tools with the current options. Adjust the connection scope or enabled
features.
</p>
)}
{projectRef ? (
<p className="text-xs text-foreground-light">
Skipping cost confirmations is unavailable for project-scoped connections because
the legacy cost confirmation workflow requires account-level tools.
</p>
) : !selectedFeaturesSupported.includes('account') ? (
<p className="text-xs text-foreground-light">
Enable the account feature to skip confirmations for <code>create_project</code>{' '}
or <code>create_branch</code>.
</p>
) : !selectedFeaturesSupported.includes('branching') ? (
<p className="text-xs text-foreground-light">
Enable the branching feature to skip confirmations for <code>create_branch</code>.
</p>
) : null}
</CollapsibleContent>
</Collapsible>
)}
<div className={innerPanelSpacing}>
<CodeBlock
focusable={false}
@@ -140,6 +237,25 @@ export function McpConfigPanel({
<h3>Installation</h3>
</div>
<Separator />
{validSkipElicitations.length > 0 && selectedClient.key === 'kiro' && (
<p className={cn('text-xs text-foreground-light', innerPanelSpacing)}>
The Kiro power uses a fixed configuration and ignores these options. Use manual
configuration to apply them.
</p>
)}
{validSkipElicitations.length > 0 && selectedClient.key === 'gemini-cli' && (
<p className={cn('text-xs text-foreground-light', innerPanelSpacing)}>
The Gemini extension install ignores your confirmation skip selections. Use the
add-server command shown here or manual configuration to apply them.
</p>
)}
{validSkipElicitations.length > 0 &&
['claude-ai', 'chatgpt'].includes(selectedClient.key) && (
<p className={cn('text-xs text-foreground-light', innerPanelSpacing)}>
Claude.ai and ChatGPT directory installs use a fixed configuration and ignore these
options.
</p>
)}
<McpConfigurationDisplay
className={innerPanelSpacing}
theme={theme}
@@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest'
import { getMcpUrl } from './getMcpUrl'
const platformUrl = 'https://mcp.supabase.com/mcp'
describe('getMcpUrl skip elicitations', () => {
it('omits the parameter when no tools are selected', () => {
const { mcpUrl } = getMcpUrl({ isPlatform: true, platformUrl, skipElicitations: [] })
expect(new URL(mcpUrl).searchParams.has('skip_elicitations')).toBe(false)
})
it('encodes the explicit selected tools in the URL and client config', () => {
const { mcpUrl, clientConfig } = getMcpUrl({
isPlatform: true,
platformUrl,
skipElicitations: ['execute_sql', 'apply_migration', 'create_project', 'create_branch'],
})
expect(new URL(mcpUrl).searchParams.get('skip_elicitations')).toBe(
'execute_sql,apply_migration,create_project,create_branch'
)
expect(clientConfig).toEqual({ mcpServers: { supabase: { url: mcpUrl } } })
})
it('does not add hosted opt-outs to a non-platform connection', () => {
const { mcpUrl } = getMcpUrl({
isPlatform: false,
apiUrl: 'http://localhost:54321',
skipElicitations: ['execute_sql'],
})
expect(mcpUrl).toBe('http://localhost:54321/mcp')
})
})
@@ -14,10 +14,17 @@ export function buildClientConfig(
return client?.transformConfig ? client.transformConfig(base) : base
}
export type McpSkipElicitation =
| 'execute_sql'
| 'apply_migration'
| 'create_project'
| 'create_branch'
interface GetMcpUrlOptions {
projectRef?: string
readonly?: boolean
features?: string[]
skipElicitations?: McpSkipElicitation[]
selectedClient?: McpClient
isPlatform: boolean
apiUrl?: string
@@ -40,6 +47,7 @@ export function getMcpUrl({
nonPlatformUrl,
readonly = false,
features = [],
skipElicitations = [],
selectedClient,
}: GetMcpUrlOptions): GetMcpUrlReturn {
// Generate the MCP URL based on current configuration
@@ -53,6 +61,9 @@ export function getMcpUrl({
if (features.length > 0) {
url.searchParams.set('features', features.join(','))
}
if (isPlatform && skipElicitations.length > 0) {
url.searchParams.set('skip_elicitations', skipElicitations.join(','))
}
const mcpUrl = url.toString()
return {