tiny-stdio-mcp-server 0.1.14 → 0.1.16
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 +6 -2
- package/dist/jsonrpc.js +2 -1
- package/dist/server.js +178 -168
- package/dist/types.d.ts +1 -4
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ server.tool("search", "Search for things", schema, async ({ query, limit }) => {
|
|
|
58
58
|
});
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
For structured-data tools, pass a root-object output schema. The server advertises it as MCP `Tool.outputSchema`, validates
|
|
61
|
+
For structured-data tools, pass a root-object output schema. The server advertises it as MCP `Tool.outputSchema`, validates successful handler results, and returns them as `CallToolResult.structuredContent`. Plain object returns receive a JSON text backstop in `content[]` for older clients. Explicit `CallToolResult` values keep their handler-supplied content blocks; the JSON text backstop is added only when `content` is empty.
|
|
62
62
|
|
|
63
63
|
```ts
|
|
64
64
|
const input = defineSchema({
|
|
@@ -89,7 +89,11 @@ server.tool(
|
|
|
89
89
|
);
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Output schemas must have `type: "object"` at the root
|
|
92
|
+
Output schemas must have `type: "object"` at the root because MCP structured content is an object. Otherwise, any schema accepted by Ajv is supported, including composition keywords, nullable type unions, and local `$defs`/`$ref` references. Input and output schemas compile synchronously during `.tool()` or `.registerTool()` registration, so malformed schemas throw immediately instead of failing on the first tool call.
|
|
93
|
+
|
|
94
|
+
Successful structured results must satisfy `outputSchema`. Validation failures use JSON-RPC `-32602` for inputs and `-32603` for outputs, with Ajv's formatted error text in the message and the raw Ajv error array in `error.data`. Explicit handler results with `isError: true` are passed through unchanged and are exempt from structured-content and output-schema validation.
|
|
95
|
+
|
|
96
|
+
Tools whose natural result is prose, images, audio, files, or other content blocks should omit `outputSchema` and keep returning content.
|
|
93
97
|
|
|
94
98
|
### `.listen()`
|
|
95
99
|
|
package/dist/jsonrpc.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -47,7 +47,8 @@ export function createServer(options) {
|
|
|
47
47
|
? params.protocolVersion
|
|
48
48
|
: undefined;
|
|
49
49
|
const result = {
|
|
50
|
-
protocolVersion: requestedProtocol !== undefined &&
|
|
50
|
+
protocolVersion: requestedProtocol !== undefined &&
|
|
51
|
+
SUPPORTED_PROTOCOL_VERSIONS.has(requestedProtocol)
|
|
51
52
|
? requestedProtocol
|
|
52
53
|
: PROTOCOL_VERSION,
|
|
53
54
|
capabilities: {
|
|
@@ -95,6 +96,9 @@ export function createServer(options) {
|
|
|
95
96
|
for (const tool of tools.values()) {
|
|
96
97
|
const descriptor = { ...tool };
|
|
97
98
|
delete descriptor.handler;
|
|
99
|
+
delete descriptor.inputValidator;
|
|
100
|
+
delete descriptor
|
|
101
|
+
.outputValidator;
|
|
98
102
|
toolList.push({
|
|
99
103
|
...descriptor,
|
|
100
104
|
});
|
|
@@ -121,19 +125,25 @@ export function createServer(options) {
|
|
|
121
125
|
};
|
|
122
126
|
}
|
|
123
127
|
const toolArgs = (params?.arguments ?? {});
|
|
124
|
-
if (options.validateToolArguments !== false &&
|
|
128
|
+
if (options.validateToolArguments !== false &&
|
|
129
|
+
!tool.inputValidator(toolArgs)) {
|
|
130
|
+
const errors = tool.inputValidator.errors ?? [];
|
|
125
131
|
return {
|
|
126
132
|
error: {
|
|
127
133
|
code: JSON_RPC_ERROR_CODES.INVALID_PARAMS,
|
|
128
|
-
message:
|
|
134
|
+
message: `Invalid tool arguments: ${jsonSchemaValidator.errorsText(errors)}`,
|
|
135
|
+
data: errors,
|
|
129
136
|
},
|
|
130
137
|
};
|
|
131
138
|
}
|
|
132
139
|
try {
|
|
133
140
|
const handlerResult = await tool.handler(toolArgs);
|
|
134
141
|
const result = normalizeToolResult(handlerResult, tool.outputSchema);
|
|
135
|
-
if (
|
|
136
|
-
|
|
142
|
+
if (result.isError !== true &&
|
|
143
|
+
tool.outputValidator !== undefined &&
|
|
144
|
+
!tool.outputValidator(result.structuredContent)) {
|
|
145
|
+
const errors = tool.outputValidator.errors ?? [];
|
|
146
|
+
throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, `Invalid structured tool result: ${jsonSchemaValidator.errorsText(errors)}`, errors);
|
|
137
147
|
}
|
|
138
148
|
return { result };
|
|
139
149
|
}
|
|
@@ -220,7 +230,8 @@ export function createServer(options) {
|
|
|
220
230
|
return internalError(toErrorMessage(error));
|
|
221
231
|
}
|
|
222
232
|
}
|
|
223
|
-
if (method === "resources/subscribe" ||
|
|
233
|
+
if (method === "resources/subscribe" ||
|
|
234
|
+
method === "resources/unsubscribe") {
|
|
224
235
|
if (!supportResourceSubscriptions) {
|
|
225
236
|
return {
|
|
226
237
|
error: {
|
|
@@ -233,8 +244,8 @@ export function createServer(options) {
|
|
|
233
244
|
if (uri === undefined || !isValidUri(uri)) {
|
|
234
245
|
return invalidParams("Resource URI required");
|
|
235
246
|
}
|
|
236
|
-
if (method === "resources/subscribe"
|
|
237
|
-
|
|
247
|
+
if (method === "resources/subscribe" &&
|
|
248
|
+
findReadableResource(uri, resources, resourceTemplates) === undefined) {
|
|
238
249
|
return resourceNotFound(uri);
|
|
239
250
|
}
|
|
240
251
|
if (method === "resources/subscribe") {
|
|
@@ -292,7 +303,21 @@ export function createServer(options) {
|
|
|
292
303
|
}) + "\n");
|
|
293
304
|
return;
|
|
294
305
|
}
|
|
295
|
-
|
|
306
|
+
let handled;
|
|
307
|
+
try {
|
|
308
|
+
handled = await messageHandler(request.method, request.params);
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
if (!isNotification) {
|
|
312
|
+
const requestWithId = request;
|
|
313
|
+
write(formatErrorResponse(requestWithId.id, {
|
|
314
|
+
code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
|
|
315
|
+
message: "Internal error",
|
|
316
|
+
}) + "\n");
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const { result, error } = handled;
|
|
296
321
|
if (isNotification) {
|
|
297
322
|
return;
|
|
298
323
|
}
|
|
@@ -322,26 +347,38 @@ export function createServer(options) {
|
|
|
322
347
|
const server = {
|
|
323
348
|
tool(name, description, inputSchema, handler, outputSchema) {
|
|
324
349
|
assertNonEmptyName(name, "Tool name required");
|
|
350
|
+
const inputValidator = jsonSchemaValidator.compile(inputSchema);
|
|
351
|
+
let outputValidator;
|
|
325
352
|
if (outputSchema !== undefined) {
|
|
326
|
-
|
|
353
|
+
assertObjectRootSchema(outputSchema, "outputSchema");
|
|
354
|
+
outputValidator = jsonSchemaValidator.compile(outputSchema);
|
|
327
355
|
}
|
|
328
356
|
tools.set(name, {
|
|
329
357
|
name,
|
|
330
358
|
description,
|
|
331
359
|
inputSchema: inputSchema,
|
|
332
|
-
...(outputSchema === undefined
|
|
360
|
+
...(outputSchema === undefined
|
|
361
|
+
? {}
|
|
362
|
+
: { outputSchema: outputSchema }),
|
|
333
363
|
handler: handler,
|
|
364
|
+
inputValidator,
|
|
365
|
+
...(outputValidator === undefined ? {} : { outputValidator }),
|
|
334
366
|
});
|
|
335
367
|
return server;
|
|
336
368
|
},
|
|
337
369
|
registerTool(definition, handler) {
|
|
338
370
|
assertNonEmptyName(definition.name, "Tool name required");
|
|
371
|
+
const inputValidator = jsonSchemaValidator.compile(definition.inputSchema);
|
|
372
|
+
let outputValidator;
|
|
339
373
|
if (definition.outputSchema !== undefined) {
|
|
340
|
-
|
|
374
|
+
assertObjectRootSchema(definition.outputSchema, "outputSchema");
|
|
375
|
+
outputValidator = jsonSchemaValidator.compile(definition.outputSchema);
|
|
341
376
|
}
|
|
342
377
|
tools.set(definition.name, {
|
|
343
378
|
...definition,
|
|
344
379
|
handler: handler,
|
|
380
|
+
inputValidator,
|
|
381
|
+
...(outputValidator === undefined ? {} : { outputValidator }),
|
|
345
382
|
});
|
|
346
383
|
return server;
|
|
347
384
|
},
|
|
@@ -382,17 +419,20 @@ export function createServer(options) {
|
|
|
382
419
|
return resourceTemplates.delete(uriTemplate);
|
|
383
420
|
},
|
|
384
421
|
async notifyToolsChanged() {
|
|
385
|
-
if (supportNotifications &&
|
|
422
|
+
if (supportNotifications &&
|
|
423
|
+
[...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
|
|
386
424
|
await broadcastNotification("notifications/tools/list_changed");
|
|
387
425
|
}
|
|
388
426
|
},
|
|
389
427
|
async notifyPromptsChanged() {
|
|
390
|
-
if (supportNotifications &&
|
|
428
|
+
if (supportNotifications &&
|
|
429
|
+
[...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
|
|
391
430
|
await broadcastNotification("notifications/prompts/list_changed");
|
|
392
431
|
}
|
|
393
432
|
},
|
|
394
433
|
async notifyResourcesChanged() {
|
|
395
|
-
if (supportNotifications &&
|
|
434
|
+
if (supportNotifications &&
|
|
435
|
+
[...messageLifecycles].some((lifecycle) => lifecycle.notificationReady)) {
|
|
396
436
|
await broadcastNotification("notifications/resources/list_changed");
|
|
397
437
|
}
|
|
398
438
|
},
|
|
@@ -412,20 +452,17 @@ export function createServer(options) {
|
|
|
412
452
|
},
|
|
413
453
|
async connect(transport) {
|
|
414
454
|
return new Promise((resolve) => {
|
|
415
|
-
const lifecycle = { initialized: false, initializeAccepted: false, notificationReady: false, resourceSubscriptions: new Set() };
|
|
416
|
-
const messageHandler = (method, params) => handleMessageWithLifecycle(method, lifecycle, params);
|
|
417
|
-
messageLifecycles.add(lifecycle);
|
|
418
455
|
const listener = (notification) => {
|
|
419
456
|
transport.writable.write(`${JSON.stringify(notification)}\n`);
|
|
420
457
|
};
|
|
421
|
-
|
|
458
|
+
const session = server.createMessageSession(listener);
|
|
422
459
|
const rl = readline.createInterface({
|
|
423
460
|
input: transport.readable,
|
|
424
461
|
crlfDelay: Infinity,
|
|
425
462
|
});
|
|
426
463
|
const pendingMessages = new Set();
|
|
427
464
|
rl.on("line", (line) => {
|
|
428
|
-
const message = processLine(line, (data) => transport.writable.write(data),
|
|
465
|
+
const message = processLine(line, (data) => transport.writable.write(data), session.handleMessage);
|
|
429
466
|
pendingMessages.add(message);
|
|
430
467
|
void message.finally(() => {
|
|
431
468
|
pendingMessages.delete(message);
|
|
@@ -433,19 +470,15 @@ export function createServer(options) {
|
|
|
433
470
|
});
|
|
434
471
|
rl.on("close", async () => {
|
|
435
472
|
await Promise.all([...pendingMessages]);
|
|
436
|
-
|
|
437
|
-
messageLifecycles.delete(lifecycle);
|
|
473
|
+
session.close();
|
|
438
474
|
resolve();
|
|
439
475
|
});
|
|
440
476
|
});
|
|
441
477
|
},
|
|
442
478
|
async connectSDK(transport) {
|
|
443
479
|
return new Promise((resolve, reject) => {
|
|
444
|
-
const lifecycle = { initialized: false, initializeAccepted: false, notificationReady: false, resourceSubscriptions: new Set() };
|
|
445
|
-
const messageHandler = (method, params) => handleMessageWithLifecycle(method, lifecycle, params);
|
|
446
|
-
messageLifecycles.add(lifecycle);
|
|
447
480
|
const listener = (notification) => transport.send(notification);
|
|
448
|
-
|
|
481
|
+
const session = server.createMessageSession(listener);
|
|
449
482
|
transport.onmessage = async (message) => {
|
|
450
483
|
// Ignore responses (we only handle requests/notifications)
|
|
451
484
|
if (!("method" in message)) {
|
|
@@ -456,7 +489,12 @@ export function createServer(options) {
|
|
|
456
489
|
if (message.method === "initialize") {
|
|
457
490
|
return;
|
|
458
491
|
}
|
|
459
|
-
|
|
492
|
+
try {
|
|
493
|
+
await session.handleMessage(message.method, message.params);
|
|
494
|
+
}
|
|
495
|
+
catch {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
460
498
|
return;
|
|
461
499
|
}
|
|
462
500
|
if (message.method === "notifications/initialized") {
|
|
@@ -471,7 +509,22 @@ export function createServer(options) {
|
|
|
471
509
|
return;
|
|
472
510
|
}
|
|
473
511
|
const request = message;
|
|
474
|
-
|
|
512
|
+
let handled;
|
|
513
|
+
try {
|
|
514
|
+
handled = await session.handleMessage(request.method, request.params);
|
|
515
|
+
}
|
|
516
|
+
catch {
|
|
517
|
+
await transport.send({
|
|
518
|
+
jsonrpc: "2.0",
|
|
519
|
+
id: request.id,
|
|
520
|
+
error: {
|
|
521
|
+
code: JSON_RPC_ERROR_CODES.INTERNAL_ERROR,
|
|
522
|
+
message: "Internal error",
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
const { result, error } = handled;
|
|
475
528
|
if (error) {
|
|
476
529
|
const response = {
|
|
477
530
|
jsonrpc: "2.0",
|
|
@@ -490,13 +543,11 @@ export function createServer(options) {
|
|
|
490
543
|
}
|
|
491
544
|
};
|
|
492
545
|
transport.onclose = () => {
|
|
493
|
-
|
|
494
|
-
messageLifecycles.delete(lifecycle);
|
|
546
|
+
session.close();
|
|
495
547
|
resolve();
|
|
496
548
|
};
|
|
497
549
|
void transport.start().catch((error) => {
|
|
498
|
-
|
|
499
|
-
messageLifecycles.delete(lifecycle);
|
|
550
|
+
session.close();
|
|
500
551
|
reject(error);
|
|
501
552
|
});
|
|
502
553
|
});
|
|
@@ -592,14 +643,14 @@ function isCallToolResult(value) {
|
|
|
592
643
|
if (!hasContentArray(value) || !value.content.every(isContentItem)) {
|
|
593
644
|
return false;
|
|
594
645
|
}
|
|
595
|
-
if (hasOwnProperty(value, "structuredContent")
|
|
596
|
-
|
|
597
|
-
|
|
646
|
+
if (hasOwnProperty(value, "structuredContent") &&
|
|
647
|
+
value.structuredContent !== undefined &&
|
|
648
|
+
!isJsonObject(value.structuredContent)) {
|
|
598
649
|
return false;
|
|
599
650
|
}
|
|
600
|
-
return !(hasOwnProperty(value, "isError")
|
|
601
|
-
|
|
602
|
-
|
|
651
|
+
return !(hasOwnProperty(value, "isError") &&
|
|
652
|
+
value.isError !== undefined &&
|
|
653
|
+
typeof value.isError !== "boolean");
|
|
603
654
|
}
|
|
604
655
|
function normalizeToolResult(handlerResult, outputSchema) {
|
|
605
656
|
if (hasContentArray(handlerResult) && !isCallToolResult(handlerResult)) {
|
|
@@ -614,131 +665,71 @@ function normalizeToolResult(handlerResult, outputSchema) {
|
|
|
614
665
|
}
|
|
615
666
|
return result;
|
|
616
667
|
}
|
|
617
|
-
|
|
618
|
-
|
|
668
|
+
if (isCallToolResult(handlerResult) && handlerResult.isError === true) {
|
|
669
|
+
return handlerResult;
|
|
670
|
+
}
|
|
671
|
+
const callToolResult = isCallToolResult(handlerResult)
|
|
672
|
+
? handlerResult
|
|
673
|
+
: undefined;
|
|
674
|
+
const structuredContent = callToolResult
|
|
675
|
+
? callToolResult.structuredContent
|
|
619
676
|
: handlerResult;
|
|
620
677
|
if (!isJsonObject(structuredContent)) {
|
|
621
678
|
throw new ToolError(JSON_RPC_ERROR_CODES.INTERNAL_ERROR, "Structured tool result must be an object");
|
|
622
679
|
}
|
|
623
680
|
return {
|
|
624
|
-
content:
|
|
625
|
-
|
|
626
|
-
|
|
681
|
+
content: callToolResult !== undefined && callToolResult.content.length > 0
|
|
682
|
+
? callToolResult.content
|
|
683
|
+
: [{ type: "text", text: JSON.stringify(structuredContent) }],
|
|
684
|
+
...(callToolResult?.isError !== undefined
|
|
685
|
+
? { isError: callToolResult.isError }
|
|
627
686
|
: {}),
|
|
628
687
|
structuredContent,
|
|
629
688
|
};
|
|
630
689
|
}
|
|
631
|
-
function assertSupportedOutputSchema(schema) {
|
|
632
|
-
assertObjectRootSchema(schema, "outputSchema");
|
|
633
|
-
assertSupportedJsonSchema(schema, "outputSchema");
|
|
634
|
-
}
|
|
635
690
|
function assertObjectRootSchema(schema, path) {
|
|
636
691
|
if (schema.type !== "object") {
|
|
637
692
|
throw new Error(`${path} root type must be "object"`);
|
|
638
693
|
}
|
|
639
694
|
}
|
|
640
|
-
function assertSupportedJsonSchema(schema, path) {
|
|
641
|
-
for (const keyword of ["anyOf", "allOf", "not", "if", "then", "else", "contains", "prefixItems"]) {
|
|
642
|
-
if (schema[keyword] !== undefined) {
|
|
643
|
-
throw new Error(`${path} uses unsupported keyword "${keyword}"`);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
const type = schema.type;
|
|
647
|
-
if (Array.isArray(type)) {
|
|
648
|
-
const supported = new Set(["string", "number", "integer", "boolean", "object", "array", "null"]);
|
|
649
|
-
for (const item of type) {
|
|
650
|
-
if (!supported.has(item)) {
|
|
651
|
-
throw new Error(`${path} uses unsupported type "${item}"`);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
else if (type !== undefined &&
|
|
656
|
-
type !== "string" &&
|
|
657
|
-
type !== "number" &&
|
|
658
|
-
type !== "integer" &&
|
|
659
|
-
type !== "boolean" &&
|
|
660
|
-
type !== "object" &&
|
|
661
|
-
type !== "array") {
|
|
662
|
-
throw new Error(`${path} uses unsupported type "${type}"`);
|
|
663
|
-
}
|
|
664
|
-
if (isJsonObject(schema.properties)) {
|
|
665
|
-
for (const [key, child] of Object.entries(schema.properties)) {
|
|
666
|
-
if (isJsonObject(child)) {
|
|
667
|
-
assertSupportedJsonSchema(child, `${path}.properties.${key}`);
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
throw new Error(`${path}.properties.${key} must be an object schema`);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
else if (schema.properties !== undefined) {
|
|
675
|
-
throw new Error(`${path}.properties must be an object`);
|
|
676
|
-
}
|
|
677
|
-
const additionalProperties = schema.additionalProperties;
|
|
678
|
-
if (typeof additionalProperties === "object" && additionalProperties !== null) {
|
|
679
|
-
if (Array.isArray(additionalProperties)) {
|
|
680
|
-
throw new Error(`${path}.additionalProperties must be an object schema or boolean`);
|
|
681
|
-
}
|
|
682
|
-
assertSupportedJsonSchema(additionalProperties, `${path}.additionalProperties`);
|
|
683
|
-
}
|
|
684
|
-
else if (additionalProperties !== undefined
|
|
685
|
-
&& typeof additionalProperties !== "boolean") {
|
|
686
|
-
throw new Error(`${path}.additionalProperties must be an object schema or boolean`);
|
|
687
|
-
}
|
|
688
|
-
const items = schema.items;
|
|
689
|
-
if (Array.isArray(items)) {
|
|
690
|
-
throw new Error(`${path}.items uses unsupported tuple array schemas`);
|
|
691
|
-
}
|
|
692
|
-
if (typeof items === "object" && items !== null && !Array.isArray(items)) {
|
|
693
|
-
assertSupportedJsonSchema(items, `${path}.items`);
|
|
694
|
-
}
|
|
695
|
-
else if (items !== undefined && typeof items !== "boolean") {
|
|
696
|
-
throw new Error(`${path}.items must be an object schema or boolean`);
|
|
697
|
-
}
|
|
698
|
-
const oneOf = schema.oneOf;
|
|
699
|
-
if (Array.isArray(oneOf)) {
|
|
700
|
-
for (const [index, child] of oneOf.entries()) {
|
|
701
|
-
if (typeof child === "object" && child !== null && !Array.isArray(child)) {
|
|
702
|
-
assertSupportedJsonSchema(child, `${path}.oneOf[${index}]`);
|
|
703
|
-
}
|
|
704
|
-
else {
|
|
705
|
-
throw new Error(`${path}.oneOf[${index}] must be an object schema`);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
else if (oneOf !== undefined) {
|
|
710
|
-
throw new Error(`${path}.oneOf must be an array`);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
695
|
function isJsonObject(value) {
|
|
714
696
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
715
697
|
}
|
|
716
698
|
function isGetPromptResult(value) {
|
|
717
|
-
if (typeof value !== "object" ||
|
|
699
|
+
if (typeof value !== "object" ||
|
|
700
|
+
value === null ||
|
|
701
|
+
!hasOwnProperty(value, "messages")) {
|
|
718
702
|
return false;
|
|
719
703
|
}
|
|
720
|
-
return (!hasOwnProperty(value, "description") ||
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
704
|
+
return ((!hasOwnProperty(value, "description") ||
|
|
705
|
+
value.description === undefined ||
|
|
706
|
+
typeof value.description === "string") &&
|
|
707
|
+
Array.isArray(value.messages) &&
|
|
708
|
+
value.messages.every((message) => typeof message === "object" &&
|
|
709
|
+
message !== null &&
|
|
710
|
+
hasOwnProperty(message, "role") &&
|
|
711
|
+
(message.role === "user" || message.role === "assistant") &&
|
|
712
|
+
hasOwnProperty(message, "content") &&
|
|
713
|
+
isPromptContentItem(message.content)));
|
|
728
714
|
}
|
|
729
715
|
function isReadResourceResult(value) {
|
|
730
|
-
if (typeof value !== "object" ||
|
|
716
|
+
if (typeof value !== "object" ||
|
|
717
|
+
value === null ||
|
|
718
|
+
!hasOwnProperty(value, "contents")) {
|
|
731
719
|
return false;
|
|
732
720
|
}
|
|
733
|
-
return Array.isArray(value.contents)
|
|
734
|
-
&& value.contents.every(isResourceContents);
|
|
721
|
+
return (Array.isArray(value.contents) && value.contents.every(isResourceContents));
|
|
735
722
|
}
|
|
736
723
|
function hasContentArray(value) {
|
|
737
|
-
return typeof value === "object" &&
|
|
738
|
-
&&
|
|
724
|
+
return (typeof value === "object" &&
|
|
725
|
+
value !== null &&
|
|
726
|
+
hasOwnProperty(value, "content") &&
|
|
727
|
+
Array.isArray(value.content));
|
|
739
728
|
}
|
|
740
729
|
function isContentItem(value) {
|
|
741
|
-
if (typeof value !== "object" ||
|
|
730
|
+
if (typeof value !== "object" ||
|
|
731
|
+
value === null ||
|
|
732
|
+
!hasOwnProperty(value, "type")) {
|
|
742
733
|
return false;
|
|
743
734
|
}
|
|
744
735
|
const block = value;
|
|
@@ -749,56 +740,71 @@ function isContentItem(value) {
|
|
|
749
740
|
return hasOwnProperty(block, "text") && typeof block.text === "string";
|
|
750
741
|
}
|
|
751
742
|
if (block.type === "image" || block.type === "audio") {
|
|
752
|
-
return hasOwnProperty(block, "data")
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
743
|
+
return (hasOwnProperty(block, "data") &&
|
|
744
|
+
typeof block.data === "string" &&
|
|
745
|
+
isBase64(block.data) &&
|
|
746
|
+
hasOwnProperty(block, "mimeType") &&
|
|
747
|
+
typeof block.mimeType === "string");
|
|
757
748
|
}
|
|
758
749
|
if (block.type === "resource_link") {
|
|
759
|
-
return hasOwnProperty(block, "uri")
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
750
|
+
return (hasOwnProperty(block, "uri") &&
|
|
751
|
+
typeof block.uri === "string" &&
|
|
752
|
+
isValidUri(block.uri) &&
|
|
753
|
+
hasOwnProperty(block, "name") &&
|
|
754
|
+
typeof block.name === "string" &&
|
|
755
|
+
(!hasOwnProperty(block, "title") ||
|
|
756
|
+
block.title === undefined ||
|
|
757
|
+
typeof block.title === "string") &&
|
|
758
|
+
(!hasOwnProperty(block, "description") ||
|
|
759
|
+
block.description === undefined ||
|
|
760
|
+
typeof block.description === "string") &&
|
|
761
|
+
(!hasOwnProperty(block, "mimeType") ||
|
|
762
|
+
block.mimeType === undefined ||
|
|
763
|
+
typeof block.mimeType === "string") &&
|
|
764
|
+
(!hasOwnProperty(block, "size") ||
|
|
765
|
+
block.size === undefined ||
|
|
766
|
+
typeof block.size === "number"));
|
|
767
|
+
}
|
|
768
|
+
if (block.type !== "resource" ||
|
|
769
|
+
!hasOwnProperty(block, "resource") ||
|
|
770
|
+
typeof block.resource !== "object" ||
|
|
771
|
+
block.resource === null) {
|
|
773
772
|
return false;
|
|
774
773
|
}
|
|
775
774
|
return isResourceContents(block.resource);
|
|
776
775
|
}
|
|
777
776
|
function isResourceContents(value) {
|
|
778
|
-
if (typeof value !== "object"
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
777
|
+
if (typeof value !== "object" ||
|
|
778
|
+
value === null ||
|
|
779
|
+
!hasOwnProperty(value, "uri") ||
|
|
780
|
+
typeof value.uri !== "string" ||
|
|
781
|
+
!isValidUri(value.uri)) {
|
|
783
782
|
return false;
|
|
784
783
|
}
|
|
785
|
-
if (hasOwnProperty(value, "mimeType") &&
|
|
784
|
+
if (hasOwnProperty(value, "mimeType") &&
|
|
785
|
+
value.mimeType !== undefined &&
|
|
786
|
+
typeof value.mimeType !== "string") {
|
|
786
787
|
return false;
|
|
787
788
|
}
|
|
788
|
-
return (hasOwnProperty(value, "text") && typeof value.text === "string")
|
|
789
|
-
|
|
789
|
+
return ((hasOwnProperty(value, "text") && typeof value.text === "string") ||
|
|
790
|
+
(hasOwnProperty(value, "blob") &&
|
|
791
|
+
typeof value.blob === "string" &&
|
|
792
|
+
isBase64(value.blob)));
|
|
790
793
|
}
|
|
791
794
|
function hasValidContentAnnotations(value) {
|
|
792
|
-
if (!hasOwnProperty(value, "annotations") ||
|
|
795
|
+
if (!hasOwnProperty(value, "annotations") ||
|
|
796
|
+
value.annotations === undefined) {
|
|
793
797
|
return true;
|
|
794
798
|
}
|
|
795
799
|
if (!isJsonObject(value.annotations)) {
|
|
796
800
|
return false;
|
|
797
801
|
}
|
|
798
802
|
const { audience, priority, lastModified } = value.annotations;
|
|
799
|
-
return (audience === undefined ||
|
|
800
|
-
|
|
801
|
-
|
|
803
|
+
return ((audience === undefined ||
|
|
804
|
+
(Array.isArray(audience) &&
|
|
805
|
+
audience.every((item) => item === "user" || item === "assistant"))) &&
|
|
806
|
+
(priority === undefined || typeof priority === "number") &&
|
|
807
|
+
(lastModified === undefined || typeof lastModified === "string"));
|
|
802
808
|
}
|
|
803
809
|
function isBase64(value) {
|
|
804
810
|
if (value.length === 0) {
|
|
@@ -811,7 +817,8 @@ function isBase64(value) {
|
|
|
811
817
|
const paddingStart = value.indexOf("=");
|
|
812
818
|
const encoded = paddingStart === -1 ? value : value.slice(0, paddingStart);
|
|
813
819
|
const padding = paddingStart === -1 ? "" : value.slice(paddingStart);
|
|
814
|
-
if (padding.length > 2 ||
|
|
820
|
+
if (padding.length > 2 ||
|
|
821
|
+
[...padding].some((character) => character !== "=")) {
|
|
815
822
|
return false;
|
|
816
823
|
}
|
|
817
824
|
if ([...encoded].some((character) => !alphabet.includes(character))) {
|
|
@@ -823,7 +830,10 @@ function isPromptContentItem(value) {
|
|
|
823
830
|
if (!isContentItem(value)) {
|
|
824
831
|
return false;
|
|
825
832
|
}
|
|
826
|
-
return !(typeof value === "object" &&
|
|
833
|
+
return !(typeof value === "object" &&
|
|
834
|
+
value !== null &&
|
|
835
|
+
hasOwnProperty(value, "type") &&
|
|
836
|
+
value.type === "resource_link");
|
|
827
837
|
}
|
|
828
838
|
function hasOwnProperty(value, name) {
|
|
829
839
|
return Object.prototype.hasOwnProperty.call(value, name);
|
package/dist/types.d.ts
CHANGED
|
@@ -164,10 +164,7 @@ export interface ResourceTemplateDefinition extends ResourceTemplate {
|
|
|
164
164
|
}
|
|
165
165
|
export interface HandleResult {
|
|
166
166
|
result?: unknown;
|
|
167
|
-
error?:
|
|
168
|
-
code: number;
|
|
169
|
-
message: string;
|
|
170
|
-
};
|
|
167
|
+
error?: JSONRPCError;
|
|
171
168
|
}
|
|
172
169
|
export type PromptContentItem = {
|
|
173
170
|
type: "text";
|
package/dist/types.js
CHANGED