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, }, }; } }

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