关于 using-mtcute
using-mtcute 是帮助 TypeScript 开发者使用 mtcute 的技能;mtcute 是面向 Telegram 原生 MTProto API 的类型安全库。它介绍平台包选择、客户端方法、更新处理,以及查询 API 类型和签名的内置工具。
主要功能
- 01选择适合目标平台的 mtcute 包
- 02配置 Telegram 客户端认证与生命周期
- 03使用高级方法操作 Telegram API
- 04通过 Dispatcher 路由更新
- 05查询方法、类和 TL 定义
适用场景
- 01构建 TypeScript Telegram 客户端
- 02实现消息与更新处理
- 03查找高级方法或原始 TL 调用签名
MCP 相关
README 提到可选用 Context7 MCP 查阅 mtcute 文档;未描述 MCP 服务或客户端实现。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mtcute/ mtcute --skill using-mtcute安装后在 Claude Code 中输入/using-mtcute确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
tools/get-class.jsget-constructor.jsget-method.js详细介绍
mtcute — TypeScript MTProto 库
什么是 mtcute?
mtcute 是一个现代、类型安全的 TypeScript 库,用于 Telegram 的 MTProto 协议。与 Bot API 封装库(grammy、telegraf、node-telegram-bot-api)不同,mtcute 直接使用 Telegram 原生二进制协议,因此可以访问 完整的 Telegram API,而不仅仅是机器人 API 子集。
架构概览
核心包(你可能不会直接使用这些包):
- @mtcute/core:MTProto 客户端、高级方法、TL 架构、类型
- @mtcute/html-parser:HTML ↔ Telegram 实体
- @mtcute/markdown-parser:Markdown ↔ Telegram 实体
- @mtcute/file-id:Bot API file_id 解析
平台包(使用与你的目标平台相匹配的包):
- @mtcute/node、@mtcute/bun、@mtcute/deno:服务端 JavaScript 的运行时绑定
- @mtcute/web:浏览器绑定(IndexedDB、WebCrypto、WebSocket)
额外包(仅在需要其涵盖的特定功能时使用):
- @mtcute/dispatcher:更新路由、过滤器、机器人框架
- @mtcute/convert:从其他库导入会话
- @mtcute/test:单元测试辅助工具
始终从平台包安装并导入所有内容,而不是从 @mtcute/core 导入:
// ✅ Correct — platform package pre-configures crypto, transport, storage
import { TelegramClient } from '@mtcute/node'
// ❌ Wrong — raw core client requires manual platform setup
import { TelegramClient } from '@mtcute/core'
基本用法
创建客户端
import { TelegramClient } from '@mtcute/node'
const tg = new TelegramClient({
apiId: Number(process.env.API_ID),
apiHash: process.env.API_HASH,
storage: 'my-account', // SQLite file name (Node.js)
})
客户端生命周期
创建 TelegramClient 时,它会处于 disconnected 状态。
大多数情况下,你可以使用 start 方法来连接并验证身份:
// Bot login
const self = await tg.start({ botToken: process.env.BOT_TOKEN })
// User login (interactive)
const self = await tg.start({
phone: () => input('Phone: '),
code: () => input('Code: '),
password: () => input('2FA password: '),
})
不过,在某些情况下,你可能需要手动控制生命周期:
// Manually connect
await tg.connect()
// Manually disconnect
await tg.disconnect()
// Disconnect and destroy the instance
await tg.destroy()
调用高级方法
TelegramClient 类提供了 300 多个高级便捷方法。下面列出了一些最常用的方法:
- 消息:
sendText、sendMedia、getHistory、editMessage、deleteMessages、forwardMessages、searchMessages,…… - 聊天:
getChat、getChatMember、banChatMember、setChatTitle、setChatPhoto,…… - 用户:
getUsers、getMe、setMyProfilePhoto,…… - 文件:
downloadFile、uploadFile、downloadAsStream,…… - 对话:
getDialogs、getPeerDialogs,…… - 机器人:
answerInlineQuery、answerCallbackQuery、setMyCommands,…… - 论坛:
createForumTopic、editForumTopic,…… - 贴纸:
getStickerSet、createStickerSet,…… - 故事:
sendStory、getStories,…… - 身份验证:
start、logOut、sendCode,…… - 密码:
enable2fa、change2fa,……
// Send a text message
await tg.sendText('me', 'Hello!')
// Send with formatting
await tg.sendText(chatId, html`Hello, <b>${name}</b>!`)
// Send media
await tg.sendMedia(chatId, {
type: 'photo',
file: 'file:./photo.jpg', // note the file: prefix!
caption: 'Check this out',
})
// Get chat info
const chat = await tg.getChat('username')
// Download file
await tg.downloadToFile('path/to/save.jpg', photo)
有些方法还有对应的“批量”版本,接受数组而不是单个参数:
const durov = await tg.getUser('durov')
const [durov, telegram] = await tg.getUsers(['durov', 'telegram'])
// Similarly with `getChat` and `getChats`, `getPeer` and `getPeers`
不要混淆这两类方法。如果方法名是复数,它很可能会返回和/或接受数组,请牢记这一点。
Peer 解析
mtcute 的高级方法接受 InputPeerLike 作为聊天/用户参数,它可以是:
- 数字 ID:
123456789 - 用户名字符串:
'username' - 表示当前用户的
'me'/'self' tl.TypeInputPeer对象- 高级对象(
User、Chat、Message等)
使用 Dispatcher 处理更新
import { Dispatcher, filters } from '@mtcute/dispatcher'
const dp = Dispatcher.for(tg)
dp.onNewMessage(filters.chat('private'), async (msg) => {
await msg.replyText('Hello!')
})
dp.onNewMessage(filters.command('start'), async (msg) => {
await msg.replyText('Welcome!')
})
dp.onCallbackQuery(filters.dataPrefix('btn_'), async (query) => {
await query.answer({ text: 'Clicked!' })
})
// Start receiving updates
await tg.startUpdatesLoop()
原始 TL 方法调用
对于高级 API 未封装的方法,请使用 .call():
const result = await tg.call({
_: 'messages.getEmojiKeywords',
langCode: 'en',
})
// result is fully typed based on the method's return type
TL 类型系统
mtcute 根据 Telegram 的 TL 架构生成 TypeScript 类型。所有类型都位于 tl 命名空间下:
import { tl } from '@mtcute/core'
| TL 概念 | TypeScript 名称 | 示例 |
|---|---|---|
对象 user | tl.RawUser | { _: 'user', id: number, ... } |
带命名空间的对象 messages.chats | tl.messages.RawChats | |
方法 users.getUsers | tl.users.RawGetUsersRequest | |
| 联合类型 | tl.TypeUser | tl.RawUser | tl.RawUserEmpty |
每个 TL 对象都有一个 _ 判别字段,其值为构造函数名称(例如 _: 'user')。
提供了类型守卫:tl.isAnyPeer()、tl.isAnyMessage() 等。
完整的 TL 架构以 JSON 格式提供,路径为 @mtcute/node/tl/api-schema.json(或任意平台包)。格式如下:
{
"l": 223, // layer number
"e": [ // array of TL entries
{
"kind": "class" | "method",
"name": "user",
"id": 826896937, // constructor ID
"type": "User", // return/union type
"arguments": [{
"name": "id",
"type": "int53", // base type name (union or primitive)
"typeModifiers"?: {
"predicate"?: "flags.0", // conditional field, e.g. "flags.3"
"isVector"?: true, // optional: when true, type is actually Vector<type>
}
}, ...],
"comment": "..."
},
...
],
"u": { "User": "..." } // union comments
}
当设置了 typeModifiers.predicate(例如 "flags.3")时,该字段为可选字段,且仅当 flags 字段的第 3 位设为 1 时才会出现。isVector 为 true 时,实际类型为 Vector<type>。
查找类型和方法签名
三个内置工具会从 node_modules 中已安装的 @mtcute/* 包读取信息。它们都支持模糊匹配,并能自动纠正拼写错误。
何时使用哪个工具:
- 需要原始 TL 类型/方法定义或其 TS 接口 →
get-constructor - 需要高级客户端方法签名(参数、返回类型、JSDoc)→
get-method - 需要高级封装类/接口定义(Message、Chat 等)→
get-class - 需要了解原始 API 调用所需的 TL 参数 →
get-constructor --with-references - 不确定该使用哪个方法/类 →
get-method --search或get-class --search
get-constructor:查找 TL 架构
显示 TL 定义、TypeScript 类型、联合类型成员,以及返回类型。
node .claude/skills/using-mtcute/tools/get-constructor.js <name>
node .claude/skills/using-mtcute/tools/get-constructor.js --with-references <name>
接受以下任意格式的输入:
- TL 名称:
user、messages.sendMessage - TS 类型名称:
RawUser、TypeInputUser、tl.messages.RawChats、messages.RawGetHistoryRequest
需要了解构造函数参数或返回类型引用的类型时,请使用 --with-references;该参数会将所有被引用的构造函数/联合类型追加到输出中。
get-method:查找高级客户端方法
显示 TelegramClient 中完整的 JSDoc 和方法签名。
node .claude/skills/using-mtcute/tools/get-method.js <method-name>
node .claude/skills/using-mtcute/tools/get-method.js --search <keyword>
node .claude/skills/using-mtcute/tools/get-method.js --list
- 默认模式:精确/模糊匹配方法名称;无匹配时,依次回退到名称和描述中的子字符串匹配
--search:同时搜索方法名称和描述,并列出所有匹配项--list:打印所有可用方法及其单行描述
get-class:查找高级类型/类
显示 highlevel/types/ 中包含所有成员的完整类/接口/类型定义。
node .claude/skills/using-mtcute/tools/get-class.js <name>
node .claude/skills/using-mtcute/tools/get-class.js --no-members <name>
node .claude/skills/using-mtcute/tools/get-class.js --search <keyword>
node .claude/skills/using-mtcute/tools/get-class.js --list
- 默认模式:精确/模糊匹配导出名称,并显示包含所有成员的完整定义
--no-members:仅显示声明行和 JSDoc,不显示主体--search:同时搜索名称和描述,并列出所有匹配项(例如--search keyboard)--list:打印所有可用导出项及其单行描述
高级类型
mtcute 会将原始 TL 对象封装为带有辅助方法的便捷类:
Message— 封装tl.RawMessage,提供.replyText()、.editText()、.delete()、.forward()等方法Chat— 封装频道/群组/用户聊天信息User— 封装tl.RawUserDocument、Photo、Video、Audio、Voice、Sticker— 媒体类型InlineQuery、CallbackQuery、ChatJoinRequest— 更新类型
这些类型位于 node_modules/@mtcute/core/dist/highlevel/types/ 中。
文本格式化
mtcute 支持使用带标签的模板字面量进行格式化:
import { html, md } from '@mtcute/node'
await tg.sendText(chat, html`<b>Bold</b> and <i>italic</i>`)
await tg.sendText(chat, md`**Bold** and *italic*`)
插入变量时,html 和 md 标签会自动进行转义。
常见模式
错误处理
import { tl } from '@mtcute/node'
try {
await tg.sendText(chatId, 'hello')
} catch (e) {
if (tl.RpcError.is(e, 'FLOOD_WAIT_%d')) {
console.log(`Rate limited, wait ${e.seconds}s`)
}
}
发送媒体
import { InputMedia } from '@mtcute/node'
// Upload from path (note the file: prefix!)
await tg.sendMedia(chatId, InputMedia.document('file:/path/to/file.pdf', {
fileName: 'report.pdf',
}))
// Upload from buffer/stream
await tg.sendMedia(chatId, InputMedia.photo(buffer))
// Upload from URL
await tg.sendMedia(chatId, InputMedia.photo('https://example.com/image.jpg'))
键盘
import { BotKeyboard } from '@mtcute/node'
// Inline keyboard
await tg.sendText(chatId, 'Pick one:', {
replyMarkup: BotKeyboard.inline([
[BotKeyboard.callback('Yes', 'btn_yes'), BotKeyboard.callback('No', 'btn_no')],
[BotKeyboard.url('Docs', 'https://mtcute.dev')],
]),
})
// Reply keyboard
await tg.sendText(chatId, 'Choose:', {
replyMarkup: BotKeyboard.reply([
[BotKeyboard.text('Option A'), BotKeyboard.text('Option B')],
]),
})
分页/迭代
许多方法都有对应的 iter* 方法,返回 AsyncIterableIterator:
// Iterate over chat history
for await (const msg of tg.iterHistory(chatId, { chunkSize: 100 })) {
console.log(msg.text)
}
// Iterate over search results
for await (const msg of tg.iterSearchMessages({ query: 'hello', chatId })) {
console.log(msg.id)
}
// Non-iter methods return paginated results with a `.next` cursor
const page = await tg.getHistory(chatId, { limit: 50 })
const nextPage = await tg.getHistory(chatId, { limit: 50, offset: page.next })
客户端事件
客户端通过 Emitter 实例提供连接生命周期和错误事件。使用 .add() 订阅,使用 .remove() 取消订阅:
// Connection state: 'offline' | 'connecting' | 'updating' | 'connected'
// 'updating' means connected but catching up on missed updates
tg.onConnectionState.add((state) => {
console.log('Connection:', state)
})
// Unhandled errors (if no listener, errors are logged to console)
tg.onError.add((err) => {
console.error('Error:', err)
})
// Raw TL updates (before dispatcher processing)
tg.onRawUpdate.add((update) => { ... })
代理/自定义传输(Node.js)
import { TelegramClient } from '@mtcute/node'
import {
HttpProxyTcpTransport,
SocksProxyTcpTransport,
MtProxyTcpTransport,
proxyTransportFromUrl,
} from '@mtcute/node'
const tg = new TelegramClient({
// or parse from URL (socks4/5, http, https, mtproto):
transport: proxyTransportFromUrl('socks5://user:[email protected]:1080'),
})
延伸阅读
完整文档和便于大模型阅读的参考资料:https://mtcute.dev/llms.txt。
如果可以使用 Context7 MCP,请优先使用它,而不是手动获取文档。库 ID 为 /mtcute/mtcute。