# Telegram MCP Server — 개발 기획서

**Version:** 1.0
**Date:** 2025-06-03
**Target:** LibrAgent (MCP 2025-06-18 Spec compliant)
**Protocol:** stdio (권장) 또는 Streamable HTTP

---

## 1. 개요

### 1.1 목적

Telegram MCP 서버는 LibrAgent 내에서 **두 가지 주요 역할**을 수행합니다:

1. **도구 (Tools)**: 메시지 발송, 읽기, 검색, 파일 다운로드 등 일반적인 Telegram API 작업
2. **채널 (Channels)**: 외부 Telegram 채팅방에서 들어오는 메시지를 실시간으로 LibrAgent 세션에 주입 (proactive injection)

### 1.2 아키텍처 흐름

```
Telegram User ──Telegram Message──> Telegram MCP Server
                                           │
                                   Channel Notification
                                           │
                                           ▼
                                    LibrAgent MCP Proxy
                                           │
                                   Agent Session (Think-Act-Observe)
                                           │
                                           ▼
                                    User sees: "새 Telegram 메시지 도착"
```

### 1.3 핵심 요구사항

- ✅ MCP 2025-06-18 스펙 준수
- ✅ `claude/channel` experimental capability 지원 (channel notification)
- ✅ `claude/channel/permission` experimental capability 지원 (permission relay)
- ✅ telegram-cli (`~/.libragent/telegram_config.json`)와 인증 정보 공유
- ✅ 세션 격리 (각 agent session마다 독립적인 Telegram client)

---

## 2. 인증 및 설정 공유

### 2.1 telegram-cli 설정 파일 구조

LibrAgent의 기존 `telegram-cli` 스킬이 사용하는 설정 파일을 **직접 읽어서** 인증을 공유합니다.

**설정 파일 위치:** `~/.libragent/telegram_config.json`

```json
{
  "api_id": 12345678,
  "api_hash": "abcdef0123456789abcdef0123456789",
  "phone": "+821012345678",
  "session_name": "telegram_session"
}
```

**세션 파일 위치:** `~/.libragent/telegram_session.session`

### 2.2 인증 공유 전략

#### 옵션 A: 직접 설정 파일 읽기 (권장)

MCP 서버 시작 시 `~/.libragent/telegram_config.json`을 읽어서 Telethon 클라이언트 초기화:

```python
from pathlib import Path
import json

CONFIG_PATH = Path.home() / ".libragent" / "telegram_config.json"
SESSION_PATH = Path.home() / ".libragent" / "telegram_session.session"

def load_config():
    if not CONFIG_PATH.exists():
        raise RuntimeError(
            "Telegram config not found. "
            "Please configure Telegram via LibrAgent's telegram-cli skill first."
        )
    with open(CONFIG_PATH) as f:
        return json.load(f)

config = load_config()
client = TelegramClient(
    str(SESSION_PATH),
    api_id=config["api_id"],
    api_hash=config["api_hash"],
)
```

**장점:**

- 별도 인증 절차 불필요
- telegram-cli 스킬과 동일한 세션 파일 공유
- telegram-cli가 재인증하면 MCP 서버도 자동으로 반영

**단점:**

- 설정 파일이 이미 구성되어 있어야 함 (첫 사용 시 telegram-cli 스킬 먼저 실행 필요)
- 동시 접속 제한 (Telethon是同한 세션 파일 동시 사용 시 충돌 가능성 — 해결책: 세션 객체 복사 또는 독립 세션 파일)

#### 옵션 B: 독립 세션 파일 사용

MCP 서버가 별도의 세션 파일 (`~/.libragent/telegram_mcp.session`) 을 사용하여 telegram-cli와 분리:

```python
MCP_SESSION_PATH = Path.home() / ".libragent" / "telegram_mcp.session"

client = TelegramClient(
    str(MCP_SESSION_PATH),
    api_id=config["api_id"],
    api_hash=config["api_hash"],
)
```

**장점:**

- telegram-cli와 독립적 (충돌 없음)
- telegram-cli가 로그아웃해도 MCP 서버는 유지 가능

**단점:**

- 첫 실행 시 인증 코드 수신 → 입력 필요 (telegram-cli와 별도 설정 필요)

### 2.3 권장 사항

