Skip to content

Commit 1cdf806

Browse files
authored
fix(sequential-thinking): use z.coerce for number and boolean params (#3533)
fix(sequential-thinking): use z.coerce for number and safe preprocess for boolean params Uses z.coerce.number() for number fields and a z.preprocess() helper for boolean fields to handle string-typed parameters from LLM clients. The preprocess approach correctly handles "false" → false, avoiding the z.coerce.boolean() footgun where Boolean("false") === true. Fixes #3428
1 parent c7e0c7e commit 1cdf806

File tree

1 file changed

+17
-7
lines changed

1 file changed

+17
-7
lines changed

src/sequentialthinking/index.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
55
import { z } from "zod";
66
import { SequentialThinkingServer } from './lib.js';
77

8+
/** Safe boolean coercion that correctly handles string "false" */
9+
const coercedBoolean = z.preprocess((val) => {
10+
if (typeof val === "boolean") return val;
11+
if (typeof val === "string") {
12+
if (val.toLowerCase() === "true") return true;
13+
if (val.toLowerCase() === "false") return false;
14+
}
15+
return val;
16+
}, z.boolean());
17+
818
const server = new McpServer({
919
name: "sequential-thinking-server",
1020
version: "0.2.0",
@@ -72,14 +82,14 @@ You should:
7282
11. Only set nextThoughtNeeded to false when truly done and a satisfactory answer is reached`,
7383
inputSchema: {
7484
thought: z.string().describe("Your current thinking step"),
75-
nextThoughtNeeded: z.boolean().describe("Whether another thought step is needed"),
76-
thoughtNumber: z.number().int().min(1).describe("Current thought number (numeric value, e.g., 1, 2, 3)"),
77-
totalThoughts: z.number().int().min(1).describe("Estimated total thoughts needed (numeric value, e.g., 5, 10)"),
78-
isRevision: z.boolean().optional().describe("Whether this revises previous thinking"),
79-
revisesThought: z.number().int().min(1).optional().describe("Which thought is being reconsidered"),
80-
branchFromThought: z.number().int().min(1).optional().describe("Branching point thought number"),
85+
nextThoughtNeeded: coercedBoolean.describe("Whether another thought step is needed"),
86+
thoughtNumber: z.coerce.number().int().min(1).describe("Current thought number (numeric value, e.g., 1, 2, 3)"),
87+
totalThoughts: z.coerce.number().int().min(1).describe("Estimated total thoughts needed (numeric value, e.g., 5, 10)"),
88+
isRevision: coercedBoolean.optional().describe("Whether this revises previous thinking"),
89+
revisesThought: z.coerce.number().int().min(1).optional().describe("Which thought is being reconsidered"),
90+
branchFromThought: z.coerce.number().int().min(1).optional().describe("Branching point thought number"),
8191
branchId: z.string().optional().describe("Branch identifier"),
82-
needsMoreThoughts: z.boolean().optional().describe("If more thoughts are needed")
92+
needsMoreThoughts: coercedBoolean.optional().describe("If more thoughts are needed")
8393
},
8494
annotations: {
8595
readOnlyHint: true,

0 commit comments

Comments
 (0)