@lucasdoreac/mcp-continuity-server
Version:
Um servidor MCP para gerenciamento de continuidade e estado em projetos
249 lines (233 loc) • 8.58 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { StateManager } from '../services/stateManager.js';
import { AutoSetup } from '../services/autoSetup.js';
import { RepositoryTools } from '../services/repositoryTools.js';
export class MCPServer {
constructor() {
// Inicializa o servidor MCP
this.server = new Server(
{
name: 'MCP Continuity Server',
version: '1.0.9',
},
{
capabilities: {
tools: {},
},
}
);
// Inicializa os serviços
this.stateManager = new StateManager();
this.autoSetup = new AutoSetup();
this.repoTools = new RepositoryTools();
// Configurar os manipuladores usando schemas oficiais
this.registerHandlers();
}
registerHandlers() {
// Registra o manipulador de lista de ferramentas
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'initProjectState',
description: 'Inicializa o estado de um projeto com base em um repositório',
inputSchema: {
type: 'object',
properties: {
repositoryUrl: {
type: 'string',
description: 'URL ou identificador do repositório'
},
workingDirectory: {
type: 'string',
description: 'Diretório de trabalho opcional (ex: \'src\', \'frontend/src\')'
}
},
required: ['repositoryUrl']
}
},
{
name: 'loadProjectState',
description: 'Carrega o estado atual de um projeto',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Caminho para o arquivo project-status.json (opcional)'
}
}
}
},
{
name: 'updateProjectState',
description: 'Atualiza campos específicos no estado do projeto',
inputSchema: {
type: 'object',
properties: {
updates: {
type: 'object',
description: 'Objeto com os campos a serem atualizados'
},
projectPath: {
type: 'string',
description: 'Caminho para o arquivo project-status.json (opcional)'
}
},
required: ['updates']
}
},
{
name: 'analyzeRepository',
description: 'Analisa a estrutura de um repositório para obter insights',
inputSchema: {
type: 'object',
properties: {
workingDirectory: {
type: 'string',
description: 'Diretório de trabalho opcional (ex: \'src\', \'frontend/src\')'
}
}
}
},
{
name: 'generateContinuityPrompt',
description: 'Gera um prompt otimizado para continuar o desenvolvimento na próxima sessão',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Caminho para o arquivo project-status.json (opcional)'
}
}
}
}
]
};
});
// Registra o manipulador de chamada de ferramentas
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
const toolName = request.params.name;
const args = request.params.arguments || {};
switch (toolName) {
case 'initProjectState':
return await this.handleInitProjectState(args);
case 'loadProjectState':
return await this.handleLoadProjectState(args);
case 'updateProjectState':
return await this.handleUpdateProjectState(args);
case 'analyzeRepository':
return await this.handleAnalyzeRepository(args);
case 'generateContinuityPrompt':
return await this.handleGenerateContinuityPrompt(args);
default:
return {
content: [{ type: 'text', text: `Ferramenta não encontrada: ${toolName}` }],
isError: true
};
}
} catch (error) {
console.error('Erro ao processar chamada:', error);
return {
content: [{ type: 'text', text: `Erro interno: ${error.message}` }],
isError: true
};
}
});
// Handlers para resources/list e prompts/list foram removidos intencionalmente
// para evitar problemas de incompatibilidade com o SDK 1.7.0
}
async handleInitProjectState(args) {
try {
const { repositoryUrl, workingDirectory = '' } = args;
const result = await this.autoSetup.setupProjectState(repositoryUrl, workingDirectory);
return {
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
};
} catch (error) {
console.error('Erro em initProjectState:', error);
return {
content: [{ type: 'text', text: `Erro ao inicializar estado do projeto: ${error.message}` }],
isError: true
};
}
}
async handleLoadProjectState(args) {
try {
const { projectPath = 'project-status.json' } = args;
const result = await this.stateManager.loadProjectState(projectPath);
return {
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
};
} catch (error) {
console.error('Erro em loadProjectState:', error);
return {
content: [{ type: 'text', text: `Erro ao carregar estado do projeto: ${error.message}` }],
isError: true
};
}
}
async handleUpdateProjectState(args) {
try {
const { updates, projectPath = 'project-status.json' } = args;
const result = await this.stateManager.updateProjectState(updates, projectPath);
return {
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
};
} catch (error) {
console.error('Erro em updateProjectState:', error);
return {
content: [{ type: 'text', text: `Erro ao atualizar estado do projeto: ${error.message}` }],
isError: true
};
}
}
async handleAnalyzeRepository(args) {
try {
const { workingDirectory = '' } = args;
const result = await this.repoTools.analyzeRepository(workingDirectory);
return {
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
};
} catch (error) {
console.error('Erro em analyzeRepository:', error);
return {
content: [{ type: 'text', text: `Erro ao analisar repositório: ${error.message}` }],
isError: true
};
}
}
async handleGenerateContinuityPrompt(args) {
try {
const { projectPath = 'project-status.json' } = args;
const state = await this.stateManager.loadProjectState(projectPath);
const prompt = this.stateManager.generateContinuityPrompt(state);
return {
content: [{ type: 'text', text: prompt }]
};
} catch (error) {
console.error('Erro em generateContinuityPrompt:', error);
return {
content: [{ type: 'text', text: `Erro ao gerar prompt de continuidade: ${error.message}` }],
isError: true
};
}
}
async start() {
// Usando console.error para evitar interferir com o transporte MCP
console.error('[INICIANDO] Servidor MCP...');
// Cria e conecta o transporte padrão (stdio)
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('[OK] Servidor MCP iniciado com sucesso!');
}
async stop() {
console.error('[PROCESSANDO] Parando servidor MCP...');
await this.server.disconnect();
console.error('[OK] Servidor MCP parado com sucesso!');
}
}