**옵션 A를 기본으로 하되, `--mcp-session` 플래그로 옵션 B를 지원**하세요:

```bash
# 기본: telegram-cli 설정 파일 공유
./telegram-mcp-server

# 독립 세션 사용
./telegram-mcp-server --mcp-session ~/.libragent/telegram_mcp.session
```

---

## 3. 채널 프로토콜 (Channel Protocol)

### 3.1 `claude/channel` experimental capability

MCP 서버가 `initialize` 응답에서 `claude/channel` experimental capability를 선언해야 합니다:

```json
{
  "protocolVersion": "2025-06-18",
  "capabilities": {
    "tools": { ... },
    "experimental": {
      "claude/channel": {
        "name": "telegram",
        "description": "Receive incoming Telegram messages from configured chats"
      }
    }
  },
  "serverInfo": {
    "name": "telegram-mcp-server",
    "version": "1.0.0"
  },
  "instructions": "This server can receive incoming Telegram messages. Configure chats using the configure_chat tool."
}
```

### 3.2 `claude/channel/permission` (Permission Relay)

사용자 승인을 필요로 하는 작업 (예: 메시지 발송) 을 위해 permission relay capability를 선언:

```json
{
  "experimental": {
    "claude/channel": { ... },
    "claude/channel/permission": {
      "description": "Request user approval before sending Telegram messages"
    }
  }
}
```

### 3.3 Channel Notification 흐름

#### 3.3.1 LibrAgent → MCP Server (Server → Client)

LibrAgent에서 `notifications/initialized`를 받은 후, MCP 서버가 channel notifications을 보낼 수 있습니다:

```
LibrAgent                     Telegram MCP Server
   │                                │
   │  notifications/initialized     │
   │ ─────────────────────────────> │
   │                                │
   │  ← (Telegram message received) │
   │                                │
   │  notifications/claude/channel  │
   │  {                            │
   │    "jsonrpc": "2.0",          │
   │    "method": "claude/channel",│
   │    "params": {                │
   │      "content": "회의는 14시입니다",│
   │      "meta": {                │
   │        "chat_id": "-1001234567890",│
   │        "chat_name": "LibrAgent Dev",│
   │        "sender": "김철수",      │
   │        "message_id": 42,       │
   │        "timestamp": "2025-06-03T14:23:00Z",│
   │        "has_media": false      │
   │      }                        │
   │    }                          │
   │  }                            │
   │ <───────────────────────────── │
```

#### 3.3.2 Notification Payload

```json
{
  "jsonrpc": "2.0",
  "method": "claude/channel",
  "params": {
    "content": "메시지 본문 (텍스트)",
    "meta": {
      "chat_id": "-1001234567890",
      "chat_name": "채팅 이름",
      "chat_type": "group|channel|private",
      "sender_id": 123456789,
      "sender_name": "발신자 이름",
      "message_id": 42,
      "timestamp": "2025-06-03T14:23:00Z",
      "has_media": false,
      "media_type": null,
      "media_url": null
    }
  }
}
```

**meta 필드 설명:**

| 필드          | 타입           | 설명                                                |
| ------------- | -------------- | --------------------------------------------------- |
| `chat_id`     | string         | Telegram chat ID (음수: 그룹/채널, 양수: 개인)      |
| `chat_name`   | string         | 채팅 이름 (또는 사용자 이름)                        |
| `chat_type`   | string         | `"private"`, `"group"`, `"channel"`, `"supergroup"` |
| `sender_id`   | integer        | 발신자 Telegram user ID                             |
| `sender_name` | string         | 발신자 이름 (first_name last_name)                  |
| `message_id`  | integer        | Telegram 메시지 ID                                  |
| `timestamp`   | string         | ISO 8601 형식 메시지 수신 시간                      |
| `has_media`   | boolean        | 미디어 첨부 여부                                    |
| `media_type`  | string \| null | `"photo"`, `"document"`, `"audio"`, `"video"` 등    |
| `media_url`   | string \| null | 미디어 다운로드 URL (필요시)                        |

### 3.4 Channel 구독 설정

어떤 채팅방에서 메시지를 수신할지 설정하는 도구를 제공합니다:

