mcpField
T
Telethon Plus

Telethon Plus

ローカル
github.com/psyb0tコミュニケーション51 週間前に更新

Telethon Plus について

Telethon Plusは、TelegramのユーザーアカウントをJSON HTTP APIとMCP経由で操作できるセルフホスト型サービスです。TelethonのMTProtoクライアントを使い、リクエスト制限とエンティティキャッシュを備えています。

主な機能

  1. 01HTTPとMCP経由でTelegramを操作
  2. 02メッセージの送受信と管理
  3. 03グループ、チャンネル、メンバーの管理
  4. 04リクエスト制限とエンティティキャッシュ
  5. 05WebSocketによる更新の配信

活用シーン

  1. 01チャットのメッセージを取得・整理
  2. 02チャットにテキストやメディアを送信
  3. 03チャンネルのメンバーや権限を管理
  4. 04Telegramのイベントをリアルタイム受信

MCP 対応

`/mcp`エンドポイントがTelegramアカウント操作をMCPクライアントに公開します。HTTP APIとツールレジストリを共有します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"psyb0t-telethon-plus": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"docker.io/psyb0t/telethon-plus:v0.5.7"
]
}
}
}
起動コマンドdocker run -i --rm docker.io/psyb0t/telethon-plus:v0.5.7

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
ocidocker.io/psyb0t/telethon-plus:v0.5.7

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

docker-telethon-plus

CI version license Docker Pulls

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いいえINFODEBUG、INFO、WARNING、ERROR
TELETHON_REQUEST_TIMEOUTいいえ60リクエストごとのタイムアウト(秒)
TELETHON_FLOOD_SLEEP_THRESHOLDいいえ60この秒数未満の FLOOD_WAIT エラーでは、自動的に待機します。Telegram からレート制限を受けることがあります。これが安全弁になります。
TELETHON_DEVICE_MODELいいえdocker-telethon-plusTelegram に認識されるデバイスの種類
TELETHON_SYSTEM_VERSIONいいえ1.0同様に OS のバージョン
TELETHON_APP_VERSIONいいえ1.0同様にアプリのバージョン
TELETHON_DOWNLOAD_DIRいいえ/tmp/telethon-plussend_file のアップロードに使う一時領域
TELETHON_AUTH_KEYいいえ""設定すると、すべてのエンドポイントで Authorization: Bearer <key> が必要になります。/healthz は認証不要のままです。空の場合、認証はありません。
スロットリングとキャッシュ(過剰なリクエストの防止)

Telegram は、過剰なリクエストを送るアカウントを禁止します。ここでのデフォルト値は、意識しなくてもサーバー側の制限を超えないよう、控えめに設定されています。仕組みを理解している場合にのみ調整してください。

変数デフォルト値機能
TELETHON_THROTTLE_ENABLEDtrue以下のすべてのレート制限を有効にするマスタースイッチ
TELETHON_THROTTLE_GLOBAL_INTERVAL_MS50送信リクエスト間に設ける最小間隔
TELETHON_THROTTLE_JITTER_MS200上乗せされるランダムな±ジッター(メトロノームのようなトラフィックパターンを防ぎます)
TELETHON_THROTTLE_PER_CHAT_INTERVAL_MS1100同じチャットへの送信間に設ける最小間隔(Telegram の「1 秒あたり 1 回/チャット」という上限に余裕を加えています)
TELETHON_THROTTLE_PER_CHAT_READ_INTERVAL_MS250同じチャットからの読み取り間に設ける最小間隔。単一チャンネルのスクレイピングが読み取り枠を独占するのを防ぎます。
TELETHON_THROTTLE_ADAPTIVEtrueFLOOD_WAIT が発生するたびに、1 時間、すべての待機時間を 2 倍にします。静かな状態が 1 時間続くとリセットされます。
TELETHON_BUCKET_RESOLVE_PER_MIN5resolveUsername の上限。アカウントが 22 時間の利用禁止を受ける主な原因です
TELETHON_BUCKET_GET_FULL_PER_MIN10getFullChannel/getFullUser/get_participants の上限
TELETHON_BUCKET_JOIN_PER_HOUR5チャンネル/グループへの参加回数の上限
TELETHON_BUCKET_CREATE_PER_HOUR5チャンネル/グループの作成回数の上限
TELETHON_BUCKET_SEND_PER_MIN20すべてのチャットを通じた送信回数の上限
TELETHON_BUCKET_READ_PER_MIN600読み取り操作の上限。ツール呼び出しごとではなく、サーバー側の API 呼び出しごとにカウントされます。get_messages(limit=300) は 3 枠を消費します(Telegram の GetHistory は 1 ページあたり最大 100 件です)。get_dialogs(limit=500) も同様に 5 枠を消費します。
TELETHON_CACHE_ENABLEDtrue解決済みのエンティティをディスクに保存します
TELETHON_CACHE_PATH/cache/entities.json再ビルド後もデータを保持するには、/cache をホストボリュームとしてマウントします
TELETHON_CACHE_TTL_SECONDS6048007 日間です。期限切れにしない場合は 0 に設定します。
TELETHON_FLOOD_SLEEP_THRESHOLD60Telethon の自動待機機能です。FLOOD_WAIT がこの秒数より短い場合は、その時間だけ待機します。これを超える場合はエラーを発生させます。エラーを発生させない場合は非常に大きな値(例:86400)に設定できますが、悪意のある FLOOD_WAIT が発生すると、その時間いっぱいプロセスがブロックされます。

