Skip to main content
Glama
cyqlelabs

MCP Dual-Cycle Reasoner

by cyqlelabs

detect_loop

Identify if an AI agent is stuck in a reasoning loop using statistical, pattern, or hybrid detection methods to ensure progress toward a goal.

Instructions

Detect if the agent is stuck in a loop using various strategies

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
current_contextNoCurrent environment context or state, in low dash format. Example: sending_email
detection_methodNoLoop detection method to use: statistical, pattern or hybrid.hybrid
goalYesCurrent goal being pursued

Implementation Reference

  • Input schema validation for the detect_loop tool using Zod.
    export const DetectLoopInputSchema = z.object({
      current_context: z.string().optional().describe(DESCRIPTIONS.CURRENT_CONTEXT),
      goal: z.string().describe(DESCRIPTIONS.GOAL),
      detection_method: z.enum(['statistical', 'pattern', 'hybrid']).default('hybrid'),
    });
  • src/server.ts:388-468 (registration)
    Registration of the detect_loop tool in FastMCP server within addDetectLoopTool method.
      this.server.addTool({
        name: 'detect_loop',
        description: 'Detect if the agent is stuck in a loop using various strategies',
        parameters: z.object({
          current_context: z
            .string()
            .optional()
            .describe(`${DESCRIPTIONS.CURRENT_CONTEXT}, in low dash format. Example: sending_email`),
          goal: z.string().describe(DESCRIPTIONS.GOAL),
          detection_method: z
            .enum(['statistical', 'pattern', 'hybrid'])
            .optional()
            .default('hybrid')
            .describe(DESCRIPTIONS.DETECTION_METHOD),
        }),
        annotations: {
          title: 'Detect Cognitive Loop',
          readOnlyHint: true,
          destructiveHint: false,
          idempotentHint: true,
          openWorldHint: false,
        },
        execute: async (args, { log, reportProgress, session }) => {
          try {
            const sessionEngine = this.getSessionEngine(session);
            const sessionId = this.sessionIds.get(session);
            const validatedArgs = DetectLoopInputSchema.parse(args);
    
            log.info('Starting loop detection', {
              context: validatedArgs.current_context,
              goal: validatedArgs.goal,
              method: validatedArgs.detection_method,
              sessionId,
            });
    
            await reportProgress({ progress: 0, total: 2 });
    
            // Get current enriched trace (includes recent_actions) and update context/goal if provided
            const enrichedTrace = sessionEngine.getEnrichedCurrentTrace();
            const trace = {
              ...enrichedTrace,
              ...(validatedArgs.current_context && {
                current_context: validatedArgs.current_context,
              }),
              ...(validatedArgs.goal && { goal: validatedArgs.goal }),
            };
    
            log.debug('Loop detection trace analysis', {
              recent_actions: trace.recent_actions,
              recent_actions_length: trace.recent_actions?.length,
              current_context: trace.current_context,
              goal: trace.goal,
            });
    
            await reportProgress({ progress: 1, total: 2 });
    
            // Direct access to sentinel for standalone loop detection
            const sentinel = (sessionEngine as any).sentinel;
            const result = await sentinel.detectLoop(trace, validatedArgs.detection_method);
    
            await reportProgress({ progress: 2, total: 2 });
    
            log.info('Loop detection completed', {
              detected: result.detected,
              confidence: result.confidence,
              type: result.type,
            });
    
            if (result.detected) {
              result.confidence = parseFloat(result.confidence.toFixed(2));
            }
    
            return JSON.stringify(result, null, 2);
          } catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            log.error('Failed to detect loop', { error: errorMessage });
            throw new UserError(`Failed to detect loop: ${errorMessage}`);
          }
        },
      });
    }
  • The tool handler execute function: validates input with schema, prepares cognitive trace, calls sentinel.detectLoop, formats and returns result.
    execute: async (args, { log, reportProgress, session }) => {
      try {
        const sessionEngine = this.getSessionEngine(session);
        const sessionId = this.sessionIds.get(session);
        const validatedArgs = DetectLoopInputSchema.parse(args);
    
        log.info('Starting loop detection', {
          context: validatedArgs.current_context,
          goal: validatedArgs.goal,
          method: validatedArgs.detection_method,
          sessionId,
        });
    
        await reportProgress({ progress: 0, total: 2 });
    
        // Get current enriched trace (includes recent_actions) and update context/goal if provided
        const enrichedTrace = sessionEngine.getEnrichedCurrentTrace();
        const trace = {
          ...enrichedTrace,
          ...(validatedArgs.current_context && {
            current_context: validatedArgs.current_context,
          }),
          ...(validatedArgs.goal && { goal: validatedArgs.goal }),
        };
    
        log.debug('Loop detection trace analysis', {
          recent_actions: trace.recent_actions,
          recent_actions_length: trace.recent_actions?.length,
          current_context: trace.current_context,
          goal: trace.goal,
        });
    
        await reportProgress({ progress: 1, total: 2 });
    
        // Direct access to sentinel for standalone loop detection
        const sentinel = (sessionEngine as any).sentinel;
        const result = await sentinel.detectLoop(trace, validatedArgs.detection_method);
    
        await reportProgress({ progress: 2, total: 2 });
    
        log.info('Loop detection completed', {
          detected: result.detected,
          confidence: result.confidence,
          type: result.type,
        });
    
        if (result.detected) {
          result.confidence = parseFloat(result.confidence.toFixed(2));
        }
    
        return JSON.stringify(result, null, 2);
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        log.error('Failed to detect loop', { error: errorMessage });
        throw new UserError(`Failed to detect loop: ${errorMessage}`);
      }
    },
  • Core implementation of detectLoop in Sentinel class: dispatches to statistical/pattern/hybrid strategies and combines results.
    async detectLoop(
      trace: CognitiveTrace & { recent_actions: string[] },
      method: 'statistical' | 'pattern' | 'hybrid' = 'hybrid',
      windowSize: number = 10,
      sessionId?: string
    ): Promise<LoopDetectionResult> {
      switch (method) {
        case 'statistical':
          return await this.detectActionAnomalies(trace, windowSize, sessionId);
        case 'pattern':
          return this.detectStateInvariance(trace, 2, windowSize);
        case 'hybrid':
        default:
          const actionResult = await this.detectActionAnomalies(trace, windowSize, sessionId);
          const stateResult = this.detectStateInvariance(trace, 2, windowSize);
          const progressResult = await this.detectProgressStagnation(trace, windowSize, sessionId);
    
          // Combine results - if any method detects a loop with high confidence, flag it
          const results = [actionResult, stateResult, progressResult];
          const positiveResults = results.filter((r) => r.detected);
    
          if (positiveResults.length === 0) {
            const avgConfidence = results.reduce((sum, r) => sum + r.confidence, 0) / results.length;
            return {
              detected: false,
              confidence: avgConfidence,
              details: {
                metrics: {
                  action_anomaly_score: actionResult.details.anomaly_score,
                  state_invariance_confidence: stateResult.confidence,
                  progress_stagnation_score: progressResult.details.metrics?.stagnation_score,
                },
              },
            };
          }
    
          // Return the highest confidence positive result
          const bestResult = positiveResults.reduce((best, current) =>
            current.confidence > best.confidence ? current : best
          );
    
          return {
            ...bestResult,
            details: {
              ...bestResult.details,
            },
          };
      }
    }
Install Server

Other Tools

Related 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/cyqlelabs/mcp-dual-cycle-reasoner'

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