integrate-sdk 0.2.3 → 0.2.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.
package/README.md CHANGED
@@ -98,6 +98,187 @@ await client.server.listToolsByIntegration({ integration: "github" });
98
98
  await client._callToolByName("slack_send_message", { channel: "#general", text: "Hello" });
99
99
  ```
100
100
 
101
+ ## OAuth Authorization
102
+
103
+ The SDK implements OAuth 2.0 Authorization Code Flow with PKCE for secure third-party service authorization. Users must authorize your application to access their GitHub, Gmail, or other accounts.
104
+
105
+ ### How It Works
106
+
107
+ 1. **Your App**: Creates client with OAuth configuration
108
+ 2. **SDK**: Initiates OAuth flow (popup or redirect)
109
+ 3. **User**: Authorizes permissions on provider's website
110
+ 4. **Provider**: Redirects back with authorization code
111
+ 5. **Your Server**: Exchanges code for tokens and stores them
112
+ 6. **SDK**: Includes session token in all API requests
113
+ 7. **Your Server**: Uses stored OAuth tokens for API calls
114
+
115
+ ### Quick Start
116
+
117
+ ```typescript
118
+ import { createMCPClient, githubPlugin } from "integrate-sdk";
119
+
120
+ // Create client with OAuth flow configuration
121
+ const client = createMCPClient({
122
+ plugins: [
123
+ githubPlugin({
124
+ clientId: process.env.GITHUB_CLIENT_ID!,
125
+ clientSecret: process.env.GITHUB_CLIENT_SECRET!,
126
+ scopes: ["repo", "user"],
127
+ redirectUri: "http://localhost:3000/oauth/callback",
128
+ }),
129
+ ],
130
+ oauthFlow: {
131
+ mode: 'popup', // or 'redirect'
132
+ popupOptions: { width: 600, height: 700 },
133
+ },
134
+ });
135
+
136
+ // Check if authorized
137
+ const isAuthorized = await client.isAuthorized('github');
138
+
139
+ if (!isAuthorized) {
140
+ // Initiate OAuth flow - opens popup or redirects
141
+ await client.authorize('github');
142
+ }
143
+
144
+ // Now you can use GitHub tools
145
+ const repos = await client.github.listOwnRepos({});
146
+ ```
147
+
148
+ ### Popup Flow (Recommended for SPAs)
149
+
150
+ Best for single-page applications - authorization happens in a popup without leaving your app.
151
+
152
+ ```typescript
153
+ const client = createMCPClient({
154
+ plugins: [githubPlugin({ ... })],
155
+ oauthFlow: { mode: 'popup' },
156
+ });
157
+
158
+ // This opens a popup for authorization
159
+ await client.authorize('github');
160
+
161
+ // After user approves, continues automatically
162
+ const repos = await client.github.listOwnRepos({});
163
+ ```
164
+
165
+ **Callback Page**: Create `/oauth/callback.html`:
166
+
167
+ ```html
168
+ <!DOCTYPE html>
169
+ <html>
170
+ <head>
171
+ <title>OAuth Callback</title>
172
+ <script type="module">
173
+ import { sendCallbackToOpener } from 'integrate-sdk';
174
+
175
+ const params = new URLSearchParams(window.location.search);
176
+ sendCallbackToOpener({
177
+ code: params.get('code'),
178
+ state: params.get('state'),
179
+ error: params.get('error')
180
+ });
181
+ </script>
182
+ </head>
183
+ <body>
184
+ <p>Authorization successful! Closing...</p>
185
+ </body>
186
+ </html>
187
+ ```
188
+
189
+ ### Redirect Flow (Traditional Web Apps)
190
+
191
+ Best for traditional server-rendered applications.
192
+
193
+ ```typescript
194
+ // Main page
195
+ const client = createMCPClient({
196
+ plugins: [githubPlugin({ ... })],
197
+ oauthFlow: { mode: 'redirect' },
198
+ });
199
+
200
+ if (!await client.isAuthorized('github')) {
201
+ await client.authorize('github'); // Redirects to GitHub
202
+ }
203
+
204
+ // Callback page (e.g., /oauth/callback)
205
+ const params = new URLSearchParams(window.location.search);
206
+ await client.handleOAuthCallback({
207
+ code: params.get('code')!,
208
+ state: params.get('state')!
209
+ });
210
+
211
+ // Save session token for future use
212
+ const sessionToken = client.getSessionToken();
213
+ localStorage.setItem('session_token', sessionToken);
214
+
215
+ // Redirect back to main app
216
+ ```
217
+
218
+ ### Session Token Management
219
+
220
+ Store and restore sessions to avoid re-authorization:
221
+
222
+ ```typescript
223
+ // Restore previous session
224
+ const client = createMCPClient({
225
+ plugins: [githubPlugin({ ... })],
226
+ sessionToken: localStorage.getItem('session_token'),
227
+ });
228
+
229
+ // Check if session is still valid
230
+ if (!await client.isAuthorized('github')) {
231
+ await client.authorize('github');
232
+ }
233
+
234
+ // Store token after new authorization
235
+ const token = client.getSessionToken();
236
+ localStorage.setItem('session_token', token);
237
+ ```
238
+
239
+ ### Multiple Providers
240
+
241
+ Authorize multiple services independently:
242
+
243
+ ```typescript
244
+ const client = createMCPClient({
245
+ plugins: [
246
+ githubPlugin({ ... }),
247
+ gmailPlugin({ ... }),
248
+ ],
249
+ oauthFlow: { mode: 'popup' },
250
+ });
251
+
252
+ // Get list of all authorized providers
253
+ const authorized = await client.authorizedProviders();
254
+ console.log('Authorized:', authorized); // ['github', 'gmail']
255
+
256
+ // Or check and authorize each provider individually
257
+ if (!await client.isAuthorized('github')) {
258
+ await client.authorize('github');
259
+ }
260
+
261
+ if (!await client.isAuthorized('gmail')) {
262
+ await client.authorize('gmail');
263
+ }
264
+
265
+ // Use both services
266
+ const repos = await client.github.listOwnRepos({});
267
+ const messages = await client.gmail.listMessages({});
268
+ ```
269
+
270
+ ### Server Requirements
271
+
272
+ Your MCP server must implement these OAuth endpoints:
273
+
274
+ **GET `/oauth/authorize`** - Returns authorization URL
275
+ **POST `/oauth/callback`** - Exchanges code for tokens, returns session token
276
+ **GET `/oauth/status`** - Checks authorization status
277
+
278
+ All tool endpoints must accept `X-Session-Token` header and use stored OAuth tokens for API calls.
279
+
280
+ [→ View complete OAuth flow implementation guide](/docs/guides/oauth-flow.md)
281
+
101
282
  ## Built-in Plugins
102
283
 
103
284
  ### GitHub Plugin
package/dist/client.d.ts CHANGED
@@ -9,6 +9,7 @@ import { type AuthenticationError } from "./errors.js";
9
9
  import type { GitHubPluginClient } from "./plugins/github-client.js";
10
10
  import type { GmailPluginClient } from "./plugins/gmail-client.js";
11
11
  import type { ServerPluginClient } from "./plugins/server-client.js";
12
+ import type { AuthStatus, OAuthCallbackParams } from "./oauth/types.js";
12
13
  /**
13
14
  * Tool invocation options
14
15
  */
@@ -54,6 +55,7 @@ export declare class MCPClient<TPlugins extends readonly MCPPlugin[] = readonly
54
55
  private authState;
55
56
  private connectionMode;
56
57
  private connecting;
58
+ private oauthManager;
57
59
  readonly github: PluginNamespaces<TPlugins> extends {
58
60
  github: GitHubPluginClient;
59
61
  } ? GitHubPluginClient : never;
@@ -169,6 +171,97 @@ export declare class MCPClient<TPlugins extends readonly MCPPlugin[] = readonly
169
171
  * Check if a specific provider is authenticated
170
172
  */
171
173
  isProviderAuthenticated(provider: string): boolean;
174
+ /**
175
+ * Check if a provider is authorized via OAuth
176
+ * Queries the MCP server to verify OAuth token validity
177
+ *
178
+ * @param provider - Provider name (github, gmail, etc.)
179
+ * @returns Authorization status
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const isAuthorized = await client.isAuthorized('github');
184
+ * if (!isAuthorized) {
185
+ * await client.authorize('github');
186
+ * }
187
+ * ```
188
+ */
189
+ isAuthorized(provider: string): Promise<boolean>;
190
+ /**
191
+ * Get list of all authorized providers
192
+ * Checks all configured OAuth providers and returns names of authorized ones
193
+ *
194
+ * @returns Array of authorized provider names
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const authorized = await client.authorizedProviders();
199
+ * console.log('Authorized services:', authorized); // ['github', 'gmail']
200
+ *
201
+ * // Check if specific service is in the list
202
+ * if (authorized.includes('github')) {
203
+ * const repos = await client.github.listOwnRepos({});
204
+ * }
205
+ * ```
206
+ */
207
+ authorizedProviders(): Promise<string[]>;
208
+ /**
209
+ * Get detailed authorization status for a provider
210
+ *
211
+ * @param provider - Provider name
212
+ * @returns Full authorization status including scopes and expiration
213
+ */
214
+ getAuthorizationStatus(provider: string): Promise<AuthStatus>;
215
+ /**
216
+ * Initiate OAuth authorization flow for a provider
217
+ * Opens authorization URL in popup or redirects based on configuration
218
+ *
219
+ * @param provider - Provider name (github, gmail, etc.)
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * // Popup flow
224
+ * await client.authorize('github');
225
+ *
226
+ * // Redirect flow
227
+ * await client.authorize('github'); // User is redirected away
228
+ * ```
229
+ */
230
+ authorize(provider: string): Promise<void>;
231
+ /**
232
+ * Handle OAuth callback after user authorization
233
+ * Call this from your OAuth callback page with code and state from URL
234
+ *
235
+ * @param params - Callback parameters containing code and state
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * // In your callback route (e.g., /oauth/callback)
240
+ * const params = new URLSearchParams(window.location.search);
241
+ * await client.handleOAuthCallback({
242
+ * code: params.get('code')!,
243
+ * state: params.get('state')!
244
+ * });
245
+ *
246
+ * // Now you can use the client
247
+ * const repos = await client.github.listOwnRepos({});
248
+ * ```
249
+ */
250
+ handleOAuthCallback(params: OAuthCallbackParams): Promise<void>;
251
+ /**
252
+ * Get the current session token
253
+ * Useful for storing and restoring sessions
254
+ *
255
+ * @returns Session token or undefined if not authorized
256
+ */
257
+ getSessionToken(): string | undefined;
258
+ /**
259
+ * Set session token manually
260
+ * Use this if you have an existing session token
261
+ *
262
+ * @param token - Session token
263
+ */
264
+ setSessionToken(token: string): void;
172
265
  /**
173
266
  * Manually trigger re-authentication for a specific provider
174
267
  * Useful if you want to proactively refresh tokens
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,OAAO,EAEP,mBAAmB,EAIpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAsBxE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,KAAK,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,EAAE,GAAG,KAAK,CAAC;AAClE,KAAK,SAAS,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAE1F;;GAEG;AACH,KAAK,WAAW,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,EAAE,EAAE,SAAS,MAAM,IACvE,EAAE,SAAS,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC;AAEhD;;GAEG;AACH,KAAK,gBAAgB,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,IACzD,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,SAAS,IAAI,GAAG;IAAE,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAAG,EAAE,CAAC,GACpF,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG;IAAE,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAAG,EAAE,CAAC,CAAC;AAEpF;;;;GAIG;AACH,qBAAa,SAAS,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,GAAG,SAAS,SAAS,EAAE;IACjF,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,gBAAgB,CAAC,CAAgB;IACzC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,SAAS,CAAuF;IACxG,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,YAAY,CAAe;IAGnC,SAAgB,MAAM,EAAG,gBAAgB,CAAC,QAAQ,CAAC,SAAS;QAAE,MAAM,EAAE,kBAAkB,CAAA;KAAE,GACtF,kBAAkB,GAClB,KAAK,CAAC;IACV,SAAgB,KAAK,EAAG,gBAAgB,CAAC,QAAQ,CAAC,SAAS;QAAE,KAAK,EAAE,iBAAiB,CAAA;KAAE,GACnF,iBAAiB,GACjB,KAAK,CAAC;IAGV,SAAgB,MAAM,EAAG,kBAAkB,CAAC;gBAEhC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC;IAiD7C;;OAEG;YACW,eAAe;IA0B7B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAczB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;YACW,sBAAsB;IAmCpC;;OAEG;YACW,iBAAiB;IAQ/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB9B;;OAEG;YACW,UAAU;IAkBxB;;OAEG;YACW,aAAa;IAoB3B;;;;OAIG;IACG,eAAe,CACnB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,mBAAmB,CAAC;IAI/B;;;;;;;;;;;OAWG;IACG,cAAc,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,mBAAmB,CAAC;IAgC/B;;OAEG;YACW,iBAAiB;IA4E/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAI1C;;OAEG;IACH,iBAAiB,IAAI,OAAO,EAAE;IAI9B;;OAEG;IACH,eAAe,IAAI,OAAO,EAAE;IAM5B;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAKzD;;OAEG;IACH,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC;IAU9C;;OAEG;IACH,SAAS,CACP,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAClC,MAAM,IAAI;IAIb;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,mBAAmB,CAAA;KAAE,GAAG,SAAS;IAIvG;;OAEG;IACH,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIlD;;;;;;;;;;;;;;OAcG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtD;;;;;;;;;;;;;;;;OAgBG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAgB9C;;;;;OAKG;IACG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAInE;;;;;;;;;;;;;;OAcG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAahD;;;;;;;;;;;;;;;;;;OAkBG;IACG,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrE;;;;;OAKG;IACH,eAAe,IAAI,MAAM,GAAG,SAAS;IAIrC;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKpC;;;OAGG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CA2BzD;AA4DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,EACnE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,GAChC,SAAS,CAAC,QAAQ,CAAC,CAwDrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAetD"}
@@ -88,6 +88,46 @@ export interface MCPClientConfig<TPlugins extends readonly MCPPlugin[]> {
88
88
  * @default true
89
89
  */
