#
tokens: 3866/50000 7/7 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── config.example.json
├── package-lock.json
├── package.json
├── README.md
├── src
│   ├── index.ts
│   └── telegram-server
│       └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Ignore config file with sensitive data
 2 | config.json
 3 | 
 4 | # Ignore build artifacts
 5 | build/
 6 | node_modules/
 7 | 
 8 | # Ignore environment files
 9 | .env
10 | .env.*
11 | 
12 | # Ignore IDE files
13 | .vscode/
14 | .idea/
15 | 
16 | # Ignore OS files
17 | .DS_Store
18 | Thumbs.db
19 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Telegram MCP Server
 2 | 
 3 | A Model Context Protocol (MCP) server that provides Telegram integration.
 4 | 
 5 | ## Features
 6 | - Send messages through Telegram
 7 | - Secure chat ID validation
 8 | - Easy configuration
 9 | 
10 | ## Installation
11 | 
12 | 1. Clone the repository
13 | 2. Follow the [setup instructions](userInstructions/telegram_server_setup.md)
14 | 3. Configure your bot token and chat ID
15 | 4. Install dependencies: `npm install`
16 | 5. Build and run: `npm run build && npm start`
17 | 
18 | ## Requirements
19 | - Node.js 18+
20 | - Telegram bot token
21 | - Valid chat ID
22 | 
23 | ## License
24 | MIT
25 | 
```

--------------------------------------------------------------------------------
/config.example.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "telegram": {
3 |     "botToken": "YOUR_TELEGRAM_BOT_TOKEN_HERE",
4 |     "allowedChatIds": [
5 |       1234567890
6 |     ]
7 |   }
8 | }
9 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "ESNext",
 5 |     "moduleResolution": "node",
 6 |     "resolveJsonModule": true,
 7 |     "esModuleInterop": true,
 8 |     "strict": true,
 9 |     "outDir": "./build",
10 |     "rootDir": "./src"
11 |   },
12 |   "include": ["src/**/*"]
13 | }
14 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "telegram-mcp-server",
 3 |   "version": "1.0.0",
 4 |   "type": "module",
 5 |   "main": "build/index.js",
 6 |   "scripts": {
 7 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
 8 |     "start": "node build/index.js"
 9 |   },
10 |   "dependencies": {
11 |     "@modelcontextprotocol/sdk": "^1.0.0",
12 |     "node-telegram-bot-api": "^0.61.0"
13 |   },
14 |   "devDependencies": {
15 |     "@types/node": "^22.10.7",
16 |     "@types/node-telegram-bot-api": "^0.64.7",
17 |     "typescript": "^5.3.3"
18 |   }
19 | }
20 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import TelegramBot from 'node-telegram-bot-api';
  5 | import {
  6 |   CallToolRequestSchema,
  7 |   ErrorCode,
  8 |   ListResourcesRequestSchema,
  9 |   ListResourceTemplatesRequestSchema,
 10 |   ListToolsRequestSchema,
 11 |   McpError,
 12 |   ReadResourceRequestSchema,
 13 | } from '@modelcontextprotocol/sdk/types.js';
 14 | 
 15 | const TELEGRAM_TOKEN = process.env.TELEGRAM_BOT_TOKEN as string;
 16 | if (!TELEGRAM_TOKEN) {
 17 |   throw new Error('TELEGRAM_BOT_TOKEN environment variable is required');
 18 | }
 19 | 
 20 | class TelegramServer {
 21 |   private server: Server;
 22 |   private bot: TelegramBot;
 23 | 
 24 |   constructor() {
 25 |     this.server = new Server(
 26 |       {
 27 |         name: 'telegram-server',
 28 |         version: '1.0.0',
 29 |       },
 30 |       {
 31 |         capabilities: {
 32 |           resources: {},
 33 |           tools: {},
 34 |         },
 35 |       }
 36 |     );
 37 | 
 38 |     this.bot = new TelegramBot(TELEGRAM_TOKEN, { polling: true });
 39 |     this.setupBotHandlers();
 40 |     this.setupServerHandlers();
 41 |   }
 42 | 
 43 |   private setupBotHandlers() {
 44 |     this.bot.on('message', (msg: TelegramBot.Message) => {
 45 |       const chatId = msg.chat.id;
 46 |       console.log(`Received message from chat ID: ${chatId}`);
 47 |       if (!msg.text) return;
 48 |       
 49 |       // Echo messages back to user
 50 |       this.bot.sendMessage(chatId, `You said: ${msg.text}`);
 51 |     });
 52 |   }
 53 | 
 54 |   private setupServerHandlers() {
 55 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
 56 |       tools: [
 57 |         {
 58 |           name: 'send_message',
 59 |           description: 'Send a message through Telegram',
 60 |           inputSchema: {
 61 |             type: 'object',
 62 |             properties: {
 63 |               chatId: { type: 'number' },
 64 |               message: { type: 'string' }
 65 |             },
 66 |             required: ['chatId', 'message']
 67 |           }
 68 |         }
 69 |       ]
 70 |     }));
 71 | 
 72 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
 73 |       if (request.params.name === 'send_message') {
 74 |         if (!request.params.arguments || typeof request.params.arguments !== 'object') {
 75 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
 76 |         }
 77 |         
 78 |         const { chatId, message } = request.params.arguments;
 79 |         if (typeof chatId !== 'number' || typeof message !== 'string') {
 80 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid argument types');
 81 |         }
 82 |         await this.bot.sendMessage(chatId, message);
 83 |         return {
 84 |           content: [{
 85 |             type: 'text',
 86 |             text: 'Message sent successfully'
 87 |           }]
 88 |         };
 89 |       }
 90 |       throw new McpError(ErrorCode.MethodNotFound, 'Unknown tool');
 91 |     });
 92 | 
 93 |     // Error handling
 94 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
 95 |     process.on('SIGINT', async () => {
 96 |       await this.server.close();
 97 |       process.exit(0);
 98 |     });
 99 |   }
100 | 
101 |   async run() {
102 |     const transport = new StdioServerTransport();
103 |     await this.server.connect(transport);
104 |     console.error('Telegram MCP server running on stdio');
105 |   }
106 | }
107 | 
108 | const server = new TelegramServer();
109 | server.run().catch(console.error);
110 | 
```