```python
# 도구 정의 예시
tools = [
    {
        "name": "configure_chat",
        "description": "Configure which chats to receive notifications from",
        "inputSchema": {
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "enum": ["subscribe", "unsubscribe", "list"],
                    "description": "Action to perform"
                },
                "chat_id": {
                    "type": "string",
                    "description": "Chat ID to subscribe/unsubscribe (required for subscribe/unsubscribe)"
                }
            },
            "required": ["action"]
        }
    }
]
```

**동작:**

1. `configure_chat(action="list")`: 구독 중인 채팅 목록 반환
2. `configure_chat(action="subscribe", chat_id="-100...")`: 해당 채팅 구독 시작
3. `configure_chat(action="unsubscribe", chat_id="-100...")`: 구독 해제

### 3.5 폴링 vs 알림

**권장:** Telethon의 `@client.on_message()` 데코레이터를 사용한 이벤트 기반 수신

```python
from telethon import TelegramClient, events

@client.on(events.NewMessage(chats=SUBSCRIBED_CHATS))
async def handler(event):
    # Channel notification 발송
    notification = {
        "jsonrpc": "2.0",
        "method": "claude/channel",
        "params": {
            "content": event.text or "",
            "meta": extract_meta(event)
        }
    }
    await send_channel_notification(notification)
```

**대안:** 정해진 간격으로 폴링 (초기 구현용)

```python
import asyncio

async def poll_new_messages():
    while True:
        for chat_id in SUBSCRIBED_CHATS:
            messages = await client.get_messages(chat_id, limit=10, offset_id=last_seen[chat_id])
            for msg in messages:
                if msg.id > last_seen[chat_id]:
                    await send_channel_notification(build_notification(msg))
                    last_seen[chat_id] = msg.id
        await asyncio.sleep(5)  # 5초 간격
```

---

## 4. 도구 (Tools) 정의

### 4.1 필수 도구

#### 4.1.1 `send_message`

Telegram 메시지 발송

```python
{
    "name": "send_message",
    "description": "Send a text or media message to a Telegram chat",
    "inputSchema": {
        "type": "object",
        "properties": {
            "chat": {
                "type": "string",
                "description": "Chat ID, username (@username), or 'me' for saved messages"
            },
            "message": {
                "type": "string",
                "description": "Message text content"
            },
            "file": {
                "type": "string",
                "description": "Optional: Path to file to send (photo, document, etc.)"
            }
        },
        "required": ["chat", "message"]
    }
}
```

**응답:**

```json
{
  "content": [
    {
      "type": "text",
      "text": "✅ 텔레그램 메시지 발송 완료\n  받는 곳: @example_channel\n  발송 시각: 2025-06-03T14:30:00Z"
    }
  ],
  "structuredContent": {
    "message_id": 123,
    "chat": "@example_channel",
    "sent_at": "2025-06-03T14:30:00Z"
  }
}
```

#### 4.1.2 `get_messages`

최근 메시지 읽기

```python
{
    "name": "get_messages",
    "description": "Read recent messages from a Telegram chat",
    "inputSchema": {
        "type": "object",
        "properties": {
            "chat": {
                "type": "string",
                "description": "Chat ID or username"
            },
            "limit": {
                "type": "integer",
                "default": 20,
                "description": "Number of messages to retrieve (max 100)"
            },
            "offset_id": {
                "type": "integer",
                "default": 0,
                "description": "Message ID to start from (for pagination)"
            }
        },
        "required": ["chat"]
    }
}
```

**응답:**

```json
{
  "content": [
    {
      "type": "text",
      "text": "📨 텔레그램 메시지 (@example_channel)\n\n#  날짜        내용\n1  06/03 14:23  회의는 14시에 시작됩니다.\n2  06/03 13:45  [이미지]\n3  06/03 12:00 新功能 배포 완료"
    }
  ],
  "structuredContent": {
    "chat": "@example_channel",
    "count": 3,
    "messages": [
      {
        "id": 42,
        "date": "2025-06-03T14:23:00Z",
        "text": "회의는 14시에 시작됩니다.",
        "has_media": false
      }
    ]
  }
}
```

#### 4.1.3 `list_chats`

채팅 목록 조회

```python
{
    "name": "list_chats",
    "description": "List all Telegram chats, channels, and groups",
    "inputSchema": {
        "type": "object",
        "properties": {}
    }
}
```

**응답:**

