Skip to content

Commit 94ff46e

Browse files
A.R.claude
andcommitted
fix(prompts): register arg-less prompts via the SDK no-argsSchema form
A user-created prompt with zero arguments was registered with an empty argsSchema ({}); use the MCP SDK's documented two-arg (no-argsSchema) form instead so arg-less prompts are unambiguously valid. Adds a no-arg mock test plus a real-McpServer registration test that asserts no per-prompt errors are swallowed (validates both the Zod-shape and no-arg forms against the live SDK). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 783206a commit 94ff46e

2 files changed

Lines changed: 46 additions & 10 deletions

File tree

packages/mcp-server/src/prompts.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,21 @@ export function registerPrompts(server: McpServer): void {
4848
});
4949

5050
try {
51-
server.registerPrompt(
52-
prompt.name,
53-
{
54-
title: prompt.name,
55-
description: prompt.description,
56-
argsSchema: buildArgsSchema(prompt.arguments),
57-
},
58-
(args) => render(args as Record<string, unknown>),
59-
);
51+
// No-arg prompts use the SDK's two-arg form (no argsSchema); arg-bearing
52+
// prompts pass a Zod shape built from their declared arguments.
53+
if (prompt.arguments.length === 0) {
54+
server.registerPrompt(prompt.name, { title: prompt.name, description: prompt.description }, () => render());
55+
} else {
56+
server.registerPrompt(
57+
prompt.name,
58+
{
59+
title: prompt.name,
60+
description: prompt.description,
61+
argsSchema: buildArgsSchema(prompt.arguments),
62+
},
63+
(args) => render(args as Record<string, unknown>),
64+
);
65+
}
6066
} catch (err) {
6167
console.error(`[perplexity-mcp] failed to register prompt '${prompt.name}':`, err);
6268
}

packages/mcp-server/test/prompts.test.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { mkdtempSync, rmSync } from "node:fs";
22
import { tmpdir } from "node:os";
33
import { join } from "node:path";
4-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
4+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
56
import { registerPrompts } from "../src/prompts.js";
67
import { BUILTIN_PROMPTS, writePromptsConfig } from "../src/prompts-config.js";
78

@@ -86,4 +87,33 @@ describe("registerPrompts", () => {
8687
};
8788
expect(() => registerPrompts(server)).not.toThrow();
8889
});
90+
91+
it("registers a no-argument custom prompt via the no-argsSchema form", () => {
92+
writePromptsConfig(
93+
{ overrides: {}, custom: [{ name: "no-args", description: "static", arguments: [], template: "fixed text" }] },
94+
dir,
95+
);
96+
const server = mockServer();
97+
registerPrompts(server);
98+
const noArgs = server.calls.find((c) => c.name === "no-args");
99+
expect(noArgs).toBeDefined();
100+
expect(noArgs.config.argsSchema).toBeUndefined();
101+
expect(noArgs.cb().messages[0].content.text).toBe("fixed text");
102+
});
103+
104+
it("registers cleanly against a real McpServer (no swallowed per-prompt errors)", () => {
105+
// Built-ins exercise the argsSchema (Zod-shape) form; the custom prompt
106+
// exercises the no-argsSchema form. registerPrompts catches+logs per-prompt
107+
// failures, so assert console.error was never called to prove the real SDK
108+
// accepted every registration.
109+
writePromptsConfig(
110+
{ overrides: {}, custom: [{ name: "no-args", description: "static", arguments: [], template: "fixed text" }] },
111+
dir,
112+
);
113+
const server = new McpServer({ name: "test", version: "0.0.0" });
114+
const errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
115+
expect(() => registerPrompts(server)).not.toThrow();
116+
expect(errSpy).not.toHaveBeenCalled();
117+
errSpy.mockRestore();
118+
});
89119
});

0 commit comments

Comments
 (0)