diff --git a/frontend/src/lib/components/flows/content/McpOAuthConnect.svelte b/frontend/src/lib/components/flows/content/McpOAuthConnect.svelte
index 29e1aa3f70..cf9becefb5 100644
--- a/frontend/src/lib/components/flows/content/McpOAuthConnect.svelte
+++ b/frontend/src/lib/components/flows/content/McpOAuthConnect.svelte
@@ -17,26 +17,19 @@
interface Props {
onConnected: (resourcePath: string, resourceName: string) => void
onCancel?: () => void
- onDiscoveryStatus?: (
- status: 'discovering' | 'supported' | 'unsupported',
- error?: string
- ) => void
initialServerUrl?: string
initialResourceName?: string
initialResourcePath?: string
updateExistingResource?: boolean
- hideUntilDiscovered?: boolean
}
let {
onConnected,
onCancel,
- onDiscoveryStatus,
initialServerUrl = '',
initialResourceName = '',
initialResourcePath = '',
- updateExistingResource = false,
- hideUntilDiscovered = false
+ updateExistingResource = false
}: Props = $props()
let serverUrl = $state('')
@@ -53,9 +46,6 @@
let connectDisabled = $derived(
!resourcePath || (!updateExistingResource && pathError !== '')
)
- let shouldRender = $derived(
- !hideUntilDiscovered || status === 'discovered' || status === 'connecting'
- )
initializeFromProps()
@@ -77,7 +67,6 @@
async function discoverOAuth() {
status = 'discovering'
error = null
- onDiscoveryStatus?.('discovering')
try {
discoveryResult = await McpOauthService.discoverMcpOauth({
requestBody: { mcp_server_url: serverUrl }
@@ -92,13 +81,11 @@
}
}
status = 'discovered'
- onDiscoveryStatus?.('supported')
} catch (e: any) {
console.error('Error discovering OAuth settings', e)
const errorMessage = e.body?.message || e.body || e.message || 'Unknown error'
error = `Failed to discover OAuth settings: ${errorMessage}`
status = 'unsupported'
- onDiscoveryStatus?.('unsupported', error)
}
}
@@ -289,105 +276,103 @@
onDestroy(cleanup)
-{#if shouldRender}
-
-
-
- {updateExistingResource
- ? 'Connect selected MCP resource with OAuth'
- : 'Connect MCP Server with OAuth'}
-
- {#if onCancel}
-
+
+
+
+ {updateExistingResource
+ ? 'Connect selected MCP resource with OAuth'
+ : 'Connect MCP Server with OAuth'}
+
+ {#if onCancel}
+
+ {/if}
+
+
+
+
+ {#if status === 'idle'}
+
+ {:else if status === 'discovering'}
+
Discovering OAuth settings...
+ {:else if status === 'unsupported'}
+
+
OAuth is not available for this MCP server.
+ {#if error}
+
{error}
+ {/if}
+
+ {:else if status === 'discovered' && discoveryResult}
+
+ ✓ OAuth supported
+ {#if discoveryResult.supports_dynamic_registration}
+ (Dynamic Client Registration available)
{/if}
-
-{/if}
+
+ {:else if status === 'connecting'}
+
Complete authentication in popup window...
+ {/if}
+
+ {#if error && status !== 'unsupported'}
+
{error}
+ {/if}
+
diff --git a/frontend/src/lib/components/flows/content/McpToolEditor.svelte b/frontend/src/lib/components/flows/content/McpToolEditor.svelte
index 5c0b9c30a6..789451bfd8 100644
--- a/frontend/src/lib/components/flows/content/McpToolEditor.svelte
+++ b/frontend/src/lib/components/flows/content/McpToolEditor.svelte
@@ -34,36 +34,6 @@
tool: McpTool
}
- type McpResourceValue = {
- name?: string
- url: string
- token?: string | null
- }
-
- type OAuthDiscoveryStatus = 'none' | 'discovering' | 'supported' | 'unsupported'
-
- function getMcpResourceValue(value: unknown): McpResourceValue | undefined {
- if (!value || typeof value !== 'object') {
- return undefined
- }
-
- const candidate = value as Record
- const url = typeof candidate.url === 'string' ? candidate.url : undefined
-
- if (!url) {
- return undefined
- }
-
- return {
- name: typeof candidate.name === 'string' ? candidate.name : undefined,
- url,
- token:
- typeof candidate.token === 'string' || candidate.token === null
- ? candidate.token
- : undefined
- }
- }
-
function getFallbackMcpResourceName(path: string, url?: string): string {
if (path) {
const parts = path.split('/')
@@ -85,23 +55,10 @@
return error?.body?.message || error?.body || error?.message
}
- function isUnauthorizedError(error: any): boolean {
- const status = error?.status
- const message = String(getErrorMessage(error) ?? '')
-
- return (
- status === 401 ||
- status === 403 ||
- /\b(unauthorized|unauthorised|401|403)\b/i.test(message)
- )
- }
-
let { tool = $bindable() }: Props = $props()
let refreshCount = $state(0)
let resourcePicker: ResourcePicker | undefined = $state()
- let lastResourcePath = $state()
- let oauthDiscoveryStatus = $state('none')
let resourcePath = $derived(tool.value.resource_path)
@@ -128,45 +85,12 @@
let toolOptions = $derived(safeSelectItems((tools.value ?? []).map((t) => t.name)))
let error = $derived(getErrorMessage(tools.error))
- let selectedMcpResourceValue = $derived(getMcpResourceValue(selectedResource.value?.value))
- let selectedMcpHasToken = $derived(
- typeof selectedMcpResourceValue?.token === 'string' &&
- selectedMcpResourceValue.token.trim().length > 0
- )
- let selectedMcpUrlOnly = $derived(Boolean(selectedMcpResourceValue?.url && !selectedMcpHasToken))
- let selectedMcpServerUrl = $derived(selectedMcpResourceValue?.url)
- let selectedMcpResourceName = $derived(
- selectedMcpResourceValue?.name ||
- getFallbackMcpResourceName(resourcePath, selectedMcpServerUrl)
- )
- let selectedMcpUnauthorized = $derived(
- Boolean(selectedMcpUrlOnly && isUnauthorizedError(tools.error))
- )
- let connectionEstablished = $derived(
- Boolean(resourcePath?.length > 0 && tools.status !== 'loading' && !tools.error && tools.value)
- )
- let oauthDiscoveryPending = $derived(
- selectedMcpUnauthorized &&
- (oauthDiscoveryStatus === 'none' || oauthDiscoveryStatus === 'discovering')
- )
- let showConnecting = $derived(
- Boolean(
- resourcePath?.length > 0 &&
- !connectionEstablished &&
- (tools.status === 'loading' || selectedResource.status === 'loading' || oauthDiscoveryPending)
- )
- )
- let showOAuthFlow = $derived(
- selectedMcpUnauthorized && oauthDiscoveryStatus !== 'unsupported'
- )
- let connectionError = $derived(
- resourcePath?.length > 0 &&
- !connectionEstablished &&
- !showConnecting &&
- (!selectedMcpUnauthorized || oauthDiscoveryStatus === 'unsupported')
- ? error
- : undefined
- )
+ // The backend returns 401 (NotAuthorized) when the MCP server requires authentication.
+ let unauthorized = $derived(tools.error?.status === 401)
+
+ let resourceValue = $derived(selectedResource.value?.value as { url?: string; name?: string } | undefined)
+ let serverUrl = $derived(resourceValue?.url)
+ let resourceName = $derived(resourceValue?.name || getFallbackMcpResourceName(resourcePath, serverUrl))
$effect(() => {
resourcePath
@@ -191,22 +115,6 @@
})
})
- $effect(() => {
- const currentPath = resourcePath
- untrack(() => {
- if (currentPath !== lastResourcePath) {
- lastResourcePath = currentPath
- oauthDiscoveryStatus = 'none'
- }
- })
- })
-
- $effect(() => {
- if (!selectedMcpUnauthorized && oauthDiscoveryStatus !== 'none') {
- oauthDiscoveryStatus = 'none'
- }
- })
-
$effect(() => {
if (!tool.value.include_tools) {
tool.value.include_tools = []
@@ -222,15 +130,10 @@
}
})
- function handleOAuthDiscoveryStatus(status: Exclude) {
- oauthDiscoveryStatus = status
- }
-
- async function handleOAuthConnected(connectedResourcePath: string, resourceName: string) {
+ async function handleOAuthConnected(connectedResourcePath: string, connectedResourceName: string) {
await resourcePicker?.refreshResources()
tool.value.resource_path = connectedResourcePath
- tool.summary = `MCP: ${resourceName}`
- oauthDiscoveryStatus = 'none'
+ tool.summary = `MCP: ${connectedResourceName}`
selectedResource.refresh()
refreshCount += 1
}
@@ -257,95 +160,89 @@
- {#if showConnecting}
- connecting to mcp server...
- {/if}
-
- {#if showOAuthFlow}
- {#key `${resourcePath ?? ''}:${selectedMcpServerUrl ?? ''}`}
-
- {/key}
- {/if}
-
- {#if connectionError}
- {`Failed to connect to MCP server: ${connectionError}`}
- {/if}
-
- {#if connectionEstablished}
-
-
- 0}
+ {#if tools.status === 'loading' || selectedResource.status === 'loading'}
+ connecting to mcp server...
+ {:else if unauthorized}
+ {#key `${resourcePath}:${serverUrl ?? ''}`}
+
-
-
-
-
- {#snippet action()}
-
- {/snippet}
-
-
- {#if (tools.value ?? []).length === 0}
-
No tools returned by this MCP server.
- {:else}
-
- {#each tools.value ?? [] as mcpTool (mcpTool.name)}
-
- {mcpTool.name}
- {#if mcpTool.description}
- — {mcpTool.description}
- {/if}
-
- {/each}
-
- {/if}
-
+ {/key}
+ {:else if error}
+
{`Failed to connect to MCP server: ${error}`}
+ {:else if tools.status === 'ok'}
+
+
+
+
-
- {#if tool.value.include_tools && tool.value.exclude_tools}
-
-
-
-
-
-
-
-
-
-
-
+
+ {#snippet action()}
+
+ {/snippet}
+
+
+ {#if (tools.value ?? []).length === 0}
+
No tools returned by this MCP server.
+ {:else}
+
+ {#each tools.value ?? [] as mcpTool (mcpTool.name)}
+
+ {mcpTool.name}
+ {#if mcpTool.description}
+ — {mcpTool.description}
+ {/if}
+
+ {/each}
+
+ {/if}
+
+ {#if tool.value.include_tools && tool.value.exclude_tools}
+
+ {/if}
{/if}
{/if}