```json
{
  "content": [
    {
      "type": "text",
      "text": "💬 텔레그램 채팅 목록 (총 5개)\n\n#  이름              유형       마지막 활동\n1  ● LibrAgent Dev   채널       10분 전\n2  ● 프로젝트 A      그룹(42)   3시간 전\n3  김철수            개인       어제"
    }
  ],
  "structuredContent": {
    "count": 5,
    "chats": [
      {
        "id": "-1001234567890",
        "name": "LibrAgent Dev",
        "type": "channel",
        "username": "@libragent_dev",
        "subscriber_count": 150
      }
    ]
  }
}
```

#### 4.1.4 `search_messages`

메시지 검색

```python
{
    "name": "search_messages",
    "description": "Search Telegram messages by keyword",
    "inputSchema": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Search query"
            },
            "chat": {
                "type": "string",
                "description": "Optional: Limit search to specific chat"
            },
            "limit": {
                "type": "integer",
                "default": 20,
                "description": "Maximum results (max 50)"
            }
        },
        "required": ["query"]
    }
}
```

#### 4.1.5 `download_file`

메시지 첨부 파일 다운로드

```python
{
    "name": "download_file",
    "description": "Download a file from a Telegram message",
    "inputSchema": {
        "type": "object",
        "properties": {
            "chat": {
                "type": "string",
                "description": "Chat ID or username"
            },
            "message_id": {
                "type": "integer",
                "description": "Message ID containing the file"
            },
            "dest": {
                "type": "string",
                "description": "Destination path for downloaded file"
            }
        },
        "required": ["chat", "message_id"]
    }
}
```

#### 4.1.6 `get_chat_info`

채팅 정보 조회

```python
{
    "name": "get_chat_info",
    "description": "Get detailed information about a Telegram chat",
    "inputSchema": {
        "type": "object",
        "properties": {
            "chat": {
                "type": "string",
                "description": "Chat ID or username"
            }
        },
        "required": ["chat"]
    }
}
```

### 4.2 채널 관련 도구

#### 4.2.1 `configure_chat` (채팅 구독 관리)

```python
{
    "name": "configure_chat",
    "description": "Configure which chats to receive channel notifications from",
    "inputSchema": {
        "type": "object",
        "properties": {
            "action": {
                "type": "string",
                "enum": ["subscribe", "unsubscribe", "list"],
                "description": "Action: subscribe to, unsubscribe from, or list subscribed chats"
            },
            "chat_id": {
                "type": "string",
                "description": "Chat ID (required for subscribe/unsubscribe)"
            }
        },
        "required": ["action"]
    }
}
```

#### 4.2.2 `list_subscribed_chats`

구독 중인 채팅 목록 조회

```python
{
    "name": "list_subscribed_chats",
    "description": "List chats currently configured for channel notifications",
    "inputSchema": {
        "type": "object",
        "properties": {}
    }
}
```

---

## 5. Permission Relay (선택적)

### 5.1 개요

`claude/channel/permission` capability를 지원하면, LibrAgent가 외부 요청 (예: 메시지 발송) 에 대해 사용자 승인을 MCP 서버를 통해 요청할 수 있습니다.

### 5.2 Permission Request 흐름

```
LibrAgent                 Telegram MCP Server              User (UI)
   │                              │                            │
   │  ChannelPermissionRequest    │                            │
   │  {                          │                            │
   │    requestId: "abc123",      │                            │
   │    toolName: "send_message", │                            │
   │    description: "Send to...",│                            │
   │    inputPreview: "Hello..."  │                            │
   │  }                           │                            │
   │ ───────────────────────────> │                            │
   │                              │  Permission UI 표시         │
   │                              │ ──────────────> │          │
   │                              │                            │
   │                              │  User approval             │
   │                              │ <────────────── │          │
   │                              │                            │
   │  ChannelPermissionVerdict    │                            │
   │  {                          │                            │
   │    requestId: "abc123",      │                            │
   │    behavior: "allow"         │                            │
   │  }                           │                            │
   │ <────────────────────────── │                            │
   │                              │                            │
```

### 5.3 Permission Request Payload

LibrAgent가 MCP 서버에 보내는 요청:

```json
{
  "jsonrpc": "2.0",
  "method": "claude/channel/permission",
  "params": {
    "requestId": "unique-request-id",
    "toolName": "send_message",
    "description": "Send a message to @example_channel",
    "inputPreview": "회의는 14시에 시작됩니다."
  }
}
```

