ai 4.1.63 → 4.1.65

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.
@@ -0,0 +1,157 @@
1
+ import type { ChildProcess, IOType } from 'node:child_process';
2
+ import { Stream } from 'node:stream';
3
+ import {
4
+ JSONRPCMessage,
5
+ JSONRPCMessageSchema,
6
+ } from '../core/tool/mcp/json-rpc-message';
7
+ import { MCPTransport } from '../core/tool/mcp/mcp-transport';
8
+ import { MCPClientError } from '../errors';
9
+ import { createChildProcess } from './create-child-process';
10
+
11
+ export interface StdioConfig {
12
+ command: string;
13
+ args?: string[];
14
+ env?: Record<string, string>;
15
+ stderr?: IOType | Stream | number;
16
+ cwd?: string;
17
+ }
18
+
19
+ export class StdioMCPTransport implements MCPTransport {
20
+ private process?: ChildProcess;
21
+ private abortController: AbortController = new AbortController();
22
+ private readBuffer: ReadBuffer = new ReadBuffer();
23
+ private serverParams: StdioConfig;
24
+
25
+ onclose?: () => void;
26
+ onerror?: (error: unknown) => void;
27
+ onmessage?: (message: JSONRPCMessage) => void;
28
+
29
+ constructor(server: StdioConfig) {
30
+ this.serverParams = server;
31
+ }
32
+
33
+ async start(): Promise<void> {
34
+ if (this.process) {
35
+ throw new MCPClientError({
36
+ message: 'StdioMCPTransport already started.',
37
+ });
38
+ }
39
+
40
+ return new Promise(async (resolve, reject) => {
41
+ try {
42
+ const process = await createChildProcess(
43
+ this.serverParams,
44
+ this.abortController.signal,
45
+ );
46
+
47
+ this.process = process;
48
+
49
+ this.process.on('error', error => {
50
+ if (error.name === 'AbortError') {
51
+ this.onclose?.();
52
+ return;
53
+ }
54
+
55
+ reject(error);
56
+ this.onerror?.(error);
57
+ });
58
+
59
+ this.process.on('spawn', () => {
60
+ resolve();
61
+ });
62
+
63
+ this.process.on('close', _code => {
64
+ this.process = undefined;
65
+ this.onclose?.();
66
+ });
67
+
68
+ this.process.stdin?.on('error', error => {
69
+ this.onerror?.(error);
70
+ });
71
+
72
+ this.process.stdout?.on('data', chunk => {
73
+ this.readBuffer.append(chunk);
74
+ this.processReadBuffer();
75
+ });
76
+
77
+ this.process.stdout?.on('error', error => {
78
+ this.onerror?.(error);
79
+ });
80
+ } catch (error) {
81
+ reject(error);
82
+ this.onerror?.(error);
83
+ }
84
+ });
85
+ }
86
+
87
+ private processReadBuffer() {
88
+ while (true) {
89
+ try {
90
+ const message = this.readBuffer.readMessage();
91
+ if (message === null) {
92
+ break;
93
+ }
94
+
95
+ this.onmessage?.(message);
96
+ } catch (error) {
97
+ this.onerror?.(error as Error);
98
+ }
99
+ }
100
+ }
101
+
102
+ async close(): Promise<void> {
103
+ this.abortController.abort();
104
+ this.process = undefined;
105
+ this.readBuffer.clear();
106
+ }
107
+
108
+ send(message: JSONRPCMessage): Promise<void> {
109
+ return new Promise(resolve => {
110
+ if (!this.process?.stdin) {
111
+ throw new MCPClientError({
112
+ message: 'StdioClientTransport not connected',
113
+ });
114
+ }
115
+
116
+ const json = serializeMessage(message);
117
+ if (this.process.stdin.write(json)) {
118
+ resolve();
119
+ } else {
120
+ this.process.stdin.once('drain', resolve);
121
+ }
122
+ });
123
+ }
124
+ }
125
+
126
+ class ReadBuffer {
127
+ private buffer?: Buffer;
128
+
129
+ append(chunk: Buffer): void {
130
+ this.buffer = this.buffer ? Buffer.concat([this.buffer, chunk]) : chunk;
131
+ }
132
+
133
+ readMessage(): JSONRPCMessage | null {
134
+ if (!this.buffer) return null;
135
+
136
+ const index = this.buffer.indexOf('\n');
137
+ if (index === -1) {
138
+ return null;
139
+ }
140
+
141
+ const line = this.buffer.toString('utf8', 0, index);
142
+ this.buffer = this.buffer.subarray(index + 1);
143
+ return deserializeMessage(line);
144
+ }
145
+
146
+ clear(): void {
147
+ this.buffer = undefined;
148
+ }
149
+ }
150
+
151
+ function serializeMessage(message: JSONRPCMessage): string {
152
+ return JSON.stringify(message) + '\n';
153
+ }
154
+
155
+ export function deserializeMessage(line: string): JSONRPCMessage {
156
+ return JSONRPCMessageSchema.parse(JSON.parse(line));
157
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "4.1.63",
3
+ "version": "4.1.65",
4
4
  "description": "AI SDK by Vercel - The AI Toolkit for TypeScript and JavaScript",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -9,6 +9,7 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "files": [
11
11
  "dist/**/*",
12
+ "mcp-stdio/**/*",
12
13
  "react/dist/**/*",
13
14
  "rsc/dist/**/*",
14
15
  "test/dist/**/*",
@@ -46,9 +47,9 @@
46
47
  },
47
48
  "dependencies": {
48
49
  "@ai-sdk/provider": "1.0.12",
49
- "@ai-sdk/provider-utils": "2.1.14",
50
- "@ai-sdk/react": "1.1.24",
51
- "@ai-sdk/ui-utils": "1.1.20",
50
+ "@ai-sdk/provider-utils": "2.1.15",
51
+ "@ai-sdk/react": "1.1.25",
52
+ "@ai-sdk/ui-utils": "1.1.21",
52
53
  "@opentelemetry/api": "1.9.0",
53
54
  "eventsource-parser": "^3.0.0",
54
55
  "jsondiffpatch": "0.6.0"