Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/curvy-parks-fall.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
69 changes: 54 additions & 15 deletions test/mcpSpec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,43 +21,82 @@ import {
// enum, the stdio zod enum, and the runtime validator. Add a kind to types.ts
// without teaching MCP about it (or the validator) and one of these fails.

// The exact `kind` enum a client receives for the canonical publish tool from
// the HTTP `tools/list` response.
const httpKindEnum = (() => {
// The exact surface JSON Schema a client receives for the canonical publish
// tool from the HTTP `tools/list` response.
const httpSurfaceSchema = (() => {
const tool = HTTP_MCP_TOOLS.find((t) => t.name === "publish_post");
assert.ok(tool, "publish_post tool must exist");
return (tool as any).inputSchema.properties.surfaces.items;
})();

const httpKindEnum = (() => {
// inputSchema.properties.surfaces.items.properties.kind.enum — the wire path.
const enumValues = (tool as any).inputSchema.properties.surfaces.items.properties.kind.enum;
const enumValues = httpSurfaceSchema.properties.kind.enum;
assert.ok(Array.isArray(enumValues), "surfaces.items.kind.enum must be an array");
return enumValues as string[];
})();

// A minimal valid example per kind, used to prove the schema + validator accept
// each one. Kept deliberately minimal so a field going missing from the MCP
// schema surfaces here.
// A representative valid example per kind, used to prove the schema +
// validator accept each advertised payload field. Include optional fields too so
// a field going missing from the MCP schema surfaces here.
const EXAMPLES: Record<(typeof SURFACE_KINDS)[number], Surface> = {
html: { kind: "html", html: "<p>hi</p>" },
diff: { kind: "diff", files: [{ filename: "a.ts", before: "a", after: "b" }] },
image: { kind: "image", assetId: "asset123" },
trace: { kind: "trace", steps: [{ label: "step one" }] },
html: { kind: "html", html: "<p>hi</p>", kits: ["issues"] },
diff: {
kind: "diff",
patch: "--- a/x\n+++ b/x\n@@ -1 +1 @@\n-a\n+b",
files: [{ filename: "a.ts", before: "a", after: "b", language: "ts" }],
layout: "split",
},
image: { kind: "image", assetId: "asset123", alt: "screenshot", caption: "after" },
trace: {
kind: "trace",
assetId: "trace123",
title: "Run trace",
steps: [{ label: "step one", kind: "tool", detail: "ok", ts: "2026-07-02T00:00:00Z" }],
},
markdown: { kind: "markdown", markdown: "# heading" },
terminal: { kind: "terminal", text: "$ ls\nfile.txt" },
terminal: { kind: "terminal", text: "$ ls\nfile.txt", cols: 80, title: "shell" },
mermaid: { kind: "mermaid", mermaid: "flowchart TD\nA-->B" },
json: { kind: "json", data: { ok: true, items: [1, 2, 3] } },
code: { kind: "code", code: "const x = 1;", language: "ts" },
code: { kind: "code", code: "const x = 1;", language: "ts", title: "x.ts", lineStart: 10 },
};

test("HTTP publish_post advertises exactly the canonical kind set", () => {
assert.deepEqual([...httpKindEnum].sort(), [...SURFACE_KINDS].sort());
});

test("HTTP publish_post advertises every field used by canonical examples", () => {
const assertFieldsAdvertised = (schema: any, value: object, path: string) => {
assert.ok(schema?.properties, `${path} must advertise object properties`);
for (const [key, nested] of Object.entries(value)) {
assert.ok(Object.hasOwn(schema.properties, key), `${path} must advertise ${key}`);
if (
Array.isArray(nested) &&
nested.length > 0 &&
typeof nested[0] === "object" &&
nested[0] !== null
) {
assertFieldsAdvertised(
schema.properties[key].items,
nested[0] as object,
`${path}.${key}[]`,
);
}
}
};

for (const kind of SURFACE_KINDS) {
assertFieldsAdvertised(httpSurfaceSchema, EXAMPLES[kind], `surface ${kind}`);
}
});

test("every canonical kind has a worked example (no kind left untested)", () => {
for (const kind of SURFACE_KINDS) {
assert.ok(EXAMPLES[kind], `missing test example for kind "${kind}"`);
}
});

test("the stdio publish schema accepts a minimal example of every kind", () => {
test("the stdio publish schema accepts a representative example of every kind", () => {
// The stdio schema object is z.object(STDIO_MCP_INPUT_SCHEMAS.publishPost);
// its `surfaces` field is the array schema the MCP SDK enforces.
const publishSchema = z.object(STDIO_MCP_INPUT_SCHEMAS.publishPost);
Expand All @@ -76,7 +115,7 @@ test("the stdio publish schema rejects an unknown kind", () => {
assert.equal(result.success, false);
});

test("the runtime validator accepts a minimal example of every kind", async () => {
test("the runtime validator accepts a representative example of every kind", async () => {
for (const kind of SURFACE_KINDS) {
const result = await validateSurfaces([EXAMPLES[kind]]);
assert.ok(result.ok, `validator rejected kind "${kind}": ${result.ok ? "" : result.error}`);
Expand Down
Loading