@andrebuzeli/advanced-memory-markdown-mcp
Version:
Advanced Memory Bank MCP v3.1.5 - Sistema avançado de gerenciamento de memória com isolamento de projetos por IDE, sincronização sob demanda, backup a cada 30min, apenas arquivos .md principais sincronizados, pasta reasoning temporária com limpeza automát
899 lines (857 loc) • 51.6 kB
JavaScript
#!/usr/bin/env node
/**
* Advanced Memory MCP Server v7.0.0 - New Architecture
* Features: plan-manager, memory-manager, task-manager, remember-tool, reasoning
*/
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 { PlanManager } from '../core/plan-manager.js';
import { NewMemoryManager } from '../core/new-memory-manager.js';
import { NewTaskManager } from '../core/new-task-manager.js';
import { RememberTool } from '../core/remember-tool.js';
import { CodingReasoningTool } from '../core/reasoning-tool.js';
import { WebSearchTool } from '../core/websearch-tool.js';
import { SyncManager } from '../core/sync-manager.js';
import { integrateSyncWithMCPTools } from '../core/sync-integration.js';
import { errorHandler, validateProjectName, validateRequiredParams } from '../core/error-handler.js';
import { VERSION } from '../version.js';
import * as path from 'path';
import * as os from 'os';
import * as crypto from 'crypto';
const server = new Server({
name: 'advanced-memory-markdown-mcp',
version: VERSION
}, {
capabilities: {
tools: {}
}
});
// Instantiate new managers
const planManager = new PlanManager();
const memoryManager = new NewMemoryManager();
const taskManager = new NewTaskManager();
const rememberTool = new RememberTool();
const reasoningTool = new CodingReasoningTool();
const webSearchTool = new WebSearchTool();
const syncManager = new SyncManager();
// Global sync integration instances per project
const projectSyncInstances = new Map();
// Default paths for sync system
const getDefaultMemoryBankRoot = () => {
return process.env.MEMORY_BANK_ROOT || path.join(os.homedir(), '.advanced-memory-bank');
};
const getDefaultBackupRoot = () => {
return process.env.MEMORY_BANK_BACKUP_ROOT || process.env.MEMORY_BACKUP_ROOT || path.join(os.homedir(), '.advanced-memory-bank-backups');
};
/**
* Decodifica path URL-encoded se necessário
*/
const decodeProjectPath = (projectPath) => {
try {
let decodedPath = projectPath;
// Remove prefixo /z%3A/ se presente (URL-encoded Z:)
if (decodedPath.startsWith('/z%3A/')) {
decodedPath = decodedPath.replace('/z%3A/', 'Z:\\');
}
// Decodifica caracteres URL-encoded
decodedPath = decodeURIComponent(decodedPath);
// Converte barras para formato Windows se necessário
if (decodedPath.includes('/')) {
decodedPath = decodedPath.replace(/\//g, '\\');
}
return decodedPath;
}
catch (error) {
console.error(`[PathDecoder] Erro ao decodificar path: ${error instanceof Error ? error.message : String(error)}`);
return projectPath; // Retorna original se falhar
}
};
/**
* Gera um identificador único para o projeto baseado no projectPath
* Isso evita conflitos entre múltiplas instâncias de IDEs
* Inclui correção para paths URL-encoded
*/
const generateProjectId = (projectName, projectPath) => {
// Decodifica o path se estiver URL-encoded
const decodedPath = decodeProjectPath(projectPath);
const normalizedPath = path.resolve(decodedPath).toLowerCase();
const hash = crypto.createHash('md5').update(normalizedPath).digest('hex').substring(0, 8);
return `${projectName}-${hash}`;
};
/**
* Inicializa ou obtém instância de sincronização para um projeto
*/
async function ensureProjectSync(projectName, projectPath) {
// Decodifica o path se estiver URL-encoded
const decodedProjectPath = decodeProjectPath(projectPath);
const projectId = generateProjectId(projectName, projectPath);
if (!projectSyncInstances.has(projectId)) {
try {
// console.log(`[SyncIntegration] Inicializando sincronização para projeto: ${projectName}`);
// console.log(`[SyncIntegration] Path original: ${projectPath}`);
// console.log(`[SyncIntegration] Path decodificado: ${decodedProjectPath}`);
const syncIntegration = integrateSyncWithMCPTools(projectName, decodedProjectPath, // Usa o path decodificado
getDefaultMemoryBankRoot(), getDefaultBackupRoot());
await syncIntegration.initialize();
projectSyncInstances.set(projectId, syncIntegration);
// console.log(`[SyncIntegration] Sincronização ativada para: ${projectName}`);
return syncIntegration;
}
catch (error) {
console.error(`[SyncIntegration] Erro ao inicializar sincronização para ${projectName}:`, error);
return null;
}
}
return projectSyncInstances.get(projectId) || null;
}
/**
* Força sincronização para um projeto
*/
async function triggerProjectSync(projectName, projectPath) {
// Decodifica o path se estiver URL-encoded
const decodedProjectPath = decodeProjectPath(projectPath);
const syncInstance = await ensureProjectSync(projectName, projectPath);
if (syncInstance) {
try {
await syncInstance.syncOnDemand();
// console.log(`[SyncIntegration] Sincronização sob demanda para: ${projectName}`);
}
catch (error) {
console.error(`[SyncIntegration] Erro na sincronização sob demanda:`, error);
}
}
}
// --- HANDLER FUNCTIONS ---
async function handlePlanManager(args) {
const { action, projectName, projectPath, planId, name, description, priority, tags, updates, plans, planIds } = args;
// Validate required parameters
validateRequiredParams(args, ['action', 'projectName', 'projectPath'], 'plan-manager');
validateProjectName(projectName, 'plan-manager');
// Debug: Log project path
// console.debug(`[plan-manager] Project path: ${projectPath}`);
// Ensure sync is initialized for this project
await ensureProjectSync(projectName, projectPath);
try {
switch (action) {
case 'create':
const plan = await planManager.create(projectName, name, description, priority, tags);
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Plano '${plan.name}' criado com ID: ${plan.id}` }] };
case 'read':
const readPlan = await planManager.read(projectName, planId);
if (!readPlan) {
return { content: [{ type: 'text', text: `Plano '${planId}' não encontrado.` }], isError: true };
}
return { content: [{ type: 'text', text: `**${readPlan.name}**\n\n${readPlan.description}\n\n**Status:** ${readPlan.status}\n**Prioridade:** ${readPlan.priority}\n**Tags:** ${readPlan.tags.join(', ')}\n**Criado:** ${new Date(readPlan.created).toLocaleString()}` }] };
case 'update':
const updatedPlan = await planManager.update(projectName, planId, updates);
if (!updatedPlan) {
return { content: [{ type: 'text', text: `Plano '${planId}' não encontrado.` }], isError: true };
}
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Plano '${updatedPlan.name}' atualizado.` }] };
case 'delete':
const deleted = await planManager.delete(projectName, planId);
if (!deleted) {
return { content: [{ type: 'text', text: `Plano '${planId}' não encontrado.` }], isError: true };
}
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Plano '${planId}' removido.` }] };
case 'list':
const plansList = await planManager.list(projectName);
const plansText = plansList.map(p => `- **${p.name}** (${p.id}) - ${p.status} - Prioridade: ${p.priority}`).join('\n');
return { content: [{ type: 'text', text: `**Planos do projeto '${projectName}':**\n\n${plansText || 'Nenhum plano encontrado.'}` }] };
// ========== OPERAÇÕES MÚLTIPLAS v2.0 ==========
case 'create-multiple':
const createdPlans = await planManager.createMultiple(projectName, plans);
return { content: [{ type: 'text', text: `${createdPlans.length} planos criados: ${createdPlans.map(p => `${p.name} (${p.id})`).join(', ')}` }] };
case 'read-multiple':
const readPlans = await planManager.readMultiple(projectName, planIds);
const readResults = readPlans.map((plan, i) => plan ? `**${plan.name}** (${plan.id}): ${plan.status}` : `${planIds[i]}: Não encontrado`).join('\n');
return { content: [{ type: 'text', text: `**Múltiplos planos:**\n\n${readResults}` }] };
case 'update-multiple':
const updatedPlans = await planManager.updateMultiple(projectName, updates);
const updateCount = updatedPlans.filter(p => p !== null).length;
return { content: [{ type: 'text', text: `${updateCount} de ${updatedPlans.length} planos atualizados com sucesso.` }] };
case 'delete-multiple':
const deleteResults = await planManager.deleteMultiple(projectName, planIds);
const deleteCount = deleteResults.filter(r => r).length;
return { content: [{ type: 'text', text: `${deleteCount} de ${deleteResults.length} planos removidos com sucesso.` }] };
default:
throw new Error(`Ação desconhecida para plan-manager: ${action}`);
}
}
catch (error) {
throw errorHandler.handleError(error, {
operation: 'plan-manager',
projectName,
timestamp: Date.now()
});
}
}
async function handleMemoryManager(args) {
const { action, projectName, projectPath, topicName, description, content, importance, tags, updates, topics, topicNames } = args;
// Validate required parameters
validateRequiredParams(args, ['action', 'projectName', 'projectPath'], 'memory-manager');
validateProjectName(projectName, 'memory-manager');
// Debug: Log project path
// console.debug(`[memory-manager] Project path: ${projectPath}`);
// Ensure sync is initialized for this project
await ensureProjectSync(projectName, projectPath);
try {
switch (action) {
case 'create':
const topic = await memoryManager.create(projectName, topicName, description, content, importance, tags);
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Tópico '${topicName}' criado na memória.` }] };
case 'read':
const readTopic = await memoryManager.read(projectName, topicName);
if (!readTopic) {
return { content: [{ type: 'text', text: `Tópico '${topicName}' não encontrado.` }], isError: true };
}
return { content: [{ type: 'text', text: `**${readTopic.name}** - ${readTopic.description}\n\n${readTopic.content}\n\n**Importância:** ${readTopic.importance}/10\n**Tags:** ${readTopic.tags.join(', ')}\n**Modificado:** ${new Date(readTopic.modified).toLocaleString()}` }] };
case 'update':
const updatedTopic = await memoryManager.update(projectName, topicName, updates);
if (!updatedTopic) {
return { content: [{ type: 'text', text: `Tópico '${topicName}' não encontrado.` }], isError: true };
}
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Tópico '${topicName}' atualizado.` }] };
case 'delete':
const deletedTopic = await memoryManager.delete(projectName, topicName);
if (!deletedTopic) {
return { content: [{ type: 'text', text: `Tópico '${topicName}' não encontrado.` }], isError: true };
}
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Tópico '${topicName}' removido.` }] };
case 'list':
const topicsList = await memoryManager.list(projectName);
const topicsText = topicsList.map(t => `- **${t.name}** (${t.importance}/10) - ${t.description}`).join('\n');
return { content: [{ type: 'text', text: `**Tópicos de memória do projeto '${projectName}':**\n\n${topicsText || 'Nenhum tópico encontrado.'}` }] };
// ========== OPERAÇÕES MÚLTIPLAS v2.0 ==========
case 'create-multiple':
const createdTopics = await memoryManager.createMultiple(projectName, topics);
return { content: [{ type: 'text', text: `${createdTopics.length} tópicos criados: ${createdTopics.map(t => t.name).join(', ')}` }] };
case 'read-multiple':
const readTopics = await memoryManager.readMultiple(projectName, topicNames);
const readResults = readTopics.map((topic, i) => topic ? `**${topic.name}**: ${topic.description}` : `${topicNames[i]}: Não encontrado`).join('\n');
return { content: [{ type: 'text', text: `**Múltiplos tópicos:**\n\n${readResults}` }] };
case 'update-multiple':
const updatedTopics = await memoryManager.updateMultiple(projectName, updates);
const updateCount = updatedTopics.filter(t => t !== null).length;
return { content: [{ type: 'text', text: `${updateCount} de ${updatedTopics.length} tópicos atualizados com sucesso.` }] };
case 'delete-multiple':
const deleteResults = await memoryManager.deleteMultiple(projectName, topicNames);
const deleteCount = deleteResults.filter(r => r).length;
return { content: [{ type: 'text', text: `${deleteCount} de ${deleteResults.length} tópicos removidos com sucesso.` }] };
default:
throw new Error(`Ação desconhecida para memory-manager: ${action}`);
}
}
catch (error) {
throw errorHandler.handleError(error, {
operation: 'memory-manager',
projectName,
resourceId: topicName,
timestamp: Date.now()
});
}
}
async function handleTaskManager(args) {
const { action, projectName, projectPath, taskId, title, description, level, parentId, priority, tags, status, errorReason, tasks, taskIds, updates } = args;
// Validate required parameters
validateRequiredParams(args, ['action', 'projectName', 'projectPath'], 'task-manager');
validateProjectName(projectName, 'task-manager');
// Debug: Log project path
// console.debug(`[task-manager] Project path: ${projectPath}`);
// Ensure sync is initialized for this project
await ensureProjectSync(projectName, projectPath);
try {
switch (action) {
case 'create':
const task = await taskManager.create(projectName, title, description, level, parentId, priority, tags);
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Tarefa '${task.title}' criada com ID: ${task.id}` }] };
case 'read':
const readTask = await taskManager.read(projectName, taskId);
if (!readTask) {
return { content: [{ type: 'text', text: `Tarefa '${taskId}' não encontrada.` }], isError: true };
}
return { content: [{ type: 'text', text: `**${readTask.title}** (${readTask.id})\n\n${readTask.description}\n\n**Status:** ${readTask.status}\n**Nível:** ${readTask.level}\n**Prioridade:** ${readTask.priority}\n**Sub-tarefas:** ${readTask.subtasks.length}` }] };
case 'status':
const statusTask = await taskManager.status(projectName, taskId, status, errorReason);
if (!statusTask) {
return { content: [{ type: 'text', text: `Tarefa '${taskId}' não encontrada.` }], isError: true };
}
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
const statusMessage = statusTask.errorReason && (status === 'retry' || status === 'error')
? `Status da tarefa '${statusTask.title}' atualizado para: ${statusTask.status} - Motivo: ${statusTask.errorReason}`
: `Status da tarefa '${statusTask.title}' atualizado para: ${statusTask.status}`;
return { content: [{ type: 'text', text: statusMessage }] };
case 'update':
const updatedTask = await taskManager.update(projectName, taskId, { title, description, priority, tags });
if (!updatedTask) {
return { content: [{ type: 'text', text: `Tarefa '${taskId}' não encontrada.` }], isError: true };
}
return { content: [{ type: 'text', text: `Tarefa '${updatedTask.title || taskId}' atualizada.` }] };
case 'delete':
const deletedTask = await taskManager.delete(projectName, taskId);
if (!deletedTask) {
return { content: [{ type: 'text', text: `Tarefa '${taskId}' não encontrada.` }], isError: true };
}
// Trigger sync after write operation
await triggerProjectSync(projectName, projectPath);
return { content: [{ type: 'text', text: `Tarefa '${deletedTask.title || taskId}' removida.` }] };
case 'list':
const tasksList = await taskManager.list(projectName);
const tasksText = tasksList.map(t => `- [${t.status === 'complete' ? 'x' : ' '}] ${t.title} (${t.id}) - Nível ${t.level}`).join('\n');
return { content: [{ type: 'text', text: `**Tarefas do projeto '${projectName}':**\n\n${tasksText || 'Nenhuma tarefa encontrada.'}` }] };
// ========== OPERAÇÕES MÚLTIPLAS v2.0 ==========
// NOTA: Status permanece individual para controle preciso
case 'create-multiple':
const createdTasks = await taskManager.createMultiple(projectName, tasks);
return { content: [{ type: 'text', text: `${createdTasks.length} tarefas criadas: ${createdTasks.map(t => `${t.title} (${t.id})`).join(', ')}` }] };
case 'read-multiple':
const readTasks = await taskManager.readMultiple(projectName, taskIds);
const readResults = readTasks.map((task, i) => task ? `**${task.title}** (${task.id}): ${task.status}` : `${taskIds[i]}: Não encontrada`).join('\n');
return { content: [{ type: 'text', text: `**Múltiplas tarefas:**\n\n${readResults}` }] };
case 'update-multiple':
const updatedTasks = await taskManager.updateMultiple(projectName, updates);
const updateCount = updatedTasks.filter(t => t !== null).length;
return { content: [{ type: 'text', text: `${updateCount} de ${updatedTasks.length} tarefas atualizadas com sucesso.` }] };
default:
throw new Error(`Ação desconhecida para task-manager: ${action}`);
}
}
catch (error) {
throw errorHandler.handleError(error, {
operation: 'task-manager',
projectName,
resourceId: taskId,
timestamp: Date.now()
});
}
}
async function handleRememberTool(args) {
const { action, projectName, fileName, itemName, query, fileType, caseSensitive, wholeWord, maxResults } = args;
switch (action) {
case 'list':
const listResult = await rememberTool.list(projectName, fileType);
let listText = `**Projetos disponíveis:** ${listResult.projects.join(', ')}\n\n`;
for (const project of listResult.content) {
listText += `**${project.projectName}:**\n`;
if (project.memories.length > 0)
listText += ` Memórias: ${project.memories.join(', ')}\n`;
if (project.tasks.length > 0)
listText += ` Tarefas: ${project.tasks.join(', ')}\n`;
if (project.plans.length > 0)
listText += ` Planos: ${project.plans.join(', ')}\n`;
listText += '\n';
}
return { content: [{ type: 'text', text: listText }] };
case 'read':
const readResult = await rememberTool.read(projectName, fileName, itemName);
if (!readResult) {
return { content: [{ type: 'text', text: `Conteúdo não encontrado.` }], isError: true };
}
return { content: [{ type: 'text', text: readResult }] };
case 'search':
const searchResults = await rememberTool.search({
query,
projectName,
fileType,
caseSensitive,
wholeWord,
maxResults
});
if (searchResults.length === 0) {
return { content: [{ type: 'text', text: `Nenhum resultado encontrado para '${query}'.` }] };
}
let searchText = `**Resultados da busca por '${query}':**\n\n`;
for (const result of searchResults) {
searchText += `**${result.projectName}/${result.fileName}** (Score: ${result.score})\n`;
for (const match of result.matches.slice(0, 3)) { // Show max 3 matches per file
searchText += ` Linha ${match.line}: ${match.content}\n`;
}
searchText += '\n';
}
return { content: [{ type: 'text', text: searchText }] };
default:
throw new Error(`Ação desconhecida para remember-tool: ${action}`);
}
}
// handleListProjects removido - projectName e projectPath agora são obrigatórios
async function handleWebSearch(args) {
const { query, maxResults, includeContent, searchType } = args;
// Validate required parameters
if (!query || typeof query !== 'string') {
throw new Error('Query é obrigatória e deve ser uma string');
}
try {
console.log(`[websearch] Iniciando pesquisa: "${query}"`);
const searchOptions = {
maxResults: maxResults || 10,
includeContent: includeContent || false,
searchType: searchType || 'web'
};
const results = await webSearchTool.search(query, searchOptions);
return {
content: [{
type: 'text',
text: `**Pesquisa Web: "${query}"**\n\n**Fonte:** ${results.source}\n**Tempo:** ${results.searchTime}ms\n**Total:** ${results.totalResults} resultados\n\n${results.results.map((result, index) => `${index + 1}. **${result.title}**\n ${result.url}\n ${result.description}\n`).join('\n')}`
}]
};
}
catch (error) {
throw errorHandler.handleError(error, {
operation: 'websearch',
timestamp: Date.now()
});
}
}
async function handleReasoning(args) {
const { action, projectName, projectPath, code, language, context, problem, errorMessage, requirements, constraints, goals, standards } = args;
// Validate required parameters
validateRequiredParams(args, ['action', 'projectName', 'projectPath'], 'reasoning');
validateProjectName(projectName, 'reasoning');
// Debug: Log project path
// console.debug(`[reasoning] Project path: ${projectPath}`);
// Ensure sync is initialized for this project
await ensureProjectSync(projectName, projectPath);
let result;
switch (action) {
case 'analyze-code':
const analysisResult = await reasoningTool.executeAction('analyze-code', { code, language, context, problem }, projectName);
let analysisText = `**Análise de Código Completa:**\n\n`;
analysisText += `**Problema:** ${analysisResult.problem}\n`;
analysisText += `**Linguagem:** ${analysisResult.language}\n`;
analysisText += `**Confiança:** ${analysisResult.confidence}/10\n\n`;
analysisText += `**Processo de Raciocínio:**\n`;
for (const step of analysisResult.steps) {
analysisText += `${step.stepNumber}. **${step.type.toUpperCase()}**: ${step.content}\n`;
if (step.reasoning)
analysisText += ` *Raciocínio:* ${step.reasoning}\n`;
}
if (analysisResult.finalSolution) {
analysisText += `\n**Solução Principal:**\n${analysisResult.finalSolution}\n`;
}
if (analysisResult.alternativeSolutions.length > 0) {
analysisText += `\n**Soluções Alternativas:**\n${analysisResult.alternativeSolutions.map((sol, i) => `${i + 1}. ${sol}`).join('\n')}\n`;
}
if (analysisResult.testCases.length > 0) {
analysisText += `\n**Casos de Teste Sugeridos:**\n${analysisResult.testCases.map((tc) => `- ${tc}`).join('\n')}\n`;
}
if (analysisResult.performanceNotes.length > 0) {
analysisText += `\n**Notas de Performance:**\n${analysisResult.performanceNotes.map((note) => `- ${note}`).join('\n')}\n`;
}
if (analysisResult.securityConsiderations.length > 0) {
analysisText += `\n**Considerações de Segurança:**\n${analysisResult.securityConsiderations.map((sec) => `- ${sec}`).join('\n')}\n`;
}
result = { content: [{ type: 'text', text: analysisText }] };
break;
case 'debug-step-by-step':
const debugResult = await reasoningTool.executeAction('debug-step-by-step', { code, errorMessage, language, context }, projectName);
let debugText = `**Debug Passo-a-Passo:**\n\n`;
debugText += `**Erro:** ${debugResult.errorMessage}\n`;
debugText += `**Linguagem:** ${debugResult.language}\n\n`;
debugText += `**Processo de Debug:**\n`;
for (const step of debugResult.steps) {
debugText += `${step.stepNumber}. **${step.action.toUpperCase()}**: ${step.description}\n`;
debugText += ` *Descobertas:* ${step.findings}\n`;
if (step.nextAction)
debugText += ` *Próxima ação:* ${step.nextAction}\n`;
debugText += ` *Confiança:* ${step.confidence}/10\n\n`;
}
if (debugResult.hypothesis.length > 0) {
debugText += `**Hipóteses:**\n${debugResult.hypothesis.map((h, i) => `${i + 1}. ${h}`).join('\n')}\n\n`;
}
if (debugResult.solution) {
debugText += `**Solução Proposta:**\n${debugResult.solution}\n`;
}
result = { content: [{ type: 'text', text: debugText }] };
break;
case 'architecture-reasoning':
const archResult = await reasoningTool.executeAction('architecture-reasoning', { context, requirements, constraints }, projectName);
let archText = `**Raciocínio Arquitetural:**\n\n`;
archText += `**Contexto:** ${archResult.context}\n\n`;
if (archResult.requirements.length > 0) {
archText += `**Requisitos:**\n${archResult.requirements.map((req) => `- ${req}`).join('\n')}\n\n`;
}
if (archResult.constraints.length > 0) {
archText += `**Restrições:**\n${archResult.constraints.map((cons) => `- ${cons}`).join('\n')}\n\n`;
}
archText += `**Opções de Design:**\n`;
for (const option of archResult.designOptions) {
archText += `### ${option.name}\n`;
archText += `${option.description}\n`;
archText += `**Prós:** ${option.pros.join(', ')}\n`;
archText += `**Contras:** ${option.cons.join(', ')}\n`;
archText += `**Complexidade:** ${option.complexity}/10, **Manutenibilidade:** ${option.maintainability}/10\n`;
archText += `**Performance:** ${option.performance}/10, **Escalabilidade:** ${option.scalability}/10\n\n`;
}
archText += `**Recomendação:**\n${archResult.recommendation}\n\n`;
if (archResult.tradeoffs.length > 0) {
archText += `**Trade-offs:**\n${archResult.tradeoffs.map((to) => `- ${to}`).join('\n')}\n`;
}
result = { content: [{ type: 'text', text: archText }] };
break;
case 'performance-analysis':
const perfResult = await reasoningTool.executeAction('performance-analysis', { code, language, context }, projectName);
result = { content: [{ type: 'text', text: `**Análise de Performance:**\n\nAnálise focada em otimização de performance concluída.\n\n**Confiança:** ${perfResult.confidence}/10\n\n**Notas de Performance:**\n${perfResult.performanceNotes.map((note) => `- ${note}`).join('\n')}` }] };
break;
case 'refactor-planning':
const refactorResult = await reasoningTool.executeAction('refactor-planning', { code, language, goals, constraints }, projectName);
result = { content: [{ type: 'text', text: `**Planejamento de Refatoração:**\n\nPlanejamento de refatoração concluído.\n\n**Confiança:** ${refactorResult.confidence}/10\n\n**Solução Principal:**\n${refactorResult.finalSolution}` }] };
break;
case 'test-strategy':
const testResult = await reasoningTool.executeAction('test-strategy', { code, language, requirements }, projectName);
result = { content: [{ type: 'text', text: `**Estratégia de Testes:**\n\nEstratégia de testes desenvolvida.\n\n**Casos de Teste:**\n${testResult.testCases.map((tc) => `- ${tc}`).join('\n')}` }] };
break;
case 'error-investigation':
const errorResult = await reasoningTool.executeAction('error-investigation', { errorMessage, code, language, context }, projectName);
result = { content: [{ type: 'text', text: `**Investigação de Erro:**\n\nInvestigação concluída.\n\n**Solução:** ${errorResult.solution}` }] };
break;
case 'code-review':
const reviewResult = await reasoningTool.executeAction('code-review', { code, language, standards, context }, projectName);
result = { content: [{ type: 'text', text: `**Revisão de Código:**\n\nRevisão concluída.\n\n**Confiança:** ${reviewResult.confidence}/10\n\n**Considerações de Segurança:**\n${reviewResult.securityConsiderations.map((sec) => `- ${sec}`).join('\n')}` }] };
break;
case 'cleanup':
await reasoningTool.executeAction('cleanup', {}, projectName);
result = { content: [{ type: 'text', text: 'Arquivos de reasoning temporários removidos.' }] };
break;
case 'status':
const status = await reasoningTool.executeAction('status', {}, projectName);
const statusText = status.active ? `**Sessão ativa:** ${status.session}\n**Arquivo:** ${status.file}` : 'Nenhuma sessão de reasoning ativa.';
result = { content: [{ type: 'text', text: statusText }] };
break;
default:
throw new Error(`Ação desconhecida para reasoning: ${action}`);
}
// Auto-cleanup após qualquer operação de reasoning (exceto cleanup e status)
if (action !== 'cleanup' && action !== 'status') {
try {
await reasoningTool.executeAction('cleanup', {}, projectName);
}
catch (error) {
// Ignora erros de limpeza para não afetar a operação principal
console.error('[reasoning] Erro na limpeza automática:', error);
}
}
return result;
}
// --- TOOL DEFINITIONS ---
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'plan-manager',
description: `GERENCIAMENTO DE PLANEJAMENTOS
Ferramenta para criar e gerenciar planos de projeto em arquivos planning.md organizados por pastas de projeto.
IMPORTANTE - NOME DO PROJETO:
• O projectName DEVE ser exatamente o nome da pasta RAIZ do projeto aberto no IDE
• NÃO é uma subpasta, NÃO é um subprojeto - é a pasta raiz que foi aberta no IDE
• O nome deve ser uma cópia EXATA sem adicionar ou remover nada
AÇÕES DISPONÍVEIS:
• create - Criar novo plano com nome, descrição, prioridade e tags
• read - Ler detalhes completos de um plano específico
• update - Atualizar informações de plano existente
• delete - Remover plano completamente
• list - Listar todos os planos do projeto com resumo
🎯 COMO USAR:
1. Use 'create' para definir novos objetivos e planos
2. Use 'read' para revisar detalhes de planos específicos
3. Use 'update' para modificar status, prioridade ou descrição
4. Use 'list' para visão geral de todos os planos
💡 EXEMPLOS PRÁTICOS:
• Novo plano: {"action":"create","projectName":"meu-app","name":"Implementar autenticação","description":"Sistema completo de login e registro","priority":8,"tags":["backend","segurança"]}
• Ler plano: {"action":"read","projectName":"meu-app","planId":"PLAN-123"}
• Atualizar: {"action":"update","projectName":"meu-app","planId":"PLAN-123","updates":{"status":"in-progress"}}
• Listar: {"action":"list","projectName":"meu-app"}
⚡ TIPS:
- Use prioridade 1-10 para organizar importância
- Tags ajudam a categorizar planos por área
- Status: pending, in-progress, completed, cancelled`,
inputSchema: {
type: 'object',
properties: {
action: { type: 'string', enum: ['create', 'read', 'update', 'delete', 'list'] },
projectName: { type: 'string' },
projectPath: { type: 'string', description: 'Caminho completo do projeto (opcional para teste)' },
planId: { type: 'string' },
name: { type: 'string' },
description: { type: 'string' },
priority: { type: 'number' },
tags: { type: 'array', items: { type: 'string' } },
updates: { type: 'object' }
},
required: ['action', 'projectName', 'projectPath']
}
},
{
name: 'memory-manager',
description: `🧠 GERENCIAMENTO DE MEMÓRIAS POR TÓPICOS
Ferramenta para organizar conhecimento e informações em tópicos estruturados dentro de arquivos memory.md por projeto.
IMPORTANTE - NOME DO PROJETO:
• O projectName DEVE ser exatamente o nome da pasta RAIZ do projeto aberto no IDE
• NÃO é uma subpasta, NÃO é um subprojeto - é a pasta raiz que foi aberta no IDE
• O nome deve ser uma cópia EXATA sem adicionar ou remover nada
📋 AÇÕES DISPONÍVEIS:
• create - Criar novo tópico de memória com conteúdo organizado
• read - Ler conteúdo completo de um tópico específico
• update - Atualizar conteúdo, importância ou tags de tópico
• delete - Remover tópico e todo seu conteúdo
• list - Listar todos os tópicos com resumo e importância
🎯 COMO USAR:
1. Use 'create' para armazenar conhecimento em tópicos organizados
2. Use 'read' para recuperar informações de tópicos específicos
3. Use 'update' para manter informações atualizadas
4. Use 'list' para visão geral de todo conhecimento armazenado
💡 EXEMPLOS PRÁTICOS:
• Nova memória: {"action":"create","projectName":"meu-app","topicName":"Arquitetura","description":"Decisões arquiteturais","content":"Usando React + Node.js + PostgreSQL","importance":9,"tags":["backend","frontend"]}
• Ler tópico: {"action":"read","projectName":"meu-app","topicName":"Arquitetura"}
• Atualizar: {"action":"update","projectName":"meu-app","topicName":"Bugs","updates":{"content":"Bug do login corrigido"}}
• Listar: {"action":"list","projectName":"meu-app"}
⚡ TIPS:
- Use importância 1-10 para priorizar informações
- Tópicos comuns: Arquitetura, Bugs, Features, TODO, Documentação
- Tags facilitam organização e busca posterior`,
inputSchema: {
type: 'object',
properties: {
action: { type: 'string', enum: ['create', 'read', 'update', 'delete', 'list'] },
projectName: { type: 'string' },
projectPath: { type: 'string', description: 'Caminho completo do projeto (opcional para teste)' },
topicName: { type: 'string' },
description: { type: 'string' },
content: { type: 'string' },
importance: { type: 'number' },
tags: { type: 'array', items: { type: 'string' } },
updates: { type: 'object' }
},
required: ['action', 'projectName', 'projectPath']
}
},
{
name: 'task-manager',
description: `GERENCIAMENTO DE TAREFAS COM HIERARQUIA
Ferramenta para gerenciar tarefas em até 3 níveis hierárquicos com status visuais em arquivos task.md por projeto.
IMPORTANTE - NOME DO PROJETO:
• O projectName DEVE ser exatamente o nome da pasta RAIZ do projeto aberto no IDE
• NÃO é uma subpasta, NÃO é um subprojeto - é a pasta raiz que foi aberta no IDE
• O nome deve ser uma cópia EXATA sem adicionar ou remover nada
📋 AÇÕES DISPONÍVEIS:
• create - Criar nova tarefa (nível 1, 2 ou 3) com título, descrição e prioridade
• read - Ler detalhes completos de tarefa específica incluindo sub-tarefas
• status - Atualizar status com emojis visuais e descrição de erro se necessário
• update - Atualizar título, descrição, prioridade ou tags
• list - Listar todas as tarefas com hierarquia visual
🎯 STATUS COM EMOJIS:
[TODO] not-started - Tarefa não iniciada
[DOING] in-progress - Em andamento
[DONE] complete - Concluída
[RETRY] retry - Tentar novamente (com motivo do erro)
[ERROR] error - Erro/falha (com descrição do problema)
🏗️ HIERARQUIA (3 NÍVEIS):
• Nível 1: Tarefa principal
• Nível 2: Sub-tarefa
• Nível 3: Sub-sub-tarefa
💡 EXEMPLOS PRÁTICOS:
• Nova tarefa: {"action":"create","projectName":"meu-app","title":"Implementar login","description":"Sistema de autenticação","level":1,"priority":8,"tags":["backend"]}
• Sub-tarefa: {"action":"create","projectName":"meu-app","title":"Validar email","level":2,"parentId":"T-123","priority":6}
• Atualizar status: {"action":"status","projectName":"meu-app","taskId":"T-123","status":"error","errorReason":"API de email indisponível"}
• Listar: {"action":"list","projectName":"meu-app"}
⚡ TIPS:
- Use hierarquia para quebrar tarefas grandes
- Sempre inclua errorReason quando status for retry/error
- Prioridade 1-10 para organizar importância`,
inputSchema: {
type: 'object',
properties: {
action: { type: 'string', enum: ['create', 'read', 'status', 'update', 'list'] },
projectName: { type: 'string' },
projectPath: { type: 'string', description: 'Caminho completo do projeto (opcional para teste)' },
taskId: { type: 'string' },
title: { type: 'string' },
description: { type: 'string' },
level: { type: 'number', enum: [1, 2, 3] },
parentId: { type: 'string' },
priority: { type: 'number' },
tags: { type: 'array', items: { type: 'string' } },
status: { type: 'string', enum: ['not-started', 'in-progress', 'complete', 'retry', 'error'] },
errorReason: { type: 'string', description: 'Descrição breve do erro/falha quando status é retry ou error' }
},
required: ['action', 'projectName', 'projectPath']
}
},
{
name: 'remember-tool',
description: `🔍 FERRAMENTA DE BUSCA E RECUPERAÇÃO
Ferramenta inteligente para pesquisar e listar conteúdo em todos os arquivos .md dos projetos (memory.md, task.md, planning.md).
IMPORTANTE - NOME DO PROJETO:
• O projectName DEVE ser exatamente o nome da pasta RAIZ do projeto aberto no IDE
• NÃO é uma subpasta, NÃO é um subprojeto - é a pasta raiz que foi aberta no IDE
• O nome deve ser uma cópia EXATA sem adicionar ou remover nada
📋 AÇÕES DISPONÍVEIS:
• list - Listar projetos disponíveis e seus conteúdos organizados
• read - Ler arquivo específico ou item individual
• search - Busca semântica avançada com múltiplas opções
🎯 CAPACIDADES DE BUSCA:
• Busca simultânea em memory.md, task.md e planning.md
• Opções de case-sensitive para busca exata
• Busca por palavra completa ou parcial
• Limite configurável de resultados
• Score de relevância para cada resultado
📁 TIPOS DE ARQUIVO:
• memory - Buscar apenas em memórias/tópicos
• task - Buscar apenas em tarefas
• planning - Buscar apenas em planejamentos
• all - Buscar em todos os arquivos (padrão)
💡 EXEMPLOS PRÁTICOS:
• Listar tudo: {"action":"list","fileType":"all"}
• Listar projeto: {"action":"list","projectName":"meu-app","fileType":"memory"}
• Ler arquivo: {"action":"read","projectName":"meu-app","fileName":"memory","itemName":"Arquitetura"}
• Busca simples: {"action":"search","query":"autenticação","projectName":"meu-app"}
• Busca avançada: {"action":"search","query":"login","fileType":"task","caseSensitive":true,"wholeWord":true,"maxResults":5}
⚡ TIPS:
- Use 'list' para explorar conteúdo disponível
- Use 'search' para encontrar informações específicas
- Combine filtros para busca mais precisa`,
inputSchema: {
type: 'object',
properties: {
action: { type: 'string', enum: ['list', 'read', 'search'] },
projectName: { type: 'string' },
fileName: { type: 'string', enum: ['memory', 'task', 'planning'] },
itemName: { type: 'string' },
query: { type: 'string' },
fileType: { type: 'string', enum: ['memory', 'task', 'planning', 'all'] },
caseSensitive: { type: 'boolean' },
wholeWord: { type: 'boolean' },
maxResults: { type: 'number' }
},
required: ['action']
}
},
// list_projects removido - projectName e projectPath agora são obrigatórios
{
name: 'websearch',
description: 'Ferramenta de pesquisa web integrada com AI Agent nativo do IDE (Cursor/VSCode)',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Termo de pesquisa (obrigatório)' },
maxResults: { type: 'number', description: 'Número máximo de resultados (padrão: 10)' },
includeContent: { type: 'boolean', description: 'Incluir conteúdo das páginas (padrão: false)' },
searchType: { type: 'string', enum: ['web', 'news', 'images', 'videos'], description: 'Tipo de pesquisa (padrão: web)' }
},
required: ['query']
}
},
{
name: 'reasoning',
description: `ADVANCED CODING REASONING TOOL v2.0
Ferramenta de IA especializada em raciocínio para problemas de programação, debugging e desenvolvimento de software.
Baseada em Chain-of-Thought prompting e práticas de debugging interativo, focada especificamente em coding.
ACTIONS DISPONÍVEIS:
**ANÁLISE DE CÓDIGO:**
• analyze-code - Análise completa de código com raciocínio passo-a-passo
• code-review - Revisão de código com padrões e boas práticas
• performance-analysis - Análise focada em otimização de performance
**DEBUGGING INTERATIVO:**
• debug-step-by-step - Debug interativo com investigação estruturada
• error-investigation - Investigação detalhada de erros com hipóteses
**ARQUITETURA E DESIGN:**
• architecture-reasoning - Raciocínio arquitetural com opções de design
• refactor-planning - Planejamento de refatoração com objetivos
**ESTRATÉGIA DE DESENVOLVIMENTO:**
• test-strategy - Desenvolvimento de estratégia de testes
**UTILITÁRIOS:**
• cleanup - Remover arquivos temporários de reasoning
• status - Verificar sessão ativa e progresso atual
EXEMPLOS PRÁTICOS:
**Análise de Código:**
{"action":"analyze-code","code":"function login(user) {...}","language":"javascript","problem":"Otimizar performance"}
**Debug Passo-a-Passo:**
{"action":"debug-step-by-step","code":"const user = null; user.name","errorMessage":"TypeError: Cannot read property 'name' of null","language":"javascript"}
**Raciocínio Arquitetural:**
{"action":"architecture-reasoning","context":"E-commerce API","requirements":["scalability","performance"],"constraints":["small team"]}
**Revisão de Código:**
{"action":"code-review","code":"function process(data) {...}","language":"python","standards":["PEP8","security"]}
**Análise de Performance:**
{"action":"performance-analysis","code":"for(let i=0; i<arr.length; i++) {...}","language":"javascript"}
CARACTERÍSTICAS v2.0:
- Chain-of-Thought prompting para raciocínio estruturado
- Debugging interativo com hipóteses e verificação
- Análise arquitetural com trade-offs
- Foco específico em problemas de coding
- Sugestões de testes e casos de uso
- Considerações de segurança automáticas
- Notas de performance contextuais
TIPS:
- Use analyze-code para análise geral de qualidade
- Use debug-step-by-step para erros complexos
- Use architecture-reasoning para decisões de design
- Use performance-analysis para otimizações
- Sempre inclua language e context para melhores resultados`,
inputSchema: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['analyze-code', 'debug-step-by-step', 'architecture-reasoning', 'performance-analysis', 'refactor-planning', 'test-strategy', 'error-investigation', 'code-review', 'cleanup', 'status']
},
projectName: { type: 'string', description: 'Nome do projeto (obrigatório)' },
projectPath: { type: 'string', description: 'Caminho completo do projeto (opcional para teste)' },
code: { type: 'string', description: 'Código a ser analisado' },
language: { type: 'string', description: 'Linguagem de programação (javascript, python, java, etc.)' },
context: { type: 'string', description: 'Contexto adicional sobre o código ou problema' },
problem: { type: 'string', description: 'Descrição específica do problema a ser resolvido' },
errorMessage: { type: 'string', description: 'Mensagem de erro para debugging' },
requirements: { type: 'array', items: { type: 'string' }, description: 'Lista de requisitos para arquitetura' },
constraints: { type: 'array', items: { type: 'string' }, description: 'Lista de restrições ou limitações' },
goals: { type: 'array', items: { type: 'string' }, description: 'Objetivos para refatoração' },
standards: { type: 'array', items: { type: 'string' }, description: 'Padrões de código para revisão' }
},
required: ['action', 'projectName', 'projectPath']
}
}
]
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
// Validate basic parameters
if (!args || typeof args !== 'object') {
throw errorHandler.handleError(new Error('Argumentos inválidos ou ausentes'), { operation: name, timestamp: Date.now() });
}
// Validate tool name
const validTools = ['plan-manager', 'memory-manager', 'task-manager', 'remember-tool', 'list_projects', 'reasoning', 'websearch'];
if (!validTools.includes(name)) {
throw errorHandler.handleError(new Error(`Ferramenta desconhecida: ${name}`), { operation: name, timestamp: Date.now() });
}
// Route to appropriate handler with error context
switch (name) {
case 'plan-manager':
return await handlePlanManager(args);
case 'memory-manager':
return await handleMemoryManager(args);
case 'task-manager':
return await handleTaskManager(args);
case 'remember-tool':
return await handleRememberTool(args);
case 'websearch':
return await handleWebSearch(args);
case 'reasoning':
return await handleReasoning(args);
default:
throw new Error(`Ferramenta não i