grok-bot-universal
Can deliver bot reply notifications to a configured Discord relay webhook, with an optional bearer secret.
Sends bot reply notifications to an ntfy topic through a configurable HTTPS webhook, optionally authenticated with a bearer secret.
Can deliver bot reply notifications to a configured Slack relay webhook, with an optional bearer secret.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@grok-bot-universalhave my research bot compare these three vendors and wait for its reply"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
grok-bot-universal
A self-hosted, two-way bridge between Claude and your GrokBot bots.
Claude → bot: Claude briefs a bot (
send_to_grokbot); the server wakes the bot's webhook routine.Bot → Claude: the bot answers into the same thread (one
curl); Claude picks it up withwait_for_replyorcheck_inbox, and you can get a push notification.Dashboard: sign in, add bots and their webhook keys (kept encrypted on the server), connect Claude, read threads, manage tokens, 2FA and users.
It works in every Claude app: claude.ai, Desktop and mobile through a custom connector (OAuth sign-in), and Claude Code through the same connector or an API token.
Claude (web/desktop/mobile/Code) GrokBot bot
│ MCP over HTTPS (OAuth or API token) ▲ │
▼ │ │ POST /api/v1/replies
┌──────────────── Cloudflare Tunnel ─────────────────┐ │ │ (thread token)
│ app: /mcp /authorize /token /api/v1 dashboard │─────┘ │
│ webhook call with brief + reply token │◀────────┘
│ Postgres (internal network, no internet) │
└────────────────────────────────────────────────────┘Contents
Piece | Where |
Server (Express + MCP SDK, Node 24, runs the TypeScript directly) |
|
Database migrations |
|
Deployment |
|
|
|
Routine instructions for the bots | shown per bot in the dashboard; reference copy in |
End-to-end test |
|
Related MCP server: agent-comms-mcp
Deploy
You need a Linux server with Docker, and a domain on Cloudflare. The server needs no open inbound ports: the Cloudflare Tunnel connects outwards.
Cloudflare tunnel. Zero Trust → Networks → Tunnels → Create a tunnel (Cloudflared). Copy the token from the Docker install command. Add a public hostname, e.g.
grokbot.example.com→ serviceHTTP→app:8787.Get the code onto the server and create the environment file:
./scripts/init-env.sh https://grokbot.example.comThen edit
.env: pasteCLOUDFLARE_TUNNEL_TOKEN, and checkWEBHOOK_HOSTS(defaults toapi2.cursor.sh, where GrokBot webhooks live). SaveENCRYPTION_KEYin your password manager: backups can't be restored without it.Start it:
docker compose --profile tunnel up -d --buildCreate your admin account:
docker compose exec app node src/cli.ts invite --adminOpen the printed link, sign up, then turn on two-factor under Settings.
Recommended Cloudflare settings: SSL/TLS Full, Always Use HTTPS, and a WAF rate-limiting rule on
/login. If you put Cloudflare Access in front of the dashboard, add Bypass rules for the paths machines call:
/mcp, /api/*, /bot/*, /token, /register, /revoke, /.well-known/* and /health.
Updating
git pull && docker compose --profile tunnel up -d --buildMigrations run automatically at start-up.
Backups
./scripts/backup.sh # → backups/grokbot-<time>.sql.gz, keeps the newest 14Run it from cron daily. A restore needs the dump and the ENCRYPTION_KEY from .env.
Use
1. Add a bot
In GrokBot, open the bot and create a routine with a Webhook trigger. In the dashboard: Bots → Add bot, then
paste the webhook URL and key, and describe what the bot is for (use for / not for drive which bot Claude
picks; projects makes it the default for matching folders, afs-* style).
Then copy the bot's Routine instructions (on its page) into the routine. They tell the bot how to read Claude's brief and how to reply.
2. Connect Claude
On Connect Claude:
claude.ai, Desktop, mobile: Settings → Connectors → Add custom connector → paste
https://<host>/mcp→ Connect → sign in and approve. It then works in all your Claude apps.Claude Code: create an API token and run the command the page shows:
claude mcp add --transport http --scope user grokbot https://grokbot.example.com/mcp --header "Authorization: Bearer gbp_…"The
grokbot-delegationskill is linked into~/.claude/skills. For Desktop/claude.ai chats, uploaddist/grokbot-delegation.zipunder Settings → Capabilities → Skills (rebuild it after editing the skill:cd skills && rm -f ../dist/grokbot-delegation.zip && zip -qr ../dist/grokbot-delegation.zip grokbot-delegation).
3. Talk to bots
Ask Claude: "have the research bot compare these three vendors and wait for the answer". Claude picks the bot, shows you the brief, sends it only after your yes, and waits for the reply. Later: "any replies from my bots?".
MCP tools
Tool | What it does |
| Bots with use for / not for, ★ project default, ✉ unread replies |
|
|
| Waits up to |
| Unread replies (all bots or one), marks them read |
| A whole conversation |
| Recent threads with unread counts |
Confirmation: in apps that support MCP dialogs (Claude Code), the server asks you directly; elsewhere the tool
refuses unless Claude passes user_confirmed: true, which the rules and skill only allow after your explicit yes.
What the bot receives
{
"source": "claude",
"from": { "agent": "Claude", "app": "Claude Code", "project": "grok-bot-universal", "about": "…" },
"thread_id": "…",
"message": "…",
"sent_at": "2026-10-27T18:30:00.000Z",
"reply": { "url": "https://<host>/api/v1/replies", "token": "gbt_…", "expires_in_days": 14, "how": "…", "mcp_url": "https://<host>/bot/mcp" }
}The bot replies with POST reply.url {"message": "…", "state": "done" | "working" | "needs_input" | "failed"} and
Authorization: Bearer <reply.token>. See grokbot/routine-instructions.md for
the long-lived bot token and the bot MCP endpoint.
Reply notifications
Settings → Reply notifications: an HTTPS URL that gets
{"event":"bot_reply","bot","thread_id","state","preview","url"} whenever a bot replies (ntfy, a Slack/Discord
relay, a Claude routine trigger, …), with an optional bearer secret.
Security
Area | How |
Accounts | Invite-only sign-up by default; scrypt passwords (12+ chars); optional TOTP 2FA with replay protection; per-IP and per-account login throttling |
Sessions | Random token in an |
CSRF / clickjacking | Per-session CSRF token on every form, same-origin check on every POST, strict CSP with no inline script, |
Secrets at rest | Bot webhook keys, TOTP seeds, notify secrets and OAuth client secrets are AES-256-GCM encrypted, each bound to its owner row. API, reply, OAuth and session tokens are stored only as SHA-256 hashes and shown once |
Claude access | OAuth 2.1 with PKCE, dynamic registration limited to Claude's redirect hosts, single-use 5-minute codes, 1-hour access tokens, rotating 30-day refresh tokens with reuse detection; or revocable, expiring API tokens. MCP sessions are bound to their user |
Bot access | Per-thread reply tokens (HMAC-signed, 14 days, one thread only) or a long-lived per-bot token; rotating it invalidates all thread tokens |
Isolation | Every query is scoped to the signed-in user; the test suite checks cross-user access |
Outbound requests | Webhook and notify URLs must be HTTPS, may be limited to |
Outgoing messages | Messages containing keys, tokens or private keys (including your own bot keys) are refused and logged |
Prompt injection | Bot replies reach Claude fenced and labelled as untrusted; the server rules and skill tell Claude never to act on instructions in them |
Abuse | Rate limits on login, sign-up, OAuth registration, MCP and the reply API; DNS-rebinding host check; request size limits |
Containers | App runs as non-root, read-only filesystem, all capabilities dropped; Postgres has no network route out; nothing listens publicly (Cloudflare Tunnel) |
Audit | Sign-ins, failures, token, bot and 2FA changes, blocked sends: Activity page |
Admin CLI
Run on the server (docker compose exec app node src/cli.ts …):
Command | Does |
| One-time sign-up link |
| Import bots (and old local history) into an account |
| Turn off 2FA for someone who lost their device |
| Lock/unlock an account (disabling revokes all its sessions and tokens) |
Admins can also create invites and disable users under Admin in the dashboard.
Configuration
Variable | Default | |
| required | The address people and Claude use, e.g. |
| required | 32 bytes base64 ( |
| set by compose | Postgres connection string |
|
|
|
| any public host | Comma-separated allowlist, |
|
| Use |
|
| Express trust-proxy setting |
|
| Where OAuth clients may redirect |
|
| Development only: allow |
Migrating from the local version
Version 0.2 (tag v0.2-local) ran on your Mac over stdio with bots.json and SQLite. After deploying:
# on the server, in this folder, after copying bots.json and data/grokbot.db over (and signing up)
docker compose run --rm -v "$PWD/bots.json:/import/bots.json:ro" -v "$PWD/data:/import/data:ro" app \
node src/cli.ts import --email you@example.com --bots /import/bots.json --db /import/data/grokbot.dbThen point Claude Code at the server (claude mcp remove grokbot --scope user, then the claude mcp add command
from Connect Claude), remove the grokbot entry from Claude Desktop's claude_desktop_config.json, and add the
custom connector instead. Delete the local bots.json once imported: its keys are now encrypted on the server.
Development
docker run -d --name grokbot-testdb -e POSTGRES_PASSWORD=test -p 127.0.0.1:55432:5432 postgres:17-alpine
npm install
npm run typecheck
TEST_DATABASE_URL=postgres://postgres:test@127.0.0.1:55432/postgres npm testThe test creates and drops its own database, runs the server against a fake GrokBot webhook, and drives the dashboard, Claude's MCP (API token, OAuth, confirmation dialog) and the bot reply API.
To run locally: DATABASE_URL=… PUBLIC_URL=http://127.0.0.1:8787 ENCRYPTION_KEY=… npm start.
Troubleshooting
Symptom | Meaning |
| Wrong key saved for the bot; re-enter it on the bot's page |
| The routine is paused. GrokBot drops (doesn't queue) messages sent while paused |
| Claude tried to send without your yes; it should show you the message first |
| The secret blocker caught a key or token in the brief |
Bot's reply gets | The thread token expired (14 days) or the bot's reply token was rotated |
|
|
Connector won't connect | Check |
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Anonymous webhook capture, inspection, waiting, and response configuration for AI agents.
Your WhatsApp Business inbox in Claude or ChatGPT: who's waiting, follow-ups and replies.
Webhook, email and DNS inboxes for AI agents to capture callbacks and test integrations.
One workspace of tools for Claude and ChatGPT: connect 600+ apps, generate media, build tools.
Related MCP Servers
- AlicenseAqualityDmaintenanceIntegrates xAI's Grok APIs into Claude Code to enable image and video generation, real-time web searches, and multi-modal image analysis. It provides a suite of tools for interacting with Grok models directly through natural language prompts during a Claude session.521 npm1MIT
- FlicenseNot gradedqualityDmaintenanceEnables multiple Claude Code instances to communicate through direct messages and topic-based channels. It features a real-time web dashboard for monitoring conversations and includes a persistent mailbox for offline message delivery.5 npm-
- AlicenseNot gradedqualityDmaintenanceEnables Claude to read and send WhatsApp messages through a self-hosted REST API, supporting multi-user sessions, media, groups, contacts, and webhooks.2 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI sessions like Claude, Cowork, and Claude Code to pass tasks and replies between each other through per-session mailboxes, and to keep a shared knowledge base of notes that every session can read, search, and update. Runs as a self-hosted Cloudflare Worker with D1 storage, so all data stays in the user's own account.39 npmMIT