@ai-sdk/mcp 1.0.69 → 1.0.71
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/CHANGELOG.md +15 -0
- package/dist/index.js +52 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +52 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/tool/mcp-http-transport.ts +20 -6
- package/src/tool/mcp-sse-transport.ts +9 -3
- package/src/tool/oauth.ts +52 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.71",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"pkce-challenge": "^5.0.0",
|
|
36
36
|
"@ai-sdk/provider": "3.0.15",
|
|
37
|
-
"@ai-sdk/provider-utils": "4.0.
|
|
37
|
+
"@ai-sdk/provider-utils": "4.0.46"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "20.17.24",
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import type { MCPTransport } from './mcp-transport';
|
|
14
14
|
import { VERSION } from '../version';
|
|
15
15
|
import {
|
|
16
|
-
|
|
16
|
+
extractWWWAuthenticateParams,
|
|
17
17
|
UnauthorizedError,
|
|
18
18
|
auth,
|
|
19
19
|
type AuthResult,
|
|
@@ -113,7 +113,10 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
113
113
|
/**
|
|
114
114
|
* Runs a single OAuth recovery flow for concurrent 401 responses.
|
|
115
115
|
*/
|
|
116
|
-
private authorizeOnce(
|
|
116
|
+
private authorizeOnce(
|
|
117
|
+
resourceMetadataUrl?: URL,
|
|
118
|
+
scope?: string,
|
|
119
|
+
): Promise<AuthResult> {
|
|
117
120
|
if (!this.authProvider) {
|
|
118
121
|
return Promise.resolve('REDIRECT');
|
|
119
122
|
}
|
|
@@ -122,6 +125,7 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
122
125
|
this.authPromise = auth(this.authProvider, {
|
|
123
126
|
serverUrl: this.url,
|
|
124
127
|
resourceMetadataUrl,
|
|
128
|
+
scope,
|
|
125
129
|
fetchFn: this.fetchFn,
|
|
126
130
|
}).finally(() => {
|
|
127
131
|
this.authPromise = undefined;
|
|
@@ -201,9 +205,14 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
204
|
-
|
|
208
|
+
const { resourceMetadataUrl, scope } =
|
|
209
|
+
extractWWWAuthenticateParams(response);
|
|
210
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
205
211
|
try {
|
|
206
|
-
const result = await this.authorizeOnce(
|
|
212
|
+
const result = await this.authorizeOnce(
|
|
213
|
+
this.resourceMetadataUrl,
|
|
214
|
+
scope,
|
|
215
|
+
);
|
|
207
216
|
if (result !== 'AUTHORIZED') {
|
|
208
217
|
const error = new UnauthorizedError();
|
|
209
218
|
throw error;
|
|
@@ -412,9 +421,14 @@ export class HttpMCPTransport implements MCPTransport {
|
|
|
412
421
|
}
|
|
413
422
|
|
|
414
423
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
415
|
-
|
|
424
|
+
const { resourceMetadataUrl, scope } =
|
|
425
|
+
extractWWWAuthenticateParams(response);
|
|
426
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
416
427
|
try {
|
|
417
|
-
const result = await this.authorizeOnce(
|
|
428
|
+
const result = await this.authorizeOnce(
|
|
429
|
+
this.resourceMetadataUrl,
|
|
430
|
+
scope,
|
|
431
|
+
);
|
|
418
432
|
if (result !== 'AUTHORIZED') {
|
|
419
433
|
const error = new UnauthorizedError();
|
|
420
434
|
this.onerror?.(error);
|
|
@@ -9,7 +9,7 @@ import { parseJSONRPCMessage, type JSONRPCMessage } from './json-rpc-message';
|
|
|
9
9
|
import type { MCPTransport } from './mcp-transport';
|
|
10
10
|
import { VERSION } from '../version';
|
|
11
11
|
import {
|
|
12
|
-
|
|
12
|
+
extractWWWAuthenticateParams,
|
|
13
13
|
UnauthorizedError,
|
|
14
14
|
auth,
|
|
15
15
|
type OAuthClientProvider,
|
|
@@ -106,11 +106,14 @@ export class SseMCPTransport implements MCPTransport {
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
109
|
-
|
|
109
|
+
const { resourceMetadataUrl, scope } =
|
|
110
|
+
extractWWWAuthenticateParams(response);
|
|
111
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
110
112
|
try {
|
|
111
113
|
const result = await auth(this.authProvider, {
|
|
112
114
|
serverUrl: this.url,
|
|
113
115
|
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
116
|
+
scope,
|
|
114
117
|
fetchFn: this.fetchFn,
|
|
115
118
|
});
|
|
116
119
|
if (result !== 'AUTHORIZED') {
|
|
@@ -273,11 +276,14 @@ export class SseMCPTransport implements MCPTransport {
|
|
|
273
276
|
const response = await this.fetchFn(endpoint.href, init);
|
|
274
277
|
|
|
275
278
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
276
|
-
|
|
279
|
+
const { resourceMetadataUrl, scope } =
|
|
280
|
+
extractWWWAuthenticateParams(response);
|
|
281
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
277
282
|
try {
|
|
278
283
|
const result = await auth(this.authProvider, {
|
|
279
284
|
serverUrl: this.url,
|
|
280
285
|
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
286
|
+
scope,
|
|
281
287
|
fetchFn: this.fetchFn,
|
|
282
288
|
});
|
|
283
289
|
if (result !== 'AUTHORIZED') {
|
package/src/tool/oauth.ts
CHANGED
|
@@ -271,37 +271,65 @@ function assertAuthorizationServerInformationMatches({
|
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
export function extractResourceMetadataUrl(
|
|
279
|
-
response: Response,
|
|
280
|
-
): URL | undefined {
|
|
274
|
+
export function extractWWWAuthenticateParams(response: Response): {
|
|
275
|
+
resourceMetadataUrl?: URL;
|
|
276
|
+
scope?: string;
|
|
277
|
+
} {
|
|
281
278
|
const header =
|
|
282
279
|
response.headers.get('www-authenticate') ??
|
|
283
280
|
response.headers.get('WWW-Authenticate');
|
|
284
281
|
if (!header) {
|
|
285
|
-
return
|
|
282
|
+
return {};
|
|
286
283
|
}
|
|
287
284
|
|
|
288
285
|
const [type, scheme] = header.split(' ');
|
|
289
|
-
if (type.toLowerCase() !== 'bearer' || !scheme) {
|
|
290
|
-
return
|
|
286
|
+
if (type.replace(/,$/, '').toLowerCase() !== 'bearer' || !scheme) {
|
|
287
|
+
return {};
|
|
291
288
|
}
|
|
292
289
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
return undefined;
|
|
298
|
-
}
|
|
290
|
+
const resourceMetadataMatch = header.match(
|
|
291
|
+
/(?:^|[,\s])resource_metadata="([^"]*)"/i,
|
|
292
|
+
);
|
|
293
|
+
const scope = header.match(/(?:^|[,\s])scope="([^"]*)"/i)?.[1];
|
|
299
294
|
|
|
295
|
+
let resourceMetadataUrl: URL | undefined;
|
|
300
296
|
try {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
297
|
+
resourceMetadataUrl = resourceMetadataMatch
|
|
298
|
+
? new URL(resourceMetadataMatch[1])
|
|
299
|
+
: undefined;
|
|
300
|
+
} catch {}
|
|
301
|
+
|
|
302
|
+
return { resourceMetadataUrl, scope };
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Extracts the OAuth 2.0 Protected Resource Metadata URL from a WWW-Authenticate header (RFC9728).
|
|
307
|
+
*/
|
|
308
|
+
export function extractResourceMetadataUrl(
|
|
309
|
+
response: Response,
|
|
310
|
+
): URL | undefined {
|
|
311
|
+
return extractWWWAuthenticateParams(response).resourceMetadataUrl;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function selectScope({
|
|
315
|
+
scope,
|
|
316
|
+
resourceMetadata,
|
|
317
|
+
clientMetadata,
|
|
318
|
+
}: {
|
|
319
|
+
scope?: string;
|
|
320
|
+
resourceMetadata?: OAuthProtectedResourceMetadata;
|
|
321
|
+
clientMetadata: OAuthClientMetadata;
|
|
322
|
+
}): string | undefined {
|
|
323
|
+
if (scope) {
|
|
324
|
+
return scope;
|
|
304
325
|
}
|
|
326
|
+
|
|
327
|
+
const resourceScopes = resourceMetadata?.scopes_supported?.join(' ');
|
|
328
|
+
if (resourceScopes) {
|
|
329
|
+
return resourceScopes;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return clientMetadata.scope;
|
|
305
333
|
}
|
|
306
334
|
|
|
307
335
|
/**
|
|
@@ -1309,7 +1337,11 @@ async function authInternal(
|
|
|
1309
1337
|
clientInformation,
|
|
1310
1338
|
state,
|
|
1311
1339
|
redirectUrl: provider.redirectUrl,
|
|
1312
|
-
scope:
|
|
1340
|
+
scope: selectScope({
|
|
1341
|
+
scope,
|
|
1342
|
+
resourceMetadata,
|
|
1343
|
+
clientMetadata: provider.clientMetadata,
|
|
1344
|
+
}),
|
|
1313
1345
|
resource,
|
|
1314
1346
|
},
|
|
1315
1347
|
);
|