toolcraft 0.0.103 → 0.0.105

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.
Files changed (47) hide show
  1. package/composition.json +7 -2
  2. package/dist/cli.js +53 -0
  3. package/dist/composition.json +7 -2
  4. package/dist/index.d.ts +25 -3
  5. package/dist/index.js +18 -0
  6. package/dist/mcp.d.ts +6 -0
  7. package/dist/mcp.js +121 -1
  8. package/dist/sdk.d.ts +2 -1
  9. package/dist/sdk.js +56 -0
  10. package/dist/stream.d.ts +19 -0
  11. package/dist/stream.js +92 -0
  12. package/dist/testing/harness.d.ts +11 -0
  13. package/dist/testing/harness.js +70 -0
  14. package/dist/testing/index.d.ts +1 -1
  15. package/node_modules/tiny-stdio-mcp-server/LICENSE +21 -0
  16. package/node_modules/tiny-stdio-mcp-server/README.md +231 -0
  17. package/node_modules/tiny-stdio-mcp-server/dist/content/audio.d.ts +15 -0
  18. package/node_modules/tiny-stdio-mcp-server/dist/content/audio.js +84 -0
  19. package/node_modules/tiny-stdio-mcp-server/dist/content/convert.d.ts +16 -0
  20. package/node_modules/tiny-stdio-mcp-server/dist/content/convert.js +61 -0
  21. package/node_modules/tiny-stdio-mcp-server/dist/content/file-type.d.ts +11 -0
  22. package/node_modules/tiny-stdio-mcp-server/dist/content/file-type.js +93 -0
  23. package/node_modules/tiny-stdio-mcp-server/dist/content/file.d.ts +28 -0
  24. package/node_modules/tiny-stdio-mcp-server/dist/content/file.js +110 -0
  25. package/node_modules/tiny-stdio-mcp-server/dist/content/image.d.ts +15 -0
  26. package/node_modules/tiny-stdio-mcp-server/dist/content/image.js +72 -0
  27. package/node_modules/tiny-stdio-mcp-server/dist/content/index.d.ts +7 -0
  28. package/node_modules/tiny-stdio-mcp-server/dist/content/index.js +9 -0
  29. package/node_modules/tiny-stdio-mcp-server/dist/content/mime.d.ts +7 -0
  30. package/node_modules/tiny-stdio-mcp-server/dist/content/mime.js +52 -0
  31. package/node_modules/tiny-stdio-mcp-server/dist/content/remote.d.ts +5 -0
  32. package/node_modules/tiny-stdio-mcp-server/dist/content/remote.js +69 -0
  33. package/node_modules/tiny-stdio-mcp-server/dist/index.d.ts +9 -0
  34. package/node_modules/tiny-stdio-mcp-server/dist/index.js +7 -0
  35. package/node_modules/tiny-stdio-mcp-server/dist/jsonrpc.d.ts +14 -0
  36. package/node_modules/tiny-stdio-mcp-server/dist/jsonrpc.js +118 -0
  37. package/node_modules/tiny-stdio-mcp-server/dist/schema.d.ts +20 -0
  38. package/node_modules/tiny-stdio-mcp-server/dist/schema.js +26 -0
  39. package/node_modules/tiny-stdio-mcp-server/dist/server.d.ts +35 -0
  40. package/node_modules/tiny-stdio-mcp-server/dist/server.js +865 -0
  41. package/node_modules/tiny-stdio-mcp-server/dist/testing.d.ts +7 -0
  42. package/node_modules/tiny-stdio-mcp-server/dist/testing.js +20 -0
  43. package/node_modules/tiny-stdio-mcp-server/dist/types.d.ts +247 -0
  44. package/node_modules/tiny-stdio-mcp-server/dist/types.js +22 -0
  45. package/node_modules/tiny-stdio-mcp-server/package.json +56 -0
  46. package/node_modules/toolcraft-schema/package.json +1 -1
  47. package/package.json +9 -5
