think
Break down complex problems into manageable steps with structured reasoning, enabling planning with revisions, analysis with course correction, and confidence tracking for multi-step challenges.
Instructions
Add a thought to the reasoning chain.
Use for:
Complex multi-step problems
Planning with room for revision
Analysis that might need course correction
Features:
subSteps: Micro-action plan (max 5)
alternatives: Quick options comparison
quickExtension: Inline critique/elaboration (replaces extend_thought tool)
Returns progress bar, confidence, and next action hint.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| thought | Yes | Your thinking step | |
| nextThoughtNeeded | Yes | More thinking needed? | |
| thoughtNumber | Yes | Current number | |
| totalThoughts | Yes | Estimated total | |
| confidence | No | Confidence 1-10 | |
| subSteps | No | Micro-actions (max 5) | |
| alternatives | No | Options to compare | |
| goal | No | Session goal (set on first thought) | |
| quickExtension | No | Inline extension (replaces extend_thought) | |
| isRevision | No | Revising previous thought? | |
| revisesThought | No | Which thought to revise | |
| branchFromThought | No | Branch point | |
| branchId | No | Branch identifier | |
| showTree | No | Show ASCII tree |
Implementation Reference
- src/services/thinking.service.ts:186-371 (handler)The core handler function processThought in ThinkingService that executes the logic for the 'think' tool. Handles validation, branching, stagnation detection, coaching nudges, quick extensions, dead-end warnings, and returns progress information.processThought(input: ThoughtInput): ThinkingResult { // Smart auto-reset: if thoughtNumber=1 and history not empty, start fresh session // SYNCHRONOUS reset to avoid race conditions if (input.thoughtNumber === 1 && this.thoughtHistory.length > 0 && !input.isRevision) { console.error('π New session detected (thought #1), clearing previous state...'); this.reset(); // Synchronous clear // Clear persistence file asynchronously (non-blocking) this.clearSession().catch((err) => console.error('Failed to clear session:', err)); } // Generate new sessionId for first thought of session (v2.11.0) if (input.thoughtNumber === 1 && !input.isRevision) { this.currentSessionId = new Date().toISOString(); console.error(`π New session ID: ${this.currentSessionId}`); } // Auto-adjust totalThoughts if exceeded if (input.thoughtNumber > input.totalThoughts) { input.totalThoughts = input.thoughtNumber; } // EMPTY THOUGHT VALIDATION - reject meaningless input if (!input.thought || !input.thought.trim()) { return { thoughtNumber: input.thoughtNumber, totalThoughts: input.totalThoughts, nextThoughtNeeded: true, branches: Array.from(this.branches.keys()), thoughtHistoryLength: this.thoughtHistory.length, contextSummary: this.generateContextSummary(), thoughtTree: this.generateAsciiTree(), isError: true, errorMessage: 'π« REJECTED: Empty thought. Provide meaningful content.', warning: 'π« REJECTED: Empty thought. Provide meaningful content.', }; } // SESSION GOAL (v2.10.0) - Save goal from first thought if (input.goal && input.thoughtNumber === 1) { this.sessionGoal = input.goal; console.error(`π― Session goal set: ${input.goal.substring(0, 50)}...`); } // HARD DUPLICATE REJECTION - reject before adding to history const duplicateError = this.checkDuplicateStrict(input); if (duplicateError) { return { thoughtNumber: input.thoughtNumber, totalThoughts: input.totalThoughts, nextThoughtNeeded: true, branches: Array.from(this.branches.keys()), thoughtHistoryLength: this.thoughtHistory.length, contextSummary: this.generateContextSummary(), thoughtTree: this.generateAsciiTree(), isError: true, errorMessage: duplicateError, warning: duplicateError, }; } // BRANCH VALIDATION - reject if branchFromThought references non-existent thought const branchError = this.validateBranchSource(input); if (branchError) { return { thoughtNumber: input.thoughtNumber, totalThoughts: input.totalThoughts, nextThoughtNeeded: true, branches: Array.from(this.branches.keys()), thoughtHistoryLength: this.thoughtHistory.length, contextSummary: this.generateContextSummary(), thoughtTree: this.generateAsciiTree(), isError: true, errorMessage: branchError, warning: branchError, }; } // Validate sequence (includes shallow/circular revision check) const validation = this.validateSequence(input); // HARD REJECTION for invalid revisions (shallow, circular, non-existent target) if (!validation.valid && input.isRevision) { return { thoughtNumber: input.thoughtNumber, totalThoughts: input.totalThoughts, nextThoughtNeeded: true, branches: Array.from(this.branches.keys()), thoughtHistoryLength: this.thoughtHistory.length, contextSummary: this.generateContextSummary(), thoughtTree: this.generateAsciiTree(), isError: true, errorMessage: validation.warning, warning: validation.warning, }; } // Check for stagnation before adding new thought const stagnationWarning = this.detectStagnation(input.thought); // Create record with timestamp and sessionId (v2.11.0) const record: ThoughtRecord = { ...input, timestamp: Date.now(), sessionId: this.currentSessionId, }; this.thoughtHistory.push(record); this.lastThoughtNumber = input.thoughtNumber; // Invalidate Fuse index for recall_thought (v3.4.0) this.invalidateFuseIndex(); // Handle branching if (input.branchFromThought && input.branchId) { const branchHistory = this.branches.get(input.branchId) ?? []; branchHistory.push(record); this.branches.set(input.branchId, branchHistory); } // Log to stderr for debugging const prefix = input.isRevision ? 'π Revision' : input.branchFromThought ? 'πΏ Branch' : 'π Thought'; const confidenceStr = input.confidence ? ` [conf: ${input.confidence}/10]` : ''; console.error( `${prefix} ${input.thoughtNumber}/${input.totalThoughts}${confidenceStr}: ${input.thought.substring(0, 80)}...` ); // Save session asynchronously (fire and forget) this.saveSession().catch((err) => console.error('Failed to save session:', err)); // Combine warnings const warning = [validation.warning, stagnationWarning].filter(Boolean).join('\n'); // QUICK EXTENSION (v3.1.0) - Process inline extension if provided if (input.quickExtension) { this.processQuickExtension(input.thoughtNumber, input.quickExtension); } // LATERAL THINKING TRIGGER - check for overly linear thinking // v5.0.1: Pass isFinishing flag to show subSteps check only at end let systemAdvice = this.checkLateralThinking(!input.nextThoughtNeeded); // DEAD ENDS CHECK (v3.3.0) - Warn if heading towards rejected path const deadEndWarning = this.checkDeadEnds(input.thoughtNumber); if (deadEndWarning) { systemAdvice = systemAdvice ? `${systemAdvice}\n${deadEndWarning}` : deadEndWarning; } // PROACTIVE COACH v3.1.0 - Enhanced nudges for thought quality const coachNudges = this.generateProactiveNudges(input); if (coachNudges) { systemAdvice = systemAdvice ? `${systemAdvice}\n${coachNudges}` : coachNudges; } // PRE-CONSOLIDATION AUDIT (v2.9.2) - Quality gate before finishing if (!input.nextThoughtNeeded) { const auditAdvice = this.performPreConsolidationAudit(); if (auditAdvice) { systemAdvice = systemAdvice ? `${systemAdvice}\n${auditAdvice}` : auditAdvice; } } // v4.6.0: Generate nudge only if no other warnings/advice (avoid noise) const shouldSkipNudge = !!(warning || systemAdvice); const nudge = this.nudgeService.generateNudge(input, this.getCurrentSessionThoughts(), shouldSkipNudge); return { thoughtNumber: input.thoughtNumber, totalThoughts: input.totalThoughts, nextThoughtNeeded: input.nextThoughtNeeded, branches: Array.from(this.branches.keys()), thoughtHistoryLength: this.thoughtHistory.length, contextSummary: this.generateContextSummary(), thoughtTree: this.generateAsciiTree(), // v4.2.0: Lazy Mermaid - removed from hot path, use export_session for diagrams thoughtTreeMermaid: undefined, warning: warning || undefined, averageConfidence: this.calculateAverageConfidence(), systemAdvice, sessionGoal: this.sessionGoal, nudge, }; }
- src/index.ts:68-127 (registration)Registration of the 'think' tool using McpServer.registerTool, including title, description, inputSchema, and the handler callback.server.registerTool('think', { title: 'Think', description: THINK_DESCRIPTION, inputSchema: thinkSchema }, async (args) => { try { const result = thinkingService.processThought({ thought: args.thought as string, nextThoughtNeeded: args.nextThoughtNeeded as boolean, thoughtNumber: args.thoughtNumber as number, totalThoughts: args.totalThoughts as number, isRevision: args.isRevision as boolean | undefined, revisesThought: args.revisesThought as number | undefined, branchFromThought: args.branchFromThought as number | undefined, branchId: args.branchId as string | undefined, confidence: args.confidence as number | undefined, subSteps: args.subSteps as string[] | undefined, alternatives: args.alternatives as string[] | undefined, goal: args.goal as string | undefined, quickExtension: args.quickExtension as QuickExtension | undefined, }); if (result.isError) { return { content: [{ type: 'text' as const, text: `Error: ${result.errorMessage}` }], isError: true }; } // Progress bar const current = result.thoughtNumber; const total = result.totalThoughts; const filled = Math.round((current / total) * 10); const progressBar = 'β'.repeat(filled) + 'β'.repeat(10 - filled); // Status detection const hasBlocker = result.warning?.includes('BLOCKER') || result.warning?.includes('STAGNATION'); const status = hasBlocker ? 'BLOCKED' : result.warning ? 'WARNING' : 'OK'; const nearEnd = current >= total - 1; const nextAction = hasBlocker ? 'revise' : nearEnd ? 'think_done' : 'continue'; // Conditional tree - ONLY when explicitly requested const showTree = args.showTree === true; // v5.0.1: Show systemAdvice ONLY when there are real issues const conf = result.averageConfidence ?? 10; const hasRealIssue = status !== 'OK' || conf < 7; const showAdvice = hasRealIssue && result.systemAdvice; const text = [ result.sessionGoal ? `π― ${result.sessionGoal}\n` : '', `[${progressBar}] ${current}/${total}`, result.averageConfidence ? ` | conf: ${result.averageConfidence}/10` : '', result.warning ? `\nβ οΈ ${result.warning}` : '', showTree ? `\n\n${result.thoughtTree}` : '', showAdvice ? `\n${result.systemAdvice}` : '', result.nudge ? `\nπ‘ ${result.nudge}` : '', `\n[${status}|next:${nextAction}]`, ].filter(Boolean).join(''); return { content: [{ type: 'text' as const, text }] }; } catch (error) { return { content: [{ type: 'text' as const, text: `Error: ${error instanceof Error ? error.message : 'Unknown'}` }], isError: true }; } } );
- src/index.ts:47-66 (schema)Zod input schema definition for the 'think' tool parameters.const thinkSchema = { thought: z.string().describe('Your thinking step'), nextThoughtNeeded: z.boolean().describe('More thinking needed?'), thoughtNumber: z.number().int().min(1).describe('Current number'), totalThoughts: z.number().int().min(1).describe('Estimated total'), confidence: z.number().min(1).max(10).optional().describe('Confidence 1-10'), subSteps: z.array(z.string()).max(5).optional().describe('Micro-actions (max 5)'), alternatives: z.array(z.string()).max(5).optional().describe('Options to compare'), goal: z.string().optional().describe('Session goal (set on first thought)'), quickExtension: z.object({ type: z.enum(['critique', 'elaboration', 'correction', 'alternative_scenario', 'assumption_testing', 'innovation', 'optimization', 'polish']), content: z.string(), impact: z.enum(['low', 'medium', 'high', 'blocker']).optional(), }).optional().describe('Inline extension (replaces extend_thought)'), isRevision: z.boolean().optional().describe('Revising previous thought?'), revisesThought: z.number().int().min(1).optional().describe('Which thought to revise'), branchFromThought: z.number().int().min(1).optional().describe('Branch point'), branchId: z.string().optional().describe('Branch identifier'), showTree: z.boolean().optional().describe('Show ASCII tree'), };