@ai-sdk/mcp 2.0.0-beta.9 → 2.0.0-canary.39

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,10 +1,10 @@
1
1
  {
2
2
  "name": "@ai-sdk/mcp",
3
- "version": "2.0.0-beta.9",
3
+ "version": "2.0.0-canary.39",
4
+ "type": "module",
4
5
  "license": "Apache-2.0",
5
6
  "sideEffects": false,
6
7
  "main": "./dist/index.js",
7
- "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
10
  "dist/**/*",
@@ -21,28 +21,27 @@
21
21
  "./package.json": "./package.json",
22
22
  ".": {
23
23
  "types": "./dist/index.d.ts",
24
- "import": "./dist/index.mjs",
25
- "require": "./dist/index.js"
24
+ "import": "./dist/index.js",
25
+ "default": "./dist/index.js"
26
26
  },
27
27
  "./mcp-stdio": {
28
28
  "types": "./dist/mcp-stdio/index.d.ts",
29
- "import": "./dist/mcp-stdio/index.mjs",
30
- "module": "./dist/mcp-stdio/index.mjs",
31
- "require": "./dist/mcp-stdio/index.js"
29
+ "import": "./dist/mcp-stdio/index.js",
30
+ "default": "./dist/mcp-stdio/index.js"
32
31
  }
33
32
  },
34
33
  "dependencies": {
35
34
  "pkce-challenge": "^5.0.0",
36
- "@ai-sdk/provider": "4.0.0-beta.3",
37
- "@ai-sdk/provider-utils": "5.0.0-beta.5"
35
+ "@ai-sdk/provider": "4.0.0-canary.16",
36
+ "@ai-sdk/provider-utils": "5.0.0-canary.32"
38
37
  },
39
38
  "devDependencies": {
40
39
  "@types/node": "20.17.24",
41
40
  "tsup": "^8",
42
41
  "typescript": "5.8.3",
43
- "vitest": "^4.1.0",
42
+ "vitest": "^4.1.5",
44
43
  "zod": "3.25.76",
45
- "@ai-sdk/test-server": "2.0.0-beta.0",
44
+ "@ai-sdk/test-server": "2.0.0-canary.4",
46
45
  "@vercel/ai-tsconfig": "0.0.0"
47
46
  },
48
47
  "peerDependencies": {
@@ -52,12 +51,14 @@
52
51
  "node": ">=18"
53
52
  },
54
53
  "publishConfig": {
55
- "access": "public"
54
+ "access": "public",
55
+ "provenance": true
56
56
  },
57
57
  "homepage": "https://ai-sdk.dev/docs",
58
58
  "repository": {
59
59
  "type": "git",
60
- "url": "git+https://github.com/vercel/ai.git"
60
+ "url": "https://github.com/vercel/ai",
61
+ "directory": "packages/mcp"
61
62
  },
