@tiflux/mcp
Version:
TiFlux MCP Server - Model Context Protocol integration for Claude Code and other AI clients
263 lines (237 loc) • 7.13 kB
JavaScript
/**
* ResponseBuilder - Builder para respostas Lambda Function URL
*
* Formata respostas HTTP no formato esperado pela Lambda Function URL.
* Inclui tratamento de erros, headers CORS, e headers MCP.
*
* Formato de resposta Lambda Function URL:
* {
* statusCode: 200,
* headers: { 'content-type': 'application/json', ... },
* body: '{"result": ...}'
* }
*/
class ResponseBuilder {
/**
* Cria resposta de sucesso (200 OK)
* @param {Object} data - Dados a retornar
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static success(data, sessionId = null) {
const headers = this.getDefaultHeaders();
if (sessionId) {
headers['mcp-session-id'] = sessionId;
}
return {
statusCode: 200,
headers,
body: JSON.stringify(data)
};
}
/**
* Cria resposta de erro 400 (Bad Request)
* @param {string} message - Mensagem de erro
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static badRequest(message, sessionId = null) {
return this.error(400, message, 'BAD_REQUEST', sessionId);
}
/**
* Cria resposta de erro 401 (Unauthorized)
* @param {string} message - Mensagem de erro
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static unauthorized(message = 'Header x-tiflux-api-key obrigatorio', sessionId = null) {
return this.error(401, message, 'UNAUTHORIZED', sessionId);
}
/**
* Cria resposta de erro 404 (Not Found)
* @param {string} message - Mensagem de erro
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static notFound(message = 'Endpoint nao encontrado', sessionId = null) {
return this.error(404, message, 'NOT_FOUND', sessionId);
}
/**
* Cria resposta de erro 500 (Internal Server Error)
* @param {string} message - Mensagem de erro
* @param {Error} error - Erro original (opcional, para logging)
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static internalError(message = 'Erro interno do servidor', error = null, sessionId = null) {
// Log do erro completo (sera capturado pelo CloudWatch)
if (error) {
console.error('[ResponseBuilder] Internal Error:', {
message: error.message,
stack: error.stack,
sessionId
});
}
// Nao expor detalhes internos do erro ao cliente
return this.error(500, message, 'INTERNAL_ERROR', sessionId);
}
/**
* Cria resposta de erro generica
* @param {number} statusCode - Codigo HTTP
* @param {string} message - Mensagem de erro
* @param {string} code - Codigo de erro customizado
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static error(statusCode, message, code = 'ERROR', sessionId = null) {
const headers = this.getDefaultHeaders();
if (sessionId) {
headers['mcp-session-id'] = sessionId;
}
return {
statusCode,
headers,
body: JSON.stringify({
error: {
code,
message,
statusCode
}
})
};
}
/**
* Cria resposta de health check
* @returns {Object} - Resposta Lambda formatada
*/
static health() {
return {
statusCode: 200,
headers: this.getDefaultHeaders(),
body: JSON.stringify({
status: 'healthy',
service: 'tiflux-mcp',
version: '2.0.0',
timestamp: new Date().toISOString(),
transport: 'streamable-http',
deployment: 'aws-lambda'
})
};
}
/**
* Cria resposta de informacoes do servidor MCP
* Endpoint GET /mcp para compatibilidade com MCP clients
* @returns {Object} - Resposta Lambda formatada
*/
static serverInfo() {
return {
statusCode: 200,
headers: this.getDefaultHeaders(),
body: JSON.stringify({
name: 'tiflux-mcp',
version: '2.0.0',
vendor: 'TiFlux',
transport: 'streamable-http',
deployment: 'aws-lambda',
protocol: 'mcp',
description: 'TiFlux MCP Server - AWS Lambda deployment',
endpoint: '/mcp',
methods: {
GET: 'Server information',
POST: 'MCP JSON-RPC requests'
},
headers: {
required: ['x-tiflux-api-key'],
optional: ['mcp-session-id']
},
timestamp: new Date().toISOString()
})
};
}
/**
* Cria resposta MCP JSON-RPC
* @param {Object} result - Resultado MCP
* @param {string|number} id - ID da requisicao JSON-RPC
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static mcpResponse(result, id, sessionId = null) {
const mcpData = {
jsonrpc: '2.0',
id,
result
};
return this.success(mcpData, sessionId);
}
/**
* Cria resposta de erro MCP JSON-RPC
* @param {string} message - Mensagem de erro
* @param {number} code - Codigo de erro JSON-RPC
* @param {string|number} id - ID da requisicao JSON-RPC
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static mcpError(message, code = -32603, id = null, sessionId = null) {
const headers = this.getDefaultHeaders();
if (sessionId) {
headers['mcp-session-id'] = sessionId;
}
const mcpErrorData = {
jsonrpc: '2.0',
id,
error: {
code,
message
}
};
return {
statusCode: 200, // JSON-RPC sempre retorna 200, erro vai no body
headers,
body: JSON.stringify(mcpErrorData)
};
}
/**
* Retorna headers HTTP padrao
* @returns {Object} - Headers padrao
*/
static getDefaultHeaders() {
return {
'content-type': 'application/json',
'x-powered-by': 'TiFlux MCP Lambda',
// CORS headers (ajustar conforme necessidade)
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET, POST, OPTIONS',
'access-control-allow-headers': 'content-type, x-tiflux-api-key, mcp-session-id',
'access-control-max-age': '86400'
};
}
/**
* Cria resposta para preflight CORS (OPTIONS)
* @returns {Object} - Resposta Lambda formatada
*/
static corsPreFlight() {
return {
statusCode: 200,
headers: this.getDefaultHeaders(),
body: ''
};
}
/**
* Cria resposta 204 No Content (para notificacoes JSON-RPC)
* Notificacoes nao esperam resposta, entao retornamos 204
* @param {string} sessionId - Session ID para tracking
* @returns {Object} - Resposta Lambda formatada
*/
static noContent(sessionId = null) {
const headers = this.getDefaultHeaders();
if (sessionId) {
headers['mcp-session-id'] = sessionId;
}
return {
statusCode: 204,
headers,
body: ''
};
}
}
module.exports = ResponseBuilder;