Install
$ agentstack add mcp-helderpgoncalves-feedbot Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
🤖 Feedbot
Turn community chat into a structured product backlog — and let any AI agent resolve it.
[](https://github.com/helderpgoncalves/feedbot/actions/workflows/ci.yml) [](https://github.com/helderpgoncalves/feedbot/releases) [](LICENSE) [](https://www.python.org) [](https://modelcontextprotocol.io) [](docs/DEPLOY-COOLIFY.md) [](CONTRIBUTING.md) [](https://github.com/helderpgoncalves/feedbot/discussions)
[Quickstart](#-quickstart-docker-5-minutes) · [Architecture](#how-it-works) · [Deploy](docs/DEPLOY-COOLIFY.md) · [Security](SECURITY.md) · [Contributing](CONTRIBUTING.md)
What it does
Drop the bot in your Telegram group. Users post bugs, ideas, and feature requests in plain language. Feedbot captures and structures them — optionally auto-triaged by an LLM (OpenAI or Anthropic, plug-in registry for more). Your team triages from a clean React dashboard. Any MCP-compatible client (Claude Code, Claude Desktop, Cursor, Windsurf, …) picks up tickets via the bundled MCP server (HTTP-native, no proxy process), ships the fix, and the original reporter is notified back in the same chat — replies they send route straight to the right ticket.
┌──────────────┐ ┌──────────────────┐
│ Telegram │ bot files structured row │ Feedbot API │
│ group │ ─────────────────────────► │ (FastAPI + │
│ │ ◄── reply / done in chat ─── │ Postgres) │
└──────────────┘ (same thread, no DM) └────────┬─────────┘
│ LLM classify
│ (per project)
┌──────────────┐ Bearer fbk_live_* ▼
│ MCP client │ ◄────── HTTP /mcp ──────────► ┌──────────────┐
│ (any agent) │ │ OpenAI / │
│ │ "Mark FB-A3F2 done" │ Anthropic / │
└──────────────┘ │ …registry │
└──────────────┘
┌─────────────────┐
│ React SPA │
│ team · projects│
│ keys · MCP cfg │
└─────────────────┘
You stay in your editor. Reporters stay in their chat. Nothing falls through.
✨ Highlights
| | | |---|---| | 🛡️ Closed by default (self-host) | First-run setup creates the owner. After that, the only way in is by invitation — no public sign-up. Cloud deployments can flip on signup with one env var. | | 👥 Three simple roles | owner / admin / member. Members only see projects they were explicitly added to. Designed to be obvious, not powerful. | | 🤝 One bot, N projects | A single Telegram bot serves every project. Each chat is bound to exactly one project; routing is decided server-side from chat_id. | | ✨ Frictionless onboarding | Click "Generate invite" in the dashboard → tap Open Telegram → Add to group → done. Bot confirms the link in chat. No tokens to type. | | 🧠 LLM auto-triage | OpenAI or Anthropic structured outputs fill type, severity, summary, tags, language, sentiment on every inbound message. Per-project config, encrypted keys, monthly budget cap, full cost audit. Plug-in registry for new providers. | | 🧰 MCP over HTTP — any client | Native MCP at /mcp on the API. Works with Claude Code, Claude Desktop, Cursor, Windsurf, Zed, Continue, or any agent using the MCP SDK. The dashboard generates ready-to-paste config for each. 9 tools including request_more_info for in-chat clarification. | | 💬 Conversational loop | Replies and resolutions come back to the same chat the feedback was reported in. When the reporter answers, the message is captured as user_reply and the ticket flips back to triaged automatically. Same loop also drives the dashboard's reply queue UI, so you don't need an MCP client to hold a conversation. | | 🚀 Coolify-deployable | Two Docker Compose services (api + web), one Postgres, two domains (or one + path), TLS automatic. Step-by-step in [docs/DEPLOY-COOLIFY.md](docs/DEPLOY-COOLIFY.md). | | 🔒 Hardened by default | Argon2id-hashed API keys, server-side bot tokens with constant-time compare, Fernet-encrypted LLM keys at rest, server-side sessions in Strict cookies, HSTS, CSP, rate limiting on auth routes, fail-closed on missing SMTP. | | 🪞 Boring tech, on purpose | Backend: FastAPI · SQLAlchemy 2 async · Postgres · Alembic. Frontend: React 19 · TanStack Router · TanStack Query · shadcn/ui · Tailwind. Easy to read, fork, and contribute to. |
🚀 Quickstart (Docker, 5 minutes)
> One-liner install on a fresh box: > ``bash > curl -fsSL https://get.feedbot.dev | sh > `` > Or install from source (below):
git clone https://github.com/helderpgoncalves/feedbot.git
cd feedbot
cp .env.example .env
# Generate strong dev secrets — paste each line into .env
python -c "import secrets; print('FEEDBOT_SECRET_KEY=' + secrets.token_urlsafe(48))"
python -c "import secrets; print('FEEDBOT_BOT_TOKEN=' + secrets.token_urlsafe(32))"
docker compose up --build -d
Three services come up: db (Postgres), api (FastAPI on :8000), and web (the React SPA on :3000).
Open :
- The SPA detects the empty database and routes you to
/setup. - Enter your owner email + workspace name → submit.
- The magic link prints in the API logs (
docker compose logs api | grep "magic link"); open it. - You land at
/projectsas the owner. Create projects, invite teammates from the Team page, connect a Telegram chat from a project's Telegram chats card.
> No SMTP locally? That's fine — the link prints in logs. For production deploys, [docs/DEPLOY-COOLIFY.md](docs/DEPLOY-COOLIFY.md) has the full SMTP walkthrough. EMAIL_BACKEND=console over HTTPS is refused so you can't accidentally lock yourself out.
Full walkthrough — including SMTP, Telegram bot setup, and end-to-end smoke tests — in [docs/E2E.md](docs/E2E.md).
> 💡 Want to deploy this on the public internet? Skip to [docs/DEPLOY-COOLIFY.md](docs/DEPLOY-COOLIFY.md) — managed Postgres, Let's Encrypt, SMTP, the works. ~25 minutes.
🔌 Wire up an MCP client
The Feedbot API serves the MCP protocol natively over Streamable HTTP at /mcp. No extra process to run; auth is the project's API key. Reference: .
The fastest path: open a project in the dashboard → scroll to Connect via MCP → copy the snippet for your client. The dashboard fills in the URL and a freshly-issued key for you. Below is the manual reference.
Claude Code (CLI)
claude mcp add --transport http feedbot https://your-feedbot.example.com/mcp/ \
--header "Authorization: Bearer fbk_live_..."
.mcp.json / claude_desktop_config.json / Cursor / Windsurf
{
"mcpServers": {
"feedbot": {
"type": "http",
"url": "https://your-feedbot.example.com/mcp/",
"headers": {
"Authorization": "Bearer fbk_live_..."
}
}
}
}
Any other MCP client
Three pieces of information do it:
| Field | Value | | ------------- | -------------------------------------------------- | | URL | https://your-feedbot.example.com/mcp/ | | Transport | Streamable HTTP | | Authorization | Authorization: Bearer fbk_live_... |
> Different projects get different keys. Each workspace has its own key. Same MCP server, isolated data — guaranteed by the auth layer.
In your agent: "What new bugs do we have?" — done.
> The legacy stdio package (feedbot-mcp) still works for environments that can't reach an HTTP MCP server, but new deployments should use the HTTP endpoint. The dashboard only generates HTTP snippets.
How it works
Identity & access
┌────────────────────────────────────────────────────────────┐
│ Tenant (your workspace) │
│ │
│ ┌────────┐ ┌────────┐ ┌──────────┐ │
│ │ owner │ ◄── │ admin │ ◄── │ member │ │
│ │ (1) │ │ (N) │ │ (N) │ │
│ └────────┘ └────────┘ └────┬─────┘ │
│ │ │ │ │
│ └──────────────┴────────────────┘ visible projects │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Project A,B,C… │ API keys, chat-links, │
│ │ │ members, feedback inbox │
│ └──────────────────┘ │
└────────────────────────────────────────────────────────────┘
| Role | Can do | |---|---| | owner | Everything. Created via /setup (self-host) or signup (cloud). Singular per tenant. Cannot be deleted; can transfer the role. | | admin | Invite teammates, create/delete projects, manage keys, manage chat-links, manage members. | | member | See and triage feedback only in projects they're added to. No tenant-wide actions. |
Multi-project routing — same bot, multiple groups
┌─────────────────────────────────┐
│ feedbot-api │
│ │
/start link_ ──►│ /v1/internal/redeem-link │──► chat_links: (telegram, -100…) → project A
│ │
message in group A ──►│ /v1/internal/ingest │──► resolve via chat_links → A → new feedback
│ │
message in group B ──►│ /v1/internal/ingest │──► resolve via chat_links → B → new feedback
└─────────────────────────────────┘
- The dashboard issues a single-use, 15-minute deep-link token from the project's Telegram chats card.
- Telegram's
?startgroup=link_brings the user (with the bot) into a group of their choice. - The bot calls
/v1/internal/redeem-linkwith(chat_id, token)→ server records the binding. - Every subsequent message in that chat is ingested against that project.
UNIQUE(platform, chat_id)makes it physically impossible for a chat to belong to two projects.- Bot ↔ API uses a separate server-side secret (
FEEDBOT_BOT_TOKEN), never exposed to clients.
📦 What's in this repo
A monorepo. One install, four publishable packages plus the SPA.
feedbot/
├── apps/
│ ├── web/ # React SPA: dashboard, auth, setup wizard, MCP onboarding
│ ├── marketing/ # Astro + Starlight: landing + docs at feedbot.dev
│ └── installer-host/ # Static host for install.sh at get.feedbot.dev
├── packages/
│ ├── feedbot-core/ # SQLAlchemy 2 models, repos, IDs, Argon2 hashing, LLM registry
│ ├── feedbot-api/ # FastAPI JSON server (/v1/*) + native MCP (/mcp/*) — no HTML
│ ├── feedbot-bot/ # Telegram adapter (one bot, many projects)
│ └── feedbot-mcp/ # Legacy MCP stdio bridge (kept for compat; prefer /mcp HTTP)
├── alembic/ # Single shared schema migrations
├── docker-compose.yml # db + api + web + (opt-in) bot
├── scripts/seed.py # CLI: bootstrap owner / project / API key
└── docs/
├── ARCHITECTURE.md
├── DEPLOY-COOLIFY.md
├── DEPLOYMENT.md
└── E2E.md
| Component | Role | Runs where | |---|---|---| | apps/web | React SPA. Same Docker image works for cloud and any self-host — runtime config (/config.json) is templated by Caddy from env vars on every request, so you change docker-compose.yml and restart, never rebuild. | Server (Caddy on :80, exposed as :3000) | | feedbot-core | Domain primitives — models, repos, ID generation, Argon2 hashing, LLM provider registry + classification + Fernet crypto + pricing table. No FastAPI, no Telegram. | Imported by api/bot | | feedbot-api | JSON API (/v1/*), magic-link auth, MCP server at /mcp, outbound queue endpoints. Source of truth. | Server (:8000) | | feedbot-bot | Global Telegram bot. Resolves project from chat_id. Polls the outbound queue every 5s to deliver replies and done-notifications, and routes Telegram-reply messages back to the right feedback. | Server (one process serves N projects) | | feedbot-mcp | Legacy MCP stdio bridge — thin HTTP client for environments that can't reach the HTTP endpoint. Most users should use the HTTP endpoint directly. | Developer's machine |
The SPA and the API run as separate services. In production, Caddy in the web container reverse-proxies /api/*, /mcp/*, /login, and /setup to the API container so the browser sees a single same-origin host — no CORS, cookies stay SameSite=Strict.
☁️ Cloud vs self-host
The same Docker image works for both. Two env vars on the web container decide which mode:
| Env var | Self-host (default) | Cloud | |---|---|---| | FEEDBOT_DEPLOYMENT | self-host | cloud | | FEEDBOT_ALLOW_SIGNUP | false | true |
Self-host is invite-only after the first owner is bootstrapped via /setup. One tenant, one workspace — invite teammates via the Team page. This is fully working today.
Cloud flips public sign-up on so anyone can land on app. and create their own tenant. The signup endpoint is rate-limited and only active when FEEDBOT_ALLOW_SIGNUP=true. Stripe billing, plan-tier quotas, and GDPR endpoints are tracked under M5/M6 — not yet shipped.
If you're not sure which you want: start with self-host. It's the demo customers see when they evaluate the cloud version, and the path most contributors take.
🧠 LLM auto-triage (optional, per project)
Every inbound feedback can be auto-filled with type, severity, summary, tags, language, and sentiment using OpenAI or Anthropic structured outputs. Configured per project from the project page → LLM tab:
- Provider dropdown populated from the registry (
feedbot_core/llm/providers/). Adding a new provider tomorrow is one file with@register("name"); the dropdown picks it up automatically. - API key encrypted at rest with Fernet (key derived from
FEEDBOT_SECRET_KEY). Never re-rendered. - Test connection runs a real classification round-trip and stores the outcome (
last_test_ok/last_test_error). - Cost tracking — every call writes a row to
llm_calls(provider, model, tokens, USD cost fromfeedbot_core/llm/pricing.py, latency, status). The settings page shows month-to-date spend and the last 50 calls. - Monthly budget cap — optional
monthly_budget_usd. When the running total hits the cap, classification stops and is audited withstatus=over_budgetuntil the next month. Ingest never fails because of LLM.
Disabled by default. The pipeline degrades gracefully — if no settings exist, classification is skipped (status=disabled) and the feedback flows through unchanged.
💬 Conversational loop (M4)
Replies don't open a DM. They land in the same chat the feedback was reported in, prefixed with [FB-XXXXXX]. Triage them from the dashboard's reply queue UI or an MCP client — same endpoints, same loop:
user @ Telegram group
│ "@bot the export crashes on iOS"
▼
feedbot-bot ──ingest──► feedbot-api (LLM classifies → row)
│
team via dashboard ─────────┐│
or MCP client ──reply_to_user┘
│ outbound queue
▼
feedbot-bot ──Telegram sendMessage──► same group
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [helderpgoncalves](https://github.com/helderpgoncalves)
- **Source:** [helderpgoncalves/feedbot](https://github.com/helderpgoncalves/feedbot)
- **License:** MIT
- **Homepage:** https://feedbot.dev
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.