Skip to main content
Glama

Think Done

think_done

Complete structured reasoning sessions by verifying logic, identifying gaps, and exporting reports before finalizing complex problem solutions.

Instructions

Finish thinking session: verify logic and optionally export.

MANDATORY before final answer on complex problems.

Checks:

  • Low confidence thoughts in path

  • Unaddressed blockers

  • Ignored thoughts ratio

Options:

  • exportReport: Get markdown/json report (replaces export_session)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
winningPathYesThought numbers leading to solution
summaryYesFinal logic summary
verdictYesReady for answer?
constraintCheckNoHow constraints were addressed
potentialFlawsNoWhat could go wrong
exportReportNoExport format (optional)
includeMermaidNoInclude diagram in export

Implementation Reference

  • MCP tool handler for 'think_done': processes input args, calls thinkingService.consolidate for path verification and issue detection, formats output with status/READY or BLOCKED, progress metrics, warnings; optionally appends exported session report.
    server.registerTool('think_done', { title: 'Think Done', description: THINK_DONE_DESCRIPTION, inputSchema: thinkDoneSchema },
      async (args) => {
        try {
          const result = thinkingService.consolidate({
            winningPath: args.winningPath as number[],
            summary: args.summary as string,
            constraintCheck: args.constraintCheck as string | undefined,
            potentialFlaws: args.potentialFlaws as string | undefined,
            verdict: args.verdict as 'ready' | 'needs_more_work',
          });
    
          if (result.status === 'error') {
            return { content: [{ type: 'text' as const, text: `Error: ${result.errorMessage}` }], isError: true };
          }
    
          const pa = result.pathAnalysis;
          const issues = [
            pa.lowConfidenceInPath.length > 0 ? `lowConf:#${pa.lowConfidenceInPath.join(',')}` : '',
            pa.unaddressedBlockers.length > 0 ? `blockers:#${pa.unaddressedBlockers.join(',')}` : '',
          ].filter(Boolean).join(' | ');
    
          let text = [
            result.canProceedToFinalAnswer ? '✅ READY' : '🛑 BLOCKED',
            `📊 Path: ${pa.pathLength}/${pa.totalThoughts} (${Math.round(pa.ignoredRatio * 100)}% ignored)`,
            issues ? `⚠️ ${issues}` : '',
            '',
            '--- STATUS ---',
            `verdict: ${result.canProceedToFinalAnswer ? 'READY' : 'BLOCKED'}`,
          ].filter(Boolean).join('\n');
    
          // Export if requested (merged from export_session)
          if (args.exportReport) {
            const report = thinkingService.exportSession({
              format: args.exportReport as 'markdown' | 'json',
              includeMermaid: (args.includeMermaid as boolean) ?? true,
            });
            text += '\n\n--- EXPORT ---\n' + report;
          }
    
          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 };
        }
      }
  • Zod input schema for 'think_done' tool, defining required winningPath, summary, verdict and optional fields for checks and export.
    const thinkDoneSchema = {
      winningPath: z.array(z.number().int().min(1)).describe('Thought numbers leading to solution'),
      summary: z.string().describe('Final logic summary'),
      verdict: z.enum(['ready', 'needs_more_work']).describe('Ready for answer?'),
      constraintCheck: z.string().optional().describe('How constraints were addressed'),
      potentialFlaws: z.string().optional().describe('What could go wrong'),
      exportReport: z.enum(['markdown', 'json']).optional().describe('Export format (optional)'),
      includeMermaid: z.boolean().optional().describe('Include diagram in export'),
    };
  • src/index.ts:232-232 (registration)
    Registration of 'think_done' tool with McpServer, including title, description, and inputSchema.
    server.registerTool('think_done', { title: 'Think Done', description: THINK_DONE_DESCRIPTION, inputSchema: thinkDoneSchema },
  • ConsolidateService.consolidate(): Primary helper implementing think_done logic - validates winning path connectivity, detects low-confidence thoughts in path, unaddressed blockers/critical extensions, high ignored ratio, path discontinuities; computes canProceedToFinalAnswer and pathAnalysis.
    consolidate(
      input: ConsolidateInput,
      sessionThoughts: ThoughtRecord[],
      onDeadEnd?: (path: number[], reason: string) => void,
      onSuccess?: (path: number[], summary: string) => void
    ): ConsolidateResult {
      const { winningPath, verdict } = input;
      const warnings: string[] = [];
    
      // Validate: must have thoughts to consolidate
      if (sessionThoughts.length === 0) {
        return {
          status: 'error',
          evaluation: 'Cannot consolidate empty thought history.',
          warnings: [],
          canProceedToFinalAnswer: false,
          pathAnalysis: {
            totalThoughts: 0,
            pathLength: 0,
            ignoredRatio: 0,
            lowConfidenceInPath: [],
            unaddressedBlockers: [],
            unaddressedCritical: [],
          },
          errorMessage: 'No thoughts recorded. Use sequentialthinking first.',
        };
      }
    
      // Validate: winning path must reference existing thoughts in current session
      const existingNumbers = new Set(sessionThoughts.map((t) => t.thoughtNumber));
      const invalidRefs = winningPath.filter((n) => !existingNumbers.has(n));
      if (invalidRefs.length > 0) {
        return {
          status: 'error',
          evaluation: `Invalid thought references in winning path: ${invalidRefs.join(', ')}`,
          warnings: [],
          canProceedToFinalAnswer: false,
          pathAnalysis: {
            totalThoughts: sessionThoughts.length,
            pathLength: winningPath.length,
            ignoredRatio: 0,
            lowConfidenceInPath: [],
            unaddressedBlockers: [],
            unaddressedCritical: [],
          },
          errorMessage: `Thoughts ${invalidRefs.join(', ')} do not exist in current session.`,
        };
      }
    
      // Validate: path connectivity - thoughts must be logically connected
      const connectivityCheck = this.validationService.validatePathConnectivity(
        winningPath,
        sessionThoughts
      );
      if (!connectivityCheck.valid) {
        warnings.push(`🚫 PATH DISCONTINUITY: ${connectivityCheck.error}`);
      }
    
      // Find low-confidence thoughts in winning path
      const lowConfidenceInPath = sessionThoughts
        .filter((t) => winningPath.includes(t.thoughtNumber))
        .filter((t) => t.confidence !== undefined && t.confidence < 5)
        .map((t) => t.thoughtNumber);
    
      if (lowConfidenceInPath.length > 0) {
        warnings.push(
          `⚠️ LOW CONFIDENCE: Your winning path includes thoughts with confidence < 5: #${lowConfidenceInPath.join(', ')}. Are you sure about these steps?`
        );
      }
    
      // Check ignored thoughts ratio
      const ignoredRatio = 1 - winningPath.length / sessionThoughts.length;
      if (ignoredRatio > 0.6) {
        warnings.push(
          `⚠️ HIGH DISCARD RATE: You are ignoring ${Math.round(ignoredRatio * 100)}% of your thoughts. Ensure you haven't missed important contradictions in discarded branches.`
        );
      }
    
      // Find unaddressed BLOCKER and HIGH impact critique extensions
      const unaddressedBlockers: number[] = [];
      const unaddressedCritical: number[] = [];
    
      for (const thought of sessionThoughts) {
        if (thought.extensions) {
          const hasBlocker = thought.extensions.some((e) => e.impact === 'blocker');
          const hasHighCritique = thought.extensions.some(
            (e) => e.impact === 'high' && e.type === 'critique'
          );
    
          if (winningPath.includes(thought.thoughtNumber)) {
            const hasRevision = sessionThoughts.some(
              (t) => t.isRevision && t.revisesThought === thought.thoughtNumber
            );
    
            if (hasBlocker && !hasRevision) {
              unaddressedBlockers.push(thought.thoughtNumber);
            }
            if (hasHighCritique && !hasRevision) {
              unaddressedCritical.push(thought.thoughtNumber);
            }
          }
        }
      }
    
      if (unaddressedBlockers.length > 0) {
        warnings.push(
          `🚫 UNADDRESSED BLOCKERS: Thoughts #${unaddressedBlockers.join(', ')} have BLOCKER extensions but no revisions. You MUST address these before proceeding.`
        );
      }
    
      if (unaddressedCritical.length > 0) {
        warnings.push(
          `⚠️ UNADDRESSED CRITICAL: Thoughts #${unaddressedCritical.join(', ')} have HIGH impact critiques but no revisions. Address these issues with isRevision: true.`
        );
      }
    
      // Check for missing revisions in winningPath
      const missingRevisions: number[] = [];
      for (const thought of sessionThoughts) {
        if (!winningPath.includes(thought.thoughtNumber)) continue;
        if (!thought.extensions) continue;
    
        const hasCritical = thought.extensions.some(
          (e) => (e.impact === 'high' || e.impact === 'blocker') && e.type === 'critique'
        );
        if (!hasCritical) continue;
    
        const revision = sessionThoughts.find(
          (t) => t.isRevision && t.revisesThought === thought.thoughtNumber
        );
        if (revision && !winningPath.includes(revision.thoughtNumber)) {
          missingRevisions.push(thought.thoughtNumber);
        }
      }
    
      if (missingRevisions.length > 0) {
        warnings.push(
          `🚫 MISSING REVISIONS IN PATH: Thoughts #${missingRevisions.join(', ')} have critical critiques with revisions, but those revisions are NOT in your winningPath. Include the revision thoughts or remove the flawed originals.`
        );
      }
    
      // Check for empty or too short winning path
      if (winningPath.length === 0) {
        warnings.push('⚠️ EMPTY PATH: No thoughts selected in winning path. This seems wrong.');
      } else if (winningPath.length < 2 && sessionThoughts.length > 3) {
        warnings.push(
          '⚠️ SUSPICIOUSLY SHORT PATH: Only 1 thought selected from a longer chain. Did you skip important reasoning?'
        );
      }
    
      // Determine if can proceed
      const hasBlockerWarnings = unaddressedBlockers.length > 0;
      const hasCriticalWarnings = unaddressedCritical.length > 0;
      const hasMissingRevisions = missingRevisions.length > 0;
      const hasPathDiscontinuity = !connectivityCheck.valid;
      const canProceed =
        verdict === 'ready' &&
        !hasBlockerWarnings &&
        !hasCriticalWarnings &&
        !hasMissingRevisions &&
        !hasPathDiscontinuity &&
        warnings.length <= 1;
    
      // Generate evaluation message
      let evaluation: string;
      if (canProceed) {
        evaluation =
          '✅ SYNTHESIS ACCEPTED: Your reasoning chain is coherent. You may proceed to final answer.';
    
        // v4.1.0: Save insight via callback on successful consolidation
        if (onSuccess) {
          onSuccess(winningPath, input.summary);
        }
      } else if (verdict === 'needs_more_work') {
        evaluation =
          '🔄 ACKNOWLEDGED: You identified this needs more work. Continue with sequentialthinking or extend_thought.';
    
        // Record dead end via callback
        if (onDeadEnd) {
          onDeadEnd(winningPath, input.summary);
        }
      } else {
        evaluation = `⚠️ SYNTHESIS REJECTED: ${warnings.length} issue(s) found. Address them before providing final answer.`;
      }
    
      // Log consolidation
      console.error(
        `🎯 Consolidation: verdict=${verdict}, path=[${winningPath.join(',')}], warnings=${warnings.length}, canProceed=${canProceed}`
      );
    
      return {
        status: 'success',
        evaluation,
        warnings,
        canProceedToFinalAnswer: canProceed,
        pathAnalysis: {
          totalThoughts: sessionThoughts.length,
          pathLength: winningPath.length,
          ignoredRatio: Math.round(ignoredRatio * 100) / 100,
          lowConfidenceInPath,
          unaddressedBlockers,
          unaddressedCritical,
          disconnectedAt: connectivityCheck.disconnectedAt
            ? [connectivityCheck.disconnectedAt]
            : undefined,
        },
      };
    }
  • ExportService.export(): Generates Markdown or JSON session reports including thoughts, extensions, branches, dead ends, Mermaid diagram; invoked optionally in think_done handler.
    export(data: ExportSessionData, options: ExportOptions = {}): string {
      const { format = 'markdown', includeMermaid = true } = options;
      const { thoughts, branches, deadEnds, sessionGoal, averageConfidence, mermaidDiagram } = data;
    
      if (thoughts.length === 0) {
        return format === 'json'
          ? JSON.stringify({ error: 'No thoughts recorded in current session' })
          : '# Think Session Report\n\n*No thoughts recorded in current session.*';
      }
    
      if (format === 'json') {
        return JSON.stringify(
          {
            goal: sessionGoal,
            thoughts,
            branches: Array.from(branches.entries()),
            deadEnds,
            averageConfidence,
            exportedAt: new Date().toISOString(),
          },
          null,
          2
        );
      }
    
      // Markdown format
      return this.generateMarkdown(data, includeMermaid);
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes what the tool checks (low confidence thoughts, unaddressed blockers, ignored thoughts ratio) and mentions the export option, which adds useful context. However, it doesn't disclose important behavioral traits like whether this is a read-only operation, what permissions might be needed, whether it modifies any data, or what the typical response looks like.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise and well-structured. It uses bullet points efficiently, front-loads the core purpose, and every sentence earns its place. The four-line format with clear sections (purpose, mandate, checks, options) is optimal for quick comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 7 parameters, no annotations, and no output schema, the description is somewhat complete but has gaps. It covers the purpose and usage mandate well, and mentions some verification checks. However, it doesn't explain what happens after verification, what the tool actually returns, or important behavioral aspects like whether this concludes a session or just analyzes it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 7 parameters thoroughly. The description mentions 'exportReport' as an option and implies verification checks, but doesn't add meaningful semantic context beyond what the schema provides. The baseline of 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Finish thinking session: verify logic and optionally export.' It specifies the verb ('finish'), resource ('thinking session'), and core actions (verification and export). However, it doesn't explicitly differentiate from sibling tools like think_reset or think_recall, which likely handle different aspects of thinking sessions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: 'MANDATORY before final answer on complex problems.' This gives explicit guidance on its necessity in specific scenarios. However, it doesn't mention when NOT to use it or name alternatives among sibling tools, which would be needed for a perfect score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GofMan5/think-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server