@@ -372,6 +372,36 @@ class McpService {
372372 }
373373 }
374374
375+ /**
376+ * Pooled `tools/list` for one server, with a single retry on a non-OAuth auth
377+ * failure: a rotated header key throws 401, which retires the pooled connection,
378+ * so the retry re-acquires a fresh one that re-resolves the credential. (OAuth
379+ * 401s are left to the caller's oauth-pending handling.) `listTools` is
380+ * idempotent, so the retry is always safe.
381+ */
382+ private async fetchServerTools (
383+ config : McpServerConfig ,
384+ userId : string ,
385+ workspaceId : string
386+ ) : Promise < McpTool [ ] > {
387+ for ( let attempt = 0 ; ; attempt ++ ) {
388+ try {
389+ return await this . withServerClient (
390+ {
391+ key : this . poolKey ( config . id , workspaceId , userId ) ,
392+ serverId : config . id ,
393+ allowPool : true ,
394+ } ,
395+ this . buildClient ( config , userId , workspaceId ) ,
396+ ( client ) => client . listTools ( )
397+ )
398+ } catch ( error ) {
399+ if ( attempt === 0 && isAuthError ( error ) && config . authType !== 'oauth' ) continue
400+ throw error
401+ }
402+ }
403+ }
404+
375405 /**
376406 * Run `fn` against a connected client. When `allowPool`, borrow from the warm
377407 * pool (`create` runs only on a miss, so a hit skips env resolution + DNS); a
@@ -676,15 +706,7 @@ class McpService {
676706 }
677707
678708 try {
679- const tools = await this . withServerClient (
680- {
681- key : this . poolKey ( config . id , workspaceId , userId ) ,
682- serverId : config . id ,
683- allowPool : true ,
684- } ,
685- this . buildClient ( config , userId , workspaceId ) ,
686- ( client ) => client . listTools ( )
687- )
709+ const tools = await this . fetchServerTools ( config , userId , workspaceId )
688710 logger . debug (
689711 `[${ requestId } ] Discovered ${ tools . length } tools from server ${ config . name } `
690712 )
@@ -889,15 +911,7 @@ class McpService {
889911 }
890912 authType = config . authType
891913
892- const tools = await this . withServerClient (
893- {
894- key : this . poolKey ( serverId , workspaceId , userId ) ,
895- serverId,
896- allowPool : true ,
897- } ,
898- this . buildClient ( config , userId , workspaceId ) ,
899- ( client ) => client . listTools ( )
900- )
914+ const tools = await this . fetchServerTools ( config , userId , workspaceId )
901915 logger . info ( `[${ requestId } ] Discovered ${ tools . length } tools from server ${ config . name } ` )
902916 await Promise . allSettled ( [
903917 this . cacheAdapter
@@ -957,15 +971,7 @@ class McpService {
957971
958972 for ( const config of servers ) {
959973 try {
960- const tools = await this . withServerClient (
961- {
962- key : this . poolKey ( config . id , workspaceId , userId ) ,
963- serverId : config . id ,
964- allowPool : true ,
965- } ,
966- this . buildClient ( config , userId , workspaceId ) ,
967- ( client ) => client . listTools ( )
968- )
974+ const tools = await this . fetchServerTools ( config , userId , workspaceId )
969975
970976 summaries . push ( {
971977 id : config . id ,
0 commit comments