Uses FastMCP OAuthProxy to proxy OAuth to Forgejo (git.georgsen.dk). Only users who can authenticate with Forgejo get MCP access. DCR is still used for client registration, but authorization requires Forgejo login. 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