ghostpaw-telegram
Provides tools for operating a Telegram bot: queries a local mirror of messages, chats, users, reactions, edit history, and reply chains; sends, edits, deletes, forwards, pins, and broadcasts messages; manages members (ban, unban, restrict, promote, kick); and retrieves stored file blobs and bot statistics.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ghostpaw-telegramsearch my Telegram messages for anything mentioning "refund""
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@ghostpaw/telegram
Telegram bot channel engine — fetch transport with zero runtime dependencies, SQLite message mirror with FTS5 full-text search, eager file BLOB storage, markdown rendering, and a structured LLM tool facade.
Every incoming update is mirrored into a local SQLite database before your handler runs, giving you a persistent, queryable record of everything the bot sees — including the raw bytes of every photo, document, voice message, and video, downloaded and stored immediately on receipt. It ships as a single prebundled blob designed for two audiences at once: human developers building bot backends in code, and LLM agents operating through a structured tool facade.
MCP server
Every client below starts the same stdio server: npx -y @ghostpaw/telegram mcp.
Messages live in ~/.ghostpaw/telegram.db unless the GHOSTPAW_TELEGRAM_DB
environment variable (absolute path) or --db <path> says otherwise.
Claude Code
claude mcp add ghostpaw-telegram -- npx -y @ghostpaw/telegram mcpor as a plugin, which also installs the skill:
/plugin marketplace add GhostPawJS/telegram
/plugin install ghostpaw-telegram@ghostpaw-telegramCodex CLI (~/.telegram/config.toml)
[mcp_servers.ghostpaw-telegram]
command = "npx"
args = ["-y", "@ghostpaw/telegram", "mcp"]Cursor (.cursor/mcp.json), Claude Desktop (claude_desktop_config.json)
or a project .mcp.json:
{
"mcpServers": {
"ghostpaw-telegram": {
"command": "npx",
"args": ["-y", "@ghostpaw/telegram", "mcp"]
}
}
}Claude Desktop users can also install server.mcpb from the
latest GitHub release.
A Dockerfile is included for container hosts:
docker build -t ghostpaw-telegram . && docker run -i --rm -v telegram:/data ghostpaw-telegram.
The server speaks MCP 2026-07-28 (stateless, server/discover) and the
initialize-based revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05.
Set TELEGRAM_BOT_TOKEN in the server environment to execute send and moderation actions.
Without a token, these tools return plans; local reads and tool discovery work offline.
The .mcp.json token placeholder must be supplied by the client environment.
The server reads the mirror populated by your library transport; it does not poll for updates.
Related MCP server: tdlib-mcp-server
CLI
npx -y @ghostpaw/telegram tools
npx -y @ghostpaw/telegram call tg_read '{"subcommand":"list_chats"}'
npx -y @ghostpaw/telegram --db :memory: call tg_send '{"subcommand":"send_message","chatId":123,"text":"Hello"}'The send example returns a plan unless TELEGRAM_BOT_TOKEN is set.
Agent Skill
SKILL.md and skills/telegram/ ship in the package. Print the skill with
npx -y @ghostpaw/telegram skill or copy skills/telegram/ into your skills folder.
Install
npm install @ghostpaw/telegramRequires Node.js 24+ (uses the built-in node:sqlite module).
Quick Start
import { DatabaseSync } from 'node:sqlite';
import { createBot, initTelegramTables } from '@ghostpaw/telegram';
const db = new DatabaseSync('bot.db');
initTelegramTables(db);
const bot = createBot({
token: process.env.TELEGRAM_TOKEN!,
db,
onMessage: async ({ message, user }) => {
console.log(user?.firstName, message.text);
},
});
await bot.start(); // long-pollingWebhook mode — pass a webhook config instead:
const bot = createBot({
token: process.env.TELEGRAM_TOKEN!,
db,
webhook: { path: '/webhook', port: 8443, secretToken: process.env.TG_SECRET },
onMessage: async ({ message, user }) => { /* ... */ },
});
await bot.start(); // listens on port 8443What It Stores
Every update is mirrored into SQLite before your handler runs:
Messages — text, media, edits, reply edges, albums, threads (FTS5 full-text index with Unicode diacritic folding)
Users — first name, last name, username, language code
Chats — title, type, member count, forum flag
Members — status, permissions, admin title per chat
Reactions — emoji per user per message, with per-emoji counts and event log
Files — metadata + raw bytes stored as BLOB, SHA-256 deduplicated; downloaded eagerly on receipt
Callbacks — inline button presses with data and answered state
Bot state — arbitrary key/value store and running statistics
All eight tables are created in one call: initTelegramTables(db).
Two Audiences
Human developers
Use the read, write, and network namespaces for direct-code access to every domain operation:
import { read, write, network } from '@ghostpaw/telegram';
// query the local mirror — no network calls
const chat = read.getChat(db, chatId);
const messages = read.listMessages(db, { chatId, limit: 50 });
const results = read.searchMessages(db, chatId, 'invoice');
const chain = read.replyChain(db, chatId, messageId);
// retrieve a stored file blob
const bytes = write.getFileBlob(db, fileId); // Buffer | null
// send text and media
await write.sendMessage(bot.client, chatId, 'Hello');
await write.sendPhoto(bot.client, chatId, fileId);
await write.sendDocument(bot.client, chatId, buffer, { caption: 'Report' });
await write.broadcast(bot.client, chatIds, 'Announcement');
// streaming — progressive in-place edits
const stream = write.createStream(bot.client, { chatId });
await stream.append('Thinking...');
await stream.replace('Done.');See docs/HUMAN.md for the full human-facing guide with worked examples.
LLM agents
Use the tools, skills, and soul namespaces for a structured runtime surface:
import { tools, skills, soul } from '@ghostpaw/telegram';
// 4 JSON-schema tools with structured ToolResult responses
const allTools = tools.telegramTools;
const readTool = tools.getTelegramToolByName('tg_read');
const result = readTool?.handler(db, { subcommand: 'search_messages', chatId, query: 'invoice' });
// 6 workflow playbooks for common multi-step scenarios
const allSkills = skills.telegramSkills;
// Herald persona for system prompts
const prompt = soul.renderTelegramSoulPromptFoundation();Every tool returns a discriminated result with outcome: 'success' | 'no_op' | 'error', structured data, and next-step hints. No thrown exceptions to parse.
See docs/LLM.md for the full AI-facing guide covering soul, tools, and skills.
Package Surface
Export | Role |
| One-shot DDL — call once at startup |
| Full bot composition with built-in fetch transport; polling or webhook |
| Bridge a raw grammy |
| Query the local SQLite mirror (no network) |
| Send messages, media, and actions; manage file BLOBs |
| Build inline keyboards and callback buttons |
| Manage polling and update dispatch |
| Pure markdown and text transformation |
| 4 JSON-schema tools for LLM agents |
| 6 workflow playbooks for LLM agents |
| Herald persona for system prompts |
| Tuneable runtime constants |
Tools
Tools return plans by default; existing synchronous handlers perform no outbound actions. To execute send and moderation actions, create an async facade explicitly:
const facade = tools.createTelegramToolFacade({
client: bot.client,
execute: true,
perChatPerSecond: 1,
globalPerSecond: 30,
maxRetries: 2,
});
const result = await facade.handler(db, 'tg_send', {
subcommand: 'send_message', chatId: 123, text: 'Hello',
});Omit execute to retain plan-only behavior. Execution reuses the outbound
executors, returns the shared result shape with action data and sent message
IDs where applicable, and masks bot tokens in errors. Capacity-one token buckets
limit each API call per chat and globally; Telegram 429 retry_after responses
pause retries, with two retries by default. Limits apply per facade instance;
reuse one facade for callers sharing a bot. Partial execution can occur when a
multi-call action fails (for example, kick bans then unbans).
Four tools shaped around operator intent:
Tool | What it does |
| Query messages, chats, users, reactions, edit history, reply chains |
| Send, edit, delete, forward, pin messages; set reactions; broadcast |
| Ban, unban, restrict, promote, kick users; query member status |
| Get bot stats, read bot state, list active chats |
Each tool exports runtime metadata — name, description, JSON Schema, side-effect level, readOnly flag — so agent harnesses can wire them without reading docs.
Skills
Six workflow playbooks as markdown strings:
Skill | Workflow |
| Read context, reply, pin, track threads and albums |
| Detect violations, warn, restrict, ban with audit trail |
| Promote, demote, migrate, configure permissions |
| Compose, send, handle errors, retry failed chats |
| Full-text search, reply chains, edit history |
| Debounced streaming with overflow and error recovery |
Documentation
Document | Audience |
Human developers using the | |
Agent builders wiring tools, skills, and soul | |
Advanced UI/UX patterns: streaming, approval flows, pagination | |
Architecture overview: storage model, surfaces, invariants | |
Per-entity manuals with exact public API listings |
The package has zero runtime dependencies. It uses Node 24 global fetch for Bot API requests and an in-repo synchronous Markdown parser. grammy and marked are development dependencies used for compatibility tests.
createBot accepts optional api: { fetch, apiRoot } settings for an injected
fetch implementation or a custom Bot API endpoint. The default endpoint is
https://api.telegram.org.
adaptBot continues to accept grammy Bot instances. Calls without uploads use
api.raw; file uploads use the built-in client, so grammy API transformers do
not apply to uploads. Its optional second argument accepts { fetch, apiRoot }.
Development
npm install
npm test # node:test runner
npm run typecheck # tsc --noEmit
npm run lint # biome check
npm run build # ESM + CJS + declarations via tsup
npm run test:dist # built artifact checks (after build)
npm run check:deps # verify zero runtime dependenciesThe repo is pinned to Node 24.14.0 via Volta. Use whichever version manager you prefer.
Support
If this package helps your project, consider sponsoring its maintenance:
This server cannot be deployed
Maintenance
Related MCP Connectors
Multi-tenant Telegram gateway for AI agents — HTTP+stdio, 8 tools, MTProto User API
Telegram bridge for your MCP-compatible agent. Bidirectional, no LLM in our stack.
Memory, reflection and safety for AI agents. Hosted or local, no vector database.
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI agents to send and receive messages, media, and files on Telegram, and manage chats via a bot token.1747 PyPIMIT
- FlicenseNot gradedqualityDmaintenanceConnects AI agents to Telegram via the official TDLib library, enabling tools like getting user info, listing dialogs, and searching messages.-
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to search and act on Telegram conversations, groups, channels, files, and links, with semantic search, AI-powered knowledge extraction, human-in-the-loop approvals, and PostgreSQL/pgvector persistence.Apache 2.0
- AlicenseBqualityCmaintenanceLets coding agents browse a personal Telegram account locally, retrieving per-chat text history and conversations or outgoing messages by date via QR login, read-only unless message sending is explicitly enabled. API credentials from Telegram are required, and access can be restricted to specific numeric chat IDs.3MIT