From cf1031cc0bfe6258ffdec974d666e0177ba68b49 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Wed, 28 Jan 2026 06:33:43 +0530 Subject: [PATCH] Integrate MCPProvider and enhance Telegram MCP tools - Added MCPProvider to manage the initialization and updates of MCP servers within the SocketProvider context. - Introduced utility functions for handling typed values from MCP tool arguments, improving input validation across various tools. - Updated TelegramMCPServer to include enhanced logging and type safety for tool handling. - Refactored multiple Telegram tools to utilize the new argument handling functions, ensuring consistent input processing and error management. These changes enhance the overall structure and functionality of the Telegram MCP integration, providing a more robust framework for managing Telegram interactions. --- src/App.tsx | 13 +-- src/lib/mcp/telegram/args.ts | 13 +++ src/lib/mcp/telegram/server.ts | 30 ++++--- src/lib/mcp/telegram/telegramApi.ts | 1 - src/lib/mcp/telegram/tools/getChat.ts | 4 +- src/lib/mcp/telegram/tools/getChats.ts | 7 +- src/lib/mcp/telegram/tools/getMe.ts | 2 +- src/lib/mcp/telegram/tools/getMessages.ts | 64 +++++++++----- src/lib/mcp/telegram/tools/listChats.ts | 7 +- src/lib/mcp/telegram/tools/listMessages.ts | 26 +++--- src/lib/mcp/telegram/tools/replyToMessage.ts | 32 +++++-- src/lib/mcp/telegram/tools/resolveUsername.ts | 10 ++- src/lib/mcp/telegram/tools/searchMessages.ts | 17 +++- .../mcp/telegram/tools/searchPublicChats.ts | 11 ++- src/lib/mcp/telegram/tools/sendMessage.ts | 6 +- src/lib/mcp/telegram/types.ts | 86 ++++++++++++++++++- src/providers/MCPProvider.tsx | 33 +++++++ 17 files changed, 282 insertions(+), 80 deletions(-) create mode 100644 src/lib/mcp/telegram/args.ts create mode 100644 src/providers/MCPProvider.tsx diff --git a/src/App.tsx b/src/App.tsx index 8a2277a7f..b4fd03fd5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,7 @@ import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; import { store, persistor } from './store'; import SocketProvider from './providers/SocketProvider'; +import MCPProvider from './providers/MCPProvider'; import TelegramProvider from './providers/TelegramProvider'; import AppRoutes from './AppRoutes'; @@ -11,11 +12,13 @@ function App() { - - - - - + + + + + + + diff --git a/src/lib/mcp/telegram/args.ts b/src/lib/mcp/telegram/args.ts new file mode 100644 index 000000000..5864d8d7d --- /dev/null +++ b/src/lib/mcp/telegram/args.ts @@ -0,0 +1,13 @@ +/** + * Helpers for reading typed values from MCP tool args (Record) + */ + +export function optNumber(args: Record, key: string, fallback: number): number { + const v = args[key]; + return typeof v === 'number' && Number.isFinite(v) ? v : fallback; +} + +export function optString(args: Record, key: string): string | undefined { + const v = args[key]; + return typeof v === 'string' ? v : undefined; +} diff --git a/src/lib/mcp/telegram/server.ts b/src/lib/mcp/telegram/server.ts index d0e9619e7..8b06af3e8 100644 --- a/src/lib/mcp/telegram/server.ts +++ b/src/lib/mcp/telegram/server.ts @@ -17,7 +17,11 @@ import { ErrorCategory, logAndFormatError } from "../errorHandler"; import { ValidationError } from "../validation"; import { SocketIOMCPTransportImpl } from "../transport"; import { mcpLog } from "../logger"; -import type { TelegramMCPToolHandler } from "./types"; +import { + type TelegramMCPToolHandler, + type TelegramMCPToolName, + TELEGRAM_MCP_TOOL_NAMES, +} from "./types"; import * as tools from "./tools"; export class TelegramMCPServer { @@ -27,6 +31,7 @@ export class TelegramMCPServer { constructor(socket: Socket | null | undefined) { this.transport = new SocketIOMCPTransportImpl(socket ?? undefined); this.config = { name: "telegram-mcp", version: "1.0.0" }; + mcpLog(`Telegram MCP ${this.config.name} v${this.config.version} ready`); this.setupHandlers(); } @@ -35,15 +40,14 @@ export class TelegramMCPServer { } private setupHandlers(): void { - this.transport.on( - "toolCall", - (data: { requestId: string; toolCall: MCPToolCall }) => { - void this.handleToolCallRequest(data); - }, - ); + this.transport.on("toolCall", (data: unknown) => { + void this.handleToolCallRequest( + data as { requestId: string; toolCall: MCPToolCall }, + ); + }); - this.transport.on("listTools", (data: { requestId: string }) => { - const { requestId } = data; + this.transport.on("listTools", (data: unknown) => { + const { requestId } = data as { requestId: string }; try { const toolsList = this.listTools(); this.transport.emit("listToolsResponse", { @@ -119,7 +123,12 @@ export class TelegramMCPServer { } private findToolHandler(name: string): TelegramMCPToolHandler | undefined { - const toolMap: Record = { + const isToolName = (n: string): n is TelegramMCPToolName => + (TELEGRAM_MCP_TOOL_NAMES as readonly string[]).includes(n); + + if (!isToolName(name)) return undefined; + + const toolMap: Record = { get_chats: tools.getChats, list_chats: tools.listChats, get_chat: tools.getChat, @@ -200,6 +209,7 @@ export class TelegramMCPServer { get_contact_chats: tools.getContactChats, get_last_interaction: tools.getLastInteraction, }; + return toolMap[name]; } } diff --git a/src/lib/mcp/telegram/telegramApi.ts b/src/lib/mcp/telegram/telegramApi.ts index c4074a92c..044859101 100644 --- a/src/lib/mcp/telegram/telegramApi.ts +++ b/src/lib/mcp/telegram/telegramApi.ts @@ -7,7 +7,6 @@ import { store } from '../../../store'; import { mtprotoService } from '../../../services/mtprotoService'; import { selectOrderedChats, - selectChatMessages, selectCurrentUser, } from '../../../store/telegramSelectors'; import type { TelegramChat, TelegramUser, TelegramMessage } from '../../../store/telegram/types'; diff --git a/src/lib/mcp/telegram/tools/getChat.ts b/src/lib/mcp/telegram/tools/getChat.ts index a68e91c76..02f217e00 100644 --- a/src/lib/mcp/telegram/tools/getChat.ts +++ b/src/lib/mcp/telegram/tools/getChat.ts @@ -25,8 +25,8 @@ export const tool: MCPTool = { }; export async function getChat( - args: { chat_id: string | number }, - context: TelegramMCPContext, + args: Record, + _context: TelegramMCPContext, ): Promise { try { const chatId = validateId(args.chat_id, 'chat_id'); diff --git a/src/lib/mcp/telegram/tools/getChats.ts b/src/lib/mcp/telegram/tools/getChats.ts index 93780cb21..450998353 100644 --- a/src/lib/mcp/telegram/tools/getChats.ts +++ b/src/lib/mcp/telegram/tools/getChats.ts @@ -6,6 +6,7 @@ import type { MCPTool, MCPToolResult } from '../../types'; import type { TelegramMCPContext } from '../types'; import { ErrorCategory, logAndFormatError } from '../../errorHandler'; +import { optNumber } from '../args'; import { formatEntity, getChats as getChatsApi } from '../telegramApi'; export const tool: MCPTool = { @@ -21,12 +22,12 @@ export const tool: MCPTool = { }; export async function getChats( - args: { page?: number; page_size?: number }, + args: Record, _context: TelegramMCPContext, ): Promise { try { - const page = args.page ?? 1; - const pageSize = args.page_size ?? 20; + const page = optNumber(args, 'page', 1); + const pageSize = optNumber(args, 'page_size', 20); const start = (page - 1) * pageSize; const chats = await getChatsApi(pageSize + start); diff --git a/src/lib/mcp/telegram/tools/getMe.ts b/src/lib/mcp/telegram/tools/getMe.ts index d8e449b91..4c44dad9d 100644 --- a/src/lib/mcp/telegram/tools/getMe.ts +++ b/src/lib/mcp/telegram/tools/getMe.ts @@ -18,7 +18,7 @@ export const tool: MCPTool = { }; export async function getMe( - _args: Record, + _args: Record, _context: TelegramMCPContext, ): Promise { try { diff --git a/src/lib/mcp/telegram/tools/getMessages.ts b/src/lib/mcp/telegram/tools/getMessages.ts index 9e01b0808..85c7daa39 100644 --- a/src/lib/mcp/telegram/tools/getMessages.ts +++ b/src/lib/mcp/telegram/tools/getMessages.ts @@ -2,66 +2,86 @@ * Get Messages tool - Get paginated messages from a specific chat */ -import type { MCPTool, MCPToolResult } from '../../types'; -import type { TelegramMCPContext } from '../types'; +import type { MCPTool, MCPToolResult } from "../../types"; +import type { TelegramMCPContext } from "../types"; -import { ErrorCategory, logAndFormatError } from '../../errorHandler'; -import { formatMessage, getChatById, getMessages as getMessagesApi } from '../telegramApi'; +import { ErrorCategory, logAndFormatError } from "../../errorHandler"; +import { + formatMessage, + getChatById, + getMessages as getMessagesApi, +} from "../telegramApi"; import { validateId } from '../../validation'; -import type { TelegramMessage } from '../../../store/telegram/types'; +import type { TelegramMessage } from '../../../../store/telegram/types'; +import { optNumber } from '../args'; export const tool: MCPTool = { - name: 'get_messages', - description: 'Get paginated messages from a specific chat', + name: "get_messages", + description: "Get paginated messages from a specific chat", inputSchema: { - type: 'object', + type: "object", properties: { - chat_id: { type: 'string', description: 'The ID or username of the chat' }, - page: { type: 'number', description: 'Page number (1-indexed)', default: 1 }, - page_size: { type: 'number', description: 'Number of messages per page', default: 20 }, + chat_id: { + type: "string", + description: "The ID or username of the chat", + }, + page: { + type: "number", + description: "Page number (1-indexed)", + default: 1, + }, + page_size: { + type: "number", + description: "Number of messages per page", + default: 20, + }, }, - required: ['chat_id'], + required: ["chat_id"], }, }; function senderDisplay(msg: TelegramMessage): string { - return msg.fromName ?? msg.fromId ?? 'Unknown'; + return msg.fromName ?? msg.fromId ?? "Unknown"; } export async function getMessages( - args: { chat_id: string | number; page?: number; page_size?: number }, + args: Record, _context: TelegramMCPContext, ): Promise { try { const chatId = validateId(args.chat_id, 'chat_id'); - const page = args.page ?? 1; - const pageSize = args.page_size ?? 20; + const page = optNumber(args, 'page', 1); + const pageSize = optNumber(args, 'page_size', 20); const offset = (page - 1) * pageSize; const chat = getChatById(chatId); if (!chat) { return { - content: [{ type: 'text', text: `Chat not found: ${chatId}` }], + content: [{ type: "text", text: `Chat not found: ${chatId}` }], isError: true, }; } const messages = await getMessagesApi(chatId, pageSize, offset); if (!messages || messages.length === 0) { - return { content: [{ type: 'text', text: 'No messages found for this page.' }] }; + return { + content: [{ type: "text", text: "No messages found for this page." }], + }; } const lines = messages.map((msg) => { const formatted = formatMessage(msg); - const replyStr = msg.replyToMessageId ? ` | reply to ${msg.replyToMessageId}` : ''; - const msgText = formatted.text || '[Media/No text]'; + const replyStr = msg.replyToMessageId + ? ` | reply to ${msg.replyToMessageId}` + : ""; + const msgText = formatted.text || "[Media/No text]"; return `ID: ${formatted.id} | ${senderDisplay(msg)} | Date: ${formatted.date}${replyStr} | Message: ${msgText}`; }); - return { content: [{ type: 'text', text: lines.join('\n') }] }; + return { content: [{ type: "text", text: lines.join("\n") }] }; } catch (error) { return logAndFormatError( - 'get_messages', + "get_messages", error instanceof Error ? error : new Error(String(error)), ErrorCategory.MSG, ); diff --git a/src/lib/mcp/telegram/tools/listChats.ts b/src/lib/mcp/telegram/tools/listChats.ts index f3b729383..d0ba9eee5 100644 --- a/src/lib/mcp/telegram/tools/listChats.ts +++ b/src/lib/mcp/telegram/tools/listChats.ts @@ -6,6 +6,7 @@ import type { MCPTool, MCPToolResult } from '../../types'; import type { TelegramMCPContext } from '../types'; import { ErrorCategory, logAndFormatError } from '../../errorHandler'; +import { optNumber, optString } from '../args'; import { formatEntity, getChats as getChatsApi } from '../telegramApi'; import { toHumanReadableAction } from '../toolActionParser'; @@ -27,12 +28,12 @@ export const tool: MCPTool = { }; export async function listChats( - args: { chat_type?: string; limit?: number }, + args: Record, _context: TelegramMCPContext, ): Promise { try { - const limit = args.limit ?? 20; - const chatType = args.chat_type?.toLowerCase(); + const limit = optNumber(args, 'limit', 20); + const chatType = optString(args, 'chat_type')?.toLowerCase(); const chats = await getChatsApi(limit); const contentItems: Array<{ type: 'text'; text: string }> = []; diff --git a/src/lib/mcp/telegram/tools/listMessages.ts b/src/lib/mcp/telegram/tools/listMessages.ts index bb0838500..b2ccc3a3c 100644 --- a/src/lib/mcp/telegram/tools/listMessages.ts +++ b/src/lib/mcp/telegram/tools/listMessages.ts @@ -6,6 +6,7 @@ import type { MCPTool, MCPToolResult } from '../../types'; import type { TelegramMCPContext } from '../types'; import { ErrorCategory, logAndFormatError } from '../../errorHandler'; +import { optNumber, optString } from '../args'; import { formatMessage, getChatById, getMessages as getMessagesApi } from '../telegramApi'; import { validateId } from '../../validation'; @@ -26,18 +27,15 @@ export const tool: MCPTool = { }; export async function listMessages( - args: { - chat_id: string | number; - limit?: number; - search_query?: string; - from_date?: string; - to_date?: string; - }, + args: Record, _context: TelegramMCPContext, ): Promise { try { const chatId = validateId(args.chat_id, 'chat_id'); - const limit = args.limit ?? 20; + const limit = optNumber(args, 'limit', 20); + const searchQuery = optString(args, 'search_query'); + const fromDate = optString(args, 'from_date'); + const toDate = optString(args, 'to_date'); const chat = getChatById(chatId); if (!chat) { @@ -52,17 +50,17 @@ export async function listMessages( return { content: [{ type: 'text', text: 'No messages found matching the criteria.' }] }; } - if (args.search_query) { - const q = args.search_query.toLowerCase(); + if (searchQuery) { + const q = searchQuery.toLowerCase(); messages = messages.filter((m) => (m.message ?? '').toLowerCase().includes(q)); } - if (args.from_date || args.to_date) { + if (fromDate || toDate) { messages = messages.filter((m) => { const d = new Date(m.date * 1000); - if (args.from_date && d < new Date(args.from_date)) return false; - if (args.to_date) { - const to = new Date(args.to_date); + if (fromDate && d < new Date(fromDate)) return false; + if (toDate) { + const to = new Date(toDate); to.setHours(23, 59, 59, 999); if (d > to) return false; } diff --git a/src/lib/mcp/telegram/tools/replyToMessage.ts b/src/lib/mcp/telegram/tools/replyToMessage.ts index 835089716..6dea35620 100644 --- a/src/lib/mcp/telegram/tools/replyToMessage.ts +++ b/src/lib/mcp/telegram/tools/replyToMessage.ts @@ -30,12 +30,28 @@ export const tool: MCPTool = { }; export async function replyToMessage( - args: { chat_id: string | number; message_id: number; text: string }, + args: Record, _context: TelegramMCPContext, ): Promise { try { - const chatId = validateId(args.chat_id, "chat_id"); - const { message_id, text } = args; + const chatId = validateId(args.chat_id, 'chat_id'); + const messageId = typeof args.message_id === 'number' && Number.isInteger(args.message_id) + ? args.message_id + : undefined; + const text = typeof args.text === 'string' ? args.text : ''; + + if (messageId === undefined) { + return { + content: [{ type: 'text', text: 'message_id must be an integer' }], + isError: true, + }; + } + if (!text) { + return { + content: [{ type: 'text', text: 'text is required' }], + isError: true, + }; + } const chat = getChatById(chatId); if (!chat) { @@ -45,13 +61,13 @@ export async function replyToMessage( }; } - const result = await sendMessage(chatId, text, message_id); + const result = await sendMessage(chatId, text, messageId); if (!result) { return { content: [ { - type: "text", - text: `Failed to reply to message ${message_id} in chat ${chatId}.`, + type: 'text', + text: `Failed to reply to message ${messageId} in chat ${chatId}.`, }, ], isError: true, @@ -61,8 +77,8 @@ export async function replyToMessage( return { content: [ { - type: "text", - text: `Replied to message ${message_id} in chat ${chatId}.`, + type: 'text', + text: `Replied to message ${messageId} in chat ${chatId}.`, }, ], }; diff --git a/src/lib/mcp/telegram/tools/resolveUsername.ts b/src/lib/mcp/telegram/tools/resolveUsername.ts index 48491fcf9..f0432a7b3 100644 --- a/src/lib/mcp/telegram/tools/resolveUsername.ts +++ b/src/lib/mcp/telegram/tools/resolveUsername.ts @@ -21,11 +21,17 @@ export const tool: MCPTool = { }; export async function resolveUsername( - args: { username: string }, + args: Record, _context: TelegramMCPContext, ): Promise { try { - const raw = args.username; + const raw = typeof args.username === 'string' ? args.username : ''; + if (!raw) { + return { + content: [{ type: 'text', text: 'username is required' }], + isError: true, + }; + } const username = raw.startsWith('@') ? raw : `@${raw}`; const chat = getChatById(username); if (!chat) { diff --git a/src/lib/mcp/telegram/tools/searchMessages.ts b/src/lib/mcp/telegram/tools/searchMessages.ts index d79a56e51..ac12659e4 100644 --- a/src/lib/mcp/telegram/tools/searchMessages.ts +++ b/src/lib/mcp/telegram/tools/searchMessages.ts @@ -6,6 +6,7 @@ import type { MCPTool, MCPToolResult } from '../../types'; import type { TelegramMCPContext } from '../types'; import { ErrorCategory, logAndFormatError } from '../../errorHandler'; +import { optNumber } from '../args'; import { formatMessage, getChatById, getMessages } from '../telegramApi'; import { validateId } from '../../validation'; @@ -24,12 +25,20 @@ export const tool: MCPTool = { }; export async function searchMessages( - args: { chat_id: string | number; query: string; limit?: number }, + args: Record, _context: TelegramMCPContext, ): Promise { try { const chatId = validateId(args.chat_id, 'chat_id'); - const { query, limit = 20 } = args; + const query = typeof args.query === 'string' ? args.query : ''; + const limit = optNumber(args, 'limit', 20); + + if (!query) { + return { + content: [{ type: 'text', text: 'query is required' }], + isError: true, + }; + } const chat = getChatById(chatId); if (!chat) { @@ -45,7 +54,9 @@ export async function searchMessages( } const q = query.toLowerCase(); - const filtered = messages.filter((m) => (m.message ?? '').toLowerCase().includes(q)).slice(0, limit); + const filtered = messages + .filter((m) => (m.message ?? '').toLowerCase().includes(q)) + .slice(0, limit); const lines = filtered.map((m) => { const f = formatMessage(m); diff --git a/src/lib/mcp/telegram/tools/searchPublicChats.ts b/src/lib/mcp/telegram/tools/searchPublicChats.ts index c9e393419..92a84f9ce 100644 --- a/src/lib/mcp/telegram/tools/searchPublicChats.ts +++ b/src/lib/mcp/telegram/tools/searchPublicChats.ts @@ -21,11 +21,18 @@ export const tool: MCPTool = { }; export async function searchPublicChats( - args: { query: string }, + args: Record, _context: TelegramMCPContext, ): Promise { try { - const chats = await searchChats(args.query); + const query = typeof args.query === 'string' ? args.query : ''; + if (!query) { + return { + content: [{ type: 'text', text: 'query is required' }], + isError: true, + }; + } + const chats = await searchChats(query); const results = chats.map(formatEntity); return { content: [{ type: 'text', text: JSON.stringify(results, undefined, 2) }], diff --git a/src/lib/mcp/telegram/tools/sendMessage.ts b/src/lib/mcp/telegram/tools/sendMessage.ts index 8068808f7..2412ec30d 100644 --- a/src/lib/mcp/telegram/tools/sendMessage.ts +++ b/src/lib/mcp/telegram/tools/sendMessage.ts @@ -25,13 +25,13 @@ export const tool: MCPTool = { }; export async function sendMessage( - args: { chat_id: string | number; message: string }, + args: Record, _context: TelegramMCPContext, ): Promise { try { const chatId = validateId(args.chat_id, 'chat_id'); - const { message } = args; - if (!message || typeof message !== 'string') { + const message = typeof args.message === 'string' ? args.message : ''; + if (!message) { return { content: [{ type: 'text', text: 'Message content is required' }], isError: true, diff --git a/src/lib/mcp/telegram/types.ts b/src/lib/mcp/telegram/types.ts index 9af309450..fd5e37ac4 100644 --- a/src/lib/mcp/telegram/types.ts +++ b/src/lib/mcp/telegram/types.ts @@ -3,7 +3,7 @@ */ import type { SocketIOMCPTransportImpl } from '../transport'; -import type { MCPToolResult } from '../../mcp/types'; +import type { MCPToolResult } from '../types'; import type { TelegramState } from '../../../store/telegram/types'; export interface TelegramMCPContext { @@ -15,3 +15,87 @@ export type TelegramMCPToolHandler = ( args: Record, context: TelegramMCPContext, ) => Promise; + +export const TELEGRAM_MCP_TOOL_NAMES = [ + 'get_chats', + 'list_chats', + 'get_chat', + 'create_group', + 'invite_to_group', + 'create_channel', + 'edit_chat_title', + 'delete_chat_photo', + 'leave_chat', + 'get_participants', + 'get_admins', + 'get_banned_users', + 'promote_admin', + 'demote_admin', + 'ban_user', + 'unban_user', + 'get_invite_link', + 'export_chat_invite', + 'import_chat_invite', + 'join_chat_by_link', + 'subscribe_public_channel', + 'get_messages', + 'list_messages', + 'list_topics', + 'send_message', + 'reply_to_message', + 'edit_message', + 'delete_message', + 'forward_message', + 'pin_message', + 'unpin_message', + 'mark_as_read', + 'get_message_context', + 'get_history', + 'get_pinned_messages', + 'send_reaction', + 'remove_reaction', + 'get_message_reactions', + 'list_contacts', + 'search_contacts', + 'add_contact', + 'delete_contact', + 'block_user', + 'unblock_user', + 'get_blocked_users', + 'get_me', + 'update_profile', + 'get_user_photos', + 'get_user_status', + 'mute_chat', + 'unmute_chat', + 'archive_chat', + 'unarchive_chat', + 'get_privacy_settings', + 'set_privacy_settings', + 'list_inline_buttons', + 'press_inline_button', + 'save_draft', + 'get_drafts', + 'clear_draft', + 'search_public_chats', + 'search_messages', + 'resolve_username', + 'get_media_info', + 'get_recent_actions', + 'create_poll', + 'get_bot_info', + 'set_bot_commands', + 'set_profile_photo', + 'delete_profile_photo', + 'edit_chat_photo', + 'get_sticker_sets', + 'get_gif_search', + 'get_contact_ids', + 'import_contacts', + 'export_contacts', + 'get_direct_chat_by_contact', + 'get_contact_chats', + 'get_last_interaction', +] as const; + +export type TelegramMCPToolName = (typeof TELEGRAM_MCP_TOOL_NAMES)[number]; diff --git a/src/providers/MCPProvider.tsx b/src/providers/MCPProvider.tsx new file mode 100644 index 000000000..aa441e435 --- /dev/null +++ b/src/providers/MCPProvider.tsx @@ -0,0 +1,33 @@ +import { useEffect } from 'react'; +import { useAppSelector } from '../store/hooks'; +import { socketService } from '../services/socketService'; +import { + initTelegramMCPServer, + getTelegramMCPServer, + updateTelegramMCPServerSocket, +} from '../lib/mcp/telegram'; + +/** + * MCPProvider initializes and updates MCP servers when the socket connects. + * Place inside SocketProvider so the socket is available. + */ +const MCPProvider = ({ children }: { children: React.ReactNode }) => { + const socketStatus = useAppSelector((state) => state.socket.status); + + useEffect(() => { + if (socketStatus !== 'connected') return; + + const socket = socketService.getSocket(); + const server = getTelegramMCPServer(); + + if (server) { + updateTelegramMCPServerSocket(socket); + } else { + initTelegramMCPServer(socket); + } + }, [socketStatus]); + + return <>{children}; +}; + +export default MCPProvider;