@gtkx/mcp 1.4.0 → 1.6.0
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/README.md +1 -1
- package/bin/gtkx-mcp.js +2 -2
- package/dist/app-router.d.ts +3 -5
- package/dist/app-router.d.ts.map +1 -1
- package/dist/app-router.js +21 -34
- package/dist/app-router.js.map +1 -1
- package/dist/connection-registry.d.ts +3 -4
- package/dist/connection-registry.d.ts.map +1 -1
- package/dist/connection-registry.js +5 -16
- package/dist/connection-registry.js.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/protocol/errors.d.ts +6 -7
- package/dist/protocol/errors.d.ts.map +1 -1
- package/dist/protocol/errors.js +12 -8
- package/dist/protocol/errors.js.map +1 -1
- package/dist/protocol/schemas.d.ts +1 -19
- package/dist/protocol/schemas.d.ts.map +1 -1
- package/dist/protocol/schemas.js +1 -16
- package/dist/protocol/schemas.js.map +1 -1
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +8 -5
- package/dist/reference.js.map +1 -1
- package/dist/server.d.ts +8 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +79 -18
- package/dist/server.js.map +1 -1
- package/dist/socket-server.js +1 -1
- package/dist/socket-server.js.map +1 -1
- package/dist/tool-filter.d.ts +5 -0
- package/dist/tool-filter.d.ts.map +1 -0
- package/dist/tool-filter.js +38 -0
- package/dist/tool-filter.js.map +1 -0
- package/dist/tool.d.ts +1 -0
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js +1 -1
- package/dist/tool.js.map +1 -1
- package/dist/transport.d.ts +18 -39
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +78 -127
- package/dist/transport.js.map +1 -1
- package/package.json +9 -5
- package/src/app-router.ts +34 -44
- package/src/connection-registry.ts +6 -22
- package/src/internal.ts +2 -3
- package/src/protocol/errors.ts +20 -10
- package/src/protocol/schemas.ts +0 -41
- package/src/reference.ts +8 -5
- package/src/server.ts +116 -19
- package/src/socket-server.ts +1 -1
- package/src/tool-filter.ts +54 -0
- package/src/tool.ts +2 -1
- package/src/transport.ts +106 -171
package/src/transport.ts
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-function -- the app link negotiates no MCP capabilities */
|
|
2
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
1
3
|
import type { Socket } from "node:net";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
4
|
+
import { normalizeError } from "@gtkx/utils";
|
|
5
|
+
import { Protocol } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
6
|
+
import { ReadBuffer, serializeMessage } from "@modelcontextprotocol/sdk/shared/stdio.js";
|
|
7
|
+
import {
|
|
8
|
+
ErrorCode,
|
|
9
|
+
type JSONRPCMessage,
|
|
10
|
+
type JSONRPCRequest,
|
|
11
|
+
McpError,
|
|
12
|
+
type Notification,
|
|
13
|
+
type Request,
|
|
14
|
+
type Result,
|
|
15
|
+
ResultSchema,
|
|
16
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
16
17
|
|
|
17
18
|
type ConnectionEvent = CustomEvent<ProtocolConnection>;
|
|
18
|
-
type ConnectionRequestEvent = CustomEvent<{ connection: ProtocolConnection; request: Request }>;
|
|
19
19
|
type ConnectionErrorEvent = CustomEvent<Error>;
|
|
20
|
+
type ConnectionRequestHandler = (connection: ProtocolConnection, request: JSONRPCRequest) => Promise<Result>;
|
|
21
|
+
type RequestParams = Request["params"];
|
|
22
|
+
|
|
23
|
+
type ConnectionOptions = {
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
onError: (error: Error) => void;
|
|
26
|
+
};
|
|
20
27
|
|
|
21
28
|
type AppConnections = {
|
|
22
|
-
|
|
29
|
+
onRequest: ConnectionRequestHandler;
|
|
23
30
|
} & EventTarget;
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
32
|
+
const MAX_MESSAGE_BYTES = 64 * 1024 * 1024;
|
|
33
|
+
const MAX_PENDING_WRITE_BYTES = 8 * 1024 * 1024;
|
|
28
34
|
|
|
29
35
|
function connectionDisconnectionEvent(connection: ProtocolConnection): ConnectionEvent {
|
|
30
36
|
return new CustomEvent("disconnection", { detail: connection });
|
|
@@ -34,208 +40,137 @@ function connectionErrorEvent(error: Error): ConnectionErrorEvent {
|
|
|
34
40
|
return new CustomEvent("error", { detail: error });
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
class
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.name = "ConnectionClosedError";
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
class ProtocolConnection extends EventTarget {
|
|
45
|
-
static fromSocket(
|
|
46
|
-
socket: Socket,
|
|
47
|
-
options: {
|
|
48
|
-
onClose?: () => void;
|
|
49
|
-
onError?: (error: Error) => void;
|
|
50
|
-
} = {},
|
|
51
|
-
): ProtocolConnection {
|
|
52
|
-
const connection = new ProtocolConnection(socket);
|
|
53
|
-
|
|
54
|
-
socket.on("data", (data: Buffer) => {
|
|
55
|
-
connection.feed(data);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
socket.on("close", () => {
|
|
59
|
-
connection.rejectPending(new Error("Connection closed"));
|
|
60
|
-
options.onClose?.();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (options.onError) {
|
|
64
|
-
socket.on("error", options.onError);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return connection;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private buffer = "";
|
|
71
|
-
private pending: Map<string, PendingRequest> = new Map();
|
|
72
|
-
private writer: Duplex;
|
|
73
|
-
|
|
74
|
-
id: string = crypto.randomUUID();
|
|
75
|
-
|
|
76
|
-
constructor(writer: Duplex) {
|
|
77
|
-
super();
|
|
78
|
-
this.writer = writer;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private notify<K extends keyof ProtocolConnectionEvents>(type: K, detail: ProtocolConnectionEvents[K]): void {
|
|
82
|
-
this.dispatchEvent(new CustomEvent(type, { detail }));
|
|
83
|
-
}
|
|
43
|
+
class SocketTransport implements Transport {
|
|
44
|
+
private readonly readBuffer: ReadBuffer = new ReadBuffer({ maxBufferSize: MAX_MESSAGE_BYTES });
|
|
45
|
+
private readonly socket: Socket;
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
47
|
+
onclose?: () => void;
|
|
48
|
+
onerror?: (error: Error) => void;
|
|
49
|
+
onmessage?: (message: JSONRPCMessage) => void;
|
|
89
50
|
|
|
90
|
-
|
|
91
|
-
this.
|
|
92
|
-
reject(new ConnectionClosedError());
|
|
51
|
+
constructor(socket: Socket) {
|
|
52
|
+
this.socket = socket;
|
|
93
53
|
}
|
|
94
54
|
|
|
95
|
-
private
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (typeof message.method === "string") {
|
|
99
|
-
const requestResult = RequestSchema.safeParse(parsed);
|
|
55
|
+
private read(): void {
|
|
56
|
+
for (;;) {
|
|
57
|
+
let message: JSONRPCMessage | null;
|
|
100
58
|
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
try {
|
|
60
|
+
message = this.readBuffer.readMessage();
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.onerror?.(normalizeError(error));
|
|
63
|
+
continue;
|
|
103
64
|
}
|
|
104
65
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const responseResult = ResponseSchema.safeParse(parsed);
|
|
66
|
+
if (message === null) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
111
69
|
|
|
112
|
-
|
|
113
|
-
return false;
|
|
70
|
+
this.onmessage?.(message);
|
|
114
71
|
}
|
|
72
|
+
}
|
|
115
73
|
|
|
116
|
-
|
|
74
|
+
private drop(reason: string): Promise<void> {
|
|
75
|
+
const error = new McpError(ErrorCode.ConnectionClosed, reason);
|
|
76
|
+
this.onerror?.(error);
|
|
77
|
+
this.socket.destroy();
|
|
117
78
|
|
|
118
|
-
return
|
|
79
|
+
return Promise.reject(error);
|
|
119
80
|
}
|
|
120
81
|
|
|
121
|
-
private
|
|
122
|
-
let parsed: unknown;
|
|
123
|
-
|
|
82
|
+
private receive(chunk: Buffer): void {
|
|
124
83
|
try {
|
|
125
|
-
|
|
126
|
-
} catch {
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
84
|
+
this.readBuffer.append(chunk);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
this.onerror?.(normalizeError(error));
|
|
87
|
+
this.socket.destroy();
|
|
131
88
|
|
|
132
|
-
if (this.dispatchParsed(parsed)) {
|
|
133
89
|
return;
|
|
134
90
|
}
|
|
135
91
|
|
|
136
|
-
|
|
137
|
-
const id = typeof message.id === "string" ? message.id : "unknown";
|
|
138
|
-
this.notify("invalid", { id, error: invalidRequestError("Invalid message format") });
|
|
92
|
+
this.read();
|
|
139
93
|
}
|
|
140
94
|
|
|
141
|
-
|
|
142
|
-
|
|
95
|
+
start(): Promise<void> {
|
|
96
|
+
this.socket.on("data", (chunk: Buffer) => {
|
|
97
|
+
this.receive(chunk);
|
|
98
|
+
});
|
|
143
99
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
100
|
+
this.socket.on("close", () => {
|
|
101
|
+
this.onclose?.();
|
|
102
|
+
});
|
|
147
103
|
|
|
148
|
-
|
|
149
|
-
|
|
104
|
+
this.socket.on("error", (error) => {
|
|
105
|
+
this.onerror?.(error);
|
|
106
|
+
});
|
|
150
107
|
|
|
151
|
-
|
|
152
|
-
|
|
108
|
+
return Promise.resolve();
|
|
109
|
+
}
|
|
153
110
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
);
|
|
157
|
-
} else {
|
|
158
|
-
entry.resolve(response.result);
|
|
111
|
+
send(message: JSONRPCMessage): Promise<void> {
|
|
112
|
+
if (!this.socket.writable) {
|
|
113
|
+
return Promise.reject(new McpError(ErrorCode.ConnectionClosed, "Connection stream is not writable"));
|
|
159
114
|
}
|
|
160
|
-
}
|
|
161
115
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
): void {
|
|
166
|
-
this.addEventListener(type, (event) => {
|
|
167
|
-
listener((event as CustomEvent<ProtocolConnectionEvents[K]>).detail);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
116
|
+
if (this.socket.writableLength > MAX_PENDING_WRITE_BYTES) {
|
|
117
|
+
return this.drop("Connection stream is not draining");
|
|
118
|
+
}
|
|
170
119
|
|
|
171
|
-
|
|
172
|
-
this.buffer += typeof data === "string" ? data : data.toString();
|
|
173
|
-
let newlineIndex = this.buffer.indexOf("\n");
|
|
120
|
+
this.socket.write(serializeMessage(message));
|
|
174
121
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
122
|
+
return Promise.resolve();
|
|
123
|
+
}
|
|
178
124
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
125
|
+
close(): Promise<void> {
|
|
126
|
+
this.socket.destroy();
|
|
182
127
|
|
|
183
|
-
|
|
184
|
-
}
|
|
128
|
+
return Promise.resolve();
|
|
185
129
|
}
|
|
130
|
+
}
|
|
186
131
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
132
|
+
class ProtocolConnection extends Protocol<Request, Notification, Result> {
|
|
133
|
+
static fromSocket(socket: Socket, options: ConnectionOptions): ProtocolConnection {
|
|
134
|
+
const connection = Object.assign(new ProtocolConnection(), {
|
|
135
|
+
onclose: options.onClose,
|
|
136
|
+
onerror: options.onError,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
void connection.connect(new SocketTransport(socket));
|
|
191
140
|
|
|
192
|
-
|
|
141
|
+
return connection;
|
|
193
142
|
}
|
|
194
143
|
|
|
195
|
-
|
|
196
|
-
return new Promise<T>((resolve, reject) => {
|
|
197
|
-
if (!this.writer.writable) {
|
|
198
|
-
reject(new ConnectionClosedError());
|
|
144
|
+
id: string = crypto.randomUUID();
|
|
199
145
|
|
|
200
|
-
|
|
201
|
-
}
|
|
146
|
+
protected assertCapabilityForMethod(): void {}
|
|
202
147
|
|
|
203
|
-
|
|
148
|
+
protected assertNotificationCapability(): void {}
|
|
204
149
|
|
|
205
|
-
|
|
206
|
-
this.pending.delete(id);
|
|
207
|
-
reject(requestTimeoutError(timeout));
|
|
208
|
-
}, timeout);
|
|
150
|
+
protected assertRequestHandlerCapability(): void {}
|
|
209
151
|
|
|
210
|
-
|
|
211
|
-
resolve: resolve as (result: unknown) => void,
|
|
212
|
-
reject,
|
|
213
|
-
timeout: timeoutHandle,
|
|
214
|
-
});
|
|
152
|
+
protected assertTaskCapability(): void {}
|
|
215
153
|
|
|
216
|
-
|
|
217
|
-
this.rejectWhenClosed(id, timeoutHandle, reject);
|
|
218
|
-
});
|
|
219
|
-
}
|
|
154
|
+
protected assertTaskHandlerCapability(): void {}
|
|
220
155
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
156
|
+
async send<T>(method: string, params?: RequestParams, timeout?: number): Promise<T> {
|
|
157
|
+
const result = await this.request(
|
|
158
|
+
{ method, ...(params !== undefined && { params }) },
|
|
159
|
+
ResultSchema,
|
|
160
|
+
{ ...(timeout !== undefined && { timeout }) },
|
|
161
|
+
);
|
|
226
162
|
|
|
227
|
-
|
|
163
|
+
return result as T;
|
|
228
164
|
}
|
|
229
165
|
}
|
|
230
166
|
|
|
231
167
|
export {
|
|
232
|
-
ConnectionClosedError,
|
|
233
168
|
connectionDisconnectionEvent,
|
|
234
169
|
connectionErrorEvent,
|
|
235
|
-
connectionRequestEvent,
|
|
236
170
|
ProtocolConnection,
|
|
237
171
|
type AppConnections,
|
|
238
172
|
type ConnectionEvent,
|
|
239
173
|
type ConnectionErrorEvent,
|
|
240
|
-
type
|
|
174
|
+
type ConnectionRequestHandler,
|
|
175
|
+
type RequestParams,
|
|
241
176
|
};
|