@@ -0,0 +1,865 @@
1
+ import * as readline from "readline";
2
+ import AjvModule from "ajv";
3
+ import uriTemplateParser from "uri-template";
4
+ import UriTemplate from "uri-template-lite";
5
+ import { JSON_RPC_ERROR_CODES, ToolError } from "./types.js";
6
+ import { parseMessage, formatSuccessResponse, formatErrorResponse } from "./jsonrpc.js";
7
+ import { toContentBlocks } from "./content/convert.js";
8
+ const PROTOCOL_VERSION = "2025-11-25";
9
+ const SUPPORTED_PROTOCOL_VERSIONS = new Set(["2025-03-26", "2025-06-18", PROTOCOL_VERSION]);
10
+ export function createServer(options) {
11
+ if (options.toolCallTimeoutMs !== undefined &&
12
+ (!Number.isInteger(options.toolCallTimeoutMs) || options.toolCallTimeoutMs <= 0)) {
13
+ throw new Error("toolCallTimeoutMs must be a positive integer.");
14
+ }
15
+ const Ajv = "default" in AjvModule ? AjvModule.default : AjvModule;
16
+ const jsonSchemaValidator = new Ajv({ strict: false });
17
+ const supportNotifications = options.supportNotifications !== false;
18
+ const supportResourceSubscriptions = options.supportResourceSubscriptions !== false;
19
+ const tools = new Map();
20
+ const prompts = new Map();
21
+ const resources = new Map();
22
+ const resourceTemplates = new Map();
23
+ const methods = new Map();
24
+ const notificationListeners = new Set();
25
+ const connectionNotificationListeners = new Map();
26
+ const defaultLifecycle = {
27
+ initialized: false,
28
+ initializeAccepted: false,
29
+ notificationReady: false,
30
+ resourceSubscriptions: new Set(),
31
+ abortController: new AbortController()
32
+ };
33
+ const messageLifecycles = new Set([defaultLifecycle]);
34
+ const handleMessageWithLifecycle = async (method, lifecycle, params) => {
35
+ // Allow ping and initialize before initialization
36
+ if (method === "ping") {
37
+ return { result: {} };
38
+ }
39
+ if (method === "initialize") {
40
+ // Re-initialize on the same connection is idempotent: real MCP clients
41
+ // (e.g. kimi-cli via fastmcp) re-send `initialize` on a persistent
42
+ // connection per tool call, and the official MCP SDK server re-responds
43
+ // with InitializeResult instead of erroring. Per-connection isolation is
44
+ // still enforced by the separate lifecycle object given to each connection.
45
+ lifecycle.initializeAccepted = true;
46
+ lifecycle.initialized = true;
47
+ lifecycle.notificationReady = false;
48
+ const requestedProtocol = typeof params?.protocolVersion === "string" ? params.protocolVersion : undefined;
49
+ const result = {
50
+ protocolVersion: requestedProtocol !== undefined && SUPPORTED_PROTOCOL_VERSIONS.has(requestedProtocol)
51
+ ? requestedProtocol
52
+ : PROTOCOL_VERSION,
53
+ capabilities: {
54
+ tools: {
55
+ ...(supportNotifications ? { listChanged: true } : {})
56
+ },
57
+ prompts: {
58
+ ...(supportNotifications ? { listChanged: true } : {})
59
+ },
60
+ resources: {
61
+ ...(supportNotifications ? { listChanged: true } : {}),
62
+ ...(supportResourceSubscriptions ? { subscribe: true } : {})
63
+ }
64
+ },
65
+ serverInfo: {
66
+ name: options.name,
67
+ version: options.version
68
+ }
69
+ };
70
+ return { result };
71
+ }
72
+ if (method === "notifications/initialized") {
73
+ if (!lifecycle.initializeAccepted) {
74
+ return {
75
+ error: {
76
+ code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
77
+ message: "Server not initialized"
78
+ }
79
+ };
80
+ }
81
+ lifecycle.notificationReady = true;
82
+ return { result: undefined };
83
+ }
84
+ // All other methods require initialization
85
+ if (!lifecycle.initialized) {
86
+ return {
87
+ error: {
88
+ code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
89
+ message: "Server not initialized"
90
+ }
91
+ };
92
+ }
93
+ if (method === "tools/list") {
94
+ const toolList = [];
95
+ for (const tool of tools.values()) {
96
+ const descriptor = { ...tool };
97
+ delete descriptor.handler;
98
+ delete descriptor.inputValidator;
99
+ delete descriptor.outputValidator;
100
+ toolList.push({
101
+ ...descriptor
102
+ });
103
+ }
104
+ return { result: { tools: toolList } };
105
+ }
106
+ if (method === "tools/call") {
107
+ const toolName = params?.name;
108
+ if (!toolName) {
109
+ return {
110
+ error: {
111
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
112
+ message: "Tool name required"
113
+ }
114
+ };
115
+ }
116
+ const tool = tools.get(toolName);
117
+ if (!tool) {
118
+ return {
119
+ error: {
120
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
121
+ message: `Tool not found: ${toolName}`
122
+ }
123
+ };
124
+ }
125
+ const toolArgs = (params?.arguments ?? {});
126
+ if (options.validateToolArguments !== false && !tool.inputValidator(toolArgs)) {
127
+ const errors = tool.inputValidator.errors ?? [];
128
+ return {
129
+ error: {
130
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
131
+ message: `Invalid tool arguments: ${jsonSchemaValidator.errorsText(errors)}`,
132
+ data: errors
133
+ }
134
+ };
135
+ }
136
+ try {
137
+ let handlerResult;
138
+ if (options.toolCallTimeoutMs === undefined) {
139
+ handlerResult = await tool.handler(toolArgs);
140
+ }
141
+ else {
142
+ let timeout;
143
+ const handlerPromise = Promise.resolve().then(() => tool.handler(toolArgs));
144
+ handlerResult = await Promise.race([
145
+ handlerPromise,
146
+ new Promise((_resolve, reject) => {
147
+ timeout = setTimeout(() => {
148
+ reject(new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Tool call timed out: ${toolName}`));
149
+ }, options.toolCallTimeoutMs);
150
+ })
151
+ ]).finally(() => {
152
+ if (timeout !== undefined) {
153
+ clearTimeout(timeout);
154
+ }
155
+ });
156
+ }
157
+ const result = normalizeToolResult(handlerResult, tool.outputSchema);
158
+ if (result.isError !== true &&
159
+ tool.outputValidator !== undefined &&
160
+ !tool.outputValidator(result.structuredContent)) {
161
+ const errors = tool.outputValidator.errors ?? [];
162
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Invalid structured tool result: ${jsonSchemaValidator.errorsText(errors)}`, errors);
163
+ }
164
+ return { result };
165
+ }
166
+ catch (err) {
167
+ if (err instanceof ToolError) {
168
+ return {
169
+ error: {
170
+ code: err.code,
171
+ message: err.message,
172
+ ...(err.data === undefined ? {} : { data: err.data })
173
+ }
174
+ };
175
+ }
176
+ const errorMessage = err instanceof Error ? err.message : String(err);
177
+ const result = {
178
+ content: [{ type: "text", text: `Error: ${errorMessage}` }],
179
+ isError: true
180
+ };
181
+ return { result };
182
+ }
183
+ }
184
+ if (method === "prompts/list") {
185
+ return {
186
+ result: {
187
+ prompts: [...prompts.values()].map(({ handler: _handler, ...prompt }) => prompt)
188
+ }
189
+ };
190
+ }
191
+ if (method === "prompts/get") {
192
+ const promptName = typeof params?.name === "string" ? params.name : undefined;
193
+ if (promptName === undefined) {
194
+ return invalidParams("Prompt name required");
195
+ }
196
+ const prompt = prompts.get(promptName);
197
+ if (prompt === undefined) {
198
+ return invalidParams(`Prompt not found: ${promptName}`);
199
+ }
200
+ const args = toStringArguments(params?.arguments);
201
+ if (args === undefined || !hasRequiredPromptArguments(prompt, args)) {
202
+ return invalidParams("Invalid prompt arguments");
203
+ }
204
+ try {
205
+ const result = await prompt.handler(args);
206
+ if (!isGetPromptResult(result)) {
207
+ return internalError("Invalid prompt result");
208
+ }
209
+ return { result };
210
+ }
211
+ catch (error) {
212
+ return internalError(toErrorMessage(error));
213
+ }
214
+ }
215
+ if (method === "resources/list") {
216
+ return {
217
+ result: {
218
+ resources: [...resources.values()].map(({ handler: _handler, ...resource }) => resource)
219
+ }
220
+ };
221
+ }
222
+ if (method === "resources/templates/list") {
223
+ return {
224
+ result: {
225
+ resourceTemplates: [...resourceTemplates.values()].map(({ handler: _handler, ...resourceTemplate }) => resourceTemplate)
226
+ }
227
+ };
228
+ }
229
+ if (method === "resources/read") {
230
+ const uri = typeof params?.uri === "string" ? params.uri : undefined;
231
+ if (uri === undefined || !isValidUri(uri)) {
232
+ return invalidParams("Resource URI required");
233
+ }
234
+ const resource = findReadableResource(uri, resources, resourceTemplates);
235
+ if (resource === undefined) {
236
+ return resourceNotFound(uri);
237
+ }
238
+ try {
239
+ const result = await resource.handler(uri);
240
+ if (!isReadResourceResult(result)) {
241
+ return internalError("Invalid resource result");
242
+ }
243
+ return { result };
244
+ }
245
+ catch (error) {
246
+ return internalError(toErrorMessage(error));
247
+ }
248
+ }
249
+ if (method === "resources/subscribe" || method === "resources/unsubscribe") {
250
+ if (!supportResourceSubscriptions) {
251
+ return {
252
+ error: {
253
+ code: JSON_RPC_ERROR_CODES.METHOD_NOT_FOUND,
254
+ message: "Method not found"
255
+ }
256
+ };
257
+ }
258
+ const uri = typeof params?.uri === "string" ? params.uri : undefined;
259
+ if (uri === undefined || !isValidUri(uri)) {
260
+ return invalidParams("Resource URI required");
261
+ }
262
+ if (method === "resources/subscribe" &&
263
+ findReadableResource(uri, resources, resourceTemplates) === undefined) {
264
+ return resourceNotFound(uri);
265
+ }
266
+ if (method === "resources/subscribe") {
267
+ lifecycle.resourceSubscriptions.add(uri);
268
+ }
269
+ else {
270
+ lifecycle.resourceSubscriptions.delete(uri);
271
+ }
272
+ return { result: {} };
273
+ }
274
+ const customMethod = methods.get(method);
275
+ if (customMethod !== undefined) {
276
+ try {
277
+ const result = await customMethod(params, {
278
+ signal: lifecycle.abortController.signal,
279
+ async notify(notificationMethod, notificationParams) {
280
+ if (!lifecycle.notificationReady || lifecycle.listener === undefined) {
281
+ return;
282
+ }
283
+ await lifecycle.listener({
284
+ jsonrpc: "2.0",
285
+ method: notificationMethod,
286
+ ...(notificationParams === undefined ? {} : { params: notificationParams })
287
+ });
288
+ }
289
+ });
290
+ return { result };
291
+ }
292
+ catch (error) {
293
+ return internalError(toErrorMessage(error));
294
+ }
295
+ }
296
+ return {
297
+ error: {
298
+ code: JSON_RPC_ERROR_CODES.METHOD_NOT_FOUND,
299
+ message: "Method not found"
300
+ }
301
+ };
302
+ };
303
+ const createMessageSession = (listener) => {
304
+ const lifecycle = {
305
+ initialized: false,
306
+ initializeAccepted: false,
307
+ notificationReady: false,
308
+ resourceSubscriptions: new Set(),
309
+ abortController: new AbortController(),
310
+ listener
311
+ };
312
+ messageLifecycles.add(lifecycle);
313
+ if (listener !== undefined) {
314
+ connectionNotificationListeners.set(listener, lifecycle);
315
+ }
316
+ return {
317
+ handleMessage: (method, params) => handleMessageWithLifecycle(method, lifecycle, params),
318
+ close: () => {
319
+ lifecycle.abortController.abort();
320
+ if (listener !== undefined) {
321
+ connectionNotificationListeners.delete(listener);
322
+ }
323
+ messageLifecycles.delete(lifecycle);
324
+ }
325
+ };
326
+ };
327
+ const handleMessage = (method, params) => handleMessageWithLifecycle(method, defaultLifecycle, params);
328
+ const processLine = async (line, write, messageHandler) => {
329
+ const parsed = parseMessage(line);
330
+ if (!parsed.success) {
331
+ write(formatErrorResponse(parsed.id, parsed.error) + "\n");
332
+ return;
333
+ }
334
+ const { request, isNotification } = parsed;
335
+ if (isNotification && request.method === "initialize") {
336
+ return;
337
+ }
338
+ if (!isNotification && request.method === "notifications/initialized") {
339
+ const requestWithId = request;
340
+ write(formatErrorResponse(requestWithId.id, {
341
+ code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
342
+ message: "Invalid Request"
343
+ }) + "\n");
344
+ return;
345
+ }
346
+ let handled;
347
+ try {
348
+ handled = await messageHandler(request.method, request.params);
349
+ }
350
+ catch {
351
+ if (!isNotification) {
352
+ const requestWithId = request;
353
+ write(formatErrorResponse(requestWithId.id, {
354
+ code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
355
+ message: "Internal error"
356
+ }) + "\n");
357
+ }
358
+ return;
359
+ }
360
+ const { result, error } = handled;
361
+ if (isNotification) {
362
+ return;
363
+ }
364
+ const requestWithId = request;
365
+ if (error) {
366
+ write(formatErrorResponse(requestWithId.id, error) + "\n");
367
+ }
368
+ else if (result !== undefined) {
369
+ write(formatSuccessResponse(requestWithId.id, result) + "\n");
370
+ }
371
+ };
372
+ const broadcastNotification = async (method, params, canSend = () => true) => {
373
+ const notification = {
374
+ jsonrpc: "2.0",
375
+ method,
376
+ ...(params === undefined ? {} : { params })
377
+ };
378
+ for (const listener of notificationListeners) {
379
+ listener(notification);
380
+ }
381
+ await Promise.all([...connectionNotificationListeners].map(async ([listener, lifecycle]) => {
382
+ if (lifecycle.notificationReady && canSend(lifecycle)) {
383
+ await listener(notification);
384
+ }
385
+ }));
386
+ };
387
+ const server = {
388
+ tool(name, description, inputSchema, handler, outputSchema) {
389
+ assertNonEmptyName(name, "Tool name required");
390
+ const inputValidator = jsonSchemaValidator.compile(inputSchema);
391
+ let outputValidator;
392
+ if (outputSchema !== undefined) {
393
+ assertObjectRootSchema(outputSchema, "outputSchema");
394
+ outputValidator = jsonSchemaValidator.compile(outputSchema);
395
+ }
396
+ tools.set(name, {
397
+ name,
398
+ description,
399
+ inputSchema: inputSchema,
400
+ ...(outputSchema === undefined ? {} : { outputSchema: outputSchema }),
401
+ handler: handler,
402
+ inputValidator,
403
+ ...(outputValidator === undefined ? {} : { outputValidator })
404
+ });
405
+ return server;
406
+ },
407
+ registerTool(definition, handler) {
408
+ assertNonEmptyName(definition.name, "Tool name required");
409
+ const inputValidator = jsonSchemaValidator.compile(definition.inputSchema);
410
+ let outputValidator;
411
+ if (definition.outputSchema !== undefined) {
412
+ assertObjectRootSchema(definition.outputSchema, "outputSchema");
413
+ outputValidator = jsonSchemaValidator.compile(definition.outputSchema);
414
+ }
415
+ tools.set(definition.name, {
416
+ ...definition,
417
+ handler: handler,
418
+ inputValidator,
419
+ ...(outputValidator === undefined ? {} : { outputValidator })
420
+ });
421
+ return server;
422
+ },
423
+ prompt(definition, handler) {
424
+ assertNonEmptyName(definition.name, "Prompt name required");
425
+ prompts.set(definition.name, { ...definition, handler });
426
+ return server;
427
+ },
428
+ resource(definition, handler) {
429
+ if (!isValidUri(definition.uri)) {
430
+ throw new Error(`Invalid resource URI: ${definition.uri}`);
431
+ }
432
+ resources.set(definition.uri, { ...definition, handler });
433
+ return server;
434
+ },
435
+ resourceTemplate(definition, handler) {
436
+ assertReadableUriTemplate(definition.uriTemplate);
437
+ new UriTemplate(definition.uriTemplate);
438
+ resourceTemplates.set(definition.uriTemplate, { ...definition, handler });
439
+ return server;
440
+ },
441
+ method(name, handler) {
442
+ assertNonEmptyName(name, "Method name required");
443
+ methods.set(name, handler);
444
+ return server;
445
+ },
446
+ onNotification(listener) {
447
+ notificationListeners.add(listener);
448
+ return () => {
449
+ notificationListeners.delete(listener);
450
+ };
451
+ },
452
+ removeTool(name) {
453
+ return tools.delete(name);
454
+ },
455
+ removePrompt(name) {
456
+ return prompts.delete(name);
457
+ },
458
+ removeResource(uri) {
459
+ return resources.delete(uri);
460
+ },
461
+ removeResourceTemplate(uriTemplate) {
462
+ return resourceTemplates.delete(uriTemplate);
463
+ },
464
+ async notifyToolsChanged() {
465
+ if (supportNotifications &&
466
+ [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
467
+ await broadcastNotification("notifications/tools/list_changed");
468
+ }
469
+ },
470
+ async notifyPromptsChanged() {
471
+ if (supportNotifications &&
472
+ [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
473
+ await broadcastNotification("notifications/prompts/list_changed");
474
+ }
475
+ },
476
+ async notifyResourcesChanged() {
477
+ if (supportNotifications &&
478
+ [...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
479
+ await broadcastNotification("notifications/resources/list_changed");
480
+ }
481
+ },
482
+ async notifyResourceUpdated(uri) {
483
+ if (!supportResourceSubscriptions) {
484
+ return;
485
+ }
486
+ await broadcastNotification("notifications/resources/updated", { uri }, (lifecycle) => lifecycle.resourceSubscriptions.has(uri));
487
+ },
488
+ createMessageSession,
489
+ handleMessage,
490
+ async listen() {
491
+ return server.connect({
492
+ readable: process.stdin,
493
+ writable: process.stdout
494
+ });
495
+ },
496
+ async connect(transport) {
497
+ return new Promise((resolve) => {
498
+ const listener = (notification) => {
499
+ transport.writable.write(`${JSON.stringify(notification)}\n`);
500
+ };
501
+ const session = server.createMessageSession(listener);
502
+ const rl = readline.createInterface({
503
+ input: transport.readable,
504
+ crlfDelay: Infinity
505
+ });
506
+ const pendingMessages = new Set();
507
+ rl.on("line", (line) => {
508
+ const message = processLine(line, (data) => transport.writable.write(data), session.handleMessage);
509
+ pendingMessages.add(message);
510
+ void message.finally(() => {
511
+ pendingMessages.delete(message);
512
+ });
513
+ });
514
+ rl.on("close", async () => {
515
+ await Promise.all([...pendingMessages]);
516
+ session.close();
517
+ resolve();
518
+ });
519
+ });
520
+ },
521
+ async connectSDK(transport) {
522
+ return new Promise((resolve, reject) => {
523
+ const listener = (notification) => transport.send(notification);
524
+ const session = server.createMessageSession(listener);
525
+ transport.onmessage = async (message) => {
526
+ // Ignore responses (we only handle requests/notifications)
527
+ if (!("method" in message)) {
528
+ return;
529
+ }
530
+ // Handle notifications (no id) - don't respond
531
+ if (!("id" in message) || message.id === undefined) {
532
+ if (message.method === "initialize") {
533
+ return;
534
+ }
535
+ try {
536
+ await session.handleMessage(message.method, message.params);
537
+ }
538
+ catch {
539
+ return;
540
+ }
541
+ return;
542
+ }
543
+ if (message.method === "notifications/initialized") {
544
+ await transport.send({
545
+ jsonrpc: "2.0",
546
+ id: message.id,
547
+ error: {
548
+ code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
549
+ message: "Invalid Request"
550
+ }
551
+ });
552
+ return;
553
+ }
554
+ const request = message;
555
+ let handled;
556
+ try {
557
+ handled = await session.handleMessage(request.method, request.params);
558
+ }
559
+ catch {
560
+ await transport.send({
561
+ jsonrpc: "2.0",
562
+ id: request.id,
563
+ error: {
564
+ code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
565
+ message: "Internal error"
566
+ }
567
+ });
568
+ return;
569
+ }
570
+ const { result, error } = handled;
571
+ if (error) {
572
+ const response = {
573
+ jsonrpc: "2.0",
574
+ id: request.id,
575
+ error
576
+ };
577
+ await transport.send(response);
578
+ }
579
+ else if (result !== undefined) {
580
+ const response = {
581
+ jsonrpc: "2.0",
582
+ id: request.id,
583
+ result
584
+ };
585
+ await transport.send(response);
586
+ }
587
+ };
588
+ transport.onclose = () => {
589
+ session.close();
590
+ resolve();
591
+ };
592
+ void transport.start().catch((error) => {
593
+ session.close();
594
+ reject(error);
595
+ });
596
+ });
597
+ }
598
+ };
599
+ return server;
600
+ }
601
+ function invalidParams(message) {
602
+ return {
603
+ error: {
604
+ code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
605
+ message
606
+ }
607
+ };
608
+ }
609
+ function internalError(message) {
610
+ return {
611
+ error: {
612
+ code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
613
+ message
614
+ }
615
+ };
616
+ }
617
+ function resourceNotFound(uri) {
618
+ return {
619
+ error: {
620
+ code: JSON_RPC_ERROR_CODES.RESOURCE_NOT_FOUND,
621
+ message: `Resource not found: ${uri}`
622
+ }
623
+ };
624
+ }
625
+ function toErrorMessage(error) {
626
+ return error instanceof Error ? error.message : String(error);
627
+ }
628
+ function isValidUri(uri) {
629
+ try {
630
+ new URL(uri);
631
+ return true;
632
+ }
633
+ catch {
634
+ return false;
635
+ }
636
+ }
637
+ function assertNonEmptyName(name, message) {
638
+ if (name.length === 0) {
639
+ throw new Error(message);
640
+ }
641
+ }
642
+ function assertReadableUriTemplate(uriTemplate) {
643
+ const parsed = uriTemplateParser.parse(uriTemplate);
644
+ const expanded = parsed.expand(new Proxy({}, {
645
+ get: (_target, property) => (typeof property === "string" ? "value" : undefined)
646
+ }));
647
+ if (typeof expanded !== "string" || !isValidUri(expanded)) {
648
+ throw new Error(`Invalid resource URI template: ${uriTemplate}`);
649
+ }
650
+ }
651
+ function toStringArguments(value) {
652
+ if (value === undefined) {
653
+ return {};
654
+ }
655
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
656
+ return undefined;
657
+ }
658
+ const args = {};
659
+ for (const [name, argument] of Object.entries(value)) {
660
+ if (typeof argument !== "string") {
661
+ return undefined;
662
+ }
663
+ args[name] = argument;
664
+ }
665
+ return args;
666
+ }
667
+ function hasRequiredPromptArguments(prompt, args) {
668
+ return (prompt.arguments ?? []).every((argument) => argument.required !== true || args[argument.name] !== undefined);
669
+ }
670
+ function findReadableResource(uri, resources, resourceTemplates) {
671
+ const resource = resources.get(uri);
672
+ if (resource !== undefined) {
673
+ return resource;
674
+ }
675
+ return [...resourceTemplates.values()].find((template) => matchesUriTemplate(template.uriTemplate, uri));
676
+ }
677
+ function matchesUriTemplate(template, uri) {
678
+ try {
679
+ return new UriTemplate(template).match(uri) !== null;
680
+ }
681
+ catch {
682
+ return false;
683
+ }
684
+ }
685
+ function isCallToolResult(value) {
686
+ if (!hasContentArray(value) || !value.content.every(isContentItem)) {
687
+ return false;
688
+ }
689
+ if (hasOwnProperty(value, "structuredContent") &&
690
+ value.structuredContent !== undefined &&
691
+ !isJsonObject(value.structuredContent)) {
692
+ return false;
693
+ }
694
+ return !(hasOwnProperty(value, "isError") &&
695
+ value.isError !== undefined &&
696
+ typeof value.isError !== "boolean");
697
+ }
698
+ function normalizeToolResult(handlerResult, outputSchema) {
699
+ if (hasContentArray(handlerResult) && !isCallToolResult(handlerResult)) {
700
+ throw new Error("Invalid tool result");
701
+ }
702
+ if (outputSchema === undefined) {
703
+ const result = isCallToolResult(handlerResult)
704
+ ? handlerResult
705
+ : { content: toContentBlocks(handlerResult) };
706
+ if (!isCallToolResult(result)) {
707
+ throw new Error("Invalid tool result");
708
+ }
709
+ return result;
710
+ }
711
+ if (isCallToolResult(handlerResult) && handlerResult.isError === true) {
712
+ return handlerResult;
713
+ }
714
+ const callToolResult = isCallToolResult(handlerResult) ? handlerResult : undefined;
715
+ const structuredContent = callToolResult ? callToolResult.structuredContent : handlerResult;
716
+ if (!isJsonObject(structuredContent)) {
717
+ throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, "Structured tool result must be an object");
718
+ }
719
+ return {
720
+ content: callToolResult !== undefined && callToolResult.content.length > 0
721
+ ? callToolResult.content
722
+ : [{ type: "text", text: JSON.stringify(structuredContent) }],
723
+ ...(callToolResult?.isError !== undefined ? { isError: callToolResult.isError } : {}),
724
+ structuredContent
725
+ };
726
+ }
727
+ function assertObjectRootSchema(schema, path) {
728
+ if (schema.type !== "object") {
729
+ throw new Error(`${path} root type must be "object"`);
730
+ }
731
+ }
732
+ function isJsonObject(value) {
733
+ return typeof value === "object" && value !== null && !Array.isArray(value);
734
+ }
735
+ function isGetPromptResult(value) {
736
+ if (typeof value !== "object" || value === null || !hasOwnProperty(value, "messages")) {
737
+ return false;
738
+ }
739
+ return ((!hasOwnProperty(value, "description") ||
740
+ value.description === undefined ||
741
+ typeof value.description === "string") &&
742
+ Array.isArray(value.messages) &&
743
+ value.messages.every((message) => typeof message === "object" &&
744
+ message !== null &&
745
+ hasOwnProperty(message, "role") &&
746
+ (message.role === "user" || message.role === "assistant") &&
747
+ hasOwnProperty(message, "content") &&
748
+ isPromptContentItem(message.content)));
749
+ }
750
+ function isReadResourceResult(value) {
751
+ if (typeof value !== "object" || value === null || !hasOwnProperty(value, "contents")) {
752
+ return false;
753
+ }
754
+ return Array.isArray(value.contents) && value.contents.every(isResourceContents);
755
+ }
756
+ function hasContentArray(value) {
757
+ return (typeof value === "object" &&
758
+ value !== null &&
759
+ hasOwnProperty(value, "content") &&
760
+ Array.isArray(value.content));
761
+ }
762
+ function isContentItem(value) {
763
+ if (typeof value !== "object" || value === null || !hasOwnProperty(value, "type")) {
764
+ return false;
765
+ }
766
+ const block = value;
767
+ if (!hasValidContentAnnotations(block)) {
768
+ return false;
769
+ }
770
+ if (block.type === "text") {
771
+ return hasOwnProperty(block, "text") && typeof block.text === "string";
772
+ }
773
+ if (block.type === "image" || block.type === "audio") {
774
+ return (hasOwnProperty(block, "data") &&
775
+ typeof block.data === "string" &&
776
+ isBase64(block.data) &&
777
+ hasOwnProperty(block, "mimeType") &&
778
+ typeof block.mimeType === "string");
779
+ }
780
+ if (block.type === "resource_link") {
781
+ return (hasOwnProperty(block, "uri") &&
782
+ typeof block.uri === "string" &&
783
+ isValidUri(block.uri) &&
784
+ hasOwnProperty(block, "name") &&
785
+ typeof block.name === "string" &&
786
+ (!hasOwnProperty(block, "title") ||
787
+ block.title === undefined ||
788
+ typeof block.title === "string") &&
789
+ (!hasOwnProperty(block, "description") ||
790
+ block.description === undefined ||
791
+ typeof block.description === "string") &&
792
+ (!hasOwnProperty(block, "mimeType") ||
793
+ block.mimeType === undefined ||
794
+ typeof block.mimeType === "string") &&
795
+ (!hasOwnProperty(block, "size") || block.size === undefined || typeof block.size === "number"));
796
+ }
797
+ if (block.type !== "resource" ||
798
+ !hasOwnProperty(block, "resource") ||
799
+ typeof block.resource !== "object" ||
800
+ block.resource === null) {
801
+ return false;
802
+ }
803
+ return isResourceContents(block.resource);
804
+ }
805
+ function isResourceContents(value) {
806
+ if (typeof value !== "object" ||
807
+ value === null ||
808
+ !hasOwnProperty(value, "uri") ||
809
+ typeof value.uri !== "string" ||
810
+ !isValidUri(value.uri)) {
811
+ return false;
812
+ }
813
+ if (hasOwnProperty(value, "mimeType") &&
814
+ value.mimeType !== undefined &&
815
+ typeof value.mimeType !== "string") {
816
+ return false;
817
+ }
818
+ return ((hasOwnProperty(value, "text") && typeof value.text === "string") ||
819
+ (hasOwnProperty(value, "blob") && typeof value.blob === "string" && isBase64(value.blob)));
820
+ }
821
+ function hasValidContentAnnotations(value) {
822
+ if (!hasOwnProperty(value, "annotations") || value.annotations === undefined) {
823
+ return true;
824
+ }
825
+ if (!isJsonObject(value.annotations)) {
826
+ return false;
827
+ }
828
+ const { audience, priority, lastModified } = value.annotations;
829
+ return ((audience === undefined ||
830
+ (Array.isArray(audience) &&
831
+ audience.every((item) => item === "user" || item === "assistant"))) &&
832
+ (priority === undefined || typeof priority === "number") &&
833
+ (lastModified === undefined || typeof lastModified === "string"));
834
+ }
835
+ function isBase64(value) {
836
+ if (value.length === 0) {
837
+ return true;
838
+ }
839
+ if (value.length % 4 !== 0) {
840
+ return false;
841
+ }
842
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
843
+ const paddingStart = value.indexOf("=");
844
+ const encoded = paddingStart === -1 ? value : value.slice(0, paddingStart);
845
+ const padding = paddingStart === -1 ? "" : value.slice(paddingStart);
846
+ if (padding.length > 2 || [...padding].some((character) => character !== "=")) {
847
+ return false;
848
+ }
849
+ if ([...encoded].some((character) => !alphabet.includes(character))) {
850
+ return false;
851
+ }
852
+ return Buffer.from(value, "base64").toString("base64") === value;
853
+ }
854
+ function isPromptContentItem(value) {
855
+ if (!isContentItem(value)) {
856
+ return false;
857
+ }
858
+ return !(typeof value === "object" &&
859
+ value !== null &&
860
+ hasOwnProperty(value, "type") &&
861
+ value.type === "resource_link");
862
+ }
863
+ function hasOwnProperty(value, name) {
864
+ return Object.prototype.hasOwnProperty.call(value, name);
865
+ }