server-official.js•11.9 kB
import express from 'express';
import cors from 'cors';
/**
* 🏕️ TreePod Financial - Servidor MCP Oficial para Claude Web
* Implementa exactamente el protocolo MCP según la documentación oficial
*/
const app = express();
const PORT = process.env.PORT || 3003;
// Middleware CORS específico para Claude Web
app.use(cors({
origin: ['https://claude.ai', 'https://*.claude.ai', '*'],
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Requested-With'],
credentials: true
}));
app.use(express.json());
// Logging detallado
app.use((req, res, next) => {
console.log(`📞 ${new Date().toISOString()} ${req.method} ${req.path}`);
console.log('Headers:', JSON.stringify(req.headers, null, 2));
if (req.body && Object.keys(req.body).length > 0) {
console.log('Body:', JSON.stringify(req.body, null, 2));
}
next();
});
// Datos de TreePod
const treepodData = {
financial: {
monthly: { revenue: 45000, expenses: 28000, profit: 17000, occupancy: 78 },
quarterly: { revenue: 135000, expenses: 84000, profit: 51000, occupancy: 75 },
yearly: { revenue: 540000, expenses: 336000, profit: 204000, occupancy: 73 }
},
rates: {
standard: { high: 180, medium: 140, low: 100 },
premium: { high: 250, medium: 200, low: 150 },
luxury: { high: 350, medium: 280, low: 220 }
},
occupancy: {
today: { occupied: 12, available: 3, total: 15, rate: 80 },
week: { occupied: 78, available: 27, total: 105, rate: 74 },
month: { occupied: 310, available: 155, total: 465, rate: 67 }
}
};
// Endpoint raíz - Información del servidor MCP
app.get('/', (req, res) => {
res.json({
name: "TreePod Financial MCP Server",
description: "Agente financiero para TreePod Glamping - Compatible con Claude Web",
version: "1.0.0",
protocol: "MCP",
capabilities: {
tools: true,
resources: false,
prompts: false
},
endpoints: {
mcp: "/",
health: "/health"
}
});
});
// Endpoint de salud
app.get('/health', (req, res) => {
res.json({
status: "healthy",
timestamp: new Date().toISOString(),
server: "TreePod Financial MCP",
version: "1.0.0"
});
});
// Manejar solicitudes MCP en la raíz
app.post('/', async (req, res) => {
try {
const { jsonrpc, method, params, id } = req.body;
console.log(`🔧 MCP Method: ${method}, ID: ${id}`);
// Validar JSON-RPC
if (jsonrpc !== "2.0") {
return res.status(400).json({
jsonrpc: "2.0",
id: id || null,
error: {
code: -32600,
message: "Invalid Request - jsonrpc must be '2.0'"
}
});
}
const response = {
jsonrpc: "2.0",
id: id || 1
};
switch (method) {
case 'initialize':
console.log('🚀 Inicializando servidor MCP...');
response.result = {
protocolVersion: "2024-11-05",
capabilities: {
tools: {}
},
serverInfo: {
name: "treepod-financial",
version: "1.0.0"
}
};
break;
case 'tools/list':
console.log('📋 Listando herramientas disponibles...');
response.result = {
tools: [
{
name: "test_connection",
description: "Prueba la conexión con TreePod Financial MCP",
inputSchema: {
type: "object",
properties: {
message: {
type: "string",
description: "Mensaje de prueba",
default: "Hello TreePod!"
}
}
}
},
{
name: "analyze_finances",
description: "Analiza las finanzas actuales del negocio TreePod Glamping",
inputSchema: {
type: "object",
properties: {
period: {
type: "string",
enum: ["monthly", "quarterly", "yearly"],
description: "Período de análisis",
default: "monthly"
},
include_projections: {
type: "boolean",
description: "Incluir proyecciones futuras",
default: true
}
}
}
},
{
name: "calculate_rates",
description: "Calcula tarifas óptimas para TreePod según temporada y demanda",
inputSchema: {
type: "object",
properties: {
season: {
type: "string",
enum: ["high", "medium", "low"],
description: "Temporada (alta, media, baja)",
default: "medium"
},
pod_type: {
type: "string",
enum: ["standard", "premium", "luxury"],
description: "Tipo de TreePod",
default: "standard"
},
nights: {
type: "number",
minimum: 1,
description: "Número de noches",
default: 1
}
}
}
},
{
name: "check_occupancy",
description: "Verifica el estado actual de ocupación de los TreePods",
inputSchema: {
type: "object",
properties: {
date_range: {
type: "string",
enum: ["today", "week", "month"],
description: "Rango de fechas para consultar",
default: "today"
}
}
}
}
]
};
break;
case 'tools/call':
console.log(`🛠️ Ejecutando herramienta: ${params?.name}`);
const { name, arguments: args } = params;
let toolResult;
switch (name) {
case 'test_connection':
const message = args?.message || 'Hello TreePod!';
toolResult = {
content: [
{
type: "text",
text: `🏕️ TreePod Financial MCP - ¡Conexión exitosa!\n\nMensaje: ${message}\n\n✅ Servidor funcionando correctamente\n🔗 Protocolo MCP activo\n📊 4 herramientas financieras disponibles\n🌐 Conectado via Claude Web\n🔒 Autenticación completada`
}
]
};
break;
case 'analyze_finances':
const period = args?.period || 'monthly';
const includeProjections = args?.include_projections !== false;
const data = treepodData.financial[period];
let analysisText = `📊 ANÁLISIS FINANCIERO TREEPOD GLAMPING (${period.toUpperCase()})\n\n`;
analysisText += `💰 Ingresos: $${data.revenue.toLocaleString()}\n`;
analysisText += `💸 Gastos: $${data.expenses.toLocaleString()}\n`;
analysisText += `📈 Ganancia: $${data.profit.toLocaleString()}\n`;
analysisText += `🏕️ Ocupación: ${data.occupancy}%\n`;
if (includeProjections) {
const projection = Math.round(data.revenue * 1.12);
analysisText += `\n🔮 PROYECCIÓN:\n`;
analysisText += `📊 Próximo período: $${projection.toLocaleString()}\n`;
analysisText += `📈 Crecimiento estimado: 12%`;
}
toolResult = {
content: [{ type: "text", text: analysisText }]
};
break;
case 'calculate_rates':
const season = args?.season || 'medium';
const podType = args?.pod_type || 'standard';
const nights = args?.nights || 1;
const rate = treepodData.rates[podType][season];
const total = rate * nights;
const discount = nights >= 7 ? 0.15 : nights >= 3 ? 0.1 : 0;
const finalTotal = Math.round(total * (1 - discount));
let ratesText = `💰 CALCULADORA DE TARIFAS TREEPOD\n\n`;
ratesText += `🏕️ Tipo: ${podType.toUpperCase()}\n`;
ratesText += `📅 Temporada: ${season.toUpperCase()}\n`;
ratesText += `🌙 Noches: ${nights}\n\n`;
ratesText += `💵 Tarifa base: $${rate}/noche\n`;
ratesText += `💰 Subtotal: $${total}\n`;
ratesText += `🎯 Descuento: ${(discount * 100)}%\n`;
ratesText += `✅ TOTAL: $${finalTotal}\n\n`;
ratesText += discount > 0 ? '🎉 ¡Descuento aplicado por estadía extendida!' : '💡 Tip: 3+ noches = 10% descuento, 7+ noches = 15% descuento';
toolResult = {
content: [{ type: "text", text: ratesText }]
};
break;
case 'check_occupancy':
const dateRange = args?.date_range || 'today';
const occupancyData = treepodData.occupancy[dateRange];
let occupancyText = `🏕️ ESTADO DE OCUPACIÓN TREEPOD (${dateRange.toUpperCase()})\n\n`;
occupancyText += `✅ Ocupados: ${occupancyData.occupied} pods\n`;
occupancyText += `🟢 Disponibles: ${occupancyData.available} pods\n`;
occupancyText += `📊 Total: ${occupancyData.total} pods\n`;
occupancyText += `📈 Tasa ocupación: ${occupancyData.rate}%\n\n`;
occupancyText += occupancyData.rate >= 80 ? '🔥 ¡Excelente ocupación!' :
occupancyData.rate >= 60 ? '👍 Buena ocupación' :
'⚠️ Ocupación baja - considerar promociones';
toolResult = {
content: [{ type: "text", text: occupancyText }]
};
break;
default:
throw new Error(`Herramienta desconocida: ${name}`);
}
response.result = toolResult;
break;
default:
response.error = {
code: -32601,
message: `Método no encontrado: ${method}`
};
}
console.log(`📤 Respuesta enviada para método ${method}:`, JSON.stringify(response, null, 2));
res.json(response);
} catch (error) {
console.error('❌ Error procesando solicitud MCP:', error);
res.status(500).json({
jsonrpc: "2.0",
id: req.body?.id || null,
error: {
code: -32603,
message: "Error interno del servidor",
data: error.message
}
});
}
});
// Manejar preflight CORS
app.options('*', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Accept, X-Requested-With');
res.header('Access-Control-Allow-Credentials', 'true');
res.sendStatus(200);
});
// Manejar errores 404
app.use((req, res) => {
console.log(`❌ Ruta no encontrada: ${req.method} ${req.path}`);
res.status(404).json({
error: "Endpoint no encontrado",
message: "Este servidor MCP solo acepta solicitudes POST en la raíz (/)",
available_endpoints: ["/", "/health"]
});
});
app.listen(PORT, () => {
console.log(`🏕️ TreePod Financial MCP Server (Oficial) running on http://localhost:${PORT}`);
console.log(`📊 Health check: http://localhost:${PORT}/health`);
console.log(`🔗 MCP endpoint: http://localhost:${PORT}/`);
console.log(`🌐 Compatible con Claude Web - Protocolo MCP Oficial`);
console.log(`📋 Herramientas: test_connection, analyze_finances, calculate_rates, check_occupancy`);
console.log(`🔒 CORS configurado para Claude Web`);
});