### 5.4 Permission Verdict Payload

MCP 서버가 LibrAgent에 보내는 응답:

```json
{
  "jsonrpc": "2.0",
  "method": "claude/channel/permission/verdict",
  "params": {
    "requestId": "unique-request-id",
    "behavior": "allow" // 또는 "deny"
  }
}
```

---

## 6. 구현 가이드

### 6.1 필수 구성 요소

```
telegram-mcp-server/
├── main.py              # 진입점, MCP 서버 초기화
├── telegram_client.py   # Telethon 클라이언트 관리
├── tools/
│   ├── send_message.py
│   ├── get_messages.py
│   ├── list_chats.py
│   ├── search_messages.py
│   ├── download_file.py
│   ├── get_chat_info.py
│   └── configure_chat.py
├── channel/
│   ├── notification.py  # Channel notification 발송
│   └── subscriber.py    # 구독 관리
├── config.py            # 설정 로드 (telegram-cli 공유)
└── requirements.txt     # telethon 등 의존성
```

### 6.2 Telethon 클라이언트 초기화

```python
# config.py
from pathlib import Path
import json

CONFIG_PATH = Path.home() / ".libragent" / "telegram_config.json"
DEFAULT_SESSION_PATH = Path.home() / ".libragent" / "telegram_session.session"

def load_telegram_config(mcp_session_path=None):
    """Load Telegram config from telegram-cli or use MCP-specific session."""
    if not CONFIG_PATH.exists():
        raise RuntimeError(
            "Telegram config not found. "
            "Configure via LibrAgent's telegram-cli skill first."
        )

    with open(CONFIG_PATH) as f:
        config = json.load(f)

    session_path = mcp_session_path or DEFAULT_SESSION_PATH
    return config, Path(session_path)
```

### 6.3 MCP 서버 초기화 (FastMCP 예시)

```python
# main.py
import asyncio
from fastmcp import FastMCP
from telethon import TelegramClient, events

# 설정 로드
config, session_path = load_telegram_config()

# Telegram 클라이언트
client = TelegramClient(str(session_path), config["api_id"], config["api_hash"])

# 채널 구독 상태
SUBSCRIBED_CHATS = set()
LAST_SEEN_MSG = {}

# 채널 notification 발송 함수
async def send_channel_notification(notification: dict):
    # MCP 서버의 notification 전송 API 사용
    # 이 부분은 사용하는 MCP 프레임워크에 따라 다름
    pass

# 이벤트 핸들러
@client.on(events.NewMessage(chats=SUBSCRIBED_CHATS))
async def handle_telegram_message(event):
    notification = {
        "jsonrpc": "2.0",
        "method": "claude/channel",
        "params": {
            "content": event.text or "",
            "meta": {
                "chat_id": str(event.chat_id),
                "chat_name": event.chat.title if hasattr(event.chat, 'title') else event.chat.first_name,
                "chat_type": "group" if isinstance(event.chat, events.Chat) else "private",
                "sender_id": event.sender_id,
                "sender_name": f"{event.sender.first_name} {event.sender.last_name}".strip() if event.sender else "Unknown",
                "message_id": event.id,
                "timestamp": event.date.isoformat(),
                "has_media": bool(event.media),
                "media_type": None,
                "media_url": None
            }
        }
    }
    await send_channel_notification(notification)

# FastMCP 서버 초기화
mcp = FastMCP(
    name="telegram-mcp-server",
    version="1.0.0",
    instructions="Telegram MCP server with channel support. Configure chats using configure_chat tool."
)

# experimental capability 등록
mcp.server._capabilities["experimental"] = {
    "claude/channel": {
        "name": "telegram",
        "description": "Receive incoming Telegram messages"
    },
    "claude/channel/permission": {
        "description": "Request approval for sensitive operations"
    }
}

# 도구 등록
from tools.send_message import send_message_tool
from tools.get_messages import get_messages_tool
# ...

mcp.tool(send_message_tool)
mcp.tool(get_messages_tool)
# ...

async def main():
    await client.connect()
    if not await client.is_user_authorized():
        raise RuntimeError("Not authorized. Configure Telegram first.")

    async with mcp:
        await client.run_until_disconnected()

if __name__ == "__main__":
    asyncio.run(main())
```

