Previously the outbound loop wrote every message to inbox, causing
the homelab bot to process its own responses as new tasks. Now only
explicit claude.ai send_message tool calls write to inbox.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude was just echoing raw text. Now messages include framing:
"[MCP Bridge Task from claude.ai] <message>" with instruction
to acknowledge and begin working.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MCP bot now writes to ~/homelab/telegram/inbox alongside posting
to the group chat, so the homelab bot can process the messages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bot can't see its own messages via Telegram polling. Now logs them
directly after sending so they appear in pull_updates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ingest API now requires X-Ingest-Key header matching INGEST_SECRET
from credentials. IP-based check was insufficient since NPM proxies
all external traffic from the same internal IP.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Public git.georgsen.dk unreachable from LAN due to hairpin NAT.
Authorization endpoint stays public (browser redirect), but
token exchange and token verification use internal 10.5.0.14:3000.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Checks X-Forwarded-For/X-Real-IP from NPM proxy to get real client IP.
Only allows localhost, LAN (10.5.0.x), and NetBird (100.79.x) prefixes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Parent's authorize() is abstract and returned None, causing /None redirect.
Override creates auth code and redirects to callback immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OAuthProvider is abstract — subclassed as HomelabOAuth with full
implementation of register_client, get_client, create/exchange
authorization codes, token issuance, PKCE verification, and
refresh token rotation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FastMCP's OAuthProvider handles the full OAuth flow including DCR
(Dynamic Client Registration), authorization code + PKCE, token
issuance, and refresh tokens. No more custom auth code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Desktop needs:
- /.well-known/oauth-protected-resource (RFC 9728)
- GET method on /token endpoint (sends params via query string)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Desktop uses authorization code flow, not client credentials.
Added /authorize endpoint that auto-approves (single-user setup) and
redirects with code. Token endpoint now supports both grant types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Telegram bots can't see messages from other bots in groups. Added:
- POST /api/ingest - local services log messages into bridge DB
- GET /api/health - status check endpoint
- Fixed post_init not running (manual init lifecycle)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single-process Python app that:
- Runs a Telegram bot in a group chat, logging all messages/files to libsql
- Exposes send_message, pull_updates, queue_status MCP tools over HTTP
- Downloads and stores file attachments with Telegram file_id + local path
- Accessible via NetBird mesh at mgmt.mg:8321 (no auth needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>