62
63
  "bugs": {
63
64
  "url": "https://github.com/vercel/ai/issues"
@@ -70,9 +71,7 @@
70
71
  "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
71
72
  "build:watch": "pnpm clean && tsup --watch",
72
73
  "clean": "rm -rf dist *.tsbuildinfo",
73
- "lint": "eslint \"./**/*.ts*\"",
74
74
  "type-check": "tsc --build",
75
- "prettier-check": "prettier --check \"./**/*.ts*\"",
76
75
  "test": "pnpm test:node && pnpm test:edge",
77
76
  "test:update": "pnpm test:node -u",
78
77
  "test:watch": "vitest --config vitest.node.config.js",
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export {
14
14
  } from './tool/mcp-client';
15
15
  export { ElicitationRequestSchema, ElicitResultSchema } from './tool/types';
16
16
  export type {
17
+ Configuration,
17
18
  ElicitationRequest,
18
19
  ElicitResult,
19
20
  ListToolsResult,
@@ -1,3 +1,4 @@
1
+ import { parseJSON } from '@ai-sdk/provider-utils';
1
2
  import { z } from 'zod/v4';
2
3
  import { BaseParamsSchema, RequestSchema, ResultSchema } from './types';
3
4
 
@@ -59,3 +60,9 @@ export const JSONRPCMessageSchema = z.union([
59
60
  ]);
60
61
 
61
62
  export type JSONRPCMessage = z.infer<typeof JSONRPCMessageSchema>;
63
+
64
+ export async function parseJSONRPCMessage(
65
+ text: string,
66
+ ): Promise<JSONRPCMessage> {
67
+ return JSONRPCMessageSchema.parse(await parseJSON({ text }));
68
+ }
@@ -1,19 +1,19 @@
1
- import { JSONSchema7, JSONValue } from '@ai-sdk/provider';
1
+ import type { JSONSchema7, JSONValue } from '@ai-sdk/provider';
2
2
  import {
3
3
  asSchema,
4
4
  dynamicTool,
5
- FlexibleSchema,
6
5
  jsonSchema,
7
6
  safeParseJSON,
8
7
  safeValidateTypes,
9
- Tool,
10
8
  tool,
11
- ToolExecutionOptions,
12
- ToolResultOutput,
9
+ type FlexibleSchema,
10
+ type Tool,
11
+ type ToolExecutionOptions,
12
+ type ToolResultOutput,
13
13
  } from '@ai-sdk/provider-utils';
14
- import { z } from 'zod/v4';
14
+ import type { z } from 'zod/v4';
15
15
  import { MCPClientError } from '../error/mcp-client-error';
16
- import {
16
+ import type {
17
17
  JSONRPCError,
18
18
  JSONRPCNotification,
19
19
  JSONRPCRequest,
@@ -22,43 +22,43 @@ import {
22
22
  import {
23
23
  createMcpTransport,
24
24
  isCustomMcpTransport,
25
- MCPTransport,
26
- MCPTransportConfig,
25
+ type MCPTransport,
26
+ type MCPTransportConfig,
27
27
  } from './mcp-transport';
28
28
  import {
29
- CallToolResult,
30
29
  CallToolResultSchema,
31
- ClientCapabilities,
32
- Configuration as ClientConfiguration,
33
- ElicitationRequest,
34
30
  ElicitationRequestSchema,
35
- ElicitResult,
36
31
  ElicitResultSchema,
37
32
  InitializeResultSchema,
38
33
  LATEST_PROTOCOL_VERSION,
39
- ListResourceTemplatesResult,
40
34
  ListResourceTemplatesResultSchema,
41
- ListResourcesResult,
42
35
  ListResourcesResultSchema,
43
- ListPromptsResult,
44
36
  ListPromptsResultSchema,
45
- ListToolsResult,
46
37
  ListToolsResultSchema,
47
- McpToolSet,
48
- Notification,
49
- PaginatedRequest,
50
- ReadResourceResult,
51
38
  ReadResourceResultSchema,
52
- GetPromptResult,
53
39
  GetPromptResultSchema,
54
- Request,
55
- RequestOptions,
56
- ServerCapabilities,
57
40
  SUPPORTED_PROTOCOL_VERSIONS,
58
- ToolSchemas,
59
- ToolMeta,
41
+ type CallToolResult,
42
+ type ClientCapabilities,
43
+ type Configuration,
44
+ type Configuration as ClientConfiguration,
45
+ type ElicitationRequest,
46
+ type ElicitResult,
47
+ type ListResourceTemplatesResult,
48
+ type ListResourcesResult,
49
+ type ListPromptsResult,
50
+ type ListToolsResult,
51
+ type McpToolSet,
52
+ type Notification,
53
+ type PaginatedRequest,
54
+ type ReadResourceResult,
55
+ type GetPromptResult,
56
+ type Request,
57
+ type RequestOptions,
58
+ type ServerCapabilities,
59
+ type ToolSchemas,
60
+ type ToolMeta,
60
61
  } from './types';
61
-
62
62
  const CLIENT_VERSION = '1.0.0';
63
63
 
64
64
  function mcpToModelOutput({
@@ -81,9 +81,9 @@ function mcpToModelOutput({
81
81
  }
82
82
  if (part.type === 'image' && 'data' in part && 'mimeType' in part) {
83
83
  return {
84
- type: 'image-data' as const,
85
- data: part.data as string,
84
+ type: 'file' as const,
86
85
  mediaType: part.mimeType as string,
86
+ data: { type: 'data' as const, data: part.data as string },
87
87
  };
88
88
  }
89
89
  return { type: 'text' as const, text: JSON.stringify(part) };
@@ -119,6 +119,22 @@ export async function createMCPClient(
119
119
  }
120
120
 
121
121
  export interface MCPClient {
122
+ /**
123
+ * Information about the connected MCP server, as reported during initialization.
124
+ * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#implementation
125
+ */
126
+ readonly serverInfo: Configuration;
127
+
128
+ /**
129
+ * Optional instructions provided by the server during the initialize handshake.
130
+ *
131
+ * These describe how to use the server and its features, and can be used by clients
132
+ * to improve LLM interactions (e.g. by including them in the system prompt).
133
+ *
134
+ * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#initializeresult
135
+ */
136
+ readonly instructions?: string;
137
+
122
138
  tools<TOOL_SCHEMAS extends ToolSchemas = 'automatic'>(options?: {
123
139
  schemas?: TOOL_SCHEMAS;
124
140
  }): Promise<McpToolSet<TOOL_SCHEMAS>>;
@@ -201,6 +217,8 @@ class DefaultMCPClient implements MCPClient {
201
217
  (response: JSONRPCResponse | Error) => void
202
218
  > = new Map();
203
219
  private serverCapabilities: ServerCapabilities = {};
220
+ private _serverInfo: Configuration = { name: '', version: '' };
221
+ private _serverInstructions?: string;
204
222
  private isClosed = true;
205
223
  private elicitationRequestHandler?: (
206
224
  request: ElicitationRequest,
@@ -247,6 +265,14 @@ class DefaultMCPClient implements MCPClient {
247
265
  };
248
266
  }
249
267
 
268
+ get serverInfo(): Configuration {
269
+ return this._serverInfo;
270
+ }
271
+
272
+ get instructions(): string | undefined {
273
+ return this._serverInstructions;
274
+ }
275
+
250
276
  async init(): Promise<this> {
251
277
  try {
252
278
  await this.transport.start();
@@ -277,6 +303,8 @@ class DefaultMCPClient implements MCPClient {
277
303
  }
278
304
 
279
305
  this.serverCapabilities = result.capabilities;
306
+ this._serverInfo = result.serverInfo;
307
+ this._serverInstructions = result.instructions;
280
308
 
281
309
  // Complete initialization handshake:
282
310
  await this.notification({
@@ -420,7 +448,7 @@ class DefaultMCPClient implements MCPClient {
420
448
  }: {
421
449
  name: string;
422
450
  args: Record<string, unknown>;
423
- options?: ToolExecutionOptions;
451
+ options?: ToolExecutionOptions<{}>;
424
452
  }): Promise<CallToolResult> {
425
453
  try {
426
454
  return this.request({
@@ -579,11 +607,15 @@ class DefaultMCPClient implements MCPClient {
579
607
 
580
608
  const execute = async (
581
609
  args: any,
582
- options: ToolExecutionOptions,
610
+ options: ToolExecutionOptions<{}>,
583
611
  ): Promise<unknown> => {
584
612
  options?.abortSignal?.throwIfAborted();
585
613
  const result = await self.callTool({ name, args, options });
586
614
 
615
+ if (result.isError) {
616
+ return result;
617
+ }
618
+
587
619
  if (outputSchema != null) {
588
620
  return self.extractStructuredContent(result, outputSchema, name);
589
621
  }
@@ -596,6 +628,9 @@ class DefaultMCPClient implements MCPClient {
596
628
  ? dynamicTool({
597
629
  description,
598
630
  title: resolvedTitle,
631
+ providerMetadata: {
632
+ mcp: { name: this.clientInfo.name },
633
+ },
599
634
  inputSchema: jsonSchema({
600
635
  ...inputSchema,
601
636
  properties: inputSchema.properties ?? {},
@@ -607,6 +642,9 @@ class DefaultMCPClient implements MCPClient {
607
642
  : tool({
608
643
  description,
609
644
  title: resolvedTitle,
645
+ providerMetadata: {
646
+ mcp: { name: this.clientInfo.name },
647
+ },
610
648
  inputSchema: schemas[name].inputSchema,
611
649
  ...(outputSchema != null ? { outputSchema } : {}),
612
650
  execute,
@@ -2,16 +2,21 @@ import {
2
2
  EventSourceParserStream,
3
3
  withUserAgentSuffix,
4
4
  getRuntimeEnvironmentUserAgent,
5
+ type FetchFunction,
5
6
  } from '@ai-sdk/provider-utils';
6
7
  import { MCPClientError } from '../error/mcp-client-error';
7
- import { JSONRPCMessage, JSONRPCMessageSchema } from './json-rpc-message';
8
- import { MCPTransport } from './mcp-transport';
8
+ import {
9
+ JSONRPCMessageSchema,
10
+ parseJSONRPCMessage,
11
+ type JSONRPCMessage,
12
+ } from './json-rpc-message';
13
+ import type { MCPTransport } from './mcp-transport';
9
14
  import { VERSION } from '../version';
10
15
  import {
11
- OAuthClientProvider,
12
16
  extractResourceMetadataUrl,
13
17
  UnauthorizedError,
14
18
  auth,
19
+ type OAuthClientProvider,
15
20
  } from './oauth';
16
21
  import { LATEST_PROTOCOL_VERSION } from './types';
17
22
 
@@ -31,6 +36,7 @@ export class HttpMCPTransport implements MCPTransport {
31
36
  private sessionId?: string;
32
37
  private inboundSseConnection?: { close: () => void };
33
38
  private redirectMode: RequestRedirect;
39
+ private fetchFn: FetchFunction;
34
40
 
35
41
  // Inbound SSE resumption and reconnection state
36
42
  private lastInboundEventId?: string;
@@ -51,16 +57,19 @@ export class HttpMCPTransport implements MCPTransport {
51
57
  headers,
52
58
  authProvider,
53
59
  redirect = 'error',
60
+ fetch: fetchFn,
54
61
  }: {
55
62
  url: string;
56
63
  headers?: Record<string, string>;
57
64
  authProvider?: OAuthClientProvider;
58
65
  redirect?: 'follow' | 'error';
66
+ fetch?: FetchFunction;
59
67
  }) {
60
68
  this.url = new URL(url);
61
69
  this.headers = headers;
62
70
  this.authProvider = authProvider;
63
71
  this.redirectMode = redirect;
72
+ this.fetchFn = fetchFn ?? globalThis.fetch;
64
73
  }
65
74
 
66
75
  private async commonHeaders(
@@ -111,7 +120,7 @@ export class HttpMCPTransport implements MCPTransport {
111
120
  !this.abortController.signal.aborted
112
121
  ) {
113
122
  const headers = await this.commonHeaders({});
114
- await fetch(this.url, {
123
+ await this.fetchFn(this.url.href, {
115
124
  method: 'DELETE',
116
125
  headers,
117
126
  signal: this.abortController.signal,
@@ -140,7 +149,7 @@ export class HttpMCPTransport implements MCPTransport {
140
149
  redirect: this.redirectMode,
141
150
  } satisfies RequestInit;
142
151
 
143
- const response = await fetch(this.url, init);
152
+ const response = await this.fetchFn(this.url.href, init);
144
153
 
145
154
  const sessionId = response.headers.get('mcp-session-id');
146
155
  if (sessionId) {
@@ -153,6 +162,7 @@ export class HttpMCPTransport implements MCPTransport {
153
162
  const result = await auth(this.authProvider, {
154
163
  serverUrl: this.url,
155
164
  resourceMetadataUrl: this.resourceMetadataUrl,
165
+ fetchFn: this.fetchFn,
156
166
  });
157
167
  if (result !== 'AUTHORIZED') {
158
168
  const error = new UnauthorizedError();
@@ -232,7 +242,7 @@ export class HttpMCPTransport implements MCPTransport {
232
242
  const { event, data } = value;
233
243
  if (event === 'message') {
234
244
  try {
235
- const msg = JSONRPCMessageSchema.parse(JSON.parse(data));
245
+ const msg = await parseJSONRPCMessage(data);
236
246
  this.onmessage?.(msg);
237
247
  } catch (error) {
238
248
  const e = new MCPClientError({
@@ -314,7 +324,7 @@ export class HttpMCPTransport implements MCPTransport {
314
324
  headers['last-event-id'] = resumeToken;
315
325
  }
316
326
 
317
- const response = await fetch(this.url.href, {
327
+ const response = await this.fetchFn(this.url.href, {
318
328
  method: 'GET',
319
329
  headers,
320
330
  signal: this.abortController?.signal,
@@ -332,6 +342,7 @@ export class HttpMCPTransport implements MCPTransport {
332
342
  const result = await auth(this.authProvider, {
333
343
  serverUrl: this.url,
334
344
  resourceMetadataUrl: this.resourceMetadataUrl,
345
+ fetchFn: this.fetchFn,
335
346
  });
336
347
  if (result !== 'AUTHORIZED') {
337
348
  const error = new UnauthorizedError();
@@ -379,7 +390,7 @@ export class HttpMCPTransport implements MCPTransport {
379
390
 
380
391
  if (event === 'message') {
381
392
  try {
382
- const msg = JSONRPCMessageSchema.parse(JSON.parse(data));
393
+ const msg = await parseJSONRPCMessage(data);
383
394
  this.onmessage?.(msg);
384
395
  } catch (error) {
385
396
  const e = new MCPClientError({
@@ -2,16 +2,17 @@ import {
2
2
  EventSourceParserStream,
3
3
  withUserAgentSuffix,
4
4
  getRuntimeEnvironmentUserAgent,
5
+ type FetchFunction,
5
6
  } from '@ai-sdk/provider-utils';
6
7
  import { MCPClientError } from '../error/mcp-client-error';
7
- import { JSONRPCMessage, JSONRPCMessageSchema } from './json-rpc-message';
8
- import { MCPTransport } from './mcp-transport';
8
+ import { parseJSONRPCMessage, type JSONRPCMessage } from './json-rpc-message';
9
+ import type { MCPTransport } from './mcp-transport';
9
10
  import { VERSION } from '../version';
10
11
  import {
11
- OAuthClientProvider,
12
12
  extractResourceMetadataUrl,
13
13
  UnauthorizedError,
14
14
  auth,
15
+ type OAuthClientProvider,
15
16
  } from './oauth';
16
17
  import { LATEST_PROTOCOL_VERSION } from './types';
17
18
 
@@ -27,6 +28,7 @@ export class SseMCPTransport implements MCPTransport {
27
28
  private authProvider?: OAuthClientProvider;
28
29
  private resourceMetadataUrl?: URL;
29
30
  private redirectMode: RequestRedirect;
31
+ private fetchFn: FetchFunction;
30
32
 
31
33
  onclose?: () => void;
32
34
  onerror?: (error: unknown) => void;
@@ -37,16 +39,19 @@ export class SseMCPTransport implements MCPTransport {
37
39
  headers,
38
40
  authProvider,
39
41
  redirect = 'error',
42
+ fetch: fetchFn,
40
43
  }: {
41
44
  url: string;
42
45
  headers?: Record<string, string>;
43
46
  authProvider?: OAuthClientProvider;
44
47
  redirect?: 'follow' | 'error';
48
+ fetch?: FetchFunction;
45
49
  }) {
46
50
  this.url = new URL(url);
47
51
  this.headers = headers;
48
52
  this.authProvider = authProvider;
49
53
  this.redirectMode = redirect;
54
+ this.fetchFn = fetchFn ?? globalThis.fetch;
50
55
  }
51
56
 
52
57
  private async commonHeaders(
@@ -85,7 +90,7 @@ export class SseMCPTransport implements MCPTransport {
85
90
  const headers = await this.commonHeaders({
86
91
  Accept: 'text/event-stream',
87
92
  });
88
- const response = await fetch(this.url.href, {
93
+ const response = await this.fetchFn(this.url.href, {
89
94
  headers,
90
95
  signal: this.abortController?.signal,
91
96
  redirect: this.redirectMode,
@@ -97,6 +102,7 @@ export class SseMCPTransport implements MCPTransport {
97
102
  const result = await auth(this.authProvider, {
98
103
  serverUrl: this.url,
99
104
  resourceMetadataUrl: this.resourceMetadataUrl,
105
+ fetchFn: this.fetchFn,
100
106
  });
101
107
  if (result !== 'AUTHORIZED') {
102
108
  const error = new UnauthorizedError();
@@ -162,9 +168,7 @@ export class SseMCPTransport implements MCPTransport {
162
168
  resolve();
163
169
  } else if (event === 'message') {
164
170
  try {
165
- const message = JSONRPCMessageSchema.parse(
166
- JSON.parse(data),
167
- );
171
+ const message = await parseJSONRPCMessage(data);
168
172
  this.onmessage?.(message);
169
173
  } catch (error) {
170
174
  const e = new MCPClientError({
@@ -235,7 +239,7 @@ export class SseMCPTransport implements MCPTransport {
235
239
  redirect: this.redirectMode,
236
240
  };
237
241
 
238
- const response = await fetch(endpoint, init);
242
+ const response = await this.fetchFn(endpoint.href, init);
239
243
 
240
244
  if (response.status === 401 && this.authProvider && !triedAuth) {
241
245
  this.resourceMetadataUrl = extractResourceMetadataUrl(response);
@@ -243,6 +247,7 @@ export class SseMCPTransport implements MCPTransport {
243
247
  const result = await auth(this.authProvider, {
244
248
  serverUrl: this.url,
245
249
  resourceMetadataUrl: this.resourceMetadataUrl,
250
+ fetchFn: this.fetchFn,
246
251
  });
247
252
  if (result !== 'AUTHORIZED') {
248
253
  const error = new UnauthorizedError();
@@ -273,6 +278,8 @@ export class SseMCPTransport implements MCPTransport {
273
278
  }
274
279
  }
275
280
 
276
- export function deserializeMessage(line: string): JSONRPCMessage {
277
- return JSONRPCMessageSchema.parse(JSON.parse(line));
281
+ export async function deserializeMessage(
282
+ line: string,
283
+ ): Promise<JSONRPCMessage> {
284
+ return parseJSONRPCMessage(line);
278
285
  }
@@ -1,6 +1,6 @@
1
- import { ChildProcess, spawn } from 'node:child_process';
1
+ import { spawn, type ChildProcess } from 'node:child_process';
2
2
  import { getEnvironment } from './get-environment';
3
- import { StdioConfig } from './mcp-stdio-transport';
3
+ import type { StdioConfig } from './mcp-stdio-transport';
4
4
 
5
5
  export function createChildProcess(
6
6
  config: StdioConfig,
@@ -1,7 +1,7 @@
1
1
  import type { ChildProcess, IOType } from 'node:child_process';
2
- import { Stream } from 'node:stream';
3
- import { JSONRPCMessage, JSONRPCMessageSchema } from '../json-rpc-message';
4
- import { MCPTransport } from '../mcp-transport';
2
+ import type { Stream } from 'node:stream';
3
+ import { parseJSONRPCMessage, type JSONRPCMessage } from '../json-rpc-message';
4
+ import type { MCPTransport } from '../mcp-transport';
5
5
  import { MCPClientError } from '../../error/mcp-client-error';
6
6
  import { createChildProcess } from './create-child-process';
7
7
 
@@ -68,7 +68,7 @@ export class StdioMCPTransport implements MCPTransport {
68
68
 
69
69
  this.process.stdout?.on('data', chunk => {
70
70
  this.readBuffer.append(chunk);
71
- this.processReadBuffer();
71
+ void this.processReadBuffer();
72
72
  });
73
73
 
74
74
  this.process.stdout?.on('error', error => {
@@ -81,14 +81,15 @@ export class StdioMCPTransport implements MCPTransport {
81
81
  });
82
82
  }
83
83
 
84
- private processReadBuffer() {
84
+ private async processReadBuffer() {
85
85
  while (true) {
86
- try {
87
- const message = this.readBuffer.readMessage();
88
- if (message === null) {
89
- break;
90
- }
86
+ const line = this.readBuffer.readLine();
87
+ if (line === null) {
88
+ break;
89
+ }
91
90
 
91
+ try {
92
+ const message = await deserializeMessage(line);
92
93
  this.onmessage?.(message);
93
94
  } catch (error) {
94
95
  this.onerror?.(error as Error);
@@ -127,7 +128,7 @@ class ReadBuffer {
127
128
  this.buffer = this.buffer ? Buffer.concat([this.buffer, chunk]) : chunk;
128
129
  }
129
130
 
130
- readMessage(): JSONRPCMessage | null {
131
+ readLine(): string | null {
131
132
  if (!this.buffer) return null;
132
133
 
133
134
  const index = this.buffer.indexOf('\n');
@@ -137,7 +138,7 @@ class ReadBuffer {
137
138
 
138
139
  const line = this.buffer.toString('utf8', 0, index);
139
140
  this.buffer = this.buffer.subarray(index + 1);
140
- return deserializeMessage(line);
141
+ return line;
141
142
  }
142
143
 
143
144
  clear(): void {
@@ -149,6 +150,8 @@ function serializeMessage(message: JSONRPCMessage): string {
149
150
  return JSON.stringify(message) + '\n';
150
151
  }
151
152
 
152
- export function deserializeMessage(line: string): JSONRPCMessage {
153
- return JSONRPCMessageSchema.parse(JSON.parse(line));
153
+ export async function deserializeMessage(
154
+ line: string,
155
+ ): Promise<JSONRPCMessage> {
156
+ return parseJSONRPCMessage(line);
154
157
  }
@@ -1,8 +1,9 @@
1
+ import type { FetchFunction } from '@ai-sdk/provider-utils';
1
2
  import { MCPClientError } from '../error/mcp-client-error';
2
- import { JSONRPCMessage } from './json-rpc-message';
3
+ import type { JSONRPCMessage } from './json-rpc-message';
3
4
  import { SseMCPTransport } from './mcp-sse-transport';
4
5
  import { HttpMCPTransport } from './mcp-http-transport';
5
- import { OAuthClientProvider } from './oauth';
6
+ import type { OAuthClientProvider } from './oauth';
6
7
 
7
8
  /**
8
9
  * Transport interface for MCP (Model Context Protocol) communication.
@@ -66,6 +67,13 @@ export type MCPTransportConfig = {
66
67
  * @default 'error'
67
68
  */
68
69
  redirect?: 'follow' | 'error';
70
+
71
+ /**
72
+ * Optional custom fetch implementation to use for HTTP requests.
73
+ * Useful for runtimes that need a request-local fetch.
74
+ * @default globalThis.fetch
75
+ */
76
+ fetch?: FetchFunction;
69
77
  };
70
78
 
71
79
  export function createMcpTransport(config: MCPTransportConfig): MCPTransport {
@@ -1,15 +1,13 @@
1
1
  import { delay } from '@ai-sdk/provider-utils';
2
- import { JSONRPCMessage } from './json-rpc-message';
3
- import { MCPTransport } from './mcp-transport';
2
+ import type { JSONRPCMessage } from './json-rpc-message';
3
+ import type { MCPTransport } from './mcp-transport';
4
4
  import {
5
- MCPTool,
6
- MCPResource,
7
- MCPPrompt,
8
- GetPromptResult,
9
- CallToolResult,
10
5
  LATEST_PROTOCOL_VERSION,
6
+ type MCPTool,
7
+ type MCPResource,
8
+ type MCPPrompt,
9
+ type CallToolResult,
11
10
  } from './types';
12
-
13
11
  const DEFAULT_TOOLS: MCPTool[] = [
14
12
  {
15
13
  name: 'mock-tool',