90
90
  autoCleanup?: boolean;
91
+ /**
92
+ * OAuth flow configuration
93
+ * Controls how OAuth authorization is handled (popup vs redirect)
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const client = createMCPClient({
98
+ * plugins: [githubPlugin({ ... })],
99
+ * oauthFlow: {
100
+ * mode: 'popup',
101
+ * popupOptions: { width: 600, height: 700 }
102
+ * }
103
+ * });
104
+ * ```
105
+ */
106
+ oauthFlow?: {
107
+ /** How to display OAuth authorization (default: 'redirect') */
108
+ mode?: 'popup' | 'redirect';
109
+ /** Popup window dimensions (only for popup mode) */
110
+ popupOptions?: {
111
+ width?: number;
112
+ height?: number;
113
+ };
114
+ /** Custom callback handler for receiving auth code */
115
+ onAuthCallback?: (provider: string, code: string, state: string) => Promise<void>;
116
+ };
117
+ /**
118
+ * Session token for authenticated requests
119
+ * Set automatically after OAuth flow completes
120
+ * Can be provided manually if you manage tokens externally
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * const client = createMCPClient({
125
+ * plugins: [githubPlugin({ ... })],
126
+ * sessionToken: 'existing-session-token'
127
+ * });
128
+ * ```
129
+ */
130
+ sessionToken?: string;
91
131
  }
