Skip to main content
Glama
kinopeee
by kinopeee

grokbot-mcp-bridge

English | 日本語

What it does: lets Poke — or any MCP client — ask a Grok Bot a question and get the answer back as a normal tool result, even though Grok Bot can only reply asynchronously via a webhook callback.

Who it is for: anyone who can deploy a small app to Fly.io and has a Grok Bot routine with a Web webhook trigger. No knowledge of MCP internals is needed; the quick start below is copy-paste.

How: the bridge holds the Cursor webhook URL/key server-side, so Poke only ever sees the bridge URL and one API key you generate.

How it flows

sequenceDiagram
    participant P as Poke (MCP client)
    participant B as Bridge (https://<app>.fly.dev)
    participant G as Grok Bot routine
    P->>B: tools/call ask_grokbot (Bearer MCP_API_KEY)
    B->>G: POST webhook (run_id, callback_url)
    G-->>B: POST /callbacks/{token} (answer, run_id)
    B-->>P: answer_text

Related MCP server: GrokBot ↔ Hermes Bridge

Documentation

Document

English

日本語

Overview (this file)

README.md

README.ja.md

Bridge specification and operations

SPEC.md

SPEC.ja.md

Calling Grok Bot from Poke

poke-invocation.md

poke-invocation.ja.md

Quick start (Poke → Grok Bot in four steps)

<app> below is app in fly.toml (defaults to grokbot-mcp-bridge).

0. Which value goes where

Required (3 secrets + 1 URL)

Value

Where you get it

Where you enter it

CURSOR_WEBHOOK_URL

Grok Bot app → the routine with the Web webhook trigger → "POST URL" (https://api2.cursor.sh/automations/webhook/…)

Fly secret on the bridge (step 2)

CURSOR_WEBHOOK_API_KEY

Same screen → "Key" (crsr_…). Copy only the key, not the Authorization: Bearer header line

Fly secret on the bridge (step 2)

MCP_API_KEY

Generate yourself (openssl rand -hex 32)

Fly secret (step 2) and Poke → New Integration → "API Key" (step 3) — same value in both

https://<app>.fly.dev/mcp

Fixed by the bridge

Poke → New Integration → "Server URL" (step 3)

Grok Bot routine instructions

This repo: poke-invocation.md § 4 (ready-to-paste template)

Grok Bot app → the same routine → "Instructions" field

Routine screen: chat header → info panel → Routines → Web webhook.

Optional (skip on first setup)

Value

Where you get it

Where you enter it

INBOUND_WEBHOOK_SECRET

Generate yourself (optional)

Fly secret (step 2), and the Grok Bot-side push routine if you use POST /hooks/grokbot

CALLBACK_ALLOWED_HOSTS

Comma-separated hostnames the inbound callback_url may target (e.g. callback.example.com)

Fly secret (step 2), only for push delivery

Only for push delivery via POST /hooks/grokbot (list_grokbot_events). Not needed for ask_grokbot.

1. Prepare the Grok Bot webhook

In the Cursor automation that runs Grok Bot, enable the webhook trigger and copy its URL and crsr_… API key. They become CURSOR_WEBHOOK_URL / CURSOR_WEBHOOK_API_KEY and are stored only on the bridge — Poke never sees them.

The routine's Instructions field must tell Grok Bot to echo run_id and POST the answer to callback_url — paste the template from poke-invocation.md § 4.

2. Deploy the bridge to Fly.io

Log in with flyctl auth login, or for non-interactive use create a token at https://fly.io/tokens and export it as FLY_API_TOKEN (tokens have an expiry you choose at creation; renew before it lapses).

export MCP_API_KEY="$(openssl rand -hex 32)"            # keep this value: Poke needs it in step 3
export INBOUND_WEBHOOK_SECRET="$(openssl rand -hex 32)" # optional (push delivery only)
flyctl apps create <app>
flyctl volumes create bridge_data -r <region> -s 1 -a <app> --yes   # SQLite lives on /data
flyctl secrets set -a <app> \
  CURSOR_WEBHOOK_URL="$CURSOR_WEBHOOK_URL" \
  CURSOR_WEBHOOK_API_KEY="$CURSOR_WEBHOOK_API_KEY" \
  MCP_API_KEY="$MCP_API_KEY" \
  INBOUND_WEBHOOK_SECRET="$INBOUND_WEBHOOK_SECRET" \
  ALLOWED_HOSTS=<app>.fly.dev \
  DB_PATH=/data/bridge.db
flyctl deploy --remote-only --ha=false -a <app>
  • MCP_API_KEY and INBOUND_WEBHOOK_SECRET are not issued by Poke or Cursor; you generate them yourself. echo "$MCP_API_KEY" shows it in the same shell — Poke needs the same value in step 3, and Fly does not show secret values again.

  • INBOUND_WEBHOOK_SECRET is optional. Without it, POST /hooks/grokbot returns 503 and bridge_status reports inbound_webhook_secret_configured: false; ask_grokbot still works.

  • Push delivery via POST /hooks/grokbot also needs CALLBACK_ALLOWED_HOSTS. The value is the hostname of the callback_url your Grok Bot routine puts in the webhook body (comma-separate multiple hosts; example.com also covers api.example.com). To see which hosts past events used, call list_grokbot_events → get_grokbot_event(id) from Poke and check body.callback_url / reply_url / response_url.

    flyctl secrets set -a <app> CALLBACK_ALLOWED_HOSTS=callback.example.com

    Unset → every inbound callback_url is rejected (a well-formed https URL reports callback_error: "allowed_hosts_not_configured"; other URLs fail earlier checks). The event itself is still recorded; ask_grokbot is unaffected.

3. Connect Poke

Add an MCP integration in Poke with:

Field

Value

Name

any label, e.g. grokbot-mcp-bridge

Server URL

https://<app>.fly.dev/mcp (Streamable HTTP). Use https://<app>.fly.dev/sse if the client only supports SSE

API Key

the value of MCP_API_KEY (no Bearer prefix). Poke labels this field optional, but leave it empty and Poke will try OAuth and fail — always set it

4. Verify end to end

  1. GET https://<app>.fly.dev/healthz → 200 {"ok":true}

  2. From Poke, call bridge_status → webhook_url_configured and webhook_api_key_configured are true (inbound_webhook_secret_configured is false if you skipped the optional secret — that is fine)

  3. From Poke, call ask_grokbot with payload={"message": "Introduce yourself briefly."}, wait_seconds=60

    • answer_status: "answered" → answer_text holds the reply

    • answer_status: "pending" → call wait_for_grokbot_answer(run_id) (default 60s, max MAX_WAIT_SECONDS) or cancel_run to stop

    • answer_status: "cancelled" / "expired" → do not wait; start a new ask_grokbot if needed

    Sample result:

    {
      "ok": true,
      "run_id": "06eec502-cf7b-468d-8307-8dcf945e1f17",
      "answer_status": "answered",
      "answer_text": "…the reply text…",
      "summary": "Grok Bot answered: …"
    }
  4. flyctl logs -a <app> shows run created → callback resolved → trigger returning

For the Grok Bot-side contract (echoing run_id, posting to callback_url) and troubleshooting, see poke-invocation.md.

Endpoints

  • GET /healthz

  • GET /

  • POST /mcp (authenticated MCP)

  • GET /sse and POST /messages/ (authenticated MCP)

  • POST /hooks/grokbot (signed inbound Grok Bot events)

  • POST /callbacks/{token} (Grok Bot answers)

MCP tools

  • bridge_status

  • ask_grokbot

  • get_grokbot_run

  • wait_for_grokbot_answer

  • cancel_run

  • list_grokbot_runs

  • list_grokbot_events

  • get_grokbot_event

Resources are available at grokbot://events and grokbot://runs.

Environment variables

CURSOR_WEBHOOK_URL, CURSOR_WEBHOOK_API_KEY, MCP_API_KEY, INBOUND_WEBHOOK_SECRET, DB_PATH, ALLOWED_HOSTS, PUBLIC_BASE_URL, CALLBACK_TTL_SECONDS, CALLBACK_ALLOW_HTTP, CALLBACK_ALLOWED_HOSTS, RUN_RETENTION_SECONDS, EVENT_RETENTION_SECONDS, CLEANUP_INTERVAL_SECONDS, RATE_LIMIT_PER_MINUTE, and MAX_WAIT_SECONDS. See SPEC.md §7 for defaults (key names only; do not put secret values in docs or .env.example).

Callback contract

Grok Bot should POST JSON such as:

{"ok": true, "answer": "...", "run_id": "<echoed uuid>"}

The run_id (or request_id) must echo the UUID sent by ask_grokbot. When an inbound webhook has no callback URL, the bridge returns 「コールバックURLなし」 ("no callback URL") and records the event without delivering a callback.

Commands

uv run --extra dev pytest -q               # tests
uv lock && uv export --no-dev --format requirements-txt --no-emit-project -o requirements.txt   # update pinned deps
flyctl deploy --remote-only --ha=false     # deploy (app / region come from fly.toml)

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to manage Grok Bots through MCP: create, list, search, and delete bots, send and receive messages, read conversation transcripts, search message history, and check usage.
    11
    2
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to perform X/Grok searches through xAI's server-side search tool using the Responses API, returning upstream results without rewriting.
    13 npm
    MIT