@ai-sdk/mcp 2.0.71 → 2.0.73

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": "2.0.71",
3
+ "version": "2.0.73",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -31,8 +31,8 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@ai-sdk/provider": "4.0.25",
35
- "@ai-sdk/provider-utils": "5.0.57",
34
+ "@ai-sdk/provider": "4.0.26",
35
+ "@ai-sdk/provider-utils": "5.0.58",
36
36
  "cross-spawn": "^7.0.6",
37
37
  "pkce-challenge": "^5.0.1"
38
38
  },
package/src/index.ts CHANGED
@@ -48,7 +48,8 @@ export {
48
48
  export { MCPClientError } from './error/mcp-client-error';
49
49
  export type { ManagedMCPClient as Experimental_ManagedMCPClient } from './tool/mcp-client';
50
50
  export type {
51
- MCPEventsAdapter as Experimental_MCPEventsAdapter,
51
+ MCPEventOperations as Experimental_MCPEventOperations,
52
+ MCPEventAdapter as Experimental_MCPEventAdapter,
52
53
  ManagedSubscribeInput as Experimental_ManagedSubscribeInput,
53
54
  ManagedSubscription as Experimental_ManagedSubscription,
54
55
  ManagedMCPEvents as Experimental_ManagedMCPEvents,
@@ -16,8 +16,9 @@ import type { z } from 'zod/v4';
16
16
  import { createMCPEvents } from './mcp-events';
17
17
  import {
18
18
  createManagedMCPEvents,
19
+ validateMCPEventOperations,
19
20
  type ManagedMCPEvents,
20
- type MCPEventsAdapter,
21
+ type MCPEventAdapter,
21
22
  } from './mcp-events-adapter';
22
23
  import type { MCPEvents, MCPEventsConfig } from './mcp-event-types';
23
24
  import { MCPClientError } from '../error/mcp-client-error';
@@ -301,7 +302,9 @@ export type ManagedMCPClient = Omit<MCPClient, 'experimental_events'> & {
301
302
 
302
303
  export function createMCPClient(
303
304
  config: MCPClientConfig & {
304
- experimental_events: { adapter: MCPEventsAdapter };
305
+ experimental_events: {
306
+ adapter: MCPEventAdapter;
307
+ };
305
308
  },
306
309
  ): Promise<ManagedMCPClient>;
307
310
  export function createMCPClient(
@@ -486,6 +489,24 @@ class DefaultMCPClient implements Omit<MCPClient, 'experimental_events'> {
486
489
  'Configure experimental_events with either an adapter or a store, not both. Managed adapters own argument validation.',
487
490
  });
488
491
  }
492
+ if (
493
+ events?.adapter !== undefined &&
494
+ typeof events.adapter?.createAdapter !== 'function'
495
+ ) {
496
+ throw new MCPClientError({
497
+ message:
498
+ 'experimental_events.adapter must implement createAdapter. Wrap bound operations with { createAdapter: () => operations }.',
499
+ });
500
+ }
501
+ const operations = events?.adapter?.createAdapter({
502
+ transport: isCustomMcpTransport(transportConfig)
503
+ ? { type: 'custom' }
504
+ : { type: transportConfig.type, url: transportConfig.url },
505
+ });
506
+ if (events?.adapter !== undefined) {
507
+ validateMCPEventOperations(operations);
508
+ }
509
+
489
510
  this.onUncaughtError = onUncaughtError;
490
511
  this.maxRetries = prepareMaxRetries(maxRetries);
491
512
  this.clientCapabilities = capabilities ?? {};
@@ -527,8 +548,8 @@ class DefaultMCPClient implements Omit<MCPClient, 'experimental_events'> {
527
548
  store: events?.store,
528
549
  validateArguments: events?.validateArguments,
529
550
  });
530
- this.experimental_events = events?.adapter
531
- ? createManagedMCPEvents(events.adapter, directEvents.list)
551
+ this.experimental_events = operations
552
+ ? createManagedMCPEvents(operations, directEvents.list)
532
553
  : directEvents;
533
554
  }
534
555
 
@@ -1,5 +1,5 @@
1
1
  import type { JSONObject } from '@ai-sdk/provider';
2
- import type { MCPEventsAdapter } from './mcp-events-adapter';
2
+ import type { MCPEventAdapter } from './mcp-events-adapter';
3
3
  import { z } from 'zod/v4';
4
4
  import { ResultSchema, type RequestOptions } from './types';
5
5
 
@@ -112,7 +112,7 @@ export type MCPEventsConfig =
112
112
  }) => void | PromiseLike<void>;
