integrate-sdk 0.9.42-dev.0 → 0.9.44-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -736,104 +736,267 @@ function base64UrlDecode(str) {
736
736
 
737
737
  // src/oauth/email-fetcher.ts
738
738
  async function fetchUserEmail(provider, tokenData) {
739
+ const fetcher = EMAIL_FETCHERS[provider.toLowerCase()];
740
+ if (!fetcher) {
741
+ return tokenData.email;
742
+ }
739
743
  try {
740
- switch (provider.toLowerCase()) {
741
- case "github":
742
- return await fetchGitHubEmail(tokenData.accessToken);
743
- case "gmail":
744
- case "google":
745
- return await fetchGoogleEmail(tokenData.accessToken);
746
- case "notion":
747
- return await fetchNotionEmail(tokenData.accessToken);
748
- default:
749
- return tokenData.email;
750
- }
744
+ const email = await fetcher(tokenData);
745
+ return email ?? tokenData.email;
751
746
  } catch (error) {
752
747
  logger3.error(`Failed to fetch email for ${provider}:`, error);
753
- return;
748
+ return tokenData.email;
754
749
  }
755
750
  }
756
- async function fetchGitHubEmail(accessToken) {
757
- try {
758
- const userResponse = await fetch("https://api.github.com/user", {
759
- headers: {
760
- Authorization: `Bearer ${accessToken}`,
761
- Accept: "application/vnd.github.v3+json"
762
- }
763
- });
764
- if (!userResponse.ok) {
765
- return;
766
- }
767
- const user = await userResponse.json();
768
- if (user.email) {
769
- return user.email;
770
- }
771
- const emailsResponse = await fetch("https://api.github.com/user/emails", {
772
- headers: {
773
- Authorization: `Bearer ${accessToken}`,
774
- Accept: "application/vnd.github.v3+json"
775
- }
776
- });
777
- if (!emailsResponse.ok) {
778
- return;
779
- }
780
- const emails = await emailsResponse.json();
781
- const primaryEmail = emails.find((e) => e.primary && e.verified);
782
- if (primaryEmail) {
783
- return primaryEmail.email;
751
+ async function fetchGitHubEmail(token) {
752
+ const headers = {
753
+ Authorization: `Bearer ${token.accessToken}`,
754
+ Accept: "application/vnd.github.v3+json"
755
+ };
756
+ const userResponse = await fetch("https://api.github.com/user", { headers });
757
+ if (!userResponse.ok)
758
+ return;
759
+ const user = await userResponse.json();
760
+ if (user.email)
761
+ return user.email;
762
+ const emailsResponse = await fetch("https://api.github.com/user/emails", { headers });
763
+ if (!emailsResponse.ok)
764
+ return;
765
+ const emails = await emailsResponse.json();
766
+ const primary = emails.find((e) => e.primary && e.verified);
767
+ if (primary)
768
+ return primary.email;
769
+ const verified = emails.find((e) => e.verified);
770
+ if (verified)
771
+ return verified.email;
772
+ return emails[0]?.email;
773
+ }
774
+ async function fetchGoogleEmail(token) {
775
+ const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
776
+ headers: { Authorization: `Bearer ${token.accessToken}` }
777
+ });
778
+ if (!response.ok)
779
+ return;
780
+ const user = await response.json();
781
+ return user.email;
782
+ }
783
+ async function fetchNotionEmail(token) {
784
+ const response = await fetch("https://api.notion.com/v1/users/me", {
785
+ headers: {
786
+ Authorization: `Bearer ${token.accessToken}`,
787
+ "Notion-Version": "2022-06-28"
784
788
  }
785
- const verifiedEmail = emails.find((e) => e.verified);
786
- if (verifiedEmail) {
787
- return verifiedEmail.email;
789
+ });
790
+ if (!response.ok)
791
+ return;
792
+ const user = await response.json();
793
+ return user.person?.email ?? user.bot?.owner?.user?.person?.email;
794
+ }
795
+ async function fetchLinearEmail(token) {
796
+ const response = await fetch("https://api.linear.app/graphql", {
797
+ method: "POST",
798
+ headers: {
799
+ Authorization: `Bearer ${token.accessToken}`,
800
+ "Content-Type": "application/json"
801
+ },
802
+ body: JSON.stringify({ query: "{ viewer { email } }" })
803
+ });
804
+ if (!response.ok)
805
+ return;
806
+ const body = await response.json();
807
+ return body.data?.viewer?.email;
808
+ }
809
+ async function fetchHubSpotEmail(token) {
810
+ const url = `https://api.hubapi.com/oauth/v1/access-tokens/${encodeURIComponent(token.accessToken)}`;
811
+ const response = await fetch(url);
812
+ if (!response.ok)
813
+ return;
814
+ const body = await response.json();
815
+ return body.user;
816
+ }
817
+ async function fetchPolarEmail(token) {
818
+ const response = await fetch("https://api.polar.sh/v1/oauth2/userinfo", {
819
+ headers: { Authorization: `Bearer ${token.accessToken}` }
820
+ });
821
+ if (!response.ok)
822
+ return;
823
+ const body = await response.json();
824
+ return body.email;
825
+ }
826
+ async function fetchTodoistEmail(token) {
827
+ const response = await fetch("https://api.todoist.com/sync/v9/sync", {
828
+ method: "POST",
829
+ headers: {
830
+ Authorization: `Bearer ${token.accessToken}`,
831
+ "Content-Type": "application/x-www-form-urlencoded"
832
+ },
833
+ body: 'sync_token=*&resource_types=["user"]'
834
+ });
835
+ if (!response.ok)
836
+ return;
837
+ const body = await response.json();
838
+ return body.user?.email;
839
+ }
840
+ async function fetchVercelEmail(token) {
841
+ const response = await fetch("https://api.vercel.com/v2/user", {
842
+ headers: { Authorization: `Bearer ${token.accessToken}` }
843
+ });
844
+ if (!response.ok)
845
+ return;
846
+ const body = await response.json();
847
+ return body.user?.email ?? body.email;
848
+ }
849
+ async function fetchSlackEmail(token) {
850
+ const response = await fetch("https://slack.com/api/users.identity", {
851
+ headers: { Authorization: `Bearer ${token.accessToken}` }
852
+ });
853
+ if (!response.ok)
854
+ return;
855
+ const body = await response.json();
856
+ if (!body.ok)
857
+ return;
858
+ return body.user?.email;
859
+ }
860
+ async function fetchIntercomEmail(token) {
861
+ const response = await fetch("https://api.intercom.io/me", {
862
+ headers: {
863
+ Authorization: `Bearer ${token.accessToken}`,
864
+ Accept: "application/json"
788
865
  }
789
- if (emails.length > 0 && emails[0]?.email) {
790
- return emails[0].email;
866
+ });
867
+ if (!response.ok)
868
+ return;
869
+ const body = await response.json();
870
+ return body.email;
871
+ }
872
+ async function fetchAtlassianEmail(token) {
873
+ const response = await fetch("https://api.atlassian.com/me", {
874
+ headers: {
875
+ Authorization: `Bearer ${token.accessToken}`,
876
+ Accept: "application/json"
791
877
  }
878
+ });
879
+ if (!response.ok)
792
880
  return;
793
- } catch (error) {
794
- logger3.error("Failed to fetch GitHub email:", error);
881
+ const body = await response.json();
882
+ return body.email;
883
+ }
884
+ async function fetchZendeskEmail(token) {
885
+ const subdomain = token.providerConfig?.subdomain?.trim();
886
+ if (!subdomain)
795
887
  return;
796
- }
888
+ const response = await fetch(`https://${subdomain}.zendesk.com/api/v2/users/me.json`, {
889
+ headers: { Authorization: `Bearer ${token.accessToken}` }
890
+ });
891
+ if (!response.ok)
892
+ return;
893
+ const body = await response.json();
894
+ return body.user?.email;
797
895
  }
798
- async function fetchGoogleEmail(accessToken) {
799
- try {
800
- const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
801
- headers: {
802
- Authorization: `Bearer ${accessToken}`
803
- }
804
- });
805
- if (!response.ok) {
806
- return;
807
- }
808
- const user = await response.json();
809
- return user.email;
810
- } catch (error) {
811
- logger3.error("Failed to fetch Google email:", error);
896
+ async function fetchAirtableEmail(token) {
897
+ const response = await fetch("https://api.airtable.com/v0/meta/whoami", {
898
+ headers: { Authorization: `Bearer ${token.accessToken}` }
899
+ });
900
+ if (!response.ok)
812
901
  return;
813
- }
902
+ const body = await response.json();
903
+ return body.email;
814
904
  }
815
- async function fetchNotionEmail(accessToken) {
816
- try {
817
- const response = await fetch("https://api.notion.com/v1/users/me", {
818
- headers: {
819
- Authorization: `Bearer ${accessToken}`,
820
- "Notion-Version": "2022-06-28"
821
- }
822
- });
823
- if (!response.ok) {
824
- return;
905
+ async function fetchDiscordEmail(token) {
906
+ const response = await fetch("https://discord.com/api/users/@me", {
907
+ headers: { Authorization: `Bearer ${token.accessToken}` }
908
+ });
909
+ if (!response.ok)
910
+ return;
911
+ const body = await response.json();
912
+ return body.email;
913
+ }
914
+ async function fetchDropboxEmail(token) {
915
+ const response = await fetch("https://api.dropboxapi.com/2/users/get_current_account", {
916
+ method: "POST",
917
+ headers: {
918
+ Authorization: `Bearer ${token.accessToken}`
919
+ },
920
+ body: "null"
921
+ });
922
+ if (!response.ok)
923
+ return;
924
+ const body = await response.json();
925
+ return body.email;
926
+ }
927
+ async function fetchGitLabEmail(token) {
928
+ const response = await fetch("https://gitlab.com/api/v4/user", {
929
+ headers: { Authorization: `Bearer ${token.accessToken}` }
930
+ });
931
+ if (!response.ok)
932
+ return;
933
+ const body = await response.json();
934
+ return body.email;
935
+ }
936
+ async function fetchRedditEmail(token) {
937
+ const response = await fetch("https://oauth.reddit.com/api/v1/me", {
938
+ headers: {
939
+ Authorization: `Bearer ${token.accessToken}`,
940
+ "User-Agent": "integrate-sdk"
825
941
  }
826
- const user = await response.json();
827
- return user.person?.email;
828
- } catch (error) {
829
- logger3.error("Failed to fetch Notion email:", error);
942
+ });
943
+ if (!response.ok)
830
944
  return;
831
- }
945
+ const body = await response.json();
946
+ return body.name;
947
+ }
948
+ async function fetchMicrosoftEmail(token) {
949
+ const response = await fetch("https://graph.microsoft.com/v1.0/me", {
950
+ headers: { Authorization: `Bearer ${token.accessToken}` }
951
+ });
952
+ if (!response.ok)
953
+ return;
954
+ const body = await response.json();
955
+ return body.mail ?? body.userPrincipalName;
832
956
  }
833
- var logger3;
957
+ var logger3, EMAIL_FETCHERS;
834
958
  var init_email_fetcher = __esm(() => {
835
959
  init_logger();
836
960
  logger3 = createLogger("EmailFetcher");
961
+ EMAIL_FETCHERS = {
962
+ github: fetchGitHubEmail,
963
+ gmail: fetchGoogleEmail,
964
+ google: fetchGoogleEmail,
965
+ gcal: fetchGoogleEmail,
966
+ gdrive: fetchGoogleEmail,
967
+ gdocs: fetchGoogleEmail,
968
+ gsheets: fetchGoogleEmail,
969
+ gslides: fetchGoogleEmail,
970
+ gcontacts: fetchGoogleEmail,
971
+ gmeet: fetchGoogleEmail,
972
+ gchat: fetchGoogleEmail,
973
+ gtasks: fetchGoogleEmail,
974
+ ga4: fetchGoogleEmail,
975
+ youtube: fetchGoogleEmail,
976
+ notion: fetchNotionEmail,
977
+ linear: fetchLinearEmail,
978
+ hubspot: fetchHubSpotEmail,
979
+ polar: fetchPolarEmail,
980
+ todoist: fetchTodoistEmail,
981
+ vercel: fetchVercelEmail,
982
+ slack: fetchSlackEmail,
983
+ intercom: fetchIntercomEmail,
984
+ jira: fetchAtlassianEmail,
985
+ zendesk: fetchZendeskEmail,
986
+ airtable: fetchAirtableEmail,
987
+ discord: fetchDiscordEmail,
988
+ dropbox: fetchDropboxEmail,
989
+ gitlab: fetchGitLabEmail,
990
+ reddit: fetchRedditEmail,
991
+ outlook: fetchMicrosoftEmail,
992
+ teams: fetchMicrosoftEmail,
993
+ onedrive: fetchMicrosoftEmail,
994
+ sharepoint: fetchMicrosoftEmail,
995
+ excel: fetchMicrosoftEmail,
996
+ word: fetchMicrosoftEmail,
997
+ powerpoint: fetchMicrosoftEmail,
998
+ planner: fetchMicrosoftEmail
999
+ };
837
1000
  });
838
1001
 
839
1002
  // src/utils/concurrency.ts
@@ -3276,6 +3439,148 @@ class IndexedDBStorage {
3276
3439
 
3277
3440
  // src/oauth/manager.ts
3278
3441
  init_email_fetcher();
3442
+
3443
+ // src/oauth/refresh.ts
3444
+ class RefreshRejectedError extends Error {
3445
+ provider;
3446
+ constructor(provider, message) {
3447
+ super(message ?? `OAuth refresh rejected (invalid_grant) for ${provider}`);
3448
+ this.name = "RefreshRejectedError";
3449
+ this.provider = provider;
3450
+ }
3451
+ }
3452
+
3453
+ class RefreshTransientError extends Error {
3454
+ provider;
3455
+ constructor(provider, message) {
3456
+ super(message);
3457
+ this.name = "RefreshTransientError";
3458
+ this.provider = provider;
3459
+ }
3460
+ }
3461
+ var DEFAULT_REFRESH_WINDOW_MS = 2 * 60 * 1000;
3462
+ function shouldRefreshToken(tokenData, windowMs = DEFAULT_REFRESH_WINDOW_MS) {
3463
+ if (!tokenData || !tokenData.refreshToken || !tokenData.expiresAt) {
3464
+ return false;
3465
+ }
3466
+ const expiresAtMs = Date.parse(tokenData.expiresAt);
3467
+ if (Number.isNaN(expiresAtMs)) {
3468
+ return false;
3469
+ }
3470
+ return expiresAtMs - Date.now() <= windowMs;
3471
+ }
3472
+ async function refreshViaMcp(opts) {
3473
+ const url = new URL("/oauth/refresh", opts.serverUrl);
3474
+ const body = {
3475
+ provider: opts.provider,
3476
+ refresh_token: opts.refreshToken,
3477
+ client_id: opts.clientId
3478
+ };
3479
+ if (opts.clientSecret) {
3480
+ body.client_secret = opts.clientSecret;
3481
+ }
3482
+ if (opts.subdomain) {
3483
+ body.subdomain = opts.subdomain;
3484
+ }
3485
+ if (opts.extraConfig) {
3486
+ for (const [key, value] of Object.entries(opts.extraConfig)) {
3487
+ if (body[key] === undefined) {
3488
+ body[key] = value;
3489
+ }
3490
+ }
3491
+ }
3492
+ const headers = { "Content-Type": "application/json" };
3493
+ if (opts.apiKey) {
3494
+ headers["X-API-KEY"] = opts.apiKey;
3495
+ }
3496
+ let response;
3497
+ try {
3498
+ response = await fetch(url.toString(), {
3499
+ method: "POST",
3500
+ headers,
3501
+ body: JSON.stringify(body),
3502
+ signal: opts.signal
3503
+ });
3504
+ } catch (err) {
3505
+ throw new RefreshTransientError(opts.provider, `Network error refreshing ${opts.provider} token: ${err.message}`);
3506
+ }
3507
+ if (response.status === 401) {
3508
+ let parsed = {};
3509
+ try {
3510
+ parsed = await response.json();
3511
+ } catch {}
3512
+ if (parsed.error === "invalid_grant") {
3513
+ throw new RefreshRejectedError(opts.provider);
3514
+ }
3515
+ throw new RefreshTransientError(opts.provider, `Refresh endpoint returned 401`);
3516
+ }
3517
+ if (!response.ok) {
3518
+ let text = "";
3519
+ try {
3520
+ text = await response.text();
3521
+ } catch {}
3522
+ throw new RefreshTransientError(opts.provider, `Refresh endpoint returned ${response.status}: ${text || "<no body>"}`);
3523
+ }
3524
+ let result;
3525
+ try {
3526
+ result = await response.json();
3527
+ } catch (err) {
3528
+ throw new RefreshTransientError(opts.provider, `Malformed refresh response: ${err.message}`);
3529
+ }
3530
+ if (!result.accessToken) {
3531
+ throw new RefreshTransientError(opts.provider, `Refresh response missing access_token`);
3532
+ }
3533
+ if (!result.refreshToken) {
3534
+ result.refreshToken = opts.refreshToken;
3535
+ }
3536
+ return result;
3537
+ }
3538
+ async function resolveAccessToken(opts) {
3539
+ const { provider, currentTokens, force = false } = opts;
3540
+ const needsRefresh = force || shouldRefreshToken(currentTokens, opts.windowMs);
3541
+ if (!needsRefresh || !currentTokens.refreshToken) {
3542
+ return currentTokens.accessToken;
3543
+ }
3544
+ try {
3545
+ const refreshed = await refreshViaMcp({
3546
+ provider,
3547
+ refreshToken: currentTokens.refreshToken,
3548
+ clientId: opts.providerOAuth.clientId,
3549
+ clientSecret: opts.providerOAuth.clientSecret,
3550
+ subdomain: opts.providerOAuth.subdomain,
3551
+ extraConfig: opts.providerOAuth.extraConfig,
3552
+ serverUrl: opts.serverUrl,
3553
+ apiKey: opts.apiKey
3554
+ });
3555
+ const updated = {
3556
+ ...currentTokens,
3557
+ accessToken: refreshed.accessToken,
3558
+ refreshToken: refreshed.refreshToken ?? currentTokens.refreshToken,
3559
+ tokenType: refreshed.tokenType || currentTokens.tokenType,
3560
+ expiresIn: refreshed.expiresIn ?? currentTokens.expiresIn,
3561
+ expiresAt: refreshed.expiresAt ?? currentTokens.expiresAt,
3562
+ scopes: refreshed.scopes && refreshed.scopes.length > 0 ? refreshed.scopes : currentTokens.scopes
3563
+ };
3564
+ if (opts.setProviderToken) {
3565
+ try {
3566
+ await opts.setProviderToken(provider, updated, updated.email, opts.context);
3567
+ } catch {}
3568
+ }
3569
+ return updated.accessToken;
3570
+ } catch (err) {
3571
+ if (err instanceof RefreshRejectedError) {
3572
+ if (opts.setProviderToken) {
3573
+ try {
3574
+ await opts.setProviderToken(provider, null, currentTokens.email, opts.context);
3575
+ } catch {}
3576
+ }
3577
+ throw err;
3578
+ }
3579
+ return currentTokens.accessToken;
3580
+ }
3581
+ }
3582
+
3583
+ // src/oauth/manager.ts
3279
3584
  init_logger();
3280
3585
  var logger4 = createLogger("OAuth");
3281
3586
 
@@ -3291,7 +3596,10 @@ class OAuthManager {
3291
3596
  removeTokenCallback;
3292
3597
  indexedDBStorage;
3293
3598
  skipLocalStorage = false;
3294
- constructor(oauthApiBase, flowConfig, apiBaseUrl, tokenCallbacks) {
3599
+ providerOAuth = {};
3600
+ mcpServerUrl;
3601
+ mcpApiKey;
3602
+ constructor(oauthApiBase, flowConfig, apiBaseUrl, tokenCallbacks, refreshConfig) {
3295
3603
  this.oauthApiBase = oauthApiBase;
3296
3604
  this.apiBaseUrl = apiBaseUrl;
3297
3605
  this.windowManager = new OAuthWindowManager;
@@ -3303,6 +3611,9 @@ class OAuthManager {
3303
3611
  this.getTokenCallback = tokenCallbacks?.getProviderToken;
3304
3612
  this.setTokenCallback = tokenCallbacks?.setProviderToken;
3305
3613
  this.removeTokenCallback = tokenCallbacks?.removeProviderToken;
3614
+ this.providerOAuth = refreshConfig?.providers ?? {};
3615
+ this.mcpServerUrl = refreshConfig?.mcpServerUrl;
3616
+ this.mcpApiKey = refreshConfig?.apiKey;
3306
3617
  this.indexedDBStorage = new IndexedDBStorage;
3307
3618
  this.cleanupExpiredPendingAuths();
3308
3619
  }
@@ -3512,7 +3823,9 @@ class OAuthManager {
3512
3823
  try {
3513
3824
  const tokenData = await this.getTokenCallback(provider, email, context);
3514
3825
  if (tokenData) {
3515
- this.providerTokens.set(provider, tokenData);
3826
+ const refreshed = await this.maybeRefreshTokenData(provider, tokenData, context);
3827
+ this.providerTokens.set(provider, refreshed);
3828
+ return refreshed;
3516
3829
  }
3517
3830
  return tokenData;
3518
3831
  } catch (error) {
@@ -3552,6 +3865,59 @@ class OAuthManager {
3552
3865
  }
3553
3866
  await this.saveProviderToken(provider, tokenData, tokenEmail, context);
3554
3867
  }
3868
+ configureTokenRefresh(refreshConfig) {
3869
+ if (refreshConfig.providers) {
3870
+ this.providerOAuth = refreshConfig.providers;
3871
+ }
3872
+ if (refreshConfig.mcpServerUrl !== undefined) {
3873
+ this.mcpServerUrl = refreshConfig.mcpServerUrl;
3874
+ }
3875
+ if (refreshConfig.apiKey !== undefined) {
3876
+ this.mcpApiKey = refreshConfig.apiKey;
3877
+ }
3878
+ }
3879
+ async maybeRefreshTokenData(provider, tokenData, context) {
3880
+ const credentials = this.providerOAuth[provider];
3881
+ const serverUrl = this.mcpServerUrl;
3882
+ if (!credentials || !serverUrl) {
3883
+ return tokenData;
3884
+ }
3885
+ if (!shouldRefreshToken(tokenData)) {
3886
+ return tokenData;
3887
+ }
3888
+ try {
3889
+ const newAccessToken = await resolveAccessToken({
3890
+ provider,
3891
+ currentTokens: tokenData,
3892
+ providerOAuth: {
3893
+ clientId: credentials.clientId,
3894
+ clientSecret: credentials.clientSecret,
3895
+ subdomain: credentials.config?.subdomain
3896
+ },
3897
+ serverUrl,
3898
+ apiKey: this.mcpApiKey,
3899
+ setProviderToken: this.setTokenCallback,
3900
+ context
3901
+ });
3902
+ if (newAccessToken === tokenData.accessToken) {
3903
+ return tokenData;
3904
+ }
3905
+ if (this.getTokenCallback) {
3906
+ try {
3907
+ const reloaded = await this.getTokenCallback(provider, tokenData.email, context);
3908
+ if (reloaded) {
3909
+ return reloaded;
3910
+ }
3911
+ } catch {}
3912
+ }
3913
+ return { ...tokenData, accessToken: newAccessToken };
3914
+ } catch (err) {
3915
+ if (err instanceof RefreshRejectedError) {
3916
+ throw err;
3917
+ }
3918
+ return tokenData;
3919
+ }
3920
+ }
3555
3921
  clearProviderToken(provider) {
3556
3922
  this.providerTokens.delete(provider);
3557
3923
  if (!this.setTokenCallback && !this.removeTokenCallback && !this.skipLocalStorage) {
@@ -4008,10 +4374,26 @@ class MCPClientBase {
4008
4374
  };
4009
4375
  this.onReauthRequired = config.onReauthRequired;
4010
4376
  this.maxReauthRetries = config.maxReauthRetries ?? 1;
4377
+ const refreshProviders = {};
4378
+ for (const integration of this.integrations) {
4379
+ const oauth = integration?.oauth;
4380
+ if (oauth?.clientId && oauth?.provider) {
4381
+ refreshProviders[oauth.provider] = {
4382
+ clientId: oauth.clientId,
4383
+ clientSecret: oauth.clientSecret,
4384
+ config: oauth.config
4385
+ };
4386
+ }
4387
+ }
4388
+ const mcpServerUrl = config.serverUrl;
4011
4389
  this.oauthManager = new OAuthManager(oauthApiBase, config.oauthFlow, this.apiBaseUrl, {
4012
4390
  getProviderToken: config.getProviderToken,
4013
4391
  setProviderToken: config.setProviderToken,
4014
4392
  removeProviderToken: config.removeProviderToken
4393
+ }, {
4394
+ providers: refreshProviders,
4395
+ mcpServerUrl,
4396
+ apiKey: config.apiKey
4015
4397
  });
4016
4398
  this.setSessionToken(config.sessionToken || this.loadSessionTokenFromStorage());
4017
4399
  for (const integration of this.integrations) {
@@ -15978,6 +16360,34 @@ function convertJsonSchemaToGoogleSchema(jsonSchema, TypeEnum) {
15978
16360
  // src/server.ts
15979
16361
  var SERVER_LOG_CONTEXT3 = "server";
15980
16362
  var logger93 = createLogger("MCPServer", SERVER_LOG_CONTEXT3);
16363
+ async function refreshTokenIfNeeded(provider, tokenData, providers, config, context) {
16364
+ const credentials = providers[provider];
16365
+ if (!credentials || !config.serverUrl) {
16366
+ return tokenData.accessToken;
16367
+ }
16368
+ try {
16369
+ return await resolveAccessToken({
16370
+ provider,
16371
+ currentTokens: tokenData,
16372
+ providerOAuth: {
16373
+ clientId: credentials.clientId,
16374
+ clientSecret: credentials.clientSecret,
16375
+ subdomain: credentials.config?.subdomain
16376
+ },
16377
+ serverUrl: config.serverUrl,
16378
+ apiKey: config.apiKey,
16379
+ setProviderToken: config.setProviderToken,
16380
+ context
16381
+ });
16382
+ } catch (err) {
16383
+ if (err instanceof RefreshRejectedError) {
16384
+ logger93.warn(`[Token Refresh] Refresh token rejected for ${provider}; integration marked disconnected.`);
16385
+ } else {
16386
+ logger93.warn(`[Token Refresh] Failed to refresh ${provider} token: ${err.message}`);
16387
+ }
16388
+ return tokenData.accessToken;
16389
+ }
16390
+ }
15981
16391
  var globalServerConfig = null;
15982
16392
  var globalMCPHandler = null;
15983
16393
  var codeVerifierStorage = new Map;
@@ -16229,7 +16639,8 @@ function createMCPServer(config) {
16229
16639
  if (provider) {
16230
16640
  const tokenData = await config.getProviderToken(provider, undefined, context2);
16231
16641
  if (tokenData?.accessToken) {
16232
- authHeader = `Bearer ${tokenData.accessToken}`;
16642
+ const accessToken = await refreshTokenIfNeeded(provider, tokenData, providers, config, context2);
16643
+ authHeader = `Bearer ${accessToken}`;
16233
16644
  }
16234
16645
  }
16235
16646
  } catch {}