@aiwerk/mcp-bridge 2.6.3 → 2.6.4

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.
@@ -46,8 +46,11 @@ export declare class OAuth2TokenManager {
46
46
  * Takes a refreshFn that performs the actual token exchange.
47
47
  */
48
48
  private doTokenRefresh;
49
- private refreshDeviceCodeToken;
50
- private refreshAuthCodeToken;
49
+ /**
50
+ * Shared refresh token exchange for both auth_code and device_code flows.
51
+ * The only differences are which fields are optional (clientId/clientSecret).
52
+ */
53
+ private refreshStoredToken;
51
54
  private makeKey;
52
55
  private fetchToken;
53
56
  private exchangeToken;
@@ -66,7 +66,7 @@ export class OAuth2TokenManager {
66
66
  if (existingInflight) {
67
67
  return existingInflight;
68
68
  }
69
- const refreshPromise = this.doTokenRefresh(serverName, stored, (s) => this.refreshAuthCodeToken(s, config), "Auth code");
69
+ const refreshPromise = this.doTokenRefresh(serverName, stored, (s) => this.refreshStoredToken(s, config), "Auth code");
70
70
  this.tokenRefreshInflight.set(serverName, refreshPromise);
71
71
  try {
72
72
  return await refreshPromise;
@@ -98,7 +98,7 @@ export class OAuth2TokenManager {
98
98
  if (existingInflight) {
99
99
  return existingInflight;
100
100
  }
101
- const refreshPromise = this.doTokenRefresh(serverName, stored, (s) => this.refreshDeviceCodeToken(s, config), "Device code");
101
+ const refreshPromise = this.doTokenRefresh(serverName, stored, (s) => this.refreshStoredToken(s, config), "Device code");
102
102
  this.tokenRefreshInflight.set(serverName, refreshPromise);
103
103
  try {
104
104
  return await refreshPromise;
@@ -128,50 +128,20 @@ export class OAuth2TokenManager {
128
128
  error.code = -32006;
129
129
  throw error;
130
130
  }
131
- async refreshDeviceCodeToken(stored, config) {
132
- const formData = new URLSearchParams();
133
- formData.set("grant_type", "refresh_token");
134
- formData.set("refresh_token", stored.refreshToken);
135
- formData.set("client_id", config.clientId);
136
- if (config.clientSecret)
137
- formData.set("client_secret", config.clientSecret);
138
- if (config.scopes?.length)
139
- formData.set("scope", config.scopes.join(" "));
140
- const response = await fetch(stored.tokenUrl, {
141
- method: "POST",
142
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
143
- body: formData.toString(),
144
- });
145
- if (!response.ok) {
146
- throw new Error(`OAuth2 refresh token exchange failed: HTTP ${response.status}`);
147
- }
148
- const payload = (await response.json());
149
- if (!payload.access_token) {
150
- throw new Error("OAuth2 refresh response missing access_token");
151
- }
152
- const expiresIn = Number.isFinite(payload.expires_in)
153
- ? Number(payload.expires_in)
154
- : DEFAULT_EXPIRES_IN_SECONDS;
155
- const expiresAt = Date.now() + Math.max(0, expiresIn - EXPIRY_BUFFER_SECONDS) * 1000;
156
- return {
157
- accessToken: payload.access_token,
158
- refreshToken: payload.refresh_token ?? stored.refreshToken,
159
- expiresAt,
160
- tokenUrl: stored.tokenUrl,
161
- clientId: config.clientId,
162
- scopes: config.scopes,
163
- };
164
- }
165
- async refreshAuthCodeToken(stored, config) {
131
+ /**
132
+ * Shared refresh token exchange for both auth_code and device_code flows.
133
+ * The only differences are which fields are optional (clientId/clientSecret).
134
+ */
135
+ async refreshStoredToken(stored, params) {
166
136
  const formData = new URLSearchParams();
167
137
  formData.set("grant_type", "refresh_token");
168
138
  formData.set("refresh_token", stored.refreshToken);
169
- if (config.clientId)
170
- formData.set("client_id", config.clientId);
171
- if (config.clientSecret)
172
- formData.set("client_secret", config.clientSecret);
173
- if (config.scopes?.length)
174
- formData.set("scope", config.scopes.join(" "));
139
+ if (params.clientId)
140
+ formData.set("client_id", params.clientId);
141
+ if (params.clientSecret)
142
+ formData.set("client_secret", params.clientSecret);
143
+ if (params.scopes?.length)
144
+ formData.set("scope", params.scopes.join(" "));
175
145
  const response = await fetch(stored.tokenUrl, {
176
146
  method: "POST",
177
147
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
@@ -193,8 +163,8 @@ export class OAuth2TokenManager {
193
163
  refreshToken: payload.refresh_token ?? stored.refreshToken,
194
164
  expiresAt,
195
165
  tokenUrl: stored.tokenUrl,
196
- clientId: config.clientId,
197
- scopes: config.scopes,
166
+ clientId: params.clientId,
167
+ scopes: params.scopes,
198
168
  };
199
169
  }
200
170
  makeKey(tokenUrl, clientId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiwerk/mcp-bridge",
3
- "version": "2.6.3",
3
+ "version": "2.6.4",
4
4
  "description": "Standalone MCP server that multiplexes multiple MCP servers into one interface",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",