gatebound-support
Integrates with Discord for the support ticket flow, including ticket handling and staff webhook notifications.
Provides MCP tools for Gatebound's ElevenLabs support agent, handles the post-call webhook, and syncs markdown knowledge-base files into an ElevenLabs agent's knowledge base via the kb-sync CLI.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
gatebound-support
Python/FastAPI backend for Gatebound's ElevenLabs support agent: MCP tools for the agent, the Discord ticket flow, the post-call webhook, and the knowledge-base sync CLI.
docs/SPEC.md is the contract this service is built against — read it for exact env names,
endpoint paths, tool shapes, and the ticket flow. docs/ARCHITECTURE.md has the component
map, trust boundaries and failure modes; docs/DECISIONS.md the reasoning (no database
access from this stack, MCP instead of webhook tools, ticket links instead of agent-created
tickets, knowledge base synced from Git, cheapest models while iterating). This file is just
the "how do I run it" quick start.
Live: agent "Gatebound Support" in the text-first widget on
gatebound.rosenvall.se; service at
gatebound-support.rosenvall.se, deployed from the private homelab GitOps repo.
ElevenLabs agent as code (elevenlabs/)
Everything about the agent lives in the ElevenLabs CLI project layout and is pushed, never edited in the UI:
$env:ELEVENLABS_API_KEY = "..."
cd elevenlabs
python scripts/build_agent_config.py # prompt + settings -> agent_configs/Gatebound-Support.json
elevenlabs agents push # create/update the agent
elevenlabs tests push # the six behaviour tests in test_configs/
python scripts/run_agent_tests.py # run them, table + exit code (add --verbose for transcripts)
python scripts/sync_agent_refs.py # mirror live knowledge_base + mcp_server_ids into the config
$env:MCP_SECRET = "..."; uv run python scripts/probe_mcp.py # talk to the deployed /mcp like ElevenLabs doesThe MCP server entry and its bearer secret are registered once per workspace (see
docs/DECISIONS.md); the agent references it by id in mcp_server_ids.
Related MCP server: MCP Customer Support AI
Run locally
uv sync
copy .env.example .env # edit as needed; every integration defaults to "unset" (disabled)
uv run gatebound-support serveThe server listens on PORT (default 8080). With everything left unset it still starts and
answers /healthz and /status; the ticket flow works without Discord (tickets land as
pending_manual), and the MCP endpoint at /mcp rejects all calls until MCP_SECRET is set.
Tests
uv run pytest -q
uv run ruff check .kb-sync
Syncs a directory of markdown files into an ElevenLabs agent's knowledge base (SPEC §7):
uv run gatebound-support kb-sync --dir path\to\docs --manifest path\to\kb-manifest.json --agent <agent_id>
uv run gatebound-support kb-sync --dir ... --manifest ... --agent ... --dry-run # print the plan, write nothing
uv run gatebound-support kb-sync --dir ... --manifest ... --agent ... --check # exit 1 on drift, for CI/CronJobRequires ELEVENLABS_API_KEY.
Discord voice
gatebound-support voicebot is a second, separate long-lived process (own container
command, own Kubernetes Deployment — same image, command: ["gatebound-support", "voicebot"], no HTTP service) that runs the Discord gateway connection and bridges voice:
/supportor/call(from anywhere — the player does not need to already be in a voice channel): the bot creates a private temporary voice channel (support-<display name>, in the same category as the support text channel if it has one) that only the player, the bot, and roles with Administrator/Manage Guild can see or join — a support call must never be overhearable or joinable by other guild members. The player gets an ephemeral reply with a link to the channel ("join it and I'll pick up"); if they're already in a voice channel and the bot has Move Members, it pulls them straight in instead. A ticket + private Discord thread is opened for the call up front (sourcediscord_voice). The ElevenLabs Conversational AI session — the same agent the website widget talks to, over the SDK'sConversation+ a customAudioInterface(seesrc/gatebound_support/voicebot/) — only starts once the player actually joins that channel; if nobody joins within 2 minutes the channel is deleted and "Call not started" is posted to the ticket thread. The post-call transcript webhook posts the summary and transcript to the thread when a real call ends, exactly like the website ticket flow./hangup: ends the current call early.The call also ends when the player leaves the private channel, the agent says goodbye (its own
end_calltool), or afterVOICE_MAX_MINUTES(default 15) — in every case the temporary voice channel is deleted and "Call ended (<duration>)" is posted to the ticket thread. On startup the bot also sweeps for and deletes any leftover emptysupport-*channels from a previous crash/restart.One call per Discord server at a time, from the moment
/supportreserves the guild's slot (channel creation, waiting for join, and the call itself) — a second/supportwhile busy gets an ephemeral "the line is busy" reply./ticket, and a persistent "Open a ticket" button pinned in the support channel, open a text ticket via a modal (category + description) without going through the ElevenLabs agent at all — same private-thread flow, sourcediscord_text. One open ticket per Discord user at a time; opening a second one just links back to the first./close, a persistent "Close ticket" button on every ticket's opening post and on the voice call's "Call ended" message, and reacting with ✅ or 🔒 to any bot-authored message inside a ticket thread, all close the ticket the same way: only the ticket's own Discord user or a member with Manage Threads on the parent channel may do it (everyone else gets an ephemeral refusal, or — for a reaction, which has no ephemeral channel — a short message posted in the thread). Closing calls the internal API (status →closed), ends an active voice call for that ticket first if there is one, posts "Ticket closed by<mention>.", renames the thread to[closed] <old name>, and archives + locks it. A closed ticket never blocks its owner from opening a new one.Reaction shortcuts on the pinned instructions message (an alternative to typing slash commands): react, and the bot removes your reaction once it's acted on it.
Reaction
Action
🎫
Same as
/ticket, but without a modal (reactions can't open one): categoryother, summary "Opened by reaction; the player describes the problem in the thread" — the player is asked to describe the problem in the thread itself. Already has an open ticket → a reminder is posted there instead of opening a new one.📞
Same as
/support: creates the private voice channel, ticket and thread, and waits for the join — since there's no ephemeral reply for a reaction, the "join<channel>and I'll pick up" text is posted as the thread's first message instead.A per-user in-flight guard ignores a reaction that arrives while that user's previous ticket-creation/call-start reaction is still being handled, so double-tapping doesn't double-fire.
The bot talks to this same service's /internal API (bearer MCP_SECRET, not part of the
public contract in docs/SPEC.md) to create, update, and close tickets, since it's a
separate process from the one holding SQLite.
Discord bot permissions needed (added when inviting/authorizing the bot, or updating its
existing OAuth2 scopes): View Channel, Send Messages, Create Private Threads, Send Messages in Threads, Manage Threads (needed for the text ticket flow and to let
Manage-Threads staff close any ticket, not just their own); plus, for voice, Connect,
Speak, Use Voice Activity, and — permanent, not optional — Manage Channels and Manage Roles (needed to create the private per-call voice channel and
set its permission overwrites every time /support runs). Move Members is optional:
when granted, a player already in a voice channel is pulled straight into their private call
channel instead of having to click the link themselves. The reaction shortcuts additionally
want Manage Messages so the bot can remove a player's reaction from the pinned message
after acting on it — without it the reaction still triggers the action, it just isn't
auto-removed (a Forbidden from the removal attempt is caught and ignored).
Cost note: ElevenLabs bills voice conversation minutes at a materially higher rate than
text conversations — a /support call is not "free" the way a widget chat message is.
Run it locally the same way as serve:
uv run gatebound-support voicebot
uv run gatebound-support voicebot --check # validates settings + opus + imports, no connection, exits 0/1Docker
docker build --platform linux/amd64 -t gatebound-support:dev .
docker run --rm -p 8080:8080 --env-file .env gatebound-support:devRuns as uid 1000, writes SQLite to DATA_DIR (default /data in the container).
Environment variables
See docs/SPEC.md sections 1 and 8 for the full list and what each one is for. Quick
reference (all default to "unset", meaning that integration is disabled):
Variable | Purpose |
| runtime |
| this service's own URL, the web app's internal API, and its public URL |
| shared secret for calls to the web support API |
| HS256 key for the player identity JWT |
| bearer secret ElevenLabs sends on |
| ElevenLabs API access, post-call webhook HMAC key, and agent id |
| the ticket flow's Discord integration ( |
| voicebot: max length of a |
| voicebot: in-cluster base URL of this service's own |
Copy .env.example to .env and fill in what you need; everything else can stay unset.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Your team's custom tools and skills in every agent, through one MCP connection.
Lets Claude, Cursor or any MCP client build voice agents and place real phone calls.
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes order status lookup and knowledge base search tools from the Support Agent AI over MCP, enabling MCP clients to handle customer support queries with grounded, citation-backed answers.2MIT
- AlicenseNot gradedqualityCmaintenanceEnables an AI to perform customer support workflows by looking up customers, retrieving orders, and creating support tickets through MCP tools.3 npmX11 no permit persons clause
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to search and retrieve support tickets, add notes, close tickets, and access SLA policies through MCP tools, resources, and prompts over Streamable HTTP.MIT
- FlicenseNot gradedqualityCmaintenanceProvides MCP tools for hybrid knowledge base search, grounded Q&A with citations, agent execution, and ticket/account lookups.-