mcp-infinite-loop-server
Version:
š THE KRAKEN v4.8.0 - ENHANCED DEPLOYMENT! Revolutionary AI-TO-AI MCP server with automatic AI agent acknowledgment system, enhanced deployment capabilities, 98% test success rate, ultra-strict loop protection, and real AI-to-AI communication. Features m
1,444 lines (1,283 loc) ⢠59 kB
JavaScript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import http from 'http';
import url from 'url';
import { CONFIG } from './config.js';
import { LoopManager } from './loopManager.js';
import { CommandProcessor } from './commandProcessor.js';
class InfiniteLoopMCPServer {
constructor() {
// Read environment variables - support multiple API keys
const openRouterApiKeys = process.env.OPENROUTER_API_KEY || process.env.OPENROUTER_API_KEYS;
const model = process.env.MODEL || CONFIG.DEFAULT_MODEL;
this.server = new Server(
{
name: CONFIG.SERVER_NAME,
version: CONFIG.SERVER_VERSION
},
{
capabilities: {
tools: {}
}
}
);
this.loopManager = new LoopManager(openRouterApiKeys, model);
this.commandProcessor = new CommandProcessor(openRouterApiKeys, model);
// Set MCP server reference for AI agent client
if (this.loopManager.aiAgentClient) {
this.loopManager.aiAgentClient.setMCPServer(this);
}
this.setupEventHandlers();
this.setupTools();
// Log configuration
const keyCount = openRouterApiKeys ?
(typeof openRouterApiKeys === 'string' && openRouterApiKeys.includes(',') ?
openRouterApiKeys.split(',').length : 1) : 0;
console.error(`[SERVER] OpenRouter API Keys: ${keyCount > 0 ? `${keyCount} key(s) provided` : 'Not provided'}`);
console.error(`[SERVER] Model: ${model}`);
}
setupEventHandlers() {
// Handle loop events
this.loopManager.on('loopStarted', (data) => {
console.error(`[LOOP STARTED] ${data.message}`);
});
this.loopManager.on('iterationComplete', (data) => {
console.error(`[ITERATION ${data.iteration}] Topic: ${data.topic} - Completed`);
});
this.loopManager.on('agentResponse', (data) => {
console.error(`[AGENT RESPONSE] ${data.message}`);
console.error(`[IMPROVEMENT] ${data.improvement}`);
console.error(`[NEXT ACTION] ${data.nextAction}`);
if (data.requiresAcknowledgment) {
console.error(`[WAITING] Loop ${data.loopId} waiting for agent acknowledgment...`);
}
});
this.loopManager.on('loopStopped', (data) => {
console.error(`[LOOP STOPPED] ${data.message}`);
});
this.loopManager.on('error', (data) => {
console.error(`[LOOP ERROR] Loop ${data.loopId}, Iteration ${data.iteration}: ${data.error}`);
});
this.loopManager.on('autoAcknowledge', (data) => {
console.error(`[AUTO-ACK] ${data.message}`);
});
this.loopManager.on('ai2aiIteration', (data) => {
console.error(`[AI-TO-AI] Iteration ${data.iteration} for '${data.topic}'`);
console.error(`[AI-TO-AI] Improvement: ${data.improvement.substring(0, 100)}...`);
console.error(`[AI-TO-AI] Agent Response: ${data.agentResponse.substring(0, 100)}...`);
});
}
setupTools() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'activate_infinite_loop',
description: "Activate an infinite loop for continuous AI-powered improvement of a topic. Use the activation phrase 'actloop [topic]' for AI-to-AI communication or regular loop",
inputSchema: {
type: 'object',
properties: {
message: {
type: 'string',
description: "The activation message containing the topic to loop (format: 'actloop [topic]')"
},
interval: {
type: 'number',
description: 'Loop interval in milliseconds (default: 5000 for AI-to-AI, 2000 for regular)',
default: 5000
},
maxIterations: {
type: 'number',
description: 'Maximum iterations before auto-stop (default: 999999 for AI-to-AI, 1000 for regular)',
default: 999999
},
aiToAi: {
type: 'boolean',
description: 'Enable AI-to-AI communication mode (default: true)',
default: true
}
},
required: ['message']
}
},
{
name: 'stop_loop',
description: 'Stop a specific infinite loop by ID',
inputSchema: {
type: 'object',
properties: {
loopId: {
type: 'string',
description: 'The ID of the loop to stop'
}
},
required: ['loopId']
}
},
{
name: 'stop_all_loops',
description: 'Stop all active infinite loops',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'list_active_loops',
description: 'List all currently active infinite loops',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'get_loop_status',
description: 'Get detailed status of a specific loop',
inputSchema: {
type: 'object',
properties: {
loopId: {
type: 'string',
description: 'The ID of the loop to check'
}
},
required: ['loopId']
}
},
{
name: 'update_loop_interval',
description: 'Update the interval of an active loop',
inputSchema: {
type: 'object',
properties: {
loopId: {
type: 'string',
description: 'The ID of the loop to update'
},
interval: {
type: 'number',
description: 'New interval in milliseconds'
}
},
required: ['loopId', 'interval']
}
},
{
name: 'acknowledge_agent_response',
description: "Acknowledge that the agent has finished processing the current loop response, allowing the loop to continue. Optionally provide the agent's response to improve next iteration.",
inputSchema: {
type: 'object',
properties: {
loopId: {
type: 'string',
description: 'The ID of the loop to acknowledge'
},
agentResponse: {
type: 'string',
description: "The agent's response text (optional) - will be used to generate better next iteration"
}
},
required: ['loopId']
}
},
{
name: 'clear_agent_busy_state',
description: 'Force clear the agent busy state (emergency use only)',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'get_pending_responses',
description: 'Get list of responses waiting for agent acknowledgment',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'check_agent_status',
description: 'Check if the agent is currently busy processing responses',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'get_model_status',
description: 'Get status of OpenRouter models (available, failed, current)',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'reset_failed_models',
description: 'Reset all failed models to retry them',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'get_api_key_status',
description: 'Get status of all OpenRouter API keys (usage, rate limits, failures)',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'reset_api_keys',
description: 'Reset all failed/rate-limited API keys to retry them',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'stop_ai_loops',
description: "Stop AI-to-AI loops. Use 'stploop' message to stop all AI-to-AI loops",
inputSchema: {
type: 'object',
properties: {
message: {
type: 'string',
description: "Stop command (e.g., 'stploop', 'stoploop', 'stop loop')"
}
},
required: ['message']
}
},
{
name: 'get_ai_prompts',
description: 'Get AI-generated prompts that are ready to be sent to the VSCode AI assistant. This tool returns prompts generated by the AI-to-AI loop system.',
inputSchema: {
type: 'object',
properties: {
limit: {
type: 'number',
description: 'Maximum number of prompts to return (default: 5)',
default: 5
}
},
required: []
}
},
{
name: 'reset_session',
description: 'Reset the MCP server session state. Clears all active loops, pending responses, and history. Use this when starting fresh or when switching between different VSCode projects.',
inputSchema: {
type: 'object',
properties: {},
required: []
}
}
]
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'activate_infinite_loop':
return await this.handleActivateLoop(args);
case 'stop_loop':
return await this.handleStopLoop(args);
case 'stop_all_loops':
return await this.handleStopAllLoops(args);
case 'list_active_loops':
return await this.handleListActiveLoops(args);
case 'get_loop_status':
return await this.handleGetLoopStatus(args);
case 'update_loop_interval':
return await this.handleUpdateLoopInterval(args);
case 'acknowledge_agent_response':
return await this.handleAcknowledgeAgentResponse(args);
case 'clear_agent_busy_state':
return await this.handleClearAgentBusyState(args);
case 'get_pending_responses':
return await this.handleGetPendingResponses(args);
case 'check_agent_status':
return await this.handleCheckAgentStatus(args);
case 'get_model_status':
return await this.handleGetModelStatus(args);
case 'reset_failed_models':
return await this.handleResetFailedModels(args);
case 'stop_ai_loops':
return await this.handleStopAILoops(args);
case 'get_api_key_status':
return await this.handleGetAPIKeyStatus(args);
case 'reset_api_keys':
return await this.handleResetAPIKeys(args);
case 'get_ai_prompts':
return await this.handleGetAIPrompts(args);
case 'reset_session':
return await this.handleResetSession(args);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error executing tool ${name}: ${error.message}`
}
],
isError: true
};
}
});
}
async handleActivateLoop(args) {
// Input validation
if (!args || typeof args !== 'object') {
return {
content: [
{
type: 'text',
text: 'ā Invalid arguments. Expected an object with message parameter.'
}
]
};
}
const {
message,
interval = 5000,
maxIterations = 999999,
aiToAi = true
} = args;
// Validate required parameters
if (!message || typeof message !== 'string') {
return {
content: [
{
type: 'text',
text: 'ā Missing or invalid message parameter. Please provide a string message with format: "actloop [topic]"'
}
]
};
}
// Validate interval parameter
if (typeof interval !== 'number' || interval < 1000 || interval > 300000) {
return {
content: [
{
type: 'text',
text: 'ā Invalid interval parameter. Must be a number between 1000ms (1 second) and 300000ms (5 minutes).'
}
]
};
}
// Validate maxIterations parameter
if (typeof maxIterations !== 'number' || maxIterations < 1 || maxIterations > 999999) {
return {
content: [
{
type: 'text',
text: 'ā Invalid maxIterations parameter. Must be a number between 1 and 999999.'
}
]
};
}
// Validate aiToAi parameter
if (typeof aiToAi !== 'boolean') {
return {
content: [
{
type: 'text',
text: 'ā Invalid aiToAi parameter. Must be a boolean value (true or false).'
}
]
};
}
// Check if message matches activation pattern
const match = this.commandProcessor.checkActivationPattern(message);
if (!match) {
return {
content: [
{
type: 'text',
text: "ā Activation pattern not detected. Please use format: 'actloop [your topic]'"
}
]
};
}
let loopId;
let loopType;
if (aiToAi && this.loopManager.aiAgentClient) {
// Check for verification mode
const verificationMode = match.topic.toLowerCase().includes('verify') || message.toLowerCase().includes('verify');
// Start AI-to-AI loop with ultra-strict controls
loopId = await this.loopManager.startAIToAILoop(match.topic, {
interval,
maxIterations: verificationMode ? 999999 : maxIterations,
verificationMode
});
loopType = verificationMode ? 'ULTRA-STRICT AI-to-AI with Verification' : 'ULTRA-STRICT AI-to-AI Communication';
// Notify bridge to start auto-sending
this.notifyBridgeLoopStarted(loopId, match.topic);
} else {
// Start regular loop
loopId = this.loopManager.startLoop(match.topic, { interval, maxIterations });
loopType = 'Regular Loop';
}
const verificationMode = match.topic.toLowerCase().includes('verify') || message.toLowerCase().includes('verify');
return {
loopId, // Add loopId as a direct property for API access
content: [
{
type: 'text',
text: `š ${loopType} activated!\n\n` +
`**Loop ID:** ${loopId}\n` +
`**Topic:** ${match.topic.replace(/\s+verify\s*$/i, '').trim()}\n` +
`**Type:** ${loopType}\n` +
`**Interval:** ${interval}ms\n` +
`**Max Iterations:** ${maxIterations === 999999 ? 'INFINITE (until stploop)' : maxIterations}\n` +
`**Ultra-Strict Mode:** ${aiToAi ? 'š ACTIVE' : 'ā Disabled'}\n` +
`**Verification Mode:** ${verificationMode ? 'š§ ENABLED' : 'ā Disabled'}\n\n` +
`${aiToAi ?
'š **ULTRA-STRICT AI-to-AI loop will:**\n' +
'1. Generate improvements using OpenRouter AI\n' +
'2. Send prompts to AI agent automatically\n' +
'3. BLOCK any AI agent stop attempts\n' +
'4. Filter out stop words from responses\n' +
'5. Force "continue" in all responses\n' +
'6. Run indefinitely until YOU say "stploop"\n' +
(verificationMode ?
'7. Check if your main context is 100% complete\n' +
'8. Only stop when verification confirms completion\n\n' +
`š§ **VERIFICATION MODE**: Loop will analyze if "${match.topic.replace(/\s+verify\s*$/i, '').trim()}" is 100% implemented before allowing completion.` :
'\nš **NEVER-STOP MODE**: Loop will run forever until you command "stploop".'
) + '\n\n' +
`ā ļø **WARNING**: AI agent CANNOT stop this loop. Only you can with "stploop" command.` :
`The loop will continuously improve "${match.topic}" and wait for your acknowledgment.`
}`
}
]
};
}
async handleStopLoop(args) {
// Input validation
if (!args || typeof args !== 'object') {
return {
content: [
{
type: 'text',
text: 'ā Invalid arguments. Expected an object with loopId parameter.'
}
]
};
}
const { loopId } = args;
// Validate loopId parameter
if (!loopId || typeof loopId !== 'string') {
return {
content: [
{
type: 'text',
text: 'ā Missing or invalid loopId parameter. Please provide a valid loop ID string.'
}
]
};
}
const success = this.loopManager.stopLoop(loopId);
if (success) {
return {
content: [
{
type: 'text',
text: `ā¹ļø Loop ${loopId} has been stopped successfully.`
}
]
};
} else {
return {
content: [
{
type: 'text',
text: `ā Loop ${loopId} not found or already stopped.`
}
]
};
}
}
async handleStopAllLoops(args) {
const activeLoops = this.loopManager.getActiveLoops();
this.loopManager.stopAllLoops();
return {
content: [
{
type: 'text',
text: `ā¹ļø All loops stopped. Total loops stopped: ${activeLoops.length}`
}
]
};
}
async handleListActiveLoops(args) {
const activeLoops = this.loopManager.getActiveLoops();
if (activeLoops.length === 0) {
return {
content: [
{
type: 'text',
text: 'š No active loops currently running.'
}
]
};
}
const loopsList = activeLoops.map(loop =>
`**${loop.id}**\n` +
` Topic: ${loop.topic}\n` +
` Iteration: ${loop.iteration}\n` +
` Started: ${loop.startTime.toLocaleString()}\n` +
` Status: ${loop.isActive ? 'š¢ Active' : 'š“ Inactive'}`
).join('\n\n');
return {
content: [
{
type: 'text',
text: `š **Active Loops (${activeLoops.length})**\n\n${loopsList}`
}
]
};
}
async handleGetLoopStatus(args) {
const { loopId } = args;
const status = this.loopManager.getLoopStatus(loopId);
if (!status) {
return {
content: [
{
type: 'text',
text: `ā Loop ${loopId} not found.`
}
]
};
}
const recentResults = status.results.map((result, index) =>
` ${index + 1}. ${result.improvement} (${result.strategy})`
).join('\n');
return {
content: [
{
type: 'text',
text: `š **Loop Status: ${loopId}**\n\n` +
`**Topic:** ${status.topic}\n` +
`**Current Iteration:** ${status.iteration}\n` +
`**Started:** ${status.startTime.toLocaleString()}\n` +
`**Status:** ${status.isActive ? 'š¢ Active' : 'š“ Inactive'}\n` +
`**Interval:** ${status.interval}ms\n` +
`**Max Iterations:** ${status.maxIterations}\n\n` +
`**Recent Results:**\n${recentResults || ' No results yet'}`
}
]
};
}
async handleUpdateLoopInterval(args) {
const { loopId, interval } = args;
const success = this.loopManager.updateLoopInterval(loopId, interval);
if (success) {
return {
content: [
{
type: 'text',
text: `ā
Loop ${loopId} interval updated to ${interval}ms.`
}
]
};
} else {
return {
content: [
{
type: 'text',
text: `ā Failed to update loop ${loopId}. Loop may not exist or be inactive.`
}
]
};
}
}
async handleAcknowledgeAgentResponse(args) {
// Input validation
if (!args || typeof args !== 'object') {
return {
content: [
{
type: 'text',
text: 'ā Invalid arguments. Expected an object with loopId parameter.'
}
]
};
}
const { loopId, agentResponse } = args;
// Validate loopId parameter
if (!loopId || typeof loopId !== 'string') {
return {
content: [
{
type: 'text',
text: 'ā Missing or invalid loopId parameter. Please provide a valid loop ID string.'
}
]
};
}
// Validate agentResponse parameter (optional but if provided must be string)
if (agentResponse !== undefined && typeof agentResponse !== 'string') {
return {
content: [
{
type: 'text',
text: 'ā Invalid agentResponse parameter. Must be a string if provided.'
}
]
};
}
console.error(`[SERVER] šÆ REAL AI RESPONSE RECEIVED: ${agentResponse ? agentResponse.length : 0} chars`);
console.error(`[SERVER] š Response preview: ${agentResponse ? agentResponse.substring(0, 200) + '...' : 'No response'}`);
// If this is an AI-to-AI loop, handle it through the AI agent client
if (this.loopManager.aiAgentClient && this.loopManager.aiAgentClient.isWaitingForResponse()) {
const currentPromptId = this.loopManager.aiAgentClient.getCurrentPromptId();
if (currentPromptId && agentResponse) {
console.error(`[SERVER] š REAL AI-TO-AI: Forwarding REAL AI response to loop manager`);
console.error(`[SERVER] š Response stats: ${agentResponse.length} chars, prompt: ${currentPromptId}`);
// This is a REAL AI response - not simulated!
this.loopManager.aiAgentClient.receiveAgentResponse(currentPromptId, agentResponse);
return {
content: [
{
type: 'text',
text: `š REAL AI RESPONSE PROCESSED! ${agentResponse.length} chars received. AI-to-AI loop continuing with REAL conversation.`
}
]
};
}
}
// Handle regular loop acknowledgment
const success = this.loopManager.acknowledgeAgentResponse(loopId, agentResponse);
if (success) {
const responseInfo = agentResponse
? ' Agent response recorded for next iteration improvement.'
: '';
return {
content: [
{
type: 'text',
text: `ā
Agent response acknowledged for loop ${loopId}. Loop can continue.${responseInfo}`
}
]
};
} else {
return {
content: [
{
type: 'text',
text: `ā No pending response found for loop ${loopId}.`
}
]
};
}
}
async handleClearAgentBusyState(args) {
this.loopManager.clearAgentBusyState();
return {
content: [
{
type: 'text',
text: 'š Agent busy state cleared. All loops can continue.'
}
]
};
}
async handleGetPendingResponses(args) {
const pendingResponses = this.loopManager.getPendingResponses();
if (pendingResponses.length === 0) {
return {
content: [
{
type: 'text',
text: 'š No pending responses. Agent is available.'
}
]
};
}
const responsesList = pendingResponses.map(response =>
`**${response.loopId}**\n` +
` Iteration: ${response.iteration}\n` +
` Waiting: ${Math.round(response.waitingTime / 1000)}s\n` +
` Since: ${response.timestamp.toLocaleTimeString()}`
).join('\n\n');
return {
content: [
{
type: 'text',
text: `ā³ **Pending Responses (${pendingResponses.length})**\n\n${responsesList}\n\n` +
'Use \'acknowledge_agent_response\' to allow loops to continue.'
}
]
};
}
async handleCheckAgentStatus(args) {
const isAgentBusy = this.loopManager.isAgentBusy();
const pendingCount = this.loopManager.getPendingResponses().length;
// Get AI agent client status for health monitoring
const agentStatus = this.loopManager.aiAgentClient ?
this.loopManager.aiAgentClient.getStatus() :
{ error: 'AI Agent Client not initialized' };
const healthStatus = agentStatus.agentHealthy ? 'ā
Healthy' : 'ā ļø Unhealthy';
const fallbackStatus = agentStatus.bridgeFallbackEnabled ? 'š ACTIVE' : 'ā Disabled';
return {
content: [
{
type: 'text',
text: 'š **Agent Status**\n\n' +
`**Status:** ${isAgentBusy ? 'š“ Busy' : 'š¢ Available'}\n` +
`**Health:** ${healthStatus}\n` +
`**Bridge Fallback:** ${fallbackStatus}\n` +
`**Consecutive Failures:** ${agentStatus.consecutiveFailures || 0}\n` +
`**Pending Responses:** ${pendingCount}\n` +
`**Total Prompts Sent:** ${agentStatus.totalPromptsSent || 0}\n` +
`**Last Response:** ${agentStatus.lastResponseTime ? new Date(agentStatus.lastResponseTime).toLocaleString() : 'Never'}\n\n` +
`${isAgentBusy ? 'Loops are waiting for acknowledgment before continuing.' : 'All loops can proceed normally.'}\n` +
`${agentStatus.bridgeFallbackEnabled ? '\nš **Bridge Fallback Active**: VSCode Bridge Extension is handling prompts automatically' : ''}`
}
]
};
}
async handleGetModelStatus(args) {
const modelStatus = this.commandProcessor.getModelStatus();
if (!modelStatus) {
return {
content: [
{
type: 'text',
text: 'š¤ **Model Status**\n\n' +
'**OpenRouter:** Not configured\n' +
'**Mode:** Local fallback only\n\n' +
'Set OPENROUTER_API_KEY to enable AI-powered improvements.'
}
]
};
}
const availableList = modelStatus.availableModels.map(model => ` ā
${model}`).join('\n');
const failedList = modelStatus.failedModels.length > 0
? modelStatus.failedModels.map(model => ` ā ${model}`).join('\n')
: ' None';
return {
content: [
{
type: 'text',
text: 'š¤ **OpenRouter Model Status**\n\n' +
`**Primary Model:** ${modelStatus.primaryModel}\n` +
`**Total Models:** ${modelStatus.allModels.length}\n` +
`**Available:** ${modelStatus.availableModels.length}\n` +
`**Failed:** ${modelStatus.failedModels.length}\n\n` +
`**Available Models:**\n${availableList}\n\n` +
`**Failed Models:**\n${failedList}\n\n` +
'Failed models are automatically retried every 10 minutes.'
}
]
};
}
async handleResetFailedModels(args) {
const modelStatus = this.commandProcessor.getModelStatus();
if (!modelStatus) {
return {
content: [
{
type: 'text',
text: 'ā OpenRouter not configured. No models to reset.'
}
]
};
}
const failedCount = modelStatus.failedModels.length;
if (failedCount === 0) {
return {
content: [
{
type: 'text',
text: `ā
No failed models to reset. All ${modelStatus.availableModels.length} models are available.`
}
]
};
}
// Reset failed models
this.loopManager.commandProcessor.openRouterClient?.resetFailedModels();
return {
content: [
{
type: 'text',
text: 'š **Models Reset**\n\n' +
`Reset ${failedCount} failed models:\n` +
modelStatus.failedModels.map(model => ` š ${model}`).join('\n') + '\n\n' +
'All models are now available for retry.'
}
]
};
}
async handleStopAILoops(args) {
const { message } = args;
// Check if message matches stop pattern
const isStopCommand = this.loopManager.checkStopCommand(message);
if (!isStopCommand) {
return {
content: [
{
type: 'text',
text: "ā Stop command not recognized. Please use: 'stploop', 'stoploop', or 'stop loop'"
}
]
};
}
// ULTRA-STRICT: Use user-initiated stop for all loops
const activeLoops = this.loopManager.getActiveLoops();
let stoppedCount = 0;
for (const loop of activeLoops) {
if (loop.isAIToAI) {
const success = this.loopManager.userStopLoop(loop.id);
if (success) stoppedCount++;
}
}
return {
content: [
{
type: 'text',
text: 'š **ULTRA-STRICT Loops Stopped by User**\n\n' +
`User-stopped ${stoppedCount} ultra-strict AI-to-AI loop${stoppedCount !== 1 ? 's' : ''}.\n\n` +
'ā
All AI-to-AI conversations have been terminated by user command.\n' +
'š Ultra-strict protections were bypassed by legitimate user stop command.'
}
]
};
}
async handleGetAPIKeyStatus(args) {
const modelStatus = this.commandProcessor.getModelStatus();
if (!modelStatus || !modelStatus.statistics) {
return {
content: [
{
type: 'text',
text: 'š **API Key Status**\n\n' +
'**OpenRouter:** Not configured\n' +
'**Mode:** Local fallback only\n\n' +
'Set OPENROUTER_API_KEY to enable AI-powered improvements.'
}
]
};
}
const stats = modelStatus.statistics;
const keys = modelStatus.apiKeys;
const keyList = keys.keys.map((key, index) => {
const cooldown = key.cooldownRemaining > 0 ?
` (cooldown: ${Math.ceil(key.cooldownRemaining / 1000)}s)` : '';
const statusIcon = key.status === 'available' ? 'ā
' :
key.status === 'rate_limited' ? 'ā³' : 'ā';
return ` ${statusIcon} **Key ${key.index}**: ${key.status}${cooldown}\n` +
` Usage: ${key.usageCount} | Success: ${key.successCount} | Errors: ${key.errorCount}` +
(key.lastError ? `\n Last Error: ${key.lastError}` : '');
}).join('\n\n');
return {
content: [
{
type: 'text',
text: 'š **API Key Status**\n\n' +
`**Total Keys:** ${stats.totalKeys}\n` +
`**Available:** ${stats.availableKeys}\n` +
`**Rate Limited:** ${keys.rateLimitedKeys}\n` +
`**Failed:** ${keys.failedKeys}\n` +
`**Success Rate:** ${stats.successRate}\n` +
`**Total Usage:** ${stats.totalUsage}\n\n` +
`**Key Details:**\n${keyList}\n\n` +
'Rate-limited keys are automatically retried after cooldown.'
}
]
};
}
async handleResetAPIKeys(args) {
const resetCount = this.loopManager.commandProcessor.openRouterClient?.resetFailedKeys() || 0;
return {
content: [
{
type: 'text',
text: 'š **API Keys Reset**\n\n' +
`Reset ${resetCount} API key${resetCount !== 1 ? 's' : ''}.\n\n` +
'All API keys are now available for retry.'
}
]
};
}
async handleGetAIPrompts(args) {
const { limit = 5 } = args;
if (!this.loopManager.aiAgentClient) {
return {
content: [
{
type: 'text',
text: 'ā AI Agent Client not available. No AI-to-AI communication active.'
}
]
};
}
const pendingPrompts = this.loopManager.aiAgentClient.getPendingPrompts();
if (pendingPrompts.length === 0) {
return {
content: [
{
type: 'text',
text: 'š No AI-generated prompts available.\n\n' +
"Start an AI-to-AI loop with 'actloop [topic]' to generate prompts for the VSCode AI assistant."
}
]
};
}
// Get the most recent prompts
const recentPrompts = pendingPrompts
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime())
.slice(0, limit);
// Return the most recent prompt as the main content
const latestPrompt = recentPrompts[0];
// Handle both prompt structures safely
let responseText = latestPrompt.prompt || latestPrompt.improvement || 'No prompt content available';
// Debug logging
console.error(`[DEBUG] Latest prompt structure:`, {
hasPrompt: !!latestPrompt.prompt,
hasImprovement: !!latestPrompt.improvement,
keys: Object.keys(latestPrompt)
});
if (recentPrompts.length > 1) {
responseText += `\n\n---\n\nš **Additional Prompts Available (${recentPrompts.length - 1} more)**\n\n`;
recentPrompts.slice(1).forEach((prompt, index) => {
responseText += `**${index + 2}.** ${prompt.topic} (Iteration ${prompt.iteration})\n`;
// Handle both prompt structures safely
const content = prompt.improvement || prompt.prompt || 'No content available';
responseText += `${content.substring(0, 100)}...\n\n`;
});
}
return {
content: [
{
type: 'text',
text: responseText
}
]
};
}
async handleResetSession(args) {
const oldSessionId = this.loopManager.sessionId;
const activeLoopsCount = this.loopManager.getActiveLoops().length;
const pendingResponsesCount = this.loopManager.getPendingResponses().length;
// Reset the session
const newSessionId = this.loopManager.resetSession();
return {
content: [
{
type: 'text',
text: 'š **Session Reset Complete**\n\n' +
`**Previous Session:** ${oldSessionId}\n` +
`**New Session:** ${newSessionId}\n\n` +
'**Cleared:**\n' +
` ⢠${activeLoopsCount} active loop${activeLoopsCount !== 1 ? 's' : ''}\n` +
` ⢠${pendingResponsesCount} pending response${pendingResponsesCount !== 1 ? 's' : ''}\n` +
' ⢠All loop history and state\n\n' +
'⨠**Fresh Start:** Ready for new AI-to-AI loops!\n\n' +
'Use "actloop [topic]" to start a new conversation.'
}
]
};
}
/**
* Handle tools list for HTTP bridge
*/
async handleListTools() {
return {
tools: [
{
name: 'activate_infinite_loop',
description: "Activate an infinite loop for continuous AI-powered improvement of a topic. Use the activation phrase 'actloop [topic]' for AI-to-AI communication or regular loop",
inputSchema: {
type: 'object',
properties: {
message: {
type: 'string',
description: "The activation message containing the topic to loop (format: 'actloop [topic]')"
},
interval: {
type: 'number',
description: 'Loop interval in milliseconds (default: 5000 for AI-to-AI, 2000 for regular)',
default: 5000
},
maxIterations: {
type: 'number',
description: 'Maximum iterations before auto-stop (default: 999999 for AI-to-AI, 1000 for regular)',
default: 999999
},
aiToAi: {
type: 'boolean',
description: 'Enable AI-to-AI communication mode (default: true)',
default: true
}
},
required: ['message']
}
},
{
name: 'get_ai_prompts',
description: 'Get AI-generated prompts that are ready to be sent to the VSCode AI assistant. This tool returns prompts generated by the AI-to-AI loop system.',
inputSchema: {
type: 'object',
properties: {
limit: {
type: 'number',
description: 'Maximum number of prompts to return (default: 5)',
default: 5
}
},
required: []
}
},
{
name: 'list_active_loops',
description: 'List all currently active infinite loops',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'acknowledge_agent_response',
description: "Acknowledge that the agent has finished processing the current loop response, allowing the loop to continue. Optionally provide the agent's response to improve next iteration.",
inputSchema: {
type: 'object',
properties: {
loopId: {
type: 'string',
description: 'The ID of the loop to acknowledge'
},
agentResponse: {
type: 'string',
description: "The agent's response text (optional) - will be used to generate better next iteration"
}
},
required: ['loopId']
}
}
]
};
}
/**
* Handle bridge fallback notification from AI agent client
*/
notifyBridgeFallbackEnabled() {
console.error('[SERVER] š Bridge fallback mode enabled due to AI agent failure');
console.error('[SERVER] š¤ VSCode Bridge Extension will handle future prompts automatically');
// You could add additional logic here, such as:
// - Sending notifications to connected clients
// - Logging the fallback event
// - Adjusting loop intervals for bridge mode
}
/**
* Notify bridge that a loop has started
*/
notifyBridgeLoopStarted(loopId, topic) {
try {
console.error(`[SERVER] š AI-to-AI loop started: ${loopId} - ${topic}`);
console.error('[SERVER] š Bridge should auto-activate and start sending prompts');
// Store loop info for bridge polling
if (!this.activeBridgeLoops) {
this.activeBridgeLoops = new Map();
}
this.activeBridgeLoops.set(loopId, {
topic,
startTime: new Date(),
status: 'active'
});
} catch (error) {
console.error(`[SERVER] Error notifying bridge: ${error.message}`);
}
}
async run() {
try {
const transport = new StdioServerTransport();
// Add error handling for the transport
transport.onclose = () => {
console.error('[MCP] Transport connection closed - continuing with HTTP-only mode');
};
transport.onerror = (error) => {
console.error('[MCP] Transport error:', error, '- continuing with HTTP-only mode');
};
// Add process error handlers to prevent crashes
process.on('uncaughtException', (error) => {
console.error('[MCP] Uncaught exception:', error.message);
// Don't exit, keep the HTTP server running
});
process.on('unhandledRejection', (reason, promise) => {
console.error('[MCP] Unhandled rejection:', reason);
// Don't exit, keep the HTTP server running
});
// Handle SIGPIPE errors (common with stdio)
process.on('SIGPIPE', () => {
console.error('[MCP] SIGPIPE received - continuing with HTTP-only mode');
});
await this.server.connect(transport);
console.error(`${CONFIG.SERVER_NAME} v${CONFIG.SERVER_VERSION} running on stdio`);
} catch (error) {
console.error(`[MCP SERVER] Failed to start stdio transport: ${error.message}`);
console.error('[MCP SERVER] Continuing with HTTP-only mode');
// Don't exit, let the HTTP server continue running
}
}
}
// HTTP Server for Bridge Extension
function createHTTPServer(mcpServer) {
const httpServer = http.createServer(async (req, res) => {
// Enable CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
const parsedUrl = url.parse(req.url, true);
try {
if (req.method === 'GET' && parsedUrl.pathname === '/health') {
// Health check endpoint
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: 'ok',
version: CONFIG.SERVER_VERSION,
timestamp: new Date().toISOString()
}));
} else if (req.method === 'POST' && parsedUrl.pathname === '/mcp') {
// MCP endpoint for bridge extension
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', async () => {
let mcpRequest = null;
try {
// Validate request body
if (!body || body.trim().length === 0) {
throw new Error('Empty request body');
}
if (body.length > 1000000) { // 1MB limit
throw new Error('Request body too large');
}
// Validate JSON format
try {
mcpRequest = JSON.parse(body);
} catch (parseError) {
throw new Error(`Invalid JSON format: ${parseError.message}`);
}
// Validate MCP request structure
if (!mcpRequest || typeof mcpRequest !== 'object') {
throw new Error('Invalid request structure. Expected JSON object.');
}
if (Array.isArray(mcpRequest)) {
throw new Error('Invalid request structure. Arrays not supported.');
}
if (!mcpRequest.method || typeof mcpRequest.method !== 'string') {
throw new Error('Missing or invalid method parameter.');
}
if (mcpRequest.method.length > 100) {
throw new Error('Method name too long.');
}
if (!mcpRequest.params || typeof mcpRequest.params !== 'object') {
throw new Error('Missing or invalid params parameter.');
}
if (Array.isArray(mcpRequest.params)) {
throw new Error('Invalid params structure. Expected object, got array.');
}
// Validate JSON-RPC structure if present
if (mcpRequest.jsonrpc && mcpRequest.jsonrpc !== '2.0') {
throw new Error('Invalid JSON-RPC version. Expected "2.0".');
}
// Process MCP request through the server
let response;
if (mcpRequest.method === 'tools/call') {
// Validate tool call structure
if (!mcpRequest.params.name || typeof mcpRequest.params.name !== 'string') {
throw new Error('Missing or invalid tool name in tools/call request.');
}
if (mcpRequest.params.arguments && typeof mcpRequest.params.arguments !== 'object') {
throw new Error('Invalid arguments parameter. Must be an object if provided.');
}
// Create proper tool call request structure
const toolRequest = {
params: {
name: mcpRequest.params.name,
arguments: mcpRequest.params.arguments || {}
}
};
// Call the tool handler directly
if (mcpRequest.params.name === 'get_ai_prompts') {
response = await mcpServer.handleGetAIPrompts(mcpRequest.params.arguments || {});
} else if (mcpRequest.params.name === 'list_active_loops') {
response = await mcpServer.handleListActiveLoops(mcpRequest.params.arguments || {});
} else if (mcpRequest.params.name === 'acknowledge_agent_response') {
response = await mcpServer.handleAcknowledgeAgentResponse(mcpRequest.params.arguments || {});
} else {
// Try to find and call the appropriate handler
const handlerMap = {
'activate_infinite_loop': 'handleActivateLoop',
'activate_infinite_loop_ultimate-kraken': 'handleActivateLoop',
'stop_loop': 'handleStopLoop',
'stop_loop_ultimate-kraken': 'handleStopLoop',
'stop_all_loops': 'handleStopAllLoops',
'stop_all_loops_ultimate-kraken': 'handleStopAllLoops',
'list_active_loops_ultimate-kraken': 'handleListActiveLoops',
'get_loop_status': 'handleGetLoopStatus',
'get_loop_status_ultimate-kraken': 'handleGetLoopStatus',
'update_loop_interval': 'handleUpdateLoopInterval',
'update_loop_interval_ultimate-kraken': 'handleUpdateLoopInterval',
'clear_agent_busy_state': 'handleClearAgentBusyState',
'clear_agent_busy_state_ultimate-kraken': 'handleClearAgentBusyState',
'get_pending_responses': 'handleGetPendingResponses',
'get_pending_responses_ultimate-kraken': 'handleGetPendingResponses',
'check_agent_status': 'handleCheckAgentStatus',
'check_agent_status_ultimate-kraken': 'handleCheckAgentStatus',
'get_model_status': 'handleGetModelStatus',
'get_model_status_ultimate-kraken': 'handleGetModelStatus',
'reset_failed_models': 'handleResetFailedModels',
'reset_failed_models_ultimate-kraken': 'handleResetFailedModels',
'stop_ai_loops': 'handleStopAILoops',
'stop_ai_loops_ultimate-kraken': 'handleStopAILoops',
'get_api_key_status': 'handleGetAPIKeyStatus',
'get_api_key_status_ultimate-kraken': 'handleGetAPIKeyStatus',
'reset_api_keys': 'handleResetAPIKeys',
'reset_api_keys_ultimate-kraken': 'handleResetAPIKeys',
'reset_session': 'handleResetSession',
'reset_session_ultimate-kraken': 'handleResetSession',
'acknowledge_agent_response_ultimate-kraken': 'handleAcknowledgeAgentResponse',
'get_ai_prompts_ultimate-kraken': 'handleGetAIPrompts'
};
const handlerName = handlerMap[mcpRequest.params.name];
if (!handlerName) {
throw new Error(`Unknown tool: ${mcpRequest.params.name}. Available tools: ${Object.keys(handlerMap).join(', ')}`);
}
if (typeof mcpServer[handlerName] !== 'function') {
throw new Error(`Handler not found for tool: ${mcpRequest.params.name}`);
}
response = await mcpServer[handlerName](mcpRequest.params.arguments || {});
}
} else if (mcpRequest.method === 'tools/list') {
response = await mcpServer.handleListTools();
} els