diff --git a/ui/user/src/lib/components/chat/ChatSidebarMcpServer.svelte b/ui/user/src/lib/components/chat/ChatSidebarMcpServer.svelte index 78d3019437..a4c9208d93 100644 --- a/ui/user/src/lib/components/chat/ChatSidebarMcpServer.svelte +++ b/ui/user/src/lib/components/chat/ChatSidebarMcpServer.svelte @@ -27,6 +27,11 @@ showDeleteConfirm = false; closeSidebarConfig(layout); } + + async function refreshProjectMcps() { + closeAll(layout); + projectMcps.items = await ChatService.listProjectMCPs(project.assistantID, project.id); + }
@@ -74,6 +79,7 @@ onProjectToolsUpdate={() => { closeAll(layout); }} + onUpdate={refreshProjectMcps} {project} />
diff --git a/ui/user/src/lib/components/chat/McpServerSetup.svelte b/ui/user/src/lib/components/chat/McpServerSetup.svelte index 9852cde2dc..45bea78812 100644 --- a/ui/user/src/lib/components/chat/McpServerSetup.svelte +++ b/ui/user/src/lib/components/chat/McpServerSetup.svelte @@ -243,26 +243,27 @@ > {#snippet connectedServerCardAction(d: ConnectedServer)} {@const requiresUpdate = requiresUserUpdate(d)} - + {#if !requiresUpdate} + + {/if} {/snippet} diff --git a/ui/user/src/lib/components/edit/McpServers.svelte b/ui/user/src/lib/components/edit/McpServers.svelte index 5834aa0290..6c742f7482 100644 --- a/ui/user/src/lib/components/edit/McpServers.svelte +++ b/ui/user/src/lib/components/edit/McpServers.svelte @@ -58,6 +58,14 @@ } function shouldShowWarning(mcp: (typeof projectMCPs.items)[0]) { + if (mcp.needsURL) { + return true; + } + + if (typeof mcp.configured === 'boolean' && mcp.configured === false) { + return true; + } + if (typeof mcp.authenticated === 'boolean') { return !mcp.authenticated; } @@ -111,7 +119,7 @@ {mcpServer.alias || mcpServer.name || DEFAULT_CUSTOM_SERVER_NAME} {#if shouldShowWarning(mcpServer)} - import type { MCPCatalogEntry, MCPCatalogServer, Project, ProjectMCP } from '$lib/services'; + import { + ChatService, + type MCPCatalogEntry, + type MCPCatalogServer, + type Project, + type ProjectMCP + } from '$lib/services'; import { twMerge } from 'tailwind-merge'; import McpServerInfo from './McpServerInfo.svelte'; import McpServerTools from './McpServerTools.svelte'; import McpOauth from './McpOauth.svelte'; + import { AlertTriangle } from 'lucide-svelte'; + import CatalogConfigureForm, { type LaunchFormData } from './CatalogConfigureForm.svelte'; + import { convertEnvHeadersToRecord } from '$lib/services/chat/mcp'; interface Props { entry?: MCPCatalogEntry | MCPCatalogServer | ProjectMCP; @@ -13,6 +22,8 @@ project?: Project; view?: 'overview' | 'tools'; onProjectToolsUpdate?: (selected: string[]) => void; + onUpdate?: () => void; + onEditConfiguration?: () => void; } let { @@ -22,10 +33,11 @@ onAuthenticate, project, view = 'overview', - onProjectToolsUpdate + onProjectToolsUpdate, + onUpdate, + onEditConfiguration }: Props = $props(); let selected = $state(view); - const tabs = [ { label: 'Overview', view: 'overview' }, { label: 'Tools', view: 'tools' } @@ -34,6 +46,60 @@ $effect(() => { selected = view; }); + + let configDialog = $state>(); + let configureForm = $state(); + let error = $state(); + let saving = $state(false); + let configuringServer = $state(); + + async function handleInitConfigureForm() { + if (!entry) return; + if ('mcpID' in entry) { + const response = await ChatService.getSingleOrRemoteMcpServer(entry.mcpID); + + let values: Record; + try { + values = await ChatService.revealSingleOrRemoteMcpServer(response.id); + } catch (error) { + if (error instanceof Error && !error.message.includes('404')) { + console.error('Failed to reveal user server values due to unexpected error', error); + } + values = {}; + } + configuringServer = response; + configureForm = { + envs: response.manifest.env?.map((env) => ({ + ...env, + value: values[env.key] ?? '' + })), + headers: response.manifest.remoteConfig?.headers?.map((header) => ({ + ...header, + value: values[header.key] ?? '' + })), + url: response.manifest.remoteConfig?.url + }; + configDialog?.open(); + } + } + + async function handleConfigureFormUpdate() { + if (!configuringServer || !configureForm) return; + try { + if (configuringServer.manifest.runtime === 'remote' && configureForm.url) { + await ChatService.updateRemoteMcpServerUrl(configuringServer.id, configureForm.url.trim()); + } + + const secretValues = convertEnvHeadersToRecord(configureForm.envs, configureForm.headers); + await ChatService.configureSingleOrRemoteMcpServer(configuringServer.id, secretValues); + + configDialog?.close(); + onUpdate?.(); + } catch (error) { + console.error('Error during configuration:', error); + configDialog?.close(); + } + }
@@ -65,8 +131,37 @@ descriptionPlaceholder="Add a description for this MCP server in the Configuration tab" > {#snippet preContent()} - {#if project} - + {#if 'configured' in entry && typeof entry.configured === 'boolean' && entry.configured === false} +
+
+
+ +

Update Required

+
+ + Due to a recent update in the server, an update on this connector's + configuration is required to continue using this server. + +
+
+ +
+
+ {:else if project} +
+ +
{/if} {/snippet} @@ -76,3 +171,14 @@ {/if}
+ + diff --git a/ui/user/src/lib/components/mcp/MyMcpServers.svelte b/ui/user/src/lib/components/mcp/MyMcpServers.svelte index c993499e44..6e687bc20e 100644 --- a/ui/user/src/lib/components/mcp/MyMcpServers.svelte +++ b/ui/user/src/lib/components/mcp/MyMcpServers.svelte @@ -420,6 +420,14 @@ secretValues ); + const updatedServer = await ChatService.getSingleOrRemoteMcpServer( + selectedEntryOrServer.server.id + ); + selectedEntryOrServer = { + ...selectedEntryOrServer, + server: updatedServer + } as ConnectedServer; + configDialog?.close(); onUpdateConfigure?.(); } else { @@ -442,6 +450,36 @@ document.getElementsByTagName('main')[0].scrollTo({ top: 0, behavior: 'instant' }); } + async function handleEditConfiguration(connectedServer: ConnectedServer) { + if (!connectedServer?.server) { + console.error('No user configured server for this entry found'); + return; + } + let values: Record; + try { + values = await ChatService.revealSingleOrRemoteMcpServer(connectedServer.server.id); + } catch (error) { + if (error instanceof Error && !error.message.includes('404')) { + console.error('Failed to reveal user server values due to unexpected error', error); + } + values = {}; + } + selectedEntryOrServer = connectedServer; + configureForm = { + envs: connectedServer.server.manifest.env?.map((env) => ({ + ...env, + value: values[env.key] ?? '' + })), + headers: connectedServer.server.manifest.remoteConfig?.headers?.map((header) => ({ + ...header, + value: values[header.key] ?? '' + })), + url: connectedServer.server.manifest.remoteConfig?.url, + hostname: connectedServer.parent?.manifest.remoteConfig?.hostname + }; + configDialog?.open(); + } + const duration = PAGE_TRANSITION_DURATION; @@ -733,6 +771,11 @@ parent={selectedEntryOrServer && 'parent' in selectedEntryOrServer ? selectedEntryOrServer.parent : undefined} + onEditConfiguration={() => { + if (selectedEntryOrServer && 'parent' in selectedEntryOrServer) { + handleEditConfiguration(selectedEntryOrServer); + } + }} /> {/if} @@ -747,35 +790,7 @@ 'menu-button', requiresUpdate && 'bg-yellow-500/10 text-yellow-500 hover:bg-yellow-500/30' )} - onclick={async () => { - if (!connectedServer?.server) { - console.error('No user configured server for this entry found'); - return; - } - let values: Record; - try { - values = await ChatService.revealSingleOrRemoteMcpServer(connectedServer.server.id); - } catch (error) { - if (error instanceof Error && !error.message.includes('404')) { - console.error('Failed to reveal user server values due to unexpected error', error); - } - values = {}; - } - selectedEntryOrServer = connectedServer; - configureForm = { - envs: connectedServer.server.manifest.env?.map((env) => ({ - ...env, - value: values[env.key] ?? '' - })), - headers: connectedServer.server.manifest.remoteConfig?.headers?.map((header) => ({ - ...header, - value: values[header.key] ?? '' - })), - url: connectedServer.server.manifest.remoteConfig?.url, - hostname: connectedServer.parent?.manifest.remoteConfig?.hostname - }; - configDialog?.open(); - }} + onclick={() => handleEditConfiguration(connectedServer)} > Edit Configuration diff --git a/ui/user/src/lib/context/projectMcps.svelte.ts b/ui/user/src/lib/context/projectMcps.svelte.ts index 9fe4414707..7ef35d69ab 100644 --- a/ui/user/src/lib/context/projectMcps.svelte.ts +++ b/ui/user/src/lib/context/projectMcps.svelte.ts @@ -6,6 +6,8 @@ const Key = Symbol('mcps'); export type ProjectMcpItem = ProjectMCP & { oauthURL?: string; authenticated?: boolean; + configured?: boolean; + needsURL?: boolean; }; export interface ProjectMCPContext { diff --git a/ui/user/src/lib/services/chat/types.ts b/ui/user/src/lib/services/chat/types.ts index 1b27ab9758..31eb259fb0 100644 --- a/ui/user/src/lib/services/chat/types.ts +++ b/ui/user/src/lib/services/chat/types.ts @@ -396,6 +396,9 @@ export interface ProjectMCP { name?: string; description?: string; icon?: string; + configured?: boolean; + needsUpdate?: boolean; + needsURL?: boolean; } export interface Credential {