92
132
  /**
93
133
  * Helper type to infer enabled tools from plugins
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,KAAK,EAAE,mBAAmB,CAAC;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE;IACpE,iCAAiC;IACjC,OAAO,EAAE,QAAQ,CAAC;IAElB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,yBAAyB;IACzB,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gBAAgB,CAAC,EAAE,aAAa,CAAC;IAEjC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAE7C;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,IACjE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,IAAI;KACnE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;CAC/C,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,KAAK,EAAE,mBAAmB,CAAC;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE;IACpE,iCAAiC;IACjC,OAAO,EAAE,QAAQ,CAAC;IAElB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,yBAAyB;IACzB,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF;;;;;;;;;;;;;;;;;;;OAmBG;IACH,gBAAgB,CAAC,EAAE,aAAa,CAAC;IAEjC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAE7C;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,EAAE;QACV,+DAA+D;QAC/D,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;QAC5B,oDAAoD;QACpD,YAAY,CAAC,EAAE;YACb,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,sDAAsD;QACtD,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACnF,CAAC;IAEF;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,IACjE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,QAAQ,SAAS,SAAS,SAAS,EAAE,IAAI;KACnE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;CAC/C,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,10 @@
4
4
  */
5
5
  export { MCPClient, createMCPClient, clearClientCache } from "./client.js";
6
6
  export type { ToolInvocationOptions } from "./client.js";
7
+ export { OAuthManager } from "./oauth/manager.js";
8
+ export { OAuthWindowManager, sendCallbackToOpener } from "./oauth/window-manager.js";
9
+ export { generateCodeVerifier, generateCodeChallenge, generateState } from "./oauth/pkce.js";
10
+ export type { OAuthFlowConfig, PopupOptions, AuthStatus, PendingAuth, AuthorizationUrlResponse, OAuthCallbackResponse, OAuthCallbackParams, } from "./oauth/types.js";
7
11
  export type { MCPClientConfig, ReauthContext, ReauthHandler } from "./config/types.js";
8
12
  export { IntegrateSDKError, AuthenticationError, AuthorizationError, TokenExpiredError, ConnectionError, ToolCallError, isAuthError, isTokenExpiredError, isAuthorizationError, parseServerError, } from "./errors.js";
9
13
  export type { MCPPlugin, OAuthConfig, ExtractPluginIds, ExtractPluginTools, } from "./plugins/types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3E,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGzD,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvF,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE/F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,YAAY,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,OAAO,EACP,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,YAAY,EACV,cAAc,EACd,2BAA2B,GAC5B,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3E,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7F,YAAY,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,WAAW,EACX,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvF,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE/F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,YAAY,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,OAAO,EACP,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,YAAY,EACV,cAAc,EACd,2BAA2B,GAC5B,MAAM,6BAA6B,CAAC"}
package/dist/index.js CHANGED
@@ -335,6 +335,15 @@ class HttpSessionTransport {
335
335
  getSessionId() {
336
336
  return this.sessionId;
337
337
  }
338
+ setHeader(key, value) {
339
+ this.headers[key] = value;
340
+ }
341
+ removeHeader(key) {
342
+ delete this.headers[key];
343
+ }
344
+ getHeaders() {
345
+ return { ...this.headers };
346
+ }
338
347
  }
339
348
 
340
349
  // src/protocol/messages.ts
@@ -361,6 +370,357 @@ function methodToToolName(methodName, pluginId) {
361
370
  return `${pluginId}_${snakeCaseMethod}`;
362
371
  }
363
372
 
