@myea/aem-mcp-handler
Version:
Advanced AEM MCP request handler with intelligent search, multi-locale support, and comprehensive content management capabilities
241 lines (235 loc) ⢠9.33 kB
JavaScript
import express from 'express';
import axios from 'axios';
import dotenv from 'dotenv';
import { handleChatMessage } from './llm-integration.js';
dotenv.config();
const router = express.Router();
// Telegram Bot configuration
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
const TELEGRAM_API_URL = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}`;
// Authorized Telegram user IDs (for security)
const AUTHORIZED_USERS = process.env.TELEGRAM_AUTHORIZED_USERS?.split(',').map(id => parseInt(id.trim())) || [];
// Store conversation history for each chat
const chatHistory = new Map();
// Helper to send Telegram message with typing indicator
async function sendTelegramMessage(chatId, text, parseMode = 'Markdown') {
if (!TELEGRAM_BOT_TOKEN) {
console.log('[Telegram] Bot token not configured, would send:', text);
return;
}
try {
// First, send typing action
await axios.post(`${TELEGRAM_API_URL}/sendChatAction`, {
chat_id: chatId,
action: 'typing'
});
const response = await axios.post(`${TELEGRAM_API_URL}/sendMessage`, {
chat_id: chatId,
text: text,
parse_mode: parseMode,
disable_web_page_preview: true
});
console.log('[Telegram] Message sent successfully:', response.status);
}
catch (error) {
console.error('[Telegram] Failed to send message:', error.response?.data || error.message);
// Fallback: send without markdown if parsing failed
if (error.response?.data?.error_code === 400 && parseMode === 'Markdown') {
try {
await axios.post(`${TELEGRAM_API_URL}/sendMessage`, {
chat_id: chatId,
text: text,
disable_web_page_preview: true
});
console.log('[Telegram] Message sent successfully (fallback)');
}
catch (fallbackError) {
console.error('[Telegram] Fallback send also failed:', fallbackError.message);
throw fallbackError;
}
}
else {
throw error;
}
}
}
// Main message handling in the /telegram POST endpoint
router.post('/telegram', async (req, res) => {
let chatId = null;
try {
const update = req.body;
if (!update.message) {
res.sendStatus(200);
return;
}
const message = update.message;
chatId = message.chat.id;
const userId = message.from.id;
const userName = message.from.username || message.from.first_name;
const text = message.text || '';
console.log(`[Telegram] Message from ${userName} (${userId}): ${text}`);
// Security check
if (AUTHORIZED_USERS.length > 0 && !AUTHORIZED_USERS.includes(userId)) {
console.log(`[Telegram] Unauthorized user: ${userId}`);
await sendTelegramMessage(chatId, 'š« Unauthorized access. Contact admin for access.');
res.sendStatus(200);
return;
}
// Get chat history
let history = chatHistory.get(chatId) || [];
// Handle commands
if (text.startsWith('/')) {
const [command] = text.slice(1).split(/\s+/);
switch (command.toLowerCase()) {
case 'help':
case 'start':
await sendTelegramMessage(chatId, `š¤ *Welcome to AEM ChatGPT!*
I can help you explore and modify your Adobe Experience Manager content. Try asking me things like:
**š Search & Explore:**
⢠"Find signin page under language-masters en"
⢠"List pages under /content/wknd"
⢠"What components are in the home page?"
**š Content Management:**
⢠"Change text from 'Sign In' to 'Hello World' in signin XF"
⢠"Update image path to /content/dam/new-image.jpg"
⢠"Get all text content from about page"
**š ļø Advanced Features:**
⢠Universal site discovery (works with any AEM instance)
⢠Deep component scanning in Experience Fragments
⢠Bulk content updates across multiple pages
⢠AI-powered search with fuzzy matching
**Commands:**
/help - Show this help
/clear - Clear our conversation
/status - Check system status`);
return;
case 'clear':
chatHistory.delete(chatId);
await sendTelegramMessage(chatId, "⨠Conversation history cleared!");
return;
case 'status':
// Use a simple health check instead of duplicating MCP logic
try {
const healthResponse = await axios.get('http://localhost:3000/api/health');
const health = healthResponse.data;
await sendTelegramMessage(chatId, `š¤ *System Status:*\n\n` +
`*Telegram:* ā
Connected\n` +
`*MCP Server:* ${health.mcp === 'connected' ? 'ā
Connected' : 'ā Disconnected'}\n` +
`*OpenAI:* ${health.openai ? 'ā
Connected' : 'ā Not Configured'}\n` +
`*Chat History:* ${history.length} messages\n` +
`*Time:* ${new Date().toLocaleString()}`);
}
catch (error) {
await sendTelegramMessage(chatId, `š¤ *System Status:*\n\n` +
`*Telegram:* ā
Connected\n` +
`*System:* ā Error checking status\n` +
`*Time:* ${new Date().toLocaleString()}`);
}
return;
default:
break;
}
}
// Show typing indicator
await axios.post(`${TELEGRAM_API_URL}/sendChatAction`, {
chat_id: chatId,
action: 'typing'
});
// Process message through the ChatGPT integration (no duplication!)
console.log('[Telegram] Processing through ChatGPT with MCP:', text);
const response = await handleChatMessage(text, history);
// Update history
history.push({ role: "user", content: text }, { role: "assistant", content: response });
// Keep history manageable
if (history.length > 20) {
history = history.slice(-20);
}
chatHistory.set(chatId, history);
await sendTelegramMessage(chatId, response);
}
catch (error) {
console.error('[Telegram] Error:', error);
if (chatId) {
try {
await sendTelegramMessage(chatId, `ā Sorry, I encountered an error: ${error.message}`);
}
catch (sendError) {
console.error('[Telegram] Failed to send error message:', sendError);
}
}
}
res.sendStatus(200);
});
// Telegram webhook verification endpoint
router.get('/telegram', (req, res) => {
res.send('Telegram webhook endpoint is ready');
});
// Status endpoint for Telegram integration
router.get('/telegram/status', async (req, res) => {
try {
const healthResponse = await axios.get('http://localhost:3000/api/health');
const health = healthResponse.data;
const status = {
telegram: 'ready',
bot: {
configured: !!TELEGRAM_BOT_TOKEN,
token: TELEGRAM_BOT_TOKEN ? `${TELEGRAM_BOT_TOKEN.substring(0, 10)}...` : 'not configured'
},
mcp: health.mcp,
mcpUrl: 'http://localhost:3000/mcp',
authorized_users: AUTHORIZED_USERS.length,
timestamp: new Date().toISOString()
};
res.json(status);
}
catch (error) {
res.status(500).json({
error: 'Failed to check system health',
timestamp: new Date().toISOString()
});
}
});
// Webhook setup helper endpoint
router.post('/telegram/webhook', async (req, res) => {
try {
const { webhookUrl } = req.body;
if (!webhookUrl) {
res.status(400).json({ error: 'webhookUrl is required' });
return;
}
if (!TELEGRAM_BOT_TOKEN) {
res.status(400).json({ error: 'TELEGRAM_BOT_TOKEN not configured' });
return;
}
// Set webhook URL
const response = await axios.post(`${TELEGRAM_API_URL}/setWebhook`, {
url: webhookUrl
});
res.json({
success: true,
message: 'Webhook set successfully',
data: response.data
});
}
catch (error) {
res.status(500).json({
error: error.response?.data || error.message
});
}
});
// Test endpoint to send a Telegram message
router.post('/telegram/test', async (req, res) => {
try {
const { chatId, message } = req.body;
if (!chatId || !message) {
res.status(400).json({ error: 'Both "chatId" and "message" are required' });
return;
}
await sendTelegramMessage(chatId, message);
res.json({ success: true, message: 'Telegram message sent' });
}
catch (error) {
res.status(500).json({ error: error.message });
}
});
export default router;