Telegram AI shop agent over MCP: natural-language catalog, cart & checkout on SQLite, plus weather, crypto, games and translation — split into a FastMCP server and an aiogram 3 bot that calls tools via Streamable HTTP.
Clone → fill
.env→python server.py→python bot.py→ chat in Telegram.
- About
- Features
- Architecture
- How it works
- Tech stack
- Project structure
- Quick start
- Configuration (.env)
- Run
- Telegram usage
- MCP tools
- Database schema
- Open APIs
- Roadmap / how to grow
- Troubleshooting
- Why this project
- License
ShopMCP is a reference stack for Model Context Protocol (MCP) in a real product shape: an e-commerce backend exposed as typed tools, and a Telegram front-end where an LLM decides which tool to call.
Typical use cases:
- learn MCP + FastMCP with a non-toy domain (store, cart, orders)
- ship a Telegram shop assistant without hard-coding every user phrase
- combine business tools (catalog, checkout) with open APIs (weather, CoinGecko, games)
- reuse the MCP server from Cursor, Claude Desktop, or any MCP client — not only Telegram
The bot uses ProxyAPI (OpenAI-compatible) by default; swap the base URL for official OpenAI or another provider.
| Feature | Description |
|---|---|
| MCP tool server | FastMCP over Streamable HTTP — 20+ tools for store + utilities |
| Telegram UI | aiogram 3, inline menu, paginated catalog, product photos |
| LLM tool routing | Model returns JSON {"tool": "...", "arguments": {...}} → MCP call |
| Regex fast-path | Common phrases (корзина, 89, погода в …) skip LLM when obvious |
| SQLite store | Products, cart, orders — seeded on first run |
| Cart & checkout | Per-user cart; user_id injected automatically in the bot layer |
| Open APIs | CoinGecko, Open-Meteo, FreeToGame, LibreTranslate / MyMemory |
| Session memory | Last N messages per user; /clear resets dialogue |
| Reconnecting MCP client | Auto-reconnect on expired Streamable HTTP session |
Two processes, one contract:
┌─────────────────────┐ Streamable HTTP ┌─────────────────────┐
│ telegram_bot/ │ ───────────────────────────▶ │ mcp_server/ │
│ aiogram + LLM │ /mcp (MCP tools) │ FastMCP + SQLite │
└─────────────────────┘ └─────────────────────┘
│ │
▼ ▼
ProxyAPI / OpenAI products.db
(chat completions) + external HTTP APIs
| Layer | Role |
|---|---|
| MCP Server | Source of truth: DB, business rules, external API wrappers |
| Telegram Bot | UX, dialogue, LLM prompt, tool-call parsing, formatting |
| MCP Client | Persistent ClientSession over Streamable HTTP |
This separation lets you attach other clients (IDE agents, web apps) to the same MCP server without touching Telegram code.
User (Telegram)
│
▼
telegram_bot/bot.py
├── regex shortcuts (catalog / cart / product id / weather …)
└── LLM (ProxyAPI) → JSON tool call
│
▼
mcp_client.py → MCPHttpClient.call_tool(...)
│
▼
mcp_server/server.py → @mcp.tool handlers
│
├── tools.py → db.py (SQLite)
└── open_api.py → CoinGecko, Open-Meteo, …
│
▼
Formatted reply (text, HTML, optional product photo)
- User sends text or taps an inline button.
- Bot tries deterministic parsers first; otherwise asks the LLM with a strict system prompt.
- LLM outputs a single JSON tool invocation (no markdown).
- Bot calls MCP; results are formatted for Telegram (catalog pages, cart summary, etc.).
- Turn is appended to in-memory history (
MAX_HISTORY_MESSAGES).
- Python 3.11+
- FastMCP — MCP server, Streamable HTTP transport
- aiogram 3 — async Telegram Bot API
- OpenAI Python SDK — chat completions (ProxyAPI-compatible)
- ProxyAPI — default LLM endpoint
- SQLite — products, cart, orders
- httpx, uvicorn, python-dotenv
shopmcp/
├── server.py # launch MCP server from project root
├── bot.py # launch Telegram bot from project root
├── mcp_server/
│ ├── server.py # FastMCP tool definitions
│ ├── tools.py # store logic (catalog, cart, calculator)
│ ├── open_api.py # weather, crypto, games, translate
│ ├── db.py # SQLite schema + seed data
│ ├── config.py
│ └── requirements.txt
├── telegram_bot/
│ ├── bot.py # handlers, LLM loop, formatting
│ ├── mcp_client.py # Streamable HTTP MCP client
│ ├── config.py
│ └── requirements.txt
├── .env.example
├── .gitignore
├── LICENSE
└── README.md
- Python 3.11+
- Telegram bot token from @BotFather
- API key from ProxyAPI (or OpenAI)
git clone https://github.com/nifontovoleg/shopmcp.git
cd shopmcp
python -m venv .venv
# Windows (PowerShell)
.\.venv\Scripts\Activate.ps1
# macOS / Linux
source .venv/bin/activate
pip install -r mcp_server/requirements.txt
pip install -r telegram_bot/requirements.txt
copy .env.example .env # Windows — use cp on UnixEdit .env with your tokens (see below).
# Telegram
TELEGRAM_API_TOKEN=123456:ABC...
# ProxyAPI (OpenAI-compatible)
PROXYAPI_KEY=your_proxyapi_key
PROXYAPI_BASE_URL=https://openai.api.proxyapi.ru/v1
PROXYAPI_MODEL=openai/gpt-4o-mini
# MCP Server (Streamable HTTP)
MCP_URL=http://127.0.0.1:8000/mcp
MCP_HOST=127.0.0.1
MCP_PORT=8000
MCP_TRANSPORT=streamable-http
MCP_DB_PATH=mcp_server/products.db
MCP_SEED_COUNT=100
# Optional: LibreTranslate instance
LIBRETRANSLATE_URL=https://libretranslate.de| Variable | Required | Description |
|---|---|---|
TELEGRAM_API_TOKEN |
✅ | Telegram bot token |
PROXYAPI_KEY |
✅ | LLM API key |
PROXYAPI_BASE_URL |
❌ | Default ProxyAPI OpenAI URL |
PROXYAPI_MODEL |
❌ | Default openai/gpt-4o-mini |
MCP_URL |
❌ | MCP endpoint (default local) |
MCP_HOST / MCP_PORT |
❌ | Bind address for server |
MCP_DB_PATH |
❌ | SQLite file path |
MCP_SEED_COUNT |
❌ | Demo products to seed on first run |
LIBRETRANSLATE_URL |
❌ | Translation backend |
Security: never commit
.env, bot tokens, or API keys. They are listed in.gitignore.
Terminal 1 — MCP server:
python server.pyServer listens at http://127.0.0.1:8000/mcp.
Terminal 2 — Telegram bot:
python bot.pyOpen your bot in Telegram and send /start.
| Command | Action |
|---|---|
/start |
Welcome + inline menu |
/help |
Examples and tool hints |
/clear |
Reset dialogue history |
- 🛍 Catalog — paginated product list
- 🛒 Cart — current cart
- ₿ Top crypto — CoinGecko top list
- 🌤 Weather — prompt for a city
Store
show all products
items under 500
89
out of stock
add to cart 5
cart
checkout
delete product 10
update product 5 stock 20
Open APIs
bitcoin price
top 5 cryptocurrencies
weather in Almaty
find game valorant
translate hello to Russian
The bot understands Russian and English; the LLM system prompt is tuned for Russian replies.
| Tool | Description |
|---|---|
list_products() |
Full catalog |
find_product(name) |
Search by name |
find_products_by_category(category) |
Filter by category |
find_product_by_id(product_id) |
Single product |
find_products_by_ids(product_ids) |
Batch lookup |
find_products_by_price_range(min, max) |
Price range (after discount) |
get_out_of_stock() |
Unavailable items |
find_similar_products(...) |
Similar products |
add_product(...) |
Create product |
update_product(product_id, ...) |
Update fields |
delete_product(product_id) |
Remove product |
| Tool | Description |
|---|---|
add_to_cart(user_id, product_id, quantity?) |
Add line item |
show_cart(user_id) |
View cart |
checkout(user_id) |
Place order |
| Tool | Description |
|---|---|
calculate(expression) |
Safe AST calculator |
get_crypto_price(coin_id, vs_currencies?) |
CoinGecko spot price |
get_top_cryptos(limit?, vs_currencies?) |
Top coins |
get_weather(city) |
Open-Meteo forecast |
search_games(query, limit?) |
FreeToGame search |
translate_text(text, target, source?) |
LibreTranslate + fallback |
| Table | Columns |
|---|---|
| products | id, name, category, price, description, stock, image_url, discount_percent |
| cart_items | user_id, product_id, quantity |
| orders | id, user_id, total, status, created_at |
| order_items | order_id, product_id, quantity, unit_price |
| Service | API key | Used for |
|---|---|---|
| CoinGecko | ❌ | Crypto prices |
| Open-Meteo | ❌ | Weather |
| FreeToGame | ❌ | Game search |
| LibreTranslate / MyMemory | optional | Translation |
Ideas to extend ShopMCP — pick what matches your goal:
| Direction | Idea |
|---|---|
| Database | PostgreSQL + SQLAlchemy 2, Alembic migrations, connection pooling |
| Auth & payments | Stripe / ЮKassa checkout, order webhooks, admin panel |
| MCP ecosystem | Publish server to MCP registry; add SSE/WebSocket transports |
| Native tool calling | OpenAI tools / function schema instead of JSON-in-text parsing |
| RAG | Product FAQ / policy docs in Chroma; grounded answers over catalog |
| Multi-channel | Same MCP server → web widget, VK bot, WhatsApp |
| Observability | Structured logs, OpenTelemetry, tool latency metrics |
| Deploy | Docker Compose (server + bot), healthchecks, systemd on VPS |
| Admin tools | MCP tools for analytics, low-stock alerts, bulk import CSV |
| UX | FSM checkout flow, wishlists, order status notifications |
| Security | Rate limits, admin-only destructive tools, input validation layer |
| Testing | pytest for tools.py / db.py; contract tests for MCP client |
Contributions that keep MCP tools thin and Telegram handlers separate from business logic are the easiest to merge.
Two processes use the same TELEGRAM_API_TOKEN. Stop extra python bot.py runs.
- Ensure
python server.pyis running andMCP_URLmatches. - Check logs for MCP reconnect messages in
mcp_client.py. - Restart server first, then bot.
Delete products.db (or set a fresh MCP_DB_PATH) and restart the server — it re-seeds demo products.
- Use
/clearto drop polluted history. - Confirm
PROXYAPI_MODELsupports instruction following (e.g.gpt-4o-mini). - Try a stronger model for noisy user input.
Public LibreTranslate instances can rate-limit. Set LIBRETRANSLATE_URL to your own instance or rely on MyMemory fallback.
| Goal | Outcome |
|---|---|
| Learn MCP in production shape | FastMCP server + HTTP client, not a single script |
| Telegram + agents | aiogram 3 + LLM tool routing pattern you can copy |
| E-commerce domain | Real cart/checkout state, not hello-world tools |
| Open APIs bundled | Weather, crypto, games in one demo |
| Client-agnostic backend | Reuse MCP server from IDE agents or other UIs |
MIT — free for personal, learning, and portfolio use.
Built with ☕ for MCP agents, Telegram bots, and ProxyAPI
@nifontovoleg · nifontovv.ru