| 1 | import { assert, describe, it } from "@effect/vitest" |
| 2 | import { Schema } from "effect" |
| 3 | import * as McpSchema from "effect/ai/McpSchema" |
| 4 | |
| 5 | describe("McpSchema", () => { |
| 6 | it("should preserve custom metadata when a request is decoded and encoded", () => { |
| 7 | const decode = Schema.decodeUnknownSync(McpSchema.RequestMeta) |
| 8 | const encode = Schema.encodeSync(McpSchema.RequestMeta) |
| 9 | for (const progress of [{}, { progressToken: "progress-1" }, { progressToken: 1 }]) { |
| 10 | const request = { |
| 11 | _meta: { ...progress, marker: "request", custom: { values: [null, true, 42, "value"] } } |
| 12 | } |
| 13 | assert.deepStrictEqual(encode(decode(request)), request) |
| 14 | } |
| 15 | }) |
| 16 | |
| 17 | const decodeCreateMessage = Schema.decodeUnknownSync(McpSchema.CreateMessage.payloadSchema) |
| 18 | |
| 19 | it("allows create-message metadata to be omitted", () => { |
| 20 | assert.doesNotThrow(() => decodeCreateMessage({ messages: [], maxTokens: 1 })) |
| 21 | }) |
| 22 | |
| 23 | it("requires create-message metadata to be an object", () => { |
| 24 | assert.throws(() => decodeCreateMessage({ messages: [], maxTokens: 1, metadata: "invalid" })) |
| 25 | }) |
| 26 | |
| 27 | // SEP-1330: https://modelcontextprotocol.io/seps/1330-elicitation-enum-schema-improvements-and-standards |
| 28 | // Conformance: elicitation-sep1330-enums |
| 29 | it("should preserve every November elicitation enum form when decoding a form request", () => { |
| 30 | const decoded = Schema.decodeUnknownSync(McpSchema.ElicitRequestFormParams)({ |
| 31 | mode: "form", |
| 32 | message: "Choose values", |
| 33 | requestedSchema: { |
| 34 | type: "object", |
| 35 | properties: { |
| 36 | untitled: { type: "string", enum: ["one", "two"] }, |
| 37 | titled: { type: "string", oneOf: [{ const: "one", title: "One" }] }, |
| 38 | legacy: { type: "string", enum: ["one"], enumNames: ["One"] } |
| 39 | } |
| 40 | } |
| 41 | }) |
| 42 | |
| 43 | assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded.requestedSchema.properties)), { |
| 44 | untitled: { type: "string", enum: ["one", "two"] }, |
| 45 | titled: { type: "string", oneOf: [{ const: "one", title: "One" }] }, |
| 46 | legacy: { type: "string", enum: ["one"], enumNames: ["One"] } |
| 47 | }) |
| 48 | }) |
| 49 | |
| 50 | it("round-trips an implementation with icons", () => { |
| 51 | const implementation = { name: "server", version: "1.0.0", icons: [{ src: "https://example.com/icon.png" }] } |
| 52 | assert.deepStrictEqual( |
| 53 | Schema.encodeSync(McpSchema.Implementation)(Schema.decodeUnknownSync(McpSchema.Implementation)(implementation)), |
| 54 | implementation |
| 55 | ) |
| 56 | }) |
| 57 | }) |