UNPKG

telegram-mcp-local-server

Version:

Secure Model Context Protocol (MCP) server for Telegram integration. Runs locally, allows AI agents to read chats and message history, with built-in readonly mode for safety.

346 lines 13.2 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; import { TelegramClient } from "./telegram-client.js"; import { fileURLToPath } from "url"; import { readFileSync } from "fs"; import { dirname, join } from "path"; // Determine if we're in interactive session-helper mode const isSessionMode = process.argv.includes('--session'); // Check for --session flag // Note: We intentionally avoid importing the session helper at top-level to prevent // any stdout interference with the MCP stdio transport. // Check for --help flag if (process.argv.includes('--help') || process.argv.includes('-h')) { // console.log(` // Telegram MCP Local Server // // Usage: telegram-mcp-local-server [options] // // Options: // --session Generate a new Telegram session string // --version Show version information // --help, -h Show this help message // // Environment Variables: // TELEGRAM_API_ID Your Telegram API ID // TELEGRAM_API_HASH Your Telegram API Hash // TELEGRAM_SESSION_STRING Your Telegram session string // TELEGRAM_READONLY_MODE Set to 'true' for readonly mode // // Examples: // telegram-mcp-local-server // telegram-mcp-local-server --session // TELEGRAM_READONLY_MODE=true telegram-mcp-local-server // // For more information, visit: https://github.com/yourusername/telegram-mcp-local-server // `); process.exit(0); } // Check for --version flag if (process.argv.includes('--version')) { try { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packagePath = join(__dirname, '..', 'package.json'); const packageJson = JSON.parse(readFileSync(packagePath, 'utf8')); // console.log(packageJson.version); } catch (error) { // console.log('Version information not available'); } process.exit(0); } const server = new Server({ name: "telegram-mcp-local-server", version: "1.0.7", }, { capabilities: { tools: {}, }, }); // Telegram client instance let telegramClient = null; // Check if server is running in readonly mode const isReadonlyMode = process.env.TELEGRAM_READONLY_MODE === 'true'; // Initialize Telegram client async function initializeTelegramClient(apiId, apiHash, sessionString) { if (!telegramClient) { telegramClient = new TelegramClient({ apiId: parseInt(apiId), apiHash, sessionString, }); await telegramClient.connect(); } return telegramClient; } // Auto-initialize Telegram client if environment variables are present async function autoInitializeTelegramClient() { const apiId = process.env.TELEGRAM_API_ID; const apiHash = process.env.TELEGRAM_API_HASH; const sessionString = process.env.TELEGRAM_SESSION_STRING; if (apiId && apiHash) { try { await initializeTelegramClient(apiId, apiHash, sessionString); // console.log(`Telegram client auto-initialized from environment variables (${isReadonlyMode ? 'readonly' : 'read-write'} mode)`); } catch (error) { // console.warn("Failed to auto-initialize Telegram client:", error instanceof Error ? error.message : String(error)); } } } // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = [ { name: "telegram_connect", description: "Connect to Telegram using API credentials", inputSchema: { type: "object", properties: { apiId: { type: "string", description: "Telegram API ID", }, apiHash: { type: "string", description: "Telegram API Hash", }, sessionString: { type: "string", description: "Optional session string for authentication", }, }, required: ["apiId", "apiHash"], }, }, { name: "telegram_get_chats", description: "Get list of chats from Telegram", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Maximum number of chats to retrieve (default: 50)", }, }, }, }, { name: "telegram_get_chat_history", description: "Get message history from a specific chat", inputSchema: { type: "object", properties: { chatId: { type: "string", description: "Chat ID or username", }, limit: { type: "number", description: "Maximum number of messages to retrieve (default: 50)", }, offsetId: { type: "number", description: "Message ID to start from (for pagination)", }, }, required: ["chatId"], }, }, ]; // Add send message tool only if not in readonly mode if (!isReadonlyMode) { tools.push({ name: "telegram_send_message", description: "Send a message to a specific chat", inputSchema: { type: "object", properties: { chatId: { type: "string", description: "Chat ID or username", }, message: { type: "string", description: "Message text to send", }, }, required: ["chatId", "message"], }, }); } return { tools }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case "telegram_connect": { const connectSchema = z.object({ apiId: z.string(), apiHash: z.string(), sessionString: z.string().optional(), }); const { apiId, apiHash, sessionString } = connectSchema.parse(args); try { await initializeTelegramClient(apiId, apiHash, sessionString); return { content: [ { type: "text", text: "Successfully connected to Telegram", }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to connect to Telegram: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } case "telegram_get_chats": { if (!telegramClient) { throw new McpError(ErrorCode.InvalidRequest, "Telegram client not initialized. Please connect first using telegram_connect."); } const chatsSchema = z.object({ limit: z.number().optional().default(50), }); const { limit } = chatsSchema.parse(args); try { const chats = await telegramClient.getChats(limit); return { content: [ { type: "text", text: JSON.stringify(chats, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get chats: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } case "telegram_get_chat_history": { if (!telegramClient) { throw new McpError(ErrorCode.InvalidRequest, "Telegram client not initialized. Please connect first using telegram_connect."); } const historySchema = z.object({ chatId: z.string(), limit: z.number().optional().default(50), offsetId: z.number().optional(), }); const { chatId, limit, offsetId } = historySchema.parse(args); try { const messages = await telegramClient.getChatHistory(chatId, limit, offsetId); return { content: [ { type: "text", text: JSON.stringify(messages, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get chat history: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } case "telegram_send_message": { if (isReadonlyMode) { throw new McpError(ErrorCode.InvalidRequest, "Message sending is not available in readonly mode."); } if (!telegramClient) { throw new McpError(ErrorCode.InvalidRequest, "Telegram client not initialized. Please connect first using telegram_connect."); } const sendSchema = z.object({ chatId: z.string(), message: z.string(), }); const { chatId, message } = sendSchema.parse(args); try { const result = await telegramClient.sendMessage(chatId, message); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to send message: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { if (error instanceof z.ZodError) { throw new McpError(ErrorCode.InvalidParams, `Invalid parameters: ${error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join(', ')}`); } throw error; } }); async function runServer() { // Auto-initialize Telegram client if environment variables are present await autoInitializeTelegramClient(); const transport = new StdioServerTransport(); await server.connect(transport); // console.log(`Telegram MCP server running on stdio (${isReadonlyMode ? 'readonly' : 'read-write'} mode)`); } if (isSessionMode) { (async () => { try { const { default: sessionHelper } = await import('./session-helper.js'); await sessionHelper(); process.exit(0); } catch (error) { // console.error('Error running session helper:', error); process.exit(1); } })(); } else { runServer().catch((error) => { // console.error('Server error:', error); process.exit(1); }); } //# sourceMappingURL=index.js.map