各レイヤーの連携:

  1. エンティティキャッシュが resolveUsername の呼び出しを省略します。@somechannel の初回検索では Telegram に問い合わせますが、2 回目以降は枠を消費しません。/cache ボリュームにより、コンテナを再起動しても保持されます。
  2. メソッドごとのトークンバケットが、危険なメソッドの呼び出し数を制限します。1 分以内に新しいユーザー名を 6 件解決しようとすると、6 件目は最も古い枠が期限切れになるまで待機します。
  3. チャットごとの送信間隔制限により、各チャットへの送信を 1 秒あたり 1 回以下に抑えます(余裕を加えています)。
  4. 全体の間隔制限とジッターにより、トラフィック全体のパターンを人間らしくします。
  5. 適応型バックオフ: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
数値 ID123456789
スーパーグループ/チャンネル 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/entitieschatユーザー名/ID/リンクからプロフィールを解決します。
POST /api/entities/bulkchatsユーザー名解決のバケット制限に従って、一括で解決します。
GET /api/dialogs—ダイアログの一覧を取得します。オプション:limit、archived、search(タイトル/@の部分一致)。
GET /api/messageschat最近のメッセージを読み込みます。オプション:limit、offset_id、search。
GET /api/messages/{id}chat単一のメッセージを取得します。
GET /api/messages/{id}/mediachat添付ファイルを生バイト列(バイナリストリーム)としてダウンロードします。Telegram の Content-Type と Content-Disposition: attachment; filename=... を返します。オプション:max_bytes。MCP クライアントでは、base64 を返す download_media ツールを使用してください。
POST /api/messageschat、text または file_urlメッセージを送信します。file_url がある場合、取得してメディアとして送信します(text はキャプションとして使用)。それ以外の場合は text を送信します。オプション:parse_mode、reply_to、silent、link_preview、schedule、force_document、max_bytes。
POST /api/messages/forwardfrom_chat、to_chat、message_idsメッセージを転送します。
POST /api/messages/readchat既読にします。オプション:max_id。
PATCH /api/messages/{id}chat、text編集します。
DELETE /api/messageschat、message_ids一括削除します(リクエスト本文にリストを指定)。
POST /api/messages/{id}/pinchatピン留めします。オプション:silent、pm_oneside。
POST /api/messages/{id}/unpinchatピン留めを解除します。
POST /api/messages/{id}/reactionschat、emojiリアクションを付けます。オプション:big。
DELETE /api/messages/{id}/reactionschat自分のリアクションを削除します。
GET /api/participantschatメンバーの一覧を取得します。オプション:limit、search。
POST /api/chatstitleスーパーグループまたはチャンネルを作成します。
DELETE /api/chatschat所有するスーパーグループ/チャンネルを削除します(リクエスト本文に指定)。
POST /api/chats/joinchat公開チャンネル/グループに参加します。
POST /api/chats/inviteinvite非公開の t.me/+hash を使って参加します。
POST /api/chats/leavechat退出します。
GET /api/chats/{chat}/linked—チャンネルにリンクされたディスカッショングループを解決します。
POST /api/chats/{chat}/admin/banuserユーザーを BAN します。オプション:until_seconds。
POST /api/chats/{chat}/admin/unbanuserBAN を解除します。
POST /api/chats/{chat}/admin/kickuserキックします(BAN して即座に解除)。
POST /api/chats/{chat}/admin/promoteuser管理者権限を付与します。オプションで title を指定できます。
POST /api/chats/{chat}/admin/demoteuser管理者権限を剥奪します。
POST /api/pollschat、question、options投票を作成します。オプション:quiz、correct_option、solution。
POST /api/polls/{id}/votechat、options投票します(インデックスは 0 始まり)。
GET /api/polls/{id}/resultschat現在の投票数を取得します。
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
パラメーター型デフォルト説明
limitint20ダイアログの件数(1~200)
archivedboolfalseアーカイブ済みチャットを含めるかどうか
[
  {
    "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
パラメーター型デフォルト説明
chatstring必須読み取るチャット
limitint20メッセージ数(1~200)
offset_idint0このメッセージ ID から開始します(ページネーション)
searchstring—全文検索フィルター
[
  {
    "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
}
フィールド型デフォルト説明
chatstring必須送信先のチャット
textstringfile_url がない場合は必須メッセージのテキストまたはキャプション(1~4096 文字)
file_urlstringnullメディアとして取得・送信する HTTPS URL。Telegram は拡張子/MIME からメディアの種類を自動選択します。force_document で上書きできます。
parse_modestringnullmd / markdown / html / null
reply_tointnull返信先のメッセージ ID
silentboolfalse通知なしで送信します
link_previewbooltrueリンクプレビューを表示します(テキストのみ)
schedulestringnull送信を予約する将来の ISO 日時
force_documentboolfalseファイル送信時に、Telegram に選択させず汎用ドキュメントとして送信します
max_bytesint52428800ファイル送信時に、このサイズを超えるファイルを拒否します(最大 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"
}
フィールド型デフォルト説明
chatstring必須メッセージを含むチャット
textstring必須新しいテキスト(1~4096 文字)
parse_modestringnullmd / html / null
link_previewbooltrueリンクプレビューを表示します
{
    "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
}
フィールド型デフォルト説明
chatstring必須メッセージを含むチャット
message_idslist[int]必須削除する ID(最大 100 件)
revokebooltrue自分だけでなく全員から削除します
{ "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_chatstring必須転送元のチャット
to_chatstring必須転送先のチャット
message_idslist[int]必須転送する ID(最大 100 件)
silentboolfalse通知なしで転送します
[
  {
    "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 }
フィールド型デフォルト説明
chatstring必須既読にするチャット
max_idint0このメッセージ ID までを既読にします。0 = すべて既読にします。
{ "ok": true }
GET /api/participants

グループまたはチャンネルのメンバーを一覧表示します。

GET /api/participants?chat=-1001234567890&limit=50&search=john
パラメーター型デフォルト説明
chatstring必須グループまたはチャンネル
limitint100返すメンバーの最大数(1~1000)
searchstring—名前で絞り込みます
[
  { "id": 123456789, "type": "User", "username": "johndoe", "first_name": "John" }
]

大規模な公開チャンネルでは、返されるメンバーが限られる場合や、管理者権限が必要な場合があります。

POST /api/chats

スーパーグループまたはブロードキャストチャンネルを作成します。

POST /api/chats
Content-Type: application/json

{ "title": "my-group", "megagroup": true }
フィールド型デフォルト説明
titlestring必須グループ名(1~255 文字)
megagroupbooltruetrue = スーパーグループ、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 }
エラー
ステータス発生条件
400JSON が不正、検証に失敗、または Telethon が入力を無効と判断しました。詳細は本文に記載されています。
401Bearer トークンがない、または正しくありません(TELETHON_AUTH_KEY が設定されている場合のみ)。
404不明なエンドポイントです。
502Telegram が 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 / _entries
  • telethon_plus_throttle_multiplier
  • telethon_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-Multiplier
  • X-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.pyMCP ストリーミング可能 HTTP:ツールの検出、get_me、送信と削除の一連の処理、バリデーションエラーが isError として返されること。
test_auth.py認証ミドルウェア:トークンがない場合または誤っている場合に 401、正しいトークンの場合に 200、/healthz は常に公開、MCP エンドポイントも保護されていること。

ライセンス

WTFPL — 好きなようにやってください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。