--------------------------------------------------------------------------------
/src/telegram-server/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import TelegramBot from 'node-telegram-bot-api';
  5 | import { 
  6 |   CallToolRequestSchema, 
  7 |   ErrorCode, 
  8 |   ListToolsRequestSchema, 
  9 |   McpError 
 10 | } from '@modelcontextprotocol/sdk/types.js';
 11 | 
 12 | // Extended error codes
 13 | const ExtendedErrorCode = {
 14 |   ...ErrorCode,
 15 |   Timeout: 1000
 16 | } as const;
 17 | 
 18 | import config from '../../config.json';
 19 | import path from 'path';
 20 | 
 21 | if (!config?.telegram?.botToken) {
 22 |   throw new Error('Missing telegram.botToken in config.json');
 23 | }
 24 | 
 25 | if (!config.telegram.allowedChatIds || !Array.isArray(config.telegram.allowedChatIds)) {
 26 |   throw new Error('Missing or invalid telegram.allowedChatIds in config.json');
 27 | }
 28 | 
 29 | const TELEGRAM_TOKEN = config.telegram.botToken;
 30 | const ALLOWED_CHAT_IDS = new Set(config.telegram.allowedChatIds);
 31 | 
 32 | interface PendingRequest {
 33 |   resolve: (value: string) => void;
 34 |   reject: (reason?: any) => void;
 35 |   timeout: NodeJS.Timeout;
 36 | }
 37 | 
 38 | class TelegramServer {
 39 |   private server: Server;
 40 |   private bot: TelegramBot;
 41 |   private pendingRequests: Map<number, PendingRequest> = new Map();
 42 |   private requestTimeout = 300000; // 5 minutes
 43 | 
 44 |   constructor() {
 45 |     this.server = new Server({
 46 |       name: 'telegram-server',
 47 |       version: '2.0.0',
 48 |     }, {
 49 |       capabilities: {
 50 |         resources: {},
 51 |         tools: {},
 52 |       },
 53 |     });
 54 | 
 55 |     this.bot = new TelegramBot(TELEGRAM_TOKEN, { polling: true });
 56 |     console.log('Telegram bot initialized successfully');
 57 |     this.setupBotHandlers();
 58 |     this.setupServerHandlers();
 59 |   }
 60 | 
 61 |   private setupBotHandlers() {
 62 |     this.bot.on('message', (msg) => {
 63 |       console.log(`Received message from chat ${msg.chat.id}: ${msg.text}`);
 64 |       const chatId = msg.chat.id;
 65 |       if (!ALLOWED_CHAT_IDS.has(chatId)) {
 66 |         console.warn(`Received message from unauthorized chat ID: ${chatId}`);
 67 |         return;
 68 |       }
 69 |       const messageText = msg.text ?? '';
 70 |       
 71 |       // Skip if we don't have valid text content
 72 |       if (!messageText.trim()) {
 73 |         if (this.pendingRequests.has(chatId)) {
 74 |           const pendingRequest = this.pendingRequests.get(chatId);
 75 |           if (pendingRequest) {
 76 |             clearTimeout(pendingRequest.timeout);
 77 |             this.pendingRequests.delete(chatId);
 78 |             pendingRequest.reject(new McpError(ErrorCode.InvalidParams, 'Invalid message type'));
 79 |           }
 80 |         }
 81 |         return;
 82 |       }
 83 | 
 84 |       // Check if this is a response to a pending request
 85 |       const pendingRequest = this.pendingRequests.get(chatId);
 86 |       if (pendingRequest) {
 87 |         clearTimeout(pendingRequest.timeout);
 88 |         this.pendingRequests.delete(chatId);
 89 |         pendingRequest.resolve(messageText);
 90 |         return;
 91 |       }
 92 | 
 93 |       // Default behavior for non-request messages
 94 |       console.log(`Sending response to chat ${chatId}`);
 95 |       this.bot.sendMessage(chatId, `You said: ${messageText}`);
 96 |     });
 97 |   }
 98 | 
 99 |   private setupServerHandlers() {
100 |     console.log('Setting up MCP server handlers');
101 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
102 |       tools: [
103 |         {
104 |           name: 'send_message',
105 |           description: 'Send a message through Telegram',
106 |           inputSchema: {
107 |             type: 'object',
108 |             properties: {
109 |               chatId: { type: 'number' },
110 |               message: { type: 'string' }
111 |             },
112 |             required: ['chatId', 'message']
113 |           }
114 |         },
115 |         {
116 |           name: 'request_user_input',
117 |           description: 'Request user input through Telegram',
118 |           inputSchema: {
119 |             type: 'object',
120 |             properties: {
121 |               chatId: { type: 'number' },
122 |               prompt: { type: 'string' }
123 |             },
124 |             required: ['chatId', 'prompt']
125 |           }
126 |         }
127 |       ]
128 |     }));
129 | 
130 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
131 |       switch (request.params.name) {
132 |         case 'send_message':
133 |           return this.handleSendMessage(request.params.arguments);
134 |         case 'request_user_input':
135 |           return this.handleRequestUserInput(request.params.arguments);
136 |         default:
137 |           throw new McpError(ErrorCode.MethodNotFound, 'Unknown tool');
138 |       }
139 |     });
140 | 
141 |     // Error handling
142 |     this.server.onerror = (error) => {
143 |       console.error('[MCP Error]', error);
144 |       console.log('Attempting to recover from error...');
145 |     };
146 |     process.on('SIGINT', async () => {
147 |       await this.server.close();
148 |       process.exit(0);
149 |     });
150 |   }
151 | 
152 |   private async handleSendMessage(args: any) {
153 |     if (!args || typeof args !== 'object') {
154 |       throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
155 |     }
156 |     const { chatId, message } = args;
157 |     if (typeof chatId !== 'number' || typeof message !== 'string') {
158 |       throw new McpError(ErrorCode.InvalidParams, 'Invalid argument types');
159 |     }
160 |     await this.bot.sendMessage(chatId, message);
161 |     return {
162 |       content: [{
163 |         type: 'text',
164 |         text: 'Message sent successfully'
165 |       }]
166 |     };
167 |   }
168 | 
169 |   private async handleRequestUserInput(args: any) {
170 |     if (!args || typeof args !== 'object') {
171 |       throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
172 |     }
173 |     const { chatId, prompt } = args;
174 |     if (typeof chatId !== 'number' || typeof prompt !== 'string') {
175 |       throw new McpError(ErrorCode.InvalidParams, 'Invalid argument types');
176 |     }
177 | 
178 |     // Send the prompt to the user
179 |     await this.bot.sendMessage(chatId, prompt);
180 | 
181 |     // Create and return a promise that resolves when we get a response
182 |     return new Promise<string>((resolve, reject) => {
183 |       const timeout = setTimeout(() => {
184 |         this.pendingRequests.delete(chatId);
185 |         reject(new McpError(ExtendedErrorCode.Timeout, 'Request timed out'));
186 |       }, this.requestTimeout);
187 | 
188 |       this.pendingRequests.set(chatId, {
189 |         resolve,
190 |         reject,
191 |         timeout
192 |       });
193 |     }).then(response => ({
194 |       content: [{
195 |         type: 'text',
196 |         text: response
197 |       }]
198 |     }));
199 |   }
200 | 
201 |   async run() {
202 |     const transport = new StdioServerTransport();
203 |     await this.server.connect(transport);
204 |     console.log('Telegram MCP server running on stdio');
205 |     console.log('Bot username:', this.bot.getMe());
206 |     console.log('MCP server initialized with tools:', [
207 |       'send_message',
208 |       'request_user_input'
209 |     ]);
210 |   }
211 | }
212 | 
213 | const server = new TelegramServer();
214 | server.run().catch(console.error);
215 | 
```