373
+ // src/oauth/pkce.ts
374
+ function generateCodeVerifier() {
375
+ const array = new Uint8Array(32);
376
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
377
+ crypto.getRandomValues(array);
378
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
379
+ globalThis.crypto.getRandomValues(array);
380
+ } else {
381
+ throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
382
+ }
383
+ return base64UrlEncode(array);
384
+ }
385
+ async function generateCodeChallenge(verifier) {
386
+ const encoder = new TextEncoder;
387
+ const data = encoder.encode(verifier);
388
+ let hashBuffer;
389
+ if (typeof crypto !== "undefined" && crypto.subtle) {
390
+ hashBuffer = await crypto.subtle.digest("SHA-256", data);
391
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
392
+ hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", data);
393
+ } else {
394
+ throw new Error("crypto.subtle.digest is not available. Please use Node.js 19+ or a modern browser.");
395
+ }
396
+ return base64UrlEncode(new Uint8Array(hashBuffer));
397
+ }
398
+ function generateState() {
399
+ const array = new Uint8Array(16);
400
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
401
+ crypto.getRandomValues(array);
402
+ } else if (typeof globalThis !== "undefined" && globalThis.crypto) {
403
+ globalThis.crypto.getRandomValues(array);
404
+ } else {
405
+ throw new Error("crypto.getRandomValues is not available. Please use Node.js 19+ or a modern browser.");
406
+ }
407
+ return base64UrlEncode(array);
408
+ }
409
+ function base64UrlEncode(array) {
410
+ let base64 = "";
411
+ if (typeof Buffer !== "undefined") {
412
+ base64 = Buffer.from(array).toString("base64");
413
+ } else {
414
+ const binary = String.fromCharCode(...array);
415
+ base64 = btoa(binary);
416
+ }
417
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
418
+ }
419
+
420
+ // src/oauth/window-manager.ts
421
+ function isBrowser() {
422
+ return typeof window !== "undefined" && typeof window.document !== "undefined";
423
+ }
424
+
425
+ class OAuthWindowManager {
426
+ popupWindow = null;
427
+ popupCheckInterval = null;
428
+ openPopup(url, options) {
429
+ if (!isBrowser()) {
430
+ throw new Error("OAuthWindowManager.openPopup() can only be used in browser environments");
431
+ }
432
+ const width = options?.width || 600;
433
+ const height = options?.height || 700;
434
+ const left = window.screenX + (window.outerWidth - width) / 2;
435
+ const top = window.screenY + (window.outerHeight - height) / 2;
436
+ const features = [
437
+ `width=${width}`,
438
+ `height=${height}`,
439
+ `left=${left}`,
440
+ `top=${top}`,
441
+ "toolbar=no",
442
+ "location=no",
443
+ "directories=no",
444
+ "status=no",
445
+ "menubar=no",
446
+ "scrollbars=yes",
447
+ "resizable=yes",
448
+ "copyhistory=no"
449
+ ].join(",");
450
+ this.popupWindow = window.open(url, "oauth_popup", features);
451
+ if (!this.popupWindow) {
452
+ console.warn("Popup was blocked by the browser. Please allow popups for this site.");
453
+ return null;
454
+ }
455
+ this.popupWindow.focus();
456
+ return this.popupWindow;
457
+ }
458
+ openRedirect(url) {
459
+ if (!isBrowser()) {
460
+ throw new Error("OAuthWindowManager.openRedirect() can only be used in browser environments");
461
+ }
462
+ window.location.href = url;
463
+ }
464
+ listenForCallback(mode, timeoutMs = 5 * 60 * 1000) {
465
+ if (mode === "popup") {
466
+ return this.listenForPopupCallback(timeoutMs);
467
+ } else {
468
+ return this.listenForRedirectCallback();
469
+ }
470
+ }
471
+ listenForPopupCallback(timeoutMs) {
472
+ if (!isBrowser()) {
473
+ return Promise.reject(new Error("OAuth popup callback can only be used in browser environments"));
474
+ }
475
+ return new Promise((resolve, reject) => {
476
+ const timeout = setTimeout(() => {
477
+ this.cleanup();
478
+ reject(new Error("OAuth authorization timed out"));
479
+ }, timeoutMs);
480
+ const messageHandler = (event) => {
481
+ if (event.data && event.data.type === "oauth_callback") {
482
+ clearTimeout(timeout);
483
+ window.removeEventListener("message", messageHandler);
484
+ const { code, state, error } = event.data;
485
+ if (error) {
486
+ this.cleanup();
487
+ reject(new Error(`OAuth error: ${error}`));
488
+ return;
489
+ }
490
+ if (!code || !state) {
491
+ this.cleanup();
492
+ reject(new Error("Invalid OAuth callback: missing code or state"));
493
+ return;
494
+ }
495
+ this.cleanup();
496
+ resolve({ code, state });
497
+ }
498
+ };
499
+ window.addEventListener("message", messageHandler);
500
+ this.popupCheckInterval = setInterval(() => {
501
+ if (this.popupWindow?.closed) {
502
+ clearTimeout(timeout);
503
+ clearInterval(this.popupCheckInterval);
504
+ window.removeEventListener("message", messageHandler);
505
+ this.cleanup();
506
+ reject(new Error("OAuth popup was closed by user"));
507
+ }
508
+ }, 500);
509
+ });
510
+ }
511
+ listenForRedirectCallback() {
512
+ if (!isBrowser()) {
513
+ return Promise.reject(new Error("OAuth redirect callback can only be used in browser environments"));
514
+ }
515
+ return new Promise((resolve, reject) => {
516
+ const params = new URLSearchParams(window.location.search);
517
+ const code = params.get("code");
518
+ const state = params.get("state");
519
+ const error = params.get("error");
520
+ const errorDescription = params.get("error_description");
521
+ if (error) {
522
+ const errorMsg = errorDescription || error;
523
+ reject(new Error(`OAuth error: ${errorMsg}`));
524
+ return;
525
+ }
526
+ if (!code || !state) {
527
+ reject(new Error("Invalid OAuth callback: missing code or state in URL"));
528
+ return;
529
+ }
530
+ resolve({ code, state });
531
+ });
532
+ }
533
+ cleanup() {
534
+ if (this.popupWindow && !this.popupWindow.closed) {
535
+ this.popupWindow.close();
536
+ }
537
+ this.popupWindow = null;
538
+ if (this.popupCheckInterval) {
539
+ clearInterval(this.popupCheckInterval);
540
+ this.popupCheckInterval = null;
541
+ }
542
+ }
543
+ close() {
544
+ this.cleanup();
545
+ }
546
+ }
547
+ function sendCallbackToOpener(params) {
548
+ if (!isBrowser()) {
549
+ console.error("sendCallbackToOpener() can only be used in browser environments");
550
+ return;
551
+ }
552
+ if (!window.opener) {
553
+ console.error("No opener window found. This function should only be called from a popup window.");
554
+ return;
555
+ }
556
+ window.opener.postMessage({
557
+ type: "oauth_callback",
558
+ code: params.code,
559
+ state: params.state,
560
+ error: params.error
561
+ }, "*");
562
+ window.close();
563
+ }
564
+
565
+ // src/oauth/manager.ts
566
+ class OAuthManager {
567
+ pendingAuths = new Map;
568
+ sessionToken;
569
+ windowManager;
570
+ flowConfig;
571
+ serverUrl;
572
+ constructor(serverUrl, flowConfig) {
573
+ this.serverUrl = serverUrl;
574
+ this.windowManager = new OAuthWindowManager;
575
+ this.flowConfig = {
576
+ mode: flowConfig?.mode || "redirect",
577
+ popupOptions: flowConfig?.popupOptions,
578
+ onAuthCallback: flowConfig?.onAuthCallback
579
+ };
580
+ }
581
+ async initiateFlow(provider, config) {
582
+ const codeVerifier = generateCodeVerifier();
583
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
584
+ const state = generateState();
585
+ const pendingAuth = {
586
+ provider,
587
+ state,
588
+ codeVerifier,
589
+ codeChallenge,
590
+ scopes: config.scopes,
591
+ redirectUri: config.redirectUri,
592
+ initiatedAt: Date.now()
593
+ };
594
+ this.pendingAuths.set(state, pendingAuth);
595
+ const authUrl = await this.getAuthorizationUrl(provider, config, state, codeChallenge);
596
+ if (this.flowConfig.mode === "popup") {
597
+ this.windowManager.openPopup(authUrl, this.flowConfig.popupOptions);
598
+ try {
599
+ const callbackParams = await this.windowManager.listenForCallback("popup");
600
+ await this.handleCallback(callbackParams.code, callbackParams.state);
601
+ } catch (error) {
602
+ this.pendingAuths.delete(state);
603
+ throw error;
604
+ }
605
+ } else {
606
+ this.windowManager.openRedirect(authUrl);
607
+ }
608
+ }
609
+ async handleCallback(code, state) {
610
+ const pendingAuth = this.pendingAuths.get(state);
611
+ if (!pendingAuth) {
612
+ throw new Error("Invalid state parameter: no matching OAuth flow found");
613
+ }
614
+ const fiveMinutes = 5 * 60 * 1000;
615
+ if (Date.now() - pendingAuth.initiatedAt > fiveMinutes) {
616
+ this.pendingAuths.delete(state);
617
+ throw new Error("OAuth flow expired: please try again");
618
+ }
619
+ if (this.flowConfig.onAuthCallback) {
620
+ try {
621
+ await this.flowConfig.onAuthCallback(pendingAuth.provider, code, state);
622
+ } catch (error) {
623
+ console.error("Custom OAuth callback handler failed:", error);
624
+ }
625
+ }
626
+ try {
627
+ const response = await this.exchangeCodeForToken(pendingAuth.provider, code, pendingAuth.codeVerifier, state);
628
+ this.sessionToken = response.sessionToken;
629
+ this.pendingAuths.delete(state);
630
+ return response.sessionToken;
631
+ } catch (error) {
632
+ this.pendingAuths.delete(state);
633
+ throw error;
634
+ }
635
+ }
636
+ async checkAuthStatus(provider) {
637
+ if (!this.sessionToken) {
638
+ return {
639
+ authorized: false,
640
+ provider
641
+ };
642
+ }
643
+ try {
644
+ const url = new URL("/oauth/status", this.serverUrl);
645
+ url.searchParams.set("provider", provider);
646
+ const response = await fetch(url.toString(), {
647
+ method: "GET",
648
+ headers: {
649
+ "X-Session-Token": this.sessionToken
650
+ }
651
+ });
652
+ if (!response.ok) {
653
+ return {
654
+ authorized: false,
655
+ provider
656
+ };
657
+ }
658
+ const status = await response.json();
659
+ return status;
660
+ } catch (error) {
661
+ console.error("Failed to check auth status:", error);
662
+ return {
663
+ authorized: false,
664
+ provider
665
+ };
666
+ }
667
+ }
668
+ getSessionToken() {
669
+ return this.sessionToken;
670
+ }
671
+ setSessionToken(token) {
672
+ this.sessionToken = token;
673
+ }
674
+ clearSessionToken() {
675
+ this.sessionToken = undefined;
676
+ }
677
+ async getAuthorizationUrl(provider, config, state, codeChallenge) {
678
+ const url = new URL("/oauth/authorize", this.serverUrl);
679
+ url.searchParams.set("provider", provider);
680
+ url.searchParams.set("client_id", config.clientId || "");
681
+ url.searchParams.set("scope", config.scopes.join(","));
682
+ url.searchParams.set("state", state);
683
+ url.searchParams.set("code_challenge", codeChallenge);
684
+ url.searchParams.set("code_challenge_method", "S256");
685
+ if (config.redirectUri) {
686
+ url.searchParams.set("redirect_uri", config.redirectUri);
687
+ }
688
+ const response = await fetch(url.toString(), {
689
+ method: "GET"
690
+ });
691
+ if (!response.ok) {
692
+ const error = await response.text();
693
+ throw new Error(`Failed to get authorization URL: ${error}`);
694
+ }
695
+ const data = await response.json();
696
+ return data.authorizationUrl;
697
+ }
698
+ async exchangeCodeForToken(provider, code, codeVerifier, state) {
699
+ const url = new URL("/oauth/callback", this.serverUrl);
700
+ const response = await fetch(url.toString(), {
701
+ method: "POST",
702
+ headers: {
703
+ "Content-Type": "application/json"
704
+ },
705
+ body: JSON.stringify({
706
+ provider,
707
+ code,
708
+ code_verifier: codeVerifier,
709
+ state
710
+ })
711
+ });
712
+ if (!response.ok) {
713
+ const error = await response.text();
714
+ throw new Error(`Failed to exchange code for token: ${error}`);
715
+ }
716
+ const data = await response.json();
717
+ return data;
718
+ }
719
+ close() {
720
+ this.windowManager.close();
721
+ }
722
+ }
723
+
364
724
  // src/client.ts
