From 89c6f36b1752e15bf34125c57e5cbe7d9351cc05 Mon Sep 17 00:00:00 2001 From: Jack11111eee Date: Sun, 30 Aug 2026 23:50:42 +0800 Subject: [PATCH] fix(sequentialthinking): set readOnlyHint/idempotentHint to false Every sequentialthinking call appends to the server's in-memory thoughtHistory (and branches) and returns a growing thoughtHistoryLength, so advertising readOnlyHint and idempotentHint as true is misleading: clients may skip confirmation or retry/caching safeguards they would otherwise apply. Flip both hints to false with a short comment explaining why, and add a regression test that lists the tools over stdio and asserts the annotations. Fixes #4721 --- src/sequentialthinking/__tests__/input-schema.test.ts | 10 ++++++++++ src/sequentialthinking/index.ts | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sequentialthinking/__tests__/input-schema.test.ts b/src/sequentialthinking/__tests__/input-schema.test.ts index 4ff7be663c..472eb6b53a 100644 --- a/src/sequentialthinking/__tests__/input-schema.test.ts +++ b/src/sequentialthinking/__tests__/input-schema.test.ts @@ -39,6 +39,16 @@ describe.skipIf(!existsSync(distIndexPath))('sequentialthinking input schema', ( ); }); + // Regression coverage for #4721: each call accumulates in-memory thought + // history, so the tool must not advertise itself as read-only or idempotent. + it('marks the tool as neither read-only nor idempotent', async () => { + const { tools } = await client.listTools(); + const tool = tools.find(t => t.name === 'sequentialthinking'); + expect(tool).toBeDefined(); + expect(tool!.annotations?.readOnlyHint).toBe(false); + expect(tool!.annotations?.idempotentHint).toBe(false); + }); + it('rejects a call that omits nextThoughtNeeded', async () => { const result = await client.callTool({ name: 'sequentialthinking', diff --git a/src/sequentialthinking/index.ts b/src/sequentialthinking/index.ts index 1ae09d1db8..68899ff10e 100644 --- a/src/sequentialthinking/index.ts +++ b/src/sequentialthinking/index.ts @@ -93,9 +93,11 @@ You should: needsMoreThoughts: coercedBoolean.optional().describe("If more thoughts are needed") }, annotations: { - readOnlyHint: true, + // Each call appends to the server's in-memory thought history (and + // branch list), so the tool is neither read-only nor idempotent. + readOnlyHint: false, destructiveHint: false, - idempotentHint: true, + idempotentHint: false, openWorldHint: false, }, outputSchema: {