Telethon Plus について
Telethon Plusは、TelegramのユーザーアカウントをJSON HTTP APIとMCP経由で操作できるセルフホスト型サービスです。TelethonのMTProtoクライアントを使い、リクエスト制限とエンティティキャッシュを備えています。
主な機能
- 01HTTPとMCP経由でTelegramを操作
- 02メッセージの送受信と管理
- 03グループ、チャンネル、メンバーの管理
- 04リクエスト制限とエンティティキャッシュ
- 05WebSocketによる更新の配信
活用シーン
- 01チャットのメッセージを取得・整理
- 02チャットにテキストやメディアを送信
- 03チャンネルのメンバーや権限を管理
- 04Telegramのイベントをリアルタイム受信
MCP 対応
`/mcp`エンドポイントがTelegramアカウント操作をMCPクライアントに公開します。HTTP APIとツールレジストリを共有します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
docker-telethon-plus
Telegram アカウントを HTTP リクエストで操作できます。Telethon — 使い物にならない Bot API とは違う、本物の MTProto ユーザーボットクライアント — を JSON HTTP API と Model Context Protocol エンドポイントの背後で動かします。
同じツールに、2つの入口があります。JSON を POST するか、AI エージェントに /mcp を指定して好きに使わせてください。どちらの場合も、あなた自身として、アカウントへの完全なアクセス権を使って Telegram とやり取りします。
ログインは1回だけ。セッション文字列も1つだけ。もう認証コードを入力する必要はありません。
目次
仕組み
+-------------------+ +-----------------------+
| Any HTTP client | -----> | REST /api/... | --+
+-------------------+ +-----------------------+ |
| +-----------+ Telegram
+-------------------+ +-----------------------+ +-> | Telethon | <----> Servers
| MCP-aware agent | -----> | /mcp (Streamable | --+ +-----------+ (MTProto)
| (Claude, etc.) | | HTTP transport) |
+-------------------+ +-----------------------+
Telethon クライアントは1つ。非同期ロックも1つ。どちらのインターフェースも同じツールレジストリを共有するため、重複も、変な状態も、余計な面倒もありません。
クイックスタート
services:
telethon-plus:
image: psyb0t/telethon-plus
ports:
- "8080:8080"
environment:
TELETHON_API_ID: "123456"
TELETHON_API_HASH: "your-api-hash"
TELETHON_SESSION: "1Aa...long-string-from-login-helper..."
restart: unless-stopped
API_ID / API_HASH は https://my.telegram.org/apps から取得してください。セッション文字列は、以下のログインヘルパーから取得できます。
初回ログイン
Telegram では、あなたが人間であることを一度だけ証明する必要があります。電話番号、SMS コード、必要に応じて2FAを使います。一度済ませれば、もう必要ありません。
cp .env.example .env
$EDITOR .env # put in TELETHON_API_ID and TELETHON_API_HASH
make login
make login はイメージをビルドし、対話形式の手続きを実行して、TELETHON_SESSION を .env に直接書き込みます。これで完了です。make run を実行すれば、すぐに使えます。
リポジトリがなくても大丈夫です。
docker run --rm -it \
-e TELETHON_API_ID=123456 \
-e TELETHON_API_HASH=your-api-hash \
psyb0t/telethon-plus login
出力されたセッション文字列をコピーして、TELETHON_SESSION に設定すれば完了です。
セッション文字列を持っている人は、アカウントに完全にアクセスできます。 それを持っている人は、あなた自身と同じです。コミットしたり、Slack に貼り付けたり、どこかに入れ墨したりしないでください。
設定
設定はすべて環境変数で行います。.env.example をコピーすると、コメント付きの全項目を確認できます。
| 変数 | 必須 | デフォルト | 説明 |
|---|---|---|---|
TELETHON_API_ID | はい | — | my.telegram.org から取得した API ID |
TELETHON_API_HASH | はい | — | my.telegram.org から取得した API ハッシュ |
TELETHON_SESSION | はい | — | ログインヘルパーで取得した StringSession |
TELETHON_HTTP_LISTEN_ADDRESS | いいえ | 0.0.0.0:8080 | バインドする host:port |
TELETHON_LOG_LEVEL | いいえ | INFO | DEBUG、INFO、WARNING、ERROR |
TELETHON_REQUEST_TIMEOUT | いいえ | 60 | リクエストごとのタイムアウト(秒) |
TELETHON_FLOOD_SLEEP_THRESHOLD | いいえ | 60 | この秒数未満の FLOOD_WAIT エラーでは、自動的に待機します。Telegram からレート制限を受けることがあります。これが安全弁になります。 |
TELETHON_DEVICE_MODEL | いいえ | docker-telethon-plus | Telegram に認識されるデバイスの種類 |
TELETHON_SYSTEM_VERSION | いいえ | 1.0 | 同様に OS のバージョン |
TELETHON_APP_VERSION | いいえ | 1.0 | 同様にアプリのバージョン |
TELETHON_DOWNLOAD_DIR | いいえ | /tmp/telethon-plus | send_file のアップロードに使う一時領域 |
TELETHON_AUTH_KEY | いいえ | "" | 設定すると、すべてのエンドポイントで Authorization: Bearer <key> が必要になります。/healthz は認証不要のままです。空の場合、認証はありません。 |
スロットリングとキャッシュ(過剰なリクエストの防止)
Telegram は、過剰なリクエストを送るアカウントを禁止します。ここでのデフォルト値は、意識しなくてもサーバー側の制限を超えないよう、控えめに設定されています。仕組みを理解している場合にのみ調整してください。
| 変数 | デフォルト値 | 機能 |
|---|---|---|
TELETHON_THROTTLE_ENABLED | true | 以下のすべてのレート制限を有効にするマスタースイッチ |
TELETHON_THROTTLE_GLOBAL_INTERVAL_MS | 50 | 送信リクエスト間に設ける最小間隔 |
TELETHON_THROTTLE_JITTER_MS | 200 | 上乗せされるランダムな±ジッター(メトロノームのようなトラフィックパターンを防ぎます) |
TELETHON_THROTTLE_PER_CHAT_INTERVAL_MS | 1100 | 同じチャットへの送信間に設ける最小間隔(Telegram の「1 秒あたり 1 回/チャット」という上限に余裕を加えています) |
TELETHON_THROTTLE_PER_CHAT_READ_INTERVAL_MS | 250 | 同じチャットからの読み取り間に設ける最小間隔。単一チャンネルのスクレイピングが読み取り枠を独占するのを防ぎます。 |
TELETHON_THROTTLE_ADAPTIVE | true | FLOOD_WAIT が発生するたびに、1 時間、すべての待機時間を 2 倍にします。静かな状態が 1 時間続くとリセットされます。 |
TELETHON_BUCKET_RESOLVE_PER_MIN | 5 | resolveUsername の上限。アカウントが 22 時間の利用禁止を受ける主な原因です |
TELETHON_BUCKET_GET_FULL_PER_MIN | 10 | getFullChannel/getFullUser/get_participants の上限 |
TELETHON_BUCKET_JOIN_PER_HOUR | 5 | チャンネル/グループへの参加回数の上限 |
TELETHON_BUCKET_CREATE_PER_HOUR | 5 | チャンネル/グループの作成回数の上限 |
TELETHON_BUCKET_SEND_PER_MIN | 20 | すべてのチャットを通じた送信回数の上限 |
TELETHON_BUCKET_READ_PER_MIN | 600 | 読み取り操作の上限。ツール呼び出しごとではなく、サーバー側の API 呼び出しごとにカウントされます。get_messages(limit=300) は 3 枠を消費します(Telegram の GetHistory は 1 ページあたり最大 100 件です)。get_dialogs(limit=500) も同様に 5 枠を消費します。 |
TELETHON_CACHE_ENABLED | true | 解決済みのエンティティをディスクに保存します |
TELETHON_CACHE_PATH | /cache/entities.json | 再ビルド後もデータを保持するには、/cache をホストボリュームとしてマウントします |
TELETHON_CACHE_TTL_SECONDS | 604800 | 7 日間です。期限切れにしない場合は 0 に設定します。 |
TELETHON_FLOOD_SLEEP_THRESHOLD | 60 | Telethon の自動待機機能です。FLOOD_WAIT がこの秒数より短い場合は、その時間だけ待機します。これを超える場合はエラーを発生させます。エラーを発生させない場合は非常に大きな値(例:86400)に設定できますが、悪意のある FLOOD_WAIT が発生すると、その時間いっぱいプロセスがブロックされます。 |
各レイヤーの連携:
- エンティティキャッシュが
resolveUsernameの呼び出しを省略します。@somechannelの初回検索では Telegram に問い合わせますが、2 回目以降は枠を消費しません。/cacheボリュームにより、コンテナを再起動しても保持されます。 - メソッドごとのトークンバケットが、危険なメソッドの呼び出し数を制限します。1 分以内に新しいユーザー名を 6 件解決しようとすると、6 件目は最も古い枠が期限切れになるまで待機します。
- チャットごとの送信間隔制限により、各チャットへの送信を 1 秒あたり 1 回以下に抑えます(余裕を加えています)。
- 全体の間隔制限とジッターにより、トラフィック全体のパターンを人間らしくします。
- 適応型バックオフ:FLOOD_WAIT が 1 回発生すると、1 時間、実効レートが半分になります。連続して 3 回発生すると、実効レートは 1/8 になります。1 時間操作がなければ自動的に回復します。
一括スクレイピングを行う場合(以前、22 時間の利用禁止を引き起こしたシナリオ):キャッシュと bucket_resolve_per_min=5 の組み合わせが、利用禁止を防ぎます。新しいチャンネルを 200 件解決する場合、利用禁止を受ける代わりに約 40 分かかります。
ツール
JSON を入力し、JSON を出力します。すべての入力は pydantic で検証されます。不正なデータを送信すると、問題箇所を正確に示す 400 が返されます。
チャットの参照(chat、from_chat、to_chat)には、Telethon が受け付ける任意の形式を使用できます。
| 形式 | 例 |
|---|---|
| ユーザー名 | @psyb0t |
| 電話番号 | +1234567890 |
| t.me リンク | https://t.me/psyb0t |
| 数値 ID | 123456789 |
| スーパーグループ/チャンネル ID | -1001234567890 |
| 自分の「保存済みメッセージ」 | me |
数値 ID で解決できるのは、Telethon がすでに認識しているエンティティのみです。つまり、事前に
@username/t.meで検索した結果、ダイアログ一覧、または受信メッセージを通じてセッションにキャッシュされている必要があります。MTProto では ID だけでなくaccess_hashが必要で、数値だけではそれを取得できません。特にボットの場合は、数値 ID で参照する前に@botusernameを渡すか、GET /api/dialogs/GET /api/entities?chat=@botを一度呼び出してください。ボットのトークンしかなく、ユーザー名がわからない場合は、Telegram の Bot API のgetMeを呼び出してユーザー名を取得し、それを使用してください。
レスポンスの形式
すべての 2xx レスポンスは、リソースを直接返します。{"result": ...} のラッパーやエンベロープはありません。リストは JSON 配列、単一の項目は JSON オブジェクトです。
エラーは {"detail": "..."} の形式で返されます(FastAPI 標準)。Telegram RPC エラーは 502 で返され、detail = {"telegram_error": "...", "message": "..."} となります。
クイックリファレンス
| エンドポイント | 必須パラメーター | 機能 |
|---|---|---|
GET /api/me | — | アカウントのプロフィールです。 |
GET /api/entities | chat | ユーザー名/ID/リンクからプロフィールを解決します。 |
POST /api/entities/bulk | chats | ユーザー名解決のバケット制限に従って、一括で解決します。 |
GET /api/dialogs | — | ダイアログの一覧を取得します。オプション:limit、archived、search(タイトル/@の部分一致)。 |
GET /api/messages | chat | 最近のメッセージを読み込みます。オプション:limit、offset_id、search。 |
GET /api/messages/{id} | chat | 単一のメッセージを取得します。 |
GET /api/messages/{id}/media | chat | 添付ファイルを生バイト列(バイナリストリーム)としてダウンロードします。Telegram の Content-Type と Content-Disposition: attachment; filename=... を返します。オプション:max_bytes。MCP クライアントでは、base64 を返す download_media ツールを使用してください。 |
POST /api/messages | chat、text または file_url | メッセージを送信します。file_url がある場合、取得してメディアとして送信します(text はキャプションとして使用)。それ以外の場合は text を送信します。オプション:parse_mode、reply_to、silent、link_preview、schedule、force_document、max_bytes。 |
POST /api/messages/forward | from_chat、to_chat、message_ids | メッセージを転送します。 |
POST /api/messages/read | chat | 既読にします。オプション:max_id。 |
PATCH /api/messages/{id} | chat、text | 編集します。 |
DELETE /api/messages | chat、message_ids | 一括削除します(リクエスト本文にリストを指定)。 |
POST /api/messages/{id}/pin | chat | ピン留めします。オプション:silent、pm_oneside。 |
POST /api/messages/{id}/unpin | chat | ピン留めを解除します。 |
POST /api/messages/{id}/reactions | chat、emoji | リアクションを付けます。オプション:big。 |
DELETE /api/messages/{id}/reactions | chat | 自分のリアクションを削除します。 |
GET /api/participants | chat | メンバーの一覧を取得します。オプション:limit、search。 |
POST /api/chats | title | スーパーグループまたはチャンネルを作成します。 |
DELETE /api/chats | chat | 所有するスーパーグループ/チャンネルを削除します(リクエスト本文に指定)。 |
POST /api/chats/join | chat | 公開チャンネル/グループに参加します。 |
POST /api/chats/invite | invite | 非公開の t.me/+hash を使って参加します。 |
POST /api/chats/leave | chat | 退出します。 |
GET /api/chats/{chat}/linked | — | チャンネルにリンクされたディスカッショングループを解決します。 |
POST /api/chats/{chat}/admin/ban | user | ユーザーを BAN します。オプション:until_seconds。 |
POST /api/chats/{chat}/admin/unban | user | BAN を解除します。 |
POST /api/chats/{chat}/admin/kick | user | キックします(BAN して即座に解除)。 |
POST /api/chats/{chat}/admin/promote | user | 管理者権限を付与します。オプションで title を指定できます。 |
POST /api/chats/{chat}/admin/demote | user | 管理者権限を剥奪します。 |
POST /api/polls | chat、question、options | 投票を作成します。オプション:quiz、correct_option、solution。 |
POST /api/polls/{id}/vote | chat、options | 投票します(インデックスは 0 始まり)。 |
GET /api/polls/{id}/results | chat | 現在の投票数を取得します。 |
GET /api/throttle/status | — | 現在のレート制限とキャッシュの状態を取得します。 |
GET /api/account/health | — | フラッドリスクのレベルを取得します。 |
GET /metrics | — | Prometheus 形式のメトリクスを出力します(認証不要)。 |
WS /ws/updates | ?token=... | Telegram の受信イベントをストリーミングします。 |
パス内の {chat} には、ほかの箇所と同じ形式を使用できます:@username、数値 ID、me。電話番号(+...)と t.me/... リンクは URL エンコード(%2B など)が必要です。ユーザー名と ID はそのまま指定できます。
HTTP API
標準的な REST API です。JSON を入力し、JSON を出力します。2xx の場合はリソースを直接返し、エラーの場合は {"detail": ...} を返します。
TELETHON_AUTH_KEY が設定されている場合、/healthz を除くすべてのリクエストに以下が必要です:
Authorization: Bearer your-secret-key
GET /api/me
現在の自分の情報を取得します。
GET /api/me
{
"id": 123456789,
"type": "User",
"username": "psyb0t",
"first_name": "Ciprian",
"phone": "+40..."
}
GET /api/entities
任意のチャット参照を完全なプロフィールに解決します。
GET /api/entities?chat=@telegram
{
"id": 1234567,
"type": "Channel",
"username": "telegram",
"title": "Telegram"
}
GET /api/dialogs
GET /api/dialogs?limit=10&archived=false
| パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
limit | int | 20 | ダイアログの件数(1~200) |
archived | bool | false | アーカイブ済みチャットを含めるかどうか |
[
{
"id": 123456789,
"type": "User",
"username": "someone",
"first_name": "Some",
"last_name": "One",
"unread_count": 3,
"pinned": true,
"last_message": {
"id": 999,
"date": "2026-04-29T11:00:00+00:00",
"chat_id": 123456789,
"sender_id": 123456789,
"text": "hey",
"out": false,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
}
]
GET /api/messages
GET /api/messages?chat=me&limit=5&search=hello
| パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
chat | string | 必須 | 読み取るチャット |
limit | int | 20 | メッセージ数(1~200) |
offset_id | int | 0 | このメッセージ ID から開始します(ページネーション) |
search | string | — | 全文検索フィルター |
[
{
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"chat_id": 12345,
"sender_id": 67890,
"text": "hello",
"out": false,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
]
新しいものから順に返します。一致するものがない場合は [] を返します。
POST /api/messages
メッセージを送信します。同じエンドポイントでテキストとファイルを扱います。本文に file_url が含まれる場合、URL からファイルを取得してメディアとして送信し、text はキャプションになります。それ以外の場合、text はプレーンメッセージとして送信されます。
POST /api/messages
Content-Type: application/json
{
"chat": "@psyb0t",
"text": "**hello** from a container",
"parse_mode": "md",
"silent": true,
"reply_to": 4241
}
POST /api/messages
Content-Type: application/json
{
"chat": "@psyb0t",
"file_url": "https://example.com/photo.jpg",
"text": "look at this shit",
"silent": true
}
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
chat | string | 必須 | 送信先のチャット |
text | string | file_url がない場合は必須 | メッセージのテキストまたはキャプション(1~4096 文字) |
file_url | string | null | メディアとして取得・送信する HTTPS URL。Telegram は拡張子/MIME からメディアの種類を自動選択します。force_document で上書きできます。 |
parse_mode | string | null | md / markdown / html / null |
reply_to | int | null | 返信先のメッセージ ID |
silent | bool | false | 通知なしで送信します |
link_preview | bool | true | リンクプレビューを表示します(テキストのみ) |
schedule | string | null | 送信を予約する将来の ISO 日時 |
force_document | bool | false | ファイル送信時に、Telegram に選択させず汎用ドキュメントとして送信します |
max_bytes | int | 52428800 | ファイル送信時に、このサイズを超えるファイルを拒否します(最大 2 GB) |
{
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"chat_id": 12345,
"sender_id": 67890,
"text": "hello from a container",
"out": true,
"reply_to_msg_id": 4241,
"media": false,
"media_type": null
}
PATCH /api/messages/{id}
メッセージを編集します。メッセージ ID は URL に指定し、それ以外はすべて本文に指定します。
PATCH /api/messages/4242
Content-Type: application/json
{
"chat": "me",
"text": "fixed version",
"parse_mode": "md"
}
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
chat | string | 必須 | メッセージを含むチャット |
text | string | 必須 | 新しいテキスト(1~4096 文字) |
parse_mode | string | null | md / html / null |
link_preview | bool | true | リンクプレビューを表示します |
{
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"chat_id": 99999,
"sender_id": 123456789,
"text": "fixed version",
"out": true,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
DELETE /api/messages
ID を指定してメッセージを削除します。
DELETE /api/messages
Content-Type: application/json
{
"chat": "@psyb0t",
"message_ids": [4242, 4243],
"revoke": true
}
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
chat | string | 必須 | メッセージを含むチャット |
message_ids | list[int] | 必須 | 削除する ID(最大 100 件) |
revoke | bool | true | 自分だけでなく全員から削除します |
{ "deleted": 2, "requested": 2 }
POST /api/messages/forward
POST /api/messages/forward
Content-Type: application/json
{
"from_chat": "@sourcechannel",
"to_chat": "me",
"message_ids": [101, 102, 103],
"silent": true
}
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
from_chat | string | 必須 | 転送元のチャット |
to_chat | string | 必須 | 転送先のチャット |
message_ids | list[int] | 必須 | 転送する ID(最大 100 件) |
silent | bool | false | 通知なしで転送します |
[
{
"id": 5001,
"date": "2026-04-29T12:01:00+00:00",
"chat_id": 99999,
"sender_id": 123456789,
"text": "forwarded content here",
"out": true,
"reply_to_msg_id": null,
"media": false,
"media_type": null
}
]
POST /api/messages/read
メッセージを既読にします。
POST /api/messages/read
Content-Type: application/json
{ "chat": "@psyb0t", "max_id": 0 }
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
chat | string | 必須 | 既読にするチャット |
max_id | int | 0 | このメッセージ ID までを既読にします。0 = すべて既読にします。 |
{ "ok": true }
GET /api/participants
グループまたはチャンネルのメンバーを一覧表示します。
GET /api/participants?chat=-1001234567890&limit=50&search=john
| パラメーター | 型 | デフォルト | 説明 |
|---|---|---|---|
chat | string | 必須 | グループまたはチャンネル |
limit | int | 100 | 返すメンバーの最大数(1~1000) |
search | string | — | 名前で絞り込みます |
[
{ "id": 123456789, "type": "User", "username": "johndoe", "first_name": "John" }
]
大規模な公開チャンネルでは、返されるメンバーが限られる場合や、管理者権限が必要な場合があります。
POST /api/chats
スーパーグループまたはブロードキャストチャンネルを作成します。
POST /api/chats
Content-Type: application/json
{ "title": "my-group", "megagroup": true }
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
title | string | 必須 | グループ名(1~255 文字) |
megagroup | bool | true | true = スーパーグループ、false = ブロードキャストチャンネル |
{ "id": 1234567890, "type": "Channel", "title": "my-group" }
DELETE /api/chats
自分が所有するスーパーグループまたはチャンネルを削除します。取り消しできません。
DELETE /api/chats
Content-Type: application/json
{ "chat": "-1001234567890" }
{ "ok": true }
POST /api/chats/join
公開チャンネルまたはスーパーグループに参加します。
POST /api/chats/join
Content-Type: application/json
{ "chat": "@somegroup" }
{ "ok": true }
POST /api/chats/leave
チャンネルまたはスーパーグループから退出します。
POST /api/chats/leave
Content-Type: application/json
{ "chat": "@somegroup" }
{ "ok": true }
エラー
| ステータス | 発生条件 |
|---|---|
400 | JSON が不正、検証に失敗、または Telethon が入力を無効と判断しました。詳細は本文に記載されています。 |
401 | Bearer トークンがない、または正しくありません(TELETHON_AUTH_KEY が設定されている場合のみ)。 |
404 | 不明なエンドポイントです。 |
502 | Telegram が RPC エラーを返しました(FloodWaitError、ChatWriteForbiddenError など)。本文にはエラークラスとメッセージが記載されています。 |
ヘルス
GET /healthz
{ "status": "ok", "authorized": true }
authorized: false は、コンテナは起動したもののセッションに問題があることを意味します。文字列が不正、取り消し済み、または Telegram に到達できない状態です。常に公開されており、認証は不要です。
オブザーバビリティ
GET /metrics
Prometheus 形式のメトリクスです。スクレイプしてください。認証は不要です(クラスター内から公開で読み取り可能です。アクセスを制限する必要がある場合は、通常のスクレイプネットワークポリシーの背後に配置してください)。
エクスポートされる系列:
telethon_plus_tool_calls_total{tool=...}telethon_plus_tool_errors_total{tool=...}telethon_plus_flood_events_total{bucket=...}telethon_plus_cache_hits_total/_misses_total/_entriestelethon_plus_throttle_multipliertelethon_plus_bucket_used{bucket=...}/_bucket_limit{bucket=...}telethon_plus_uptime_seconds
GET /api/throttle/status
すべてのバケットのライブ状態、倍率、最近のフラッドイベント、キャッシュ統計を確認できます:
{
"throttle": {
"enabled": true,
"adaptive": true,
"multiplier": 1.0,
"flood_events_1h": 0,
"buckets": {
"resolve_username": {"used": 0, "limit": 5, "window_seconds": 60},
"send": {"used": 0, "limit": 20, "window_seconds": 60}
},
"tracked_chats_send": 12,
"tracked_chats_read": 30,
"global_interval_ms": 50,
"per_chat_interval_ms": 1100,
"per_chat_read_interval_ms": 250,
"jitter_ms": 200
},
"cache": {"entries": 247},
"read_only": false,
"dry_run": false
}
GET /api/account/health
{
"authorized": true,
"risk": "ok",
"multiplier": 1.0,
"flood_events_1h": 0,
"read_only": false,
"dry_run": false
}
risk は ok(倍率 1×)、warning(≥2×)、high(≥8×)のいずれかです。
スロットル応答ヘッダー
すべての /api/... 応答に以下が含まれます:
X-Throttle-MultiplierX-Throttle-Flood-Events-1h- 各バケットの
X-RateLimit-Remaining-<bucket>
これにより、クライアントは /api/throttle/status をポーリングせずに、自身のスロットルを調整できます。
更新/Webhook
Telegram の受信イベント(新しいメッセージ、編集、削除、チャットアクション)を受け取る方法は 2 つあります:
WebSocket — /ws/updates
const ws = new WebSocket('ws://your-host:8080/ws/updates?token=YOUR_AUTH_KEY');
ws.onmessage = (e) => console.log(JSON.parse(e.data));
TELETHON_AUTH_KEY が設定されている場合は、?token= として渡してください。ブラウザーの WS クライアントでは Authorization ヘッダーを設定できないため、クエリー文字列を使用します。
複数のサブスクライバーに対応しており、それぞれに独自のキューが割り当てられます。処理が遅いコンシューマーでは、TELETHON_UPDATES_BUFFER_SIZE に達するとイベントが破棄されます。
アウトバウンド Webhook — TELETHON_POST_TO_URL
環境変数にエンドポイントを設定すると、すべてのイベントが JSON として POST されます。送信完了を待たずに処理されるため、Webhook の処理が遅い、または失敗しても、Telethon のループがブロックされることはありません。分散ワーカー、別プロセス、WS 接続を維持できない場合に使用してください。
イベントペイロードの形式
{
"type": "NewMessage",
"message": {
"id": 4242,
"date": "2026-04-29T12:00:00+00:00",
"text": "hi",
"out": false,
"sender_id": 12345,
"chat_id": -1001234567890,
"reply_to_msg_id": null,
"media": false,
"media_type": null
},
"chat_id": -1001234567890
}
MessageEdited、MessageDeleted、ChatAction では、同じ形式ですがフィールド数が少なくなります。
安全スイッチ
TELETHON_READ_ONLY=true
すべての書き込みエンドポイントが 403 を返します。読み取り、ステータス、メトリクスは引き続き使用できます。緊急時や、テスト用デプロイメントを無害な状態に保つためのキルスイッチです。
TELETHON_DRY_RUN=true
書き込みエンドポイントはリクエストを受け付けて検証しますが、Telegram は呼び出さず、{"dry_run": true, "would_...": {...}} を返します。本番環境に接続する前にスクリプトを検証するのに便利です。
MCP
ストリーミング可能な HTTP トランスポートを使用して /mcp/ にマウントされます。上記の表にあるすべてのツールが、同じ名前とスキーマの MCP ツールとして自動的に公開されます。
エージェントの接続先:
http://your-host:8080/mcp/
ステートレスで、すべてのリクエストは独立しており、セッション管理は不要です。Claude Desktop、カスタムエージェントなど、HTTP 経由で MCP を利用するものなら何にでも追加できます。すぐに使用できます。
エージェントとの連携
スキルは、.agents/skills/ を読み取るあらゆるエージェント(peen など)で動作し、以下のクライアントにはネイティブにインストールできます。
Claude Code
claude plugin marketplace add psyb0t/agents
claude plugin install telethon-plus@psyb0t
Claude Code では、telethon-plus サーバーの URL と、認証が有効な場合は Bearer トークンの入力を求められます。トークンは OS のキーチェーンに保存されます。
Codex
codex plugin marketplace add psyb0t/agents
codex plugin add telethon-plus@psyb0t
マーケットプレイスからインストールすると、スキルは $telethon-plus:telethon-plus として呼び出されます。また、.agents/skills/ を含むリポジトリでは、Codex がインストール不要でスキルを自動的に検出し、単に $telethon-plus として呼び出します。
OpenClaw
このスキルはリリースごとに ClawHub に公開されます:
openclaw skills install @psyb0t/telethon-plus
ローカル stdio で通信する MCP クライアント向けに、@psyb0t/telethon-plus プラグインがサービスの /mcp/ エンドポイントへのブリッジを提供します:
openclaw plugins install clawhub:@psyb0t/telethon-plus
次に、TELETHON_PLUS_URL を設定します(サーバーで認証が必要な場合は TELETHON_AUTH_KEY も設定します)。
開発
make build # build psyb0t/telethon-plus:latest
make build-test # build psyb0t/telethon-plus:latest-test
make run # run locally on :8080 (reads .env)
make login # interactive login — writes TELETHON_SESSION to .env automatically
make lint # flake8 + pyright
make format # isort + black
make test # run integration tests in Docker
make clean # remove built images
テスト
実際のテストです。実際の Telegram を使います。クソみたいなモックはありません。
tests/ はコンテナを起動し、実際のアカウントを使って REST と MCP の両方に大量のリクエストを送ります。メッセージは送信後に削除されます。何か問題があれば、すぐにわかります。
セットアップ:
cp .env.example .env
$EDITOR .env # needs TELETHON_API_ID, TELETHON_API_HASH, TELETHON_SESSION, TEST_CHAT
make test
TEST_CHAT はテストメッセージの送信先です。Saved Messages に送信するには me を使います。非公開で、あなた専用なので、ほかの人には見えません。Tools セクションにあるすべてのチャット参照形式が使えます。
make test は両方のイメージをビルドし、ソケットをマウントした状態で Docker 内で pytest を実行します。.env 以外にセットアップは必要ありません。認証情報がない場合、テストスイートは適切にスキップされます。
| テストファイル | テスト内容 |
|---|---|
test_health.py | コンテナの起動、認証の成功、OpenAPI 仕様にすべてのルートが含まれていること。 |
test_rest.py | バリデーションエラー、余分なフィールドの拒否、送信 → 編集 → 取得 → 削除の一連の処理、ダイアログ、エンティティの解決、公開チャンネルの読み取り、グループの作成/削除、参加者。 |
test_mcp.py | MCP ストリーミング可能 HTTP:ツールの検出、get_me、送信と削除の一連の処理、バリデーションエラーが isError として返されること。 |
test_auth.py | 認証ミドルウェア:トークンがない場合または誤っている場合に 401、正しいトークンの場合に 200、/healthz は常に公開、MCP エンドポイントも保護されていること。 |
ライセンス
WTFPL — 好きなようにやってください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。