365
725
  var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
366
726
  var clientCache = new Map;
@@ -379,6 +739,7 @@ class MCPClient {
379
739
  authState = new Map;
380
740
  connectionMode;
381
741
  connecting = null;
742
+ oauthManager;
382
743
  github;
383
744
  gmail;
384
745
  server;
@@ -396,6 +757,11 @@ class MCPClient {
396
757
  this.onReauthRequired = config.onReauthRequired;
397
758
  this.maxReauthRetries = config.maxReauthRetries ?? 1;
398
759
  this.connectionMode = config.connectionMode ?? "lazy";
760
+ this.oauthManager = new OAuthManager(MCP_SERVER_URL, config.oauthFlow);
761
+ if (config.sessionToken) {
762
+ this.oauthManager.setSessionToken(config.sessionToken);
763
+ this.transport.setHeader("X-Session-Token", config.sessionToken);
764
+ }
399
765
  for (const plugin of this.plugins) {
400
766
  for (const toolName of plugin.tools) {
401
767
  this.enabledToolNames.add(toolName);
@@ -631,6 +997,49 @@ class MCPClient {
631
997
  isProviderAuthenticated(provider) {
632
998
  return this.authState.get(provider)?.authenticated ?? false;
633
999
  }
1000
+ async isAuthorized(provider) {
1001
+ const status = await this.oauthManager.checkAuthStatus(provider);
1002
+ return status.authorized;
1003
+ }
1004
+ async authorizedProviders() {
1005
+ const authorized = [];
1006
+ for (const plugin of this.plugins) {
1007
+ if (plugin.oauth) {
1008
+ const status = await this.oauthManager.checkAuthStatus(plugin.oauth.provider);
1009
+ if (status.authorized) {
1010
+ authorized.push(plugin.oauth.provider);
1011
+ }
1012
+ }
1013
+ }
1014
+ return authorized;
1015
+ }
1016
+ async getAuthorizationStatus(provider) {
1017
+ return await this.oauthManager.checkAuthStatus(provider);
1018
+ }
1019
+ async authorize(provider) {
1020
+ const plugin = this.plugins.find((p) => p.oauth?.provider === provider);
1021
+ if (!plugin?.oauth) {
1022
+ throw new Error(`No OAuth configuration found for provider: ${provider}`);
1023
+ }
1024
+ await this.oauthManager.initiateFlow(provider, plugin.oauth);
1025
+ this.authState.set(provider, { authenticated: true });
1026
+ }
1027
+ async handleOAuthCallback(params) {
1028
+ const sessionToken = await this.oauthManager.handleCallback(params.code, params.state);
1029
+ this.transport.setHeader("X-Session-Token", sessionToken);
1030
+ for (const plugin of this.plugins) {
1031
+ if (plugin.oauth) {
1032
+ this.authState.set(plugin.oauth.provider, { authenticated: true });
1033
+ }
1034
+ }
1035
+ }
1036
+ getSessionToken() {
1037
+ return this.oauthManager.getSessionToken();
1038
+ }
1039
+ setSessionToken(token) {
1040
+ this.oauthManager.setSessionToken(token);
1041
+ this.transport.setHeader("X-Session-Token", token);
1042
+ }
634
1043
  async reauthenticate(provider) {
635
1044
  const state = this.authState.get(provider);
636
1045
  if (!state) {
@@ -880,6 +1289,7 @@ function getVercelAITools(client) {
880
1289
  return convertMCPToolsToVercelAI(client);
881
1290
  }
882
1291
  export {
1292
+ sendCallbackToOpener,
883
1293
  parseServerError,
884
1294
  isTokenExpiredError,
885
1295
  isAuthorizationError,
@@ -888,6 +1298,9 @@ export {
888
1298
  githubPlugin,
889
1299
  getVercelAITools,
890
1300
  genericOAuthPlugin,
1301
+ generateState,
1302
+ generateCodeVerifier,
1303
+ generateCodeChallenge,
891
1304
  createSimplePlugin,
892
1305
  createMCPClient,
893
1306
  convertMCPToolsToVercelAI,
@@ -895,6 +1308,8 @@ export {
895
1308
  clearClientCache,
896
1309
  ToolCallError,
897
1310
  TokenExpiredError,
1311
+ OAuthWindowManager,
1312
+ OAuthManager,
898
1313
  MCPMethod,
899
1314
  MCPClient,
900
1315
  IntegrateSDKError,
@@ -0,0 +1,91 @@
1
+ /**
2
+ * OAuth Manager
3
+ * Orchestrates OAuth 2.0 Authorization Code Flow with PKCE
4
+ */
5
+ import type { OAuthConfig } from "../plugins/types.js";
6
+ import type { OAuthFlowConfig, AuthStatus } from "./types.js";
7
+ /**
8
+ * OAuth Manager
9
+ * Handles OAuth authorization flows and token management
10
+ */
11
+ export declare class OAuthManager {
12
+ private pendingAuths;
13
+ private sessionToken?;
14
+ private windowManager;
15
+ private flowConfig;
16
+ private serverUrl;
17
+ constructor(serverUrl: string, flowConfig?: Partial<OAuthFlowConfig>);
18
+ /**
19
+ * Initiate OAuth authorization flow
20
+ *
21
+ * @param provider - OAuth provider (github, gmail, etc.)
22
+ * @param config - OAuth configuration
23
+ * @returns Promise that resolves when authorization is complete
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * await oauthManager.initiateFlow('github', {
28
+ * provider: 'github',
29
+ * clientId: 'abc123',
30
+ * clientSecret: 'secret',
31
+ * scopes: ['repo', 'user']
32
+ * });
33
+ * ```
34
+ */
35
+ initiateFlow(provider: string, config: OAuthConfig): Promise<void>;
36
+ /**
37
+ * Handle OAuth callback
38
+ * Call this after user authorizes (from your callback page)
39
+ *
40
+ * @param code - Authorization code from OAuth provider
41
+ * @param state - State parameter for verification
42
+ * @returns Session token for authenticated requests
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * // In your callback route
47
+ * const sessionToken = await oauthManager.handleCallback(code, state);
48
+ * ```
49
+ */
50
+ handleCallback(code: string, state: string): Promise<string>;
51
+ /**
52
+ * Check authorization status for a provider
53
+ *
54
+ * @param provider - OAuth provider to check
55
+ * @returns Authorization status
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const status = await oauthManager.checkAuthStatus('github');
60
+ * if (status.authorized) {
61
+ * console.log('GitHub is authorized');
62
+ * }
63
+ * ```
64
+ */
65
+ checkAuthStatus(provider: string): Promise<AuthStatus>;
66
+ /**
67
+ * Get session token
68
+ */
69
+ getSessionToken(): string | undefined;
70
+ /**
71
+ * Set session token (for manual token management)
72
+ */
73
+ setSessionToken(token: string): void;
74
+ /**
75
+ * Clear session token
76
+ */
77
+ clearSessionToken(): void;
78
+ /**
79
+ * Request authorization URL from MCP server
80
+ */
81
+ private getAuthorizationUrl;
82
+ /**
83
+ * Exchange authorization code for session token
84
+ */
85
+ private exchangeCodeForToken;
86
+ /**
87
+ * Close any open OAuth windows
88
+ */
89
+ close(): void;
90
+ }
91
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/oauth/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EACV,eAAe,EAEf,UAAU,EAGX,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,SAAS,CAAS;gBAGxB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAWvC;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCxE;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA8ClE;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAqC5D;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,SAAS;IAIrC;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;YACW,mBAAmB;IA+BjC;;OAEG;YACW,oBAAoB;IA8BlC;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * PKCE Utilities
3
+ * Proof Key for Code Exchange (RFC 7636) implementation
4
+ *
5
+ * PKCE enhances OAuth 2.0 security by preventing authorization code interception attacks.
6
+ * It's especially important for public clients (browser/mobile apps).
7
+ */
8
+ /**
9
+ * Generate a cryptographically secure random code verifier
10
+ * Must be 43-128 characters long, using [A-Z] [a-z] [0-9] - . _ ~
11
+ *
12
+ * @returns A random code verifier string
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const verifier = generateCodeVerifier();
17
+ * // Returns: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
18
+ * ```
19
+ */
20
+ export declare function generateCodeVerifier(): string;
21
+ /**
22
+ * Generate code challenge from verifier using SHA-256
23
+ *
24
+ * @param verifier - The code verifier to hash
25
+ * @returns A Promise resolving to the base64url-encoded SHA-256 hash
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const verifier = generateCodeVerifier();
30
+ * const challenge = await generateCodeChallenge(verifier);
31
+ * // Returns: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
32
+ * ```
33
+ */
34
+ export declare function generateCodeChallenge(verifier: string): Promise<string>;
35
+ /**
36
+ * Generate a random state parameter for CSRF protection
37
+ *
38
+ * @returns A random state string
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const state = generateState();
43
+ * // Returns: "xyzABC123"
44
+ * ```
45
+ */
46
+ export declare function generateState(): string;
47
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAgB7C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAatC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * OAuth Flow Types
3
+ * Type definitions for OAuth 2.0 Authorization Code Flow with PKCE
4
+ */
5
+ /**
6
+ * Popup window options for OAuth flow
7
+ */
8
+ export interface PopupOptions {
9
+ /** Window width in pixels (default: 600) */
10
+ width?: number;
11
+ /** Window height in pixels (default: 700) */
12
+ height?: number;
13
+ }
14
+ /**
15
+ * OAuth flow configuration
16
+ */
17
+ export interface OAuthFlowConfig {
18
+ /** How to display OAuth authorization */
19
+ mode: 'popup' | 'redirect';
20
+ /** Popup window dimensions (only for popup mode) */
21
+ popupOptions?: PopupOptions;
22
+ /** Custom callback handler for receiving auth code */
23
+ onAuthCallback?: (provider: string, code: string, state: string) => Promise<void>;
24
+ }
25
+ /**
26
+ * Authorization status for a provider
27
+ */
28
+ export interface AuthStatus {
29
+ /** Whether the provider is authorized */
30
+ authorized: boolean;
31
+ /** The provider name */
32
+ provider: string;
33
+ /** Authorized scopes */
34
+ scopes?: string[];
35
+ /** Token expiration time */
36
+ expiresAt?: string;
37
+ }
38
+ /**
39
+ * Pending OAuth authorization
40
+ * Tracks in-progress OAuth flows
41
+ */
42
+ export interface PendingAuth {
43
+ /** OAuth provider (github, gmail, etc.) */
44
+ provider: string;
45
+ /** CSRF protection state */
46
+ state: string;
47
+ /** PKCE code verifier */
48
+ codeVerifier: string;
49
+ /** PKCE code challenge */
50
+ codeChallenge: string;
51
+ /** OAuth scopes being requested */
52
+ scopes: string[];
53
+ /** Redirect URI */
54
+ redirectUri?: string;
55
+ /** Timestamp when auth was initiated */
56
+ initiatedAt: number;
57
+ }
58
+ /**
59
+ * OAuth authorization URL response from server
60
+ */
61
+ export interface AuthorizationUrlResponse {
62
+ /** The full authorization URL to redirect user to */
63
+ authorizationUrl: string;
64
+ }
65
+ /**
66
+ * OAuth callback response from server
67
+ * Contains session token after successful authorization
68
+ */
69
+ export interface OAuthCallbackResponse {
70
+ /** Session token for authenticated requests */
71
+ sessionToken: string;
72
+ /** Token expiration time */
73
+ expiresAt?: string;
74
+ }
75
+ /**
76
+ * Parameters for OAuth callback
77
+ */
78
+ export interface OAuthCallbackParams {
79
+ /** Authorization code from OAuth provider */
80
+ code: string;
81
+ /** State parameter for CSRF protection */
82
+ state: string;
83
+ }
84
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/oauth/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,yCAAyC;IACzC,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;IAC3B,oDAAoD;IACpD,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,sDAAsD;IACtD,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnF;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,UAAU,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * OAuth Window Manager
3
+ * Handles OAuth authorization UI (popup windows and redirects)
4
+ */
5
+ import type { PopupOptions, OAuthCallbackParams } from "./types.js";
6
+ /**
7
+ * OAuth Window Manager
8
+ * Manages popup windows and redirect flows for OAuth authorization
9
+ *
10
+ * Note: This class should only be used in browser environments.
11
+ * Server-side usage will throw errors.
12
+ */
13
+ export declare class OAuthWindowManager {
14
+ private popupWindow;
15
+ private popupCheckInterval;
16
+ /**
17
+ * Open OAuth authorization in a popup window
18
+ *
19
+ * @param url - The authorization URL to open
20
+ * @param options - Popup window dimensions
21
+ * @returns The opened popup window or null if blocked
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const manager = new OAuthWindowManager();
26
+ * const popup = manager.openPopup(authUrl, { width: 600, height: 700 });
27
+ * ```
28
+ */
29
+ openPopup(url: string, options?: PopupOptions): Window | null;
30
+ /**
31
+ * Redirect current window to OAuth authorization URL
32
+ *
33
+ * @param url - The authorization URL to redirect to
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const manager = new OAuthWindowManager();
38
+ * manager.openRedirect(authUrl);
39
+ * ```
40
+ */
41
+ openRedirect(url: string): void;
42
+ /**
43
+ * Listen for OAuth callback
44
+ * For popup: listens for postMessage from callback page
45
+ * For redirect: parses URL parameters after redirect back
46
+ *
47
+ * @param mode - The OAuth flow mode ('popup' or 'redirect')
48
+ * @param timeoutMs - Timeout in milliseconds (default: 5 minutes)
49
+ * @returns Promise resolving to callback parameters (code and state)
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // For popup flow
54
+ * const params = await manager.listenForCallback('popup');
55
+ *
56
+ * // For redirect flow (after redirect back)
57
+ * const params = await manager.listenForCallback('redirect');
58
+ * ```
59
+ */
60
+ listenForCallback(mode: 'popup' | 'redirect', timeoutMs?: number): Promise<OAuthCallbackParams>;
61
+ /**
62
+ * Listen for callback from popup window via postMessage
63
+ */
64
+ private listenForPopupCallback;
65
+ /**
66
+ * Parse callback parameters from current URL (for redirect flow)
67
+ */
68
+ private listenForRedirectCallback;
69
+ /**
70
+ * Clean up popup window and intervals
71
+ */
72
+ private cleanup;
73
+ /**
74
+ * Close any open popup windows
75
+ * Call this when aborting the OAuth flow
76
+ */
77
+ close(): void;
78
+ }
79
+ /**
80
+ * Helper function to send callback data from callback page to opener window
81
+ * Call this in your OAuth callback page
82
+ *
83
+ * @param params - The callback parameters from URL
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * // In your callback page (e.g., /oauth/callback.html)
88
+ * import { sendCallbackToOpener } from '@integrate/sdk';
89
+ *
90
+ * const params = new URLSearchParams(window.location.search);
91
+ * sendCallbackToOpener({
92
+ * code: params.get('code'),
93
+ * state: params.get('state'),
94
+ * error: params.get('error')
95
+ * });
96
+ * ```
97
+ */
98
+ export declare function sendCallbackToOpener(params: {
99
+ code: string | null;
100
+ state: string | null;
101
+ error?: string | null;
102
+ }): void;
103
+ //# sourceMappingURL=window-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window-manager.d.ts","sourceRoot":"","sources":["../../src/oauth/window-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AASpE;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,kBAAkB,CAA+C;IAEzE;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAwC7D;;;;;;;;;;OAUG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQ/B;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,CACf,IAAI,EAAE,OAAO,GAAG,UAAU,EAC1B,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAQ/B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAuD9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA4BjC;;OAEG;IACH,OAAO,CAAC,OAAO;IAYf;;;OAGG;IACH,KAAK,IAAI,IAAI;CAGd;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,IAAI,CAwBP"}
@@ -63,5 +63,28 @@ export declare class HttpSessionTransport {
63
63
  * Get current session ID
64
64
  */
65
65
  getSessionId(): string | undefined;
66
+ /**
67
+ * Set a custom header for all requests
68
+ * Used for session tokens and other auth headers
69
+ *
70
+ * @param key - Header name
71
+ * @param value - Header value
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * transport.setHeader('X-Session-Token', 'abc123');
76
+ * ```
77
+ */
78
+ setHeader(key: string, value: string): void;
79
+ /**
80
+ * Remove a custom header
81
+ *
82
+ * @param key - Header name to remove
83
+ */
84
+ removeHeader(key: string): void;
85
+ /**
86
+ * Get all current headers
87
+ */
88
+ getHeaders(): Record<string, string>;
66
89
  }
67
90
  //# sourceMappingURL=http-session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-session.d.ts","sourceRoot":"","sources":["../../src/transport/http-session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,eAAe,GAAG,mBAAmB,KAC3C,IAAI,CAAC;AAEV,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAC,CAAkB;IACxC,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,2BAA2B;IAMhD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACG,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3B,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,CAAC,CAAC;IAsFb;;OAEG;YACW,gBAAgB;IAiC9B;;OAEG;YACW,gBAAgB;IAiC9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,IAAI;IAS9C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBjC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;CAGnC"}
1
+ {"version":3,"file":"http-session.d.ts","sourceRoot":"","sources":["../../src/transport/http-session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,eAAe,GAAG,mBAAmB,KAC3C,IAAI,CAAC;AAEV,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAC,CAAkB;IACxC,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,2BAA2B;IAMhD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACG,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3B,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,CAAC,CAAC;IAsFb;;OAEG;YACW,gBAAgB;IAiC9B;;OAEG;YACW,gBAAgB;IAiC9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,IAAI;IAS9C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBjC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;IAIlC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI3C;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAGrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "integrate-sdk",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Type-safe TypeScript SDK for MCP Client with plugin-based OAuth provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,11 +28,11 @@
28
28
  "build:types": "tsc --emitDeclarationOnly --declaration --declarationMap",
29
29
  "dev": "bun --watch src/index.ts",
30
30
  "type-check": "tsc --noEmit",
31
- "test": "bun test tests/protocol tests/plugins tests/client tests/integrations tests/integration/simple-integration.test.ts",
32
- "test:watch": "bun test --watch tests/protocol tests/plugins tests/client tests/integrations tests/integration/simple-integration.test.ts",
33
- "test:unit": "bun test tests/protocol tests/plugins tests/client tests/integrations",
31
+ "test": "bun test tests/",
32
+ "test:watch": "bun test --watch tests/",
33
+ "test:unit": "bun test tests/protocol tests/plugins tests/client tests/integrations tests/oauth tests/transport tests/utils tests/errors",
34
34
  "test:integration": "bun test tests/integration/simple-integration.test.ts",
35
- "test:coverage": "bun test --coverage tests/protocol tests/plugins tests/client tests/integrations tests/integration/simple-integration.test.ts",
35
+ "test:coverage": "bun test --coverage tests/",
36
36
  "prepare": "simple-git-hooks"
37
37
  },
38
38
  "keywords": [