### 6.4 Python 의존성

```txt
telethon>=1.34.0
fastmcp>=0.1.0  # 또는 사용할 MCP 프레임워크
```

---

## 7. LibrAgent 측 연동 (참고)

LibrAgent에서 이 MCP 서버를 사용하려면:

### 7.1 stdio 설정

```json
{
  "mcpServers": {
    "telegram": {
      "transport": {
        "type": "stdio",
        "command": "/path/to/telegram-mcp-server/main.py"
      }
    }
  }
}
```

### 7.2 HTTP 설정

```json
{
  "mcpServers": {
    "telegram": {
      "transport": {
        "type": "http-sse",
        "url": "http://localhost:8080/mcp"
      }
    }
  }
}
```

### 7.3 LibrAgent에서 인식되는 채널 정보

LibrAgent가 `initialize` 응답에서 `claude/channel` capability를 감지하면 시스템 프롬프트에 추가:

```
## Channels

### telegram
- This external MCP server can proactively inject channel messages into the session.
- It also advertises remote permission relay support.
- Channel-specific instructions: Configure chats using configure_chat tool.
```

---

## 8. 테스트 시나리오

### 8.1 기본 테스트

1. **설정 검증**: `check_config.py` 실행 → 상태 `ok` 확인
2. **도구 호출**: `get_messages`, `list_chats` 등 기본 도구 테스트
3. **메시지 발송**: `send_message`로 테스트 메시지 발송

### 8.2 채널 테스트

1. **구독 설정**: `configure_chat(action="subscribe", chat_id="...")` 실행
2. **메시지 수신**: 구독 채팅에서 메시지 발송 → LibrAgent 세션에 notification 도착 확인
3. **구독 해제**: `configure_chat(action="unsubscribe", chat_id="...")` 실행
4. **다중 구독**: 여러 채팅 구독 → 각 채팅에서 메시지 발송 → 올바른 chat_id로 notification 도착 확인

### 8.3 Permission Relay 테스트 (선택)

1. **permission 요청**: `send_message` 호출 시 permission request 발생
2. **승인**: UI에서 승인 → 메시지 발송
3. **거절**: UI에서 거절 → 메시지 발송 취소

---

## 9. 주의사항

### 9.1 동시 접속

- Telethon은 같은 세션 파일로 동시 접속을 지원하지 않음
- telegram-cli 스킬과 MCP 서버가 동시에 실행될 때 충돌 가능성
- **해결책**: 옵션 B (독립 세션 파일) 사용 권장

### 9.2 FloodWait

- Telegram API rate limiting (FloodWait) 처리 필요
- 재시도 로직 구현 필수

### 9.3 세션 파일 백업

- `~/.libragent/telegram_session.session` 파일 백업 권장
- 세션 파일 손실 시 재인증 필요

### 9.4 보안

- `api_hash` 등 민감 정보 노출 금지
- 설정 파일 권한 `0600` 권장 (telegram-cli가 이미 적용)

---

## 10. 체크리스트

- [ ] MCP 2025-06-18 스펙 준수
- [ ] `claude/channel` experimental capability 지원
- [ ] `claude/channel/permission` experimental capability 지원 (선택)
- [ ] telegram-cli 설정 파일 공유 (`~/.libragent/telegram_config.json`)
- [ ] Telethon 이벤트 기반 메시지 수신 (`@client.on_message`)
- [ ] Channel notification 발송 (`notifications/claude/channel`)
- [ ] `configure_chat` 도구 (구독 관리)
- [ ] `send_message` 도구
- [ ] `get_messages` 도구
- [ ] `list_chats` 도구
- [ ] `search_messages` 도구
- [ ] `download_file` 도구
- [ ] `get_chat_info` 도구
- [ ] FloodWait 처리
- [ ] 에러 처리 및 로깅
- [ ] Python 의존성 (`telethon`)

---

## 11. 참고 자료

- [MCP Specification (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18)
- [Claude MCP Channel Protocol](https://modelcontextprotocol.io/docs/concepts/sampling#channel-protocol)
- [Telethon Documentation](https://docs.telethon.dev/)
- [LibrAgent telegram-cli skill](../.agents/skills/telegram-cli/SKILL.md)
