Replaced hand-rolled OAuth with FastMCP's battle-tested InMemoryOAuthProvider. Handles DCR, PKCE, token exchange, refresh tokens, and revocation out of the box. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| docs | ||
| mcp_bridge | ||
| .gitignore | ||
| credentials.example | ||
| mcp-bridge.service | ||
| README.md | ||
| requirements.txt | ||
Nexus MCP Bridge
MCP server that bridges claude.ai to a homelab Telegram group chat. Logs all messages and files to libsql, exposes three MCP tools over HTTP on the NetBird mesh.
Architecture
claude.ai ──HTTP──► MCP Bridge (mgmt.mg:8321) ──Telegram API──► Group Chat
│ │
libsql (local) Mikkel + Homelab Bot + MCP Bot
media/ (files)
Single Python process running:
- Telegram bot — polls group chat, logs everything to libsql, sends outbound messages
- FastMCP HTTP server — exposes
send_message,pull_updates,queue_statustools
Setup Guide
Step 1: Create a new Telegram bot
- Open Telegram, message @BotFather
- Send
/newbot - Name:
Nexus MCP Bridge(or whatever you like) - Username:
nexus_mcp_bot(must be unique, pick something available) - Copy the bot token BotFather gives you
Step 2: Create the Telegram group
- In Telegram, create a new group
- Name:
Homelab Bridge(or your preference) - Add members:
- Your existing homelab bot (
@georgsen_homelab_bot) - The new MCP bot (search by the username you chose)
- Your existing homelab bot (
- Important: Make both bots group admins so they can read all messages
- Tap group name → Edit → Administrators → Add both bots
- Bots need at minimum: "Read messages" permission (enabled by default for admins)
Step 3: Get the group chat ID
Option A — Send a message in the group, then check:
curl -s "https://api.telegram.org/bot<MCP_BOT_TOKEN>/getUpdates" | python3 -m json.tool
Look for "chat": {"id": -100XXXXXXXXXX} — the negative number is the group chat ID.
Option B — The bridge logs the chat ID on startup. You can start it once, send a message in the group, and check the logs.
Step 4: Configure credentials
cd ~/repos/telegram-bot-mcp
cp credentials.example credentials
Edit credentials:
MCP_BOT_TOKEN=<token from BotFather>
GROUP_CHAT_ID=<negative number from step 3>
HOMELAB_BOT_ID=8521598773
Step 5: Install and test
cd ~/repos/telegram-bot-mcp
# Create venv (if not already done)
python3 -m venv .venv
# Install dependencies
.venv/bin/pip install -r requirements.txt
# Test run (Ctrl+C to stop)
.venv/bin/python -m mcp_bridge
You should see:
Database initialized at /home/mikkel/repos/telegram-bot-mcp/data/bridge.db
MCP server starting on 0.0.0.0:8321
Telegram bot polling started
MCP Bridge bot started as @nexus_mcp_bot (ID: XXXXXXX)
Monitoring group chat: -100XXXXXXXXXX
Send a message in the group — you should see it logged.
Step 6: Install systemd service
cp mcp-bridge.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now mcp-bridge
systemctl --user status mcp-bridge
View logs:
journalctl --user -u mcp-bridge -f
Step 7: Configure claude.ai MCP connection
In claude.ai settings, add a new MCP server:
- URL:
http://mgmt.mg:8321/mcp - Transport: Streamable HTTP
This works because mgmt.mg resolves via NetBird mesh — no public exposure needed.
MCP Tools
send_message
Send a message to the group, attributed as [claude.ai].
{"message": "Fix the nexus.mg DNS record to 100.79.65.206"}
pull_updates
Get conversation messages with cursor-based pagination.
{"since_id": 0, "limit": 50}
Returns messages from all participants with attachment metadata. Use the cursor value from the response as since_id in the next call.
queue_status
Quick summary: total messages, last activity, pending outbound count.
File Structure
├── mcp_bridge/
│ ├── __main__.py # Entry point (bot + MCP server)
│ ├── config.py # Configuration loader
│ ├── db.py # libsql database layer
│ ├── telegram_bot.py # Telegram bot (logging + sending)
│ ├── mcp_server.py # FastMCP tool definitions
│ └── models.py # Data models
├── data/ # libsql database (auto-created)
├── media/ # Downloaded attachments (auto-created)
├── credentials # Bot token + chat ID (not in git)
├── credentials.example # Template
├── requirements.txt
└── mcp-bridge.service # systemd unit file
Troubleshooting
Bot doesn't see group messages:
- Ensure bot is a group admin
- Check BotFather:
/mybots→ Bot Settings → Group Privacy → Turn OFF (bots have "privacy mode" ON by default — they only see commands unless it's disabled)
Can't get group chat ID:
- Make sure you sent a message AFTER adding the bot
- For supergroups, the ID starts with
-100
MCP server unreachable from claude.ai:
- Verify NetBird is connected:
netbird status - Test locally:
curl http://mgmt.mg:8321/mcp - Check firewall: port 8321 must be open