113
113
  }
114
114
  | {
115
- adapter: MCPEventsAdapter;
115
+ adapter: MCPEventAdapter;
116
116
  store?: never;
117
117
  validateArguments?: never;
118
118
  };
@@ -1,4 +1,5 @@
1
1
  import type { JSONObject } from '@ai-sdk/provider';
2
+ import { MCPClientError } from '../error/mcp-client-error';
2
3
  import type { MCPEvents } from './mcp-event-types';
3
4
  import type { RequestOptions } from './types';
4
5
 
@@ -39,7 +40,7 @@ export type ManagedSubscribeInput = {
39
40
  * Implementations must honor request options and preserve actionable errors.
40
41
  * Cancelling a request does not cancel an already accepted remote subscription.
41
42
  */
42
- export interface MCPEventsAdapter {
43
+ export interface MCPEventOperations {
43
44
  subscribe(input: ManagedSubscribeInput): Promise<ManagedSubscription>;
44
45
 
45
46
  getSubscription(input: {
@@ -63,20 +64,69 @@ export interface MCPEventsAdapter {
63
64
  }): Promise<ManagedSubscription>;
64
65
  }
65
66
 
67
+ /**
68
+ * Creates bound subscription operations once per client, before the transport starts.
69
+ * Receives transport metadata, not credentials or a live transport instance.
70
+ * HTTP/SSE URLs are the configured endpoints, not resolved redirect targets.
71
+ * Custom transports have no standard URL and receive only their type.
72
+ */
73
+ export interface MCPEventAdapter {
74
+ createAdapter(context: {
75
+ transport: { type: 'http' | 'sse'; url: string } | { type: 'custom' };
76
+ }): MCPEventOperations;
77
+ }
78
+
79
+ /** Validate JavaScript integrations before opening the MCP transport. */
80
+ export function validateMCPEventOperations(
81
+ operations: unknown,
82
+ ): asserts operations is MCPEventOperations {
83
+ if (
84
+ operations != null &&
85
+ (typeof operations === 'object' || typeof operations === 'function') &&
86
+ 'then' in operations &&
87
+ typeof operations.then === 'function'
88
+ ) {
89
+ // Consume a rejected async factory result so the configuration error does
90
+ // not also cause an unhandled rejection. Async factories are not supported.
91
+ void Promise.resolve(operations).catch(() => {});
92
+ throw new MCPClientError({
93
+ message:
94
+ 'experimental_events.adapter.createAdapter() must return operations synchronously. Promise and thenable results are not supported.',
95
+ });
96
+ }
97
+ if (
98
+ typeof operations !== 'object' ||
99
+ operations === null ||
100
+ !('subscribe' in operations) ||
101
+ typeof operations.subscribe !== 'function' ||
102
+ !('getSubscription' in operations) ||
103
+ typeof operations.getSubscription !== 'function' ||
104
+ !('listSubscriptions' in operations) ||
105
+ typeof operations.listSubscriptions !== 'function' ||
106
+ !('unsubscribe' in operations) ||
107
+ typeof operations.unsubscribe !== 'function'
108
+ ) {
109
+ throw new MCPClientError({
110
+ message:
111
+ 'experimental_events.adapter.createAdapter() must return an object implementing subscribe, getSubscription, listSubscriptions, and unsubscribe.',
112
+ });
113
+ }
114
+ }
115
+
66
116
  /** Catalog discovery uses MCP; all subscription operations use the adapter. */
67
- export interface ManagedMCPEvents extends MCPEventsAdapter {
117
+ export interface ManagedMCPEvents extends MCPEventOperations {
68
118
  list: MCPEvents['list'];
69
119
  }
70
120
 
71
121
  export function createManagedMCPEvents(
72
- adapter: MCPEventsAdapter,
122
+ operations: MCPEventOperations,
73
123
  list: MCPEvents['list'],
74
124
  ): ManagedMCPEvents {
75
125
  return {
76
126
  list,
77
- subscribe: input => adapter.subscribe(input),
78
- getSubscription: input => adapter.getSubscription(input),
79
- listSubscriptions: input => adapter.listSubscriptions(input),
80
- unsubscribe: input => adapter.unsubscribe(input),
127
+ subscribe: input => operations.subscribe(input),
128
+ getSubscription: input => operations.getSubscription(input),
129
+ listSubscriptions: input => operations.listSubscriptions(input),
130
+ unsubscribe: input => operations.unsubscribe(input),
81
131
  };
82
132
  }