refreshExpiredMCPTokens checks each MCP OAuth2 token and refreshes any that are expired (or about to expire). Tokens without a refresh_token or that fail to refresh are returned unchanged so the caller can still attempt the connection (which will likely fail with a 401 for the expired ones).
( ctx context.Context, logger slog.Logger, configs []database.MCPServerConfig, tokens []database.MCPServerUserToken, )
| 9896 | // caller can still attempt the connection (which will likely fail with |
| 9897 | // a 401 for the expired ones). |
| 9898 | func (p *Server) refreshExpiredMCPTokens( |
| 9899 | ctx context.Context, |
| 9900 | logger slog.Logger, |
| 9901 | configs []database.MCPServerConfig, |
| 9902 | tokens []database.MCPServerUserToken, |
| 9903 | ) []database.MCPServerUserToken { |
| 9904 | configsByID := make(map[uuid.UUID]database.MCPServerConfig, len(configs)) |
| 9905 | for _, cfg := range configs { |
| 9906 | configsByID[cfg.ID] = cfg |
| 9907 | } |
| 9908 | |
| 9909 | result := slices.Clone(tokens) |
| 9910 | |
| 9911 | var eg errgroup.Group |
| 9912 | for i, tok := range result { |
| 9913 | cfg, ok := configsByID[tok.MCPServerConfigID] |
| 9914 | if !ok || cfg.AuthType != "oauth2" { |
| 9915 | continue |
| 9916 | } |
| 9917 | if tok.RefreshToken == "" { |
| 9918 | continue |
| 9919 | } |
| 9920 | |
| 9921 | eg.Go(func() error { |
| 9922 | refreshed, err := p.refreshMCPTokenIfNeeded(ctx, logger, cfg, tok) |
| 9923 | if err != nil { |
| 9924 | logger.Warn(ctx, "failed to refresh MCP oauth2 token", |
| 9925 | slog.F("server_slug", cfg.Slug), |
| 9926 | slog.Error(err), |
| 9927 | ) |
| 9928 | return nil |
| 9929 | } |
| 9930 | result[i] = refreshed |
| 9931 | return nil |
| 9932 | }) |
| 9933 | } |
| 9934 | _ = eg.Wait() |
| 9935 | |
| 9936 | return result |
| 9937 | } |
| 9938 | |
| 9939 | // refreshMCPTokenIfNeeded delegates to mcpclient.RefreshOAuth2Token |
| 9940 | // and persists the result to the database when a refresh occurs. |