@@ -43,6 +43,7 @@ type McpServer = {
4343 toolCount : number ;
4444 hasToken : boolean ;
4545 hasUserToken : boolean ;
46+ validationError ?: string ;
4647} ;
4748
4849type McpServersSettingsProps = {
@@ -185,6 +186,18 @@ type McpServersListResponse = {
185186
186187type McpServersPatchResponse = {
187188 server ?: McpServerResponse ;
189+ validation ?: {
190+ error ?: string ;
191+ } ;
192+ } ;
193+
194+ type McpServersValidateResponse = {
195+ name : string ;
196+ status : 'connected' | 'error' | 'unknown' ;
197+ toolCount : number ;
198+ validation ?: {
199+ error ?: string ;
200+ } ;
188201} ;
189202
190203const getStatusIcon = ( status : ServerStatus , className : string ) => {
@@ -217,14 +230,18 @@ const getDisplayDetail = (
217230 return 'Unknown' ;
218231} ;
219232
220- const toUiServer = ( server : McpServerResponse ) : McpServer => ( {
233+ const toUiServer = (
234+ server : McpServerResponse ,
235+ validationError ?: string ,
236+ ) : McpServer => ( {
221237 id : server . name ,
222238 name : server . name ,
223239 enabled : server . enabled ,
224240 status : server . status ,
225241 toolCount : server . toolCount ,
226242 hasToken : server . hasToken ,
227243 hasUserToken : server . hasUserToken ,
244+ validationError : server . status === 'error' ? validationError : undefined ,
228245} ) ;
229246
230247export const McpServersSettings = ( { onClose } : McpServersSettingsProps ) => {
@@ -271,6 +288,35 @@ export const McpServersSettings = ({ onClose }: McpServersSettingsProps) => {
271288 [ fetchApi ] ,
272289 ) ;
273290
291+ const validateServer = useCallback (
292+ async ( serverName : string ) => {
293+ const baseUrl = getBaseUrl ( ) ;
294+ const data = await fetchJson < McpServersValidateResponse > (
295+ `${ baseUrl } /mcp-servers/${ encodeURIComponent ( serverName ) } /validate` ,
296+ {
297+ method : 'POST' ,
298+ } ,
299+ ) ;
300+
301+ setServers ( prev =>
302+ prev . map ( server =>
303+ server . name === serverName
304+ ? {
305+ ...server ,
306+ status : data . status ,
307+ toolCount : data . toolCount ,
308+ validationError :
309+ data . status === 'error'
310+ ? ( data . validation ?. error ?? 'Validation failed' )
311+ : undefined ,
312+ }
313+ : server ,
314+ ) ,
315+ ) ;
316+ } ,
317+ [ fetchJson , getBaseUrl ] ,
318+ ) ;
319+
274320 const loadServers = useCallback ( async ( ) => {
275321 setIsLoading ( true ) ;
276322 setError ( null ) ;
@@ -279,15 +325,33 @@ export const McpServersSettings = ({ onClose }: McpServersSettingsProps) => {
279325 const data = await fetchJson < McpServersListResponse > (
280326 `${ baseUrl } /mcp-servers` ,
281327 ) ;
282- setServers ( ( data . servers ?? [ ] ) . map ( toUiServer ) ) ;
328+ const uiServers = ( data . servers ?? [ ] ) . map ( server => toUiServer ( server ) ) ;
329+ setServers ( uiServers ) ;
330+
331+ const serversToValidate = uiServers . filter ( server => server . hasToken ) ;
332+ void Promise . allSettled (
333+ serversToValidate . map ( async server => {
334+ try {
335+ await validateServer ( server . name ) ;
336+ } catch ( validationError ) {
337+ setError (
338+ prev =>
339+ prev ??
340+ ( validationError instanceof Error
341+ ? validationError . message
342+ : `Failed to validate ${ server . name } ` ) ,
343+ ) ;
344+ }
345+ } ) ,
346+ ) ;
283347 } catch ( e ) {
284348 setError (
285349 e instanceof Error ? e . message : 'Failed to load MCP server settings' ,
286350 ) ;
287351 } finally {
288352 setIsLoading ( false ) ;
289353 }
290- } , [ fetchJson , getBaseUrl ] ) ;
354+ } , [ fetchJson , getBaseUrl , validateServer ] ) ;
291355
292356 useEffect ( ( ) => {
293357 loadServers ( ) ;
@@ -313,7 +377,9 @@ export const McpServersSettings = ({ onClose }: McpServersSettingsProps) => {
313377 if ( data . server ) {
314378 setServers ( prev =>
315379 prev . map ( server =>
316- server . name === serverName ? toUiServer ( data . server ! ) : server ,
380+ server . name === serverName
381+ ? toUiServer ( data . server ! , data . validation ?. error )
382+ : server ,
317383 ) ,
318384 ) ;
319385 } else {
@@ -333,7 +399,13 @@ export const McpServersSettings = ({ onClose }: McpServersSettingsProps) => {
333399 ) ;
334400
335401 const selectedCount = useMemo (
336- ( ) => servers . filter ( server => server . enabled ) . length ,
402+ ( ) =>
403+ servers . filter ( server => {
404+ const displayStatus = getDisplayStatus ( server ) ;
405+ const isUnavailable =
406+ displayStatus === 'failed' || displayStatus === 'tokenRequired' ;
407+ return server . enabled && ! isUnavailable ;
408+ } ) . length ,
337409 [ servers ] ,
338410 ) ;
339411
@@ -456,7 +528,12 @@ export const McpServersSettings = ({ onClose }: McpServersSettingsProps) => {
456528 < div className = { classes . statusCell } >
457529 { getStatusIcon ( displayStatus , statusClass ) }
458530 { displayStatus === 'failed' ? (
459- < Tooltip content = "Token authentication failed, click edit to configure it again" >
531+ < Tooltip
532+ content = {
533+ server . validationError ??
534+ 'Validation failed. Check server URL and token.'
535+ }
536+ >
460537 < Typography
461538 component = "span"
462539 className = { classes . statusValue }
0 commit comments