Telegram Automation Engine with AI agent integration
1.7K
A production-grade Telegram automation platform with AI agent integration, multi-account orchestration, and intelligent background job processing.
The Telegram Automation Engine or simply Tele was designed to bridge a critical gap in the Telegram automation ecosystem: the need for an enterprise-grade platform that seamlessly integrates traditional Telegram bot operations with modern AI agent capabilities.
While numerous Telegram tools exist for basic automation, they typically suffer from:
| Limitation | Our Solution |
|---|---|
| Single-account constraints | Multi-account orchestration with automatic failover and health monitoring |
| No AI integration | Model Context Protocol (MCP) exposes full engine capabilities to AI agents like Claude & GPT |
| No scalable bulk operations | Background job processing with MySQL, Redis, or in-memory queue backends |
| Poor member targeting | Custom Filter DSL ā a domain-specific language for precise member filtering |
| Manual session management | Database-persisted sessions with automatic access hash caching across restarts |
Our standout innovation. The engine exposes its full capabilities through the Model Context Protocol, enabling AI agents to programmatically control Telegram operations ā transforming it from a simple automation tool into an AI-powered orchestration platform.
--mcp: Stdio transport for direct AI agent integration (Claude, GPT, etc.)--mcp-http: HTTP transport for web-based AI agent connectionsManage dozens of Telegram accounts simultaneously with enterprise-grade reliability:
Telegram's MTProto requires access hashes for efficient peer communication. Our engine:
PEER_ID_INVALID errorsA powerful domain-specific language for precise member targeting:
firstname~A,batch=50
active=false,group=mychannel
lastseen>30d,withusername=true
Supports operators: =, !=, ~ (contains), >, <, >=, <=
Long-running operations run asynchronously with full lifecycle management:
pending ā running ā completed / failedExport filtered member data with background job support, ready for integration with external analytics tools.
The project follows a feature-based architecture with clean separation of concerns:
Tele/
āāā Features/ # Business logic by feature
ā āāā Api/ # REST API controllers
ā āāā BulkAdding/ # Bulk join members to channels
ā āāā BulkSending/ # Bulk message delivery
ā āāā Exporting/ # Member data export
ā āāā Mcp/ # MCP AI agent integration layer
ā āāā Scraping/ # Channel member scraping
ā āāā TelegramBot/ # Interactive bot (keyboards, states, actions)
ā āāā TelegramClient/ # MTProto client wrapper with access hash mgmt
āāā Infrastructure/ # Cross-cutting concerns
ā āāā Database/ # EF Core context, DAOs, models
ā āāā Extensions/ # DI service registration
ā āāā Middleware/ # API key authentication
ā āāā Queue/ # Job queue (MySQL, Redis, Memory)
āāā Shared/ # Shared models, enums, utilities
āāā Models/ # Config, MemberFilter, FilterCondition
| Decision | Rationale |
|---|---|
| Feature-based folders | Each feature is self-contained with its own services, requests, and handlers ā easy to extend without touching unrelated code |
| Separated Infrastructure | Database, queue, middleware, and DI registration are decoupled from business logic |
| Polymorphic job queue | IJobQueue interface with MySQL, Redis, and In-Memory implementations ā swap backends via config |
| DAOs over direct DbContext | Database access is abstracted behind interfaces for testability |
| Background worker pattern | QueueWorker as a hosted service processes jobs asynchronously without blocking the API |
| SHA256 bot reply verification | Bot responses are hashed for secure state machine matching |
| Component | Technology |
|---|---|
| Runtime | .NET 9.0 with C# 13 |
| Telegram MTProto Client | WTelegramClientā |
| Telegram Bot API | Telegram.Botā |
| ORM | Entity Framework Core with MySQL (Pomelo) |
| AI Integration | Model Context Protocol (.NET SDK) |
| Job Queue | MySQL / Redis (Upstash-compatible) / In-Memory |
| API Documentation | Swagger / OpenAPI |
| Configuration | YAML via YamlDotNet |
| Logging | Serilog (console + rolling file) |
| Containerization | Docker (multi-stage build) |
| CI/CD | GitHub Actions |
git clone https://github.com/srckod/tele.git
cd tele
dotnet restore
dotnet build
Copy config.yaml.example to config.yaml and fill in your credentials:
ActiveMode: "Test"
Brand:
BotName: "My Automation Bot"
Test:
ApiToken: "your_bot_token"
DBHost: "localhost"
DBName: "telegram_automation"
DBUser: "root"
DBPassword: "your_password"
AppId: 12345678
AppHash: "your_app_hash"
AppPhone: "+1234567890"
# Queue backend: "redis", "mysql", or "memory"
QueueType: "memory"
Admins:
your_username: 123456789
AutomationAPIKey: "generate-a-secure-api-key"
# Normal mode (Telegram Bot + REST API)
dotnet run
# MCP stdio mode (AI agent integration)
dotnet run -- --mcp
# MCP HTTP mode (web-based AI agents)
dotnet run -- --mcp-http
Pre-built single-file executables are available from the GitHub Releasesā page:
| Platform | File | Architecture |
|---|---|---|
| Windows | Tele-win-x64.zip | x64 |
| Linux | Tele-linux-x64.tar.gz | x64 |
| macOS (Intel) | Tele-osx-x64.tar.gz | x64 |
| macOS (Apple Silicon) | Tele-osx-arm64.tar.gz | ARM64 |
Tele-win-x64.zip from the latest releaseconfig.yaml file next to Tele.exe (same directory)Tele.exe
Need a config template? Download
config.yaml.examplefrom the repositoryā , rename it toconfig.yaml, and fill in your credentials.
# Download and extract
wget https://github.com/srcKod/tele/releases/latest/download/Tele-linux-x64.tar.gz
tar -xzf Tele-linux-x64.tar.gz
cd linux-x64
# Copy your config.yaml next to the executable
cp /path/to/your/config.yaml .
# Run
./Tele
The config.yaml supports extensive configuration:
| Setting | Description |
|---|---|
ActiveMode | "Test" or "Production" ā switches between environment-specific settings |
QueueType | "redis", "mysql", or "memory" ā backend for background job processing |
Chunk | Parallelism factor for scraper operations (default: 8) |
FloodThreashold | Max send operations before cooldown (default: 50) |
FloodThreasholdPeriod | Cooldown period in hours (default: 24) |
AutomationAPIKey | API key for REST endpoint authentication |
Dual-environment configuration supports Test and Production blocks, each with independent database, Telegram credentials, and MTProto server settings.
dotnet run
Starts the Telegram Bot interface (interactive keyboard navigation) alongside the REST API on port 5000. Swagger UI is available at /swagger.
dotnet run -- --mcp
Communicates via stdio JSON-RPC. Ideal for direct integration with AI agents like Claude Desktop, Cline, or custom AI orchestration pipelines.
dotnet run -- --mcp-http
Exposes the MCP endpoint at /mcp over HTTP. Perfect for web-based AI agents (e.g. llama.cpp Web UI), remote MCP clients, and distributed AI pipelines. Swagger UI is also available at /swagger in this mode.
Important: When running the compiled EXE,
--urlsmust be the last argument. The--mcp-httpflag is filtered out internally before it reaches the host builder:Tele --mcp-http --urls "http://localhost:4951"If it still doesn't work, use the
ASPNETCORE_URLSenvironment variable instead:set ASPNETCORE_URLS=http://localhost:4951 Tele --mcp-http
The MCP HTTP endpoint uses the same X-API-Key authentication as the REST API. All POST requests to /mcp (tool calls) require a valid API key. GET requests (SSE connection initialization) are allowed without auth.
Provide the API key either via the X-API-Key header or the api_key query parameter.
Cline / VS Code MCP configuration:
{
"mcpServers": {
"tele": {
"url": "http://localhost:4951/mcp",
"type": "streamableHttp",
"headers": {
"X-API-Key": "your-api-key-here"
},
"disabled": false,
"autoApprove": []
}
}
}
If your MCP client does not support custom headers, use the api_key query parameter instead:
{
"mcpServers": {
"tele": {
"url": "http://localhost:4951/mcp?api_key=your-api-key-here",
"type": "streamableHttp",
"disabled": false,
"autoApprove": []
}
}
}
Claude Desktop MCP configuration (claude_desktop_config.json):
{
"mcpServers": {
"tele": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/Tele", "--mcp"],
"disabled": false,
"autoApprove": []
}
}
}
For the stdio mode (--mcp), no API key is needed since communication happens via stdin/stdout.
List available tools:
curl -X POST http://localhost:4951/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key-here" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Get member count:
curl -X POST http://localhost:4951/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key-here" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_member_count","arguments":{}}}'
Windows cmd.exe users: Replace single quotes with escaped double quotes:
curl -X POST http://localhost:4951/mcp -H "Content-Type: application/json" -H "X-API-Key: your-api-key-here" -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}"
All endpoints are secured with API key authentication (X-API-Key header) and documented via Swagger at /swagger.
| Method | Endpoint | Description |
|---|---|---|
GET | /api/automation/members | Query members with optional Filter DSL |
GET | /api/automation/members/count | Total member count |
GET | /api/automation/phones | List registered phones with health status |
GET | /api/automation/health | Database connection health check |
POST | /api/automation/scrape | Start channel member scraping (background job) |
POST | /api/automation/bulk-send | Send bulk messages to filtered members (background job) |
POST | /api/automation/bulk-add | Bulk join filtered members to target channel (background job) |
GET | /api/automation/jobs/{id} | Get job status and result |
GET | /api/automation/jobs | List all jobs (filterable by status, paginated) |
The engine exposes the same functionality as the REST API through MCP tools, consumable by any MCP-compatible AI agent:
| MCP Tool | Description |
|---|---|
query_members | Query members with Filter DSL, pagination support. Use filterDsl: "none" for all members |
list_phones | List phones with ban status, send attempts, flood flags |
get_member_count | Total members in database |
check_database_health | Verify database connectivity |
scrape_channel | Start background channel scraping |
bulk_send | Send bulk messages to filtered members |
bulk_add | Bulk add filtered members to target channel |
get_job_status | Poll background job status |
list_jobs | List jobs with status filtering and pagination |
Important: Tool names use snake_case (e.g., get_member_count, list_phones, query_members).
| You want | Set filterDsl to |
|---|---|
| All members (no filter) | "none" (or leave default) |
| First name contains "john", max 5 | "firstname~john,batch=5" |
| From specific channel | "group=mychannel" |
| Only active members, max 100 | "active=true,batch=100" |
| Skip first 50, get 10 | "skip=50,batch=10" |
| Empty/null firstname | "firstname=null" |
| With username, not active | "withusername=true,active=false" |
Example MCP integration with Claude:
{
"server_name": "tele",
"tool_name": "query_members",
"arguments": {
"filterDsl": "active=true,group=mychannel,batch=50",
"pageSize": 20
}
}
A compact, expressive domain-specific language for filtering Telegram members.
field=value,field!=value,field~value,batch=N,skip=N
| Field | Aliases | Type | Example |
|---|---|---|---|
firstname | fn | Text | firstname~Ali |
lastname | ln | Text | lastname=Smith |
username | un | Text | username~john |
phone | ā | Text | phone=+1234 |
lastseen | ā | Text (relative) | lastseen>30d |
active | ā | Boolean | active=true |
access | ā | Boolean | access=false |
withusername | ā | Boolean | withusername=true |
group | channel | Text | group=mychannel |
collected | ā | DateTime | collected>2024-01-01 |
batch | limit | Integer | batch=100 |
skip | offset | Integer | skip=20 |
| Operator | Meaning |
|---|---|
= | Exact match |
!= | Not equal |
~ | Contains (text fields only) |
> | Greater than (numeric/date) |
< | Less than (numeric/date) |
>= | Greater than or equal |
<= | Less than or equal |
# Find active users named "Ali" in a specific channel, limit to 50
active=true,fn~Ali,group=my_channel,batch=50
# Find inactive members without username, collected recently
active=false,withusername=false,collected>2025-01-01
# Find members not seen in 30+ days
lastseen>30d,batch=200
All bulk operations run as background jobs, ensuring the API and bot remain responsive.
Client ā API/MCP ā IJobQueue.EnqueueAsync() ā MySQL/Redis/Memory
ā
QueueWorker (HostedService)
ā
āāāāāāāāāāāāāāā¼āāāāāāāāāāāāāā
ā ā ā
ScrapeHandler BulkSend BulkAdd
ā ā ā
IJobQueue.UpdateJobStatus() ā MySQL/Redis/Memory
| Backend | When to Use |
|---|---|
| MySQL | Production ā durable, supports transactions and SELECT ... FOR UPDATE SKIP LOCKED |
| Redis | High-throughput ā Upstash-compatible, ideal for serverless deployments |
| Memory | Development ā no external dependencies, in-process |
The project includes a comprehensive CI/CD pipeline (.github/workflows/ci-cd.yml) that:
mainPushing a version tag automatically produces standalone executables:
git tag v1.0.0
git push origin v1.0.0
| Platform | Format | Architecture |
|---|---|---|
| Linux | .tar.gz | x64 |
| Windows | .zip | x64 |
| macOS (Intel) | .tar.gz | x64 |
| macOS (Apple Silicon) | .tar.gz | ARM64 |
Each executable is self-contained (no .NET runtime required).
Pre-built Docker images are available on Docker Hubā :
docker pull srckod/tele:1.0
Mount your config.yaml file into the container ā do not mount the entire /app/ directory (that would overwrite the application files):
docker run -d \
--name tele \
-p 4951:4951 \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
srckod/tele:1.0
| Flag | Purpose |
|---|---|
-d | Run in background (detached) |
-p 4951:4951 | Map host port 4951 to container port 4951 |
-v $(pwd)/config.yaml:/app/config.yaml:ro | Mount your config file as read-only |
srckod/tele:1.0 | Docker Hub image |
To run in --mcp-http mode, pass it as a command argument after the image name. You also need to set ASPNETCORE_URLS to control the listening port:
docker run -d \
--name tele-mcp \
-p 4951:4951 \
-e ASPNETCORE_URLS=http://0.0.0.0:4951 \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
srckod/tele:1.0 \
--mcp-http
The --mcp-http argument is appended after the image name (Docker passes it to the ENTRYPOINT). The -e flag sets the environment variable for the port.
docker logs tele -f
Note: Port 4951 is the HTTP API port (Swagger available at
http://localhost:4951/swagger). No HTTPS port is exposed ā use a reverse proxy (Nginx, Traefik, Caddy) for production HTTPS.
docker build -t tele .
docker run -d \
--name tele \
-p 4951:4951 \
-v $(pwd)/config.yaml:/app/config.yaml:ro \
tele
We welcome contributions! Areas of particular interest:
Please open an issue first to discuss your proposed changes.
License: MIT ā see LICENSEā for details.
Disclaimer: This tool is designed for educational and legitimate marketing purposes only. Users are responsible for ensuring compliance with applicable laws, regulations, and Telegram's Terms of Service. The authors assume no liability for misuse of this software.
Content type
Image
Digest
sha256:0988159a5ā¦
Size
62.3 MB
Last updated
4 months ago
docker pull srckod/tele