feat: add MCP tool integration via MCPO (#11)

This commit is contained in:
Daniel
2026-07-26 14:11:07 +10:00
committed by GitHub
parent 2ceba471d0
commit 4099d4aa82
11 changed files with 420 additions and 27 deletions
+31 -8
View File
@@ -72,7 +72,10 @@ def _is_allowed(user_id: int, settings: Settings) -> bool:
"""Return True if the user is in the allow-list (or no list is configured)."""
if not settings.telegram_allowed_user_ids:
return True
return user_id in settings.telegram_allowed_user_ids
allowed = user_id in settings.telegram_allowed_user_ids
if not allowed:
logger.info("Ignoring update from unauthorized user %s", user_id)
return allowed
def _is_group_enabled(chat_id: int, settings: Settings) -> bool:
@@ -82,6 +85,26 @@ def _is_group_enabled(chat_id: int, settings: Settings) -> bool:
return chat_id in settings.telegram_group_ids
def _is_chat_enabled(chat: Any, settings: Settings) -> bool:
"""Return True if the chat is allowed.
Private chats are governed only by the user allow-list. Group/channel allow-listing
applies only to non-private chats.
"""
if getattr(chat, "type", None) == "private":
return True
allowed = _is_group_enabled(chat.id, settings)
if not allowed:
logger.info(
"Ignoring update in unauthorized chat %s (type=%s); configured group IDs: %s",
chat.id,
getattr(chat, "type", None),
settings.telegram_group_ids,
)
return allowed
async def _send_long(update: Update, text: str) -> None:
"""Send text, splitting across messages if it exceeds Telegram's 4096-char limit."""
limit = 4096
@@ -100,7 +123,7 @@ async def start_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
return
chat = update.effective_chat
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
await update.message.reply_text( # type: ignore[union-attr]
@@ -124,7 +147,7 @@ async def help_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
return
chat = update.effective_chat
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
await update.message.reply_text( # type: ignore[union-attr]
@@ -152,7 +175,7 @@ async def clear_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
return
chat = update.effective_chat
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
key = _thread_key(update)
@@ -187,7 +210,7 @@ async def flush_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
return
chat = update.effective_chat
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
key = _thread_key(update)
@@ -270,7 +293,7 @@ async def recall_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
return
chat = update.effective_chat
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
# If the user supplied a keyword query, search the knowledge base
@@ -334,7 +357,7 @@ async def analyse_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
return
chat = update.effective_chat
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
await update.message.reply_text("Running analysis, please wait...") # type: ignore[union-attr]
@@ -389,7 +412,7 @@ async def message_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
chat = update.effective_chat
if user is None or not _is_allowed(user.id, settings):
return
if chat is None or not _is_group_enabled(chat.id, settings):
if chat is None or not _is_chat_enabled(chat, settings):
return
text = update.message.text # type: ignore[union-attr]