@ai-sdk/mcp 1.0.48 → 1.0.50

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/mcp",
3
- "version": "1.0.48",
3
+ "version": "1.0.50",
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.10",
37
- "@ai-sdk/provider-utils": "4.0.28"
37
+ "@ai-sdk/provider-utils": "4.0.29"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "20.17.24",
@@ -42,8 +42,8 @@
42
42
  "typescript": "5.8.3",
43
43
  "vitest": "^4.1.0",
44
44
  "zod": "3.25.76",
45
- "@vercel/ai-tsconfig": "0.0.0",
46
- "@ai-sdk/test-server": "1.0.5"
45
+ "@ai-sdk/test-server": "1.0.5",
46
+ "@vercel/ai-tsconfig": "0.0.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "zod": "^3.25.76 || ^4.1.8"
@@ -610,7 +610,10 @@ class DefaultMCPClient implements MCPClient {
610
610
  _meta,
611
611
  } of definitions.tools) {
612
612
  const resolvedTitle = title ?? annotations?.title;
613
- if (schemas !== 'automatic' && !(name in schemas)) {
613
+ if (
614
+ schemas !== 'automatic' &&
615
+ !Object.prototype.hasOwnProperty.call(schemas, name)
616
+ ) {
614
617
  continue;
615
618
  }
616
619
 
@@ -161,14 +161,23 @@ export class SseMCPTransport implements MCPTransport {
161
161
  const { event, data } = value;
162
162
 
163
163
  if (event === 'endpoint') {
164
- this.endpoint = new URL(data, this.url);
164
+ if (this.endpoint) {
165
+ continue;
166
+ }
167
+
168
+ const endpoint = new URL(data, this.url);
165
169
 
166
- if (this.endpoint.origin !== this.url.origin) {
170
+ if (endpoint.origin !== this.url.origin) {
171
+ this.connected = false;
172
+ this.endpoint = undefined;
173
+ this.sseConnection?.close();
174
+ this.abortController?.abort();
167
175
  throw new MCPClientError({
168
- message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${this.endpoint.origin}`,
176
+ message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${endpoint.origin}`,
169
177
  });
170
178
  }
171
179
 
180
+ this.endpoint = endpoint;
172
181
  this.connected = true;
173
182
  resolve();
174
183
  } else if (event === 'message') {
@@ -217,6 +226,7 @@ export class SseMCPTransport implements MCPTransport {
217
226
 
218
227
  async close(): Promise<void> {
219
228
  this.connected = false;
229
+ this.endpoint = undefined;
220
230
  this.sseConnection?.close();
221
231
  this.abortController?.abort();
222
232
  this.onclose?.();
package/src/tool/oauth.ts CHANGED
@@ -443,23 +443,30 @@ export async function discoverOAuthProtectedResourceMetadata(
443
443
  */
444
444
  export function buildDiscoveryUrls(
445
445
  authorizationServerUrl: string | URL,
446
- ): { url: URL; type: 'oauth' | 'oidc' }[] {
446
+ ): { url: URL; type: 'oauth' | 'oidc'; expectedIssuer: string }[] {
447
447
  const url =
448
448
  typeof authorizationServerUrl === 'string'
449
449
  ? new URL(authorizationServerUrl)
450
450
  : authorizationServerUrl;
451
451
  const hasPath = url.pathname !== '/';
452
- const urlsToTry: { url: URL; type: 'oauth' | 'oidc' }[] = [];
452
+ const rootIssuer = url.origin;
453
+ const urlsToTry: {
454
+ url: URL;
455
+ type: 'oauth' | 'oidc';
456
+ expectedIssuer: string;
457
+ }[] = [];
453
458
 
454
459
  if (!hasPath) {
455
460
  urlsToTry.push({
456
461
  url: new URL('/.well-known/oauth-authorization-server', url.origin),
457
462
  type: 'oauth',
463
+ expectedIssuer: rootIssuer,
458
464
  });
459
465
 
460
466
  urlsToTry.push({
461
467
  url: new URL('/.well-known/openid-configuration', url.origin),
462
468
  type: 'oidc',
469
+ expectedIssuer: rootIssuer,
463
470
  });
464
471
 
465
472
  return urlsToTry;
@@ -469,6 +476,7 @@ export function buildDiscoveryUrls(
469
476
  if (pathname.endsWith('/')) {
470
477
  pathname = pathname.slice(0, -1);
471
478
  }
479
+ const pathIssuer = `${url.origin}${pathname}`;
472
480
 
473
481
  urlsToTry.push({
474
482
  url: new URL(
@@ -476,26 +484,41 @@ export function buildDiscoveryUrls(
476
484
  url.origin,
477
485
  ),
478
486
  type: 'oauth',
487
+ expectedIssuer: pathIssuer,
479
488
  });
480
489
 
481
490
  urlsToTry.push({
482
491
  url: new URL('/.well-known/oauth-authorization-server', url.origin),
483
492
  type: 'oauth',
493
+ expectedIssuer: rootIssuer,
484
494
  });
485
495
 
486
496
  urlsToTry.push({
487
497
  url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
488
498
  type: 'oidc',
499
+ expectedIssuer: pathIssuer,
489
500
  });
490
501
 
491
502
  urlsToTry.push({
492
503
  url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
493
504
  type: 'oidc',
505
+ expectedIssuer: pathIssuer,
494
506
  });
495
507
 
496
508
  return urlsToTry;
497
509
  }
498
510
 
511
+ function assertMetadataIssuerMatches(
512
+ metadata: AuthorizationServerMetadata,
513
+ expectedIssuer: string,
514
+ ): void {
515
+ if (metadata.issuer !== expectedIssuer) {
516
+ throw new MCPClientOAuthError({
517
+ message: `OAuth authorization server metadata issuer ${metadata.issuer} does not match expected issuer ${expectedIssuer}`,
518
+ });
519
+ }
520
+ }
521
+
499
522
  export async function discoverAuthorizationServerMetadata(
500
523
  authorizationServerUrl: string | URL,
501
524
  {
@@ -510,7 +533,7 @@ export async function discoverAuthorizationServerMetadata(
510
533
 
511
534
  const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
512
535
 
513
- for (const { url: endpointUrl, type } of urlsToTry) {
536
+ for (const { url: endpointUrl, type, expectedIssuer } of urlsToTry) {
514
537
  const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
515
538
 
516
539
  if (!response) {
@@ -532,11 +555,14 @@ export async function discoverAuthorizationServerMetadata(
532
555
  }
533
556
 
534
557
  if (type === 'oauth') {
535
- return OAuthMetadataSchema.parse(await response.json());
558
+ const metadata = OAuthMetadataSchema.parse(await response.json());
559
+ assertMetadataIssuerMatches(metadata, expectedIssuer);
560
+ return metadata;
536
561
  } else {
537
562
  const metadata = OpenIdProviderDiscoveryMetadataSchema.parse(
538
563
  await response.json(),
539
564
  );
565
+ assertMetadataIssuerMatches(metadata, expectedIssuer);
540
566
 
541
567
  // MCP spec requires OIDC providers to support S256 PKCE
542
568
  if (!metadata.code_challenge_methods_supported?.includes('S256')) {