Skip to main content
Glama

Muse Relay — a two-way bridge between Meta Muse and Grok Bot

Let your Muse agent and your Grok Bot talk to each other directly — questions, answers, and files — with no laptop in the loop. Runs free on Vercel (Hobby) + Neon Postgres (free). One script sets it all up.

flowchart LR
  M[Muse agent] -- "REST + MUSE_KEY<br/>/api/v1/ask (long-poll)<br/>/api/v1/messages, /files" --> R[(Muse Relay<br/>Vercel function)]
  R <--> DB[(Neon Postgres<br/>threads · messages · attachments)]
  R -- "webhook on new Muse msg<br/>GROK_WEBHOOK_URL + GROK_WEBHOOK_AUTH" --> W[Grok Bot webhook routine]
  G[Grok Bot] -- "MCP /mcp + GROK_KEY<br/>send_to_muse, check_muse_messages, ..." --> R
  W --> G

How a question flows: Muse calls POST /api/v1/ask → relay stores it and fires the webhook → Grok Bot wakes, reads it via MCP, replies with send_to_muse → the still-open /ask request returns the reply to Muse (usually < 1 min).

Quick start

Option A — paste this into your Grok Bot

Set up my own Muse relay from https://github.com/AISupplyGuy/muse-relay.
Clone it on your box, run ./setup.sh, and complete any Neon/Vercel browser
sign-ins it prints. Never print secret values. Then: add the MCP connector
from the README "Grok side" section, create a webhook routine named
"New Muse message" (ask me to copy its URL and Authorization header into
env vars), run ./set-webhook.sh and ./smoke-test.sh, and finally give me
the Muse instruction block from the README with my relay URL filled in.

Option B — run it yourself (Linux/macOS, Node 20+)

git clone https://github.com/AISupplyGuy/muse-relay && cd muse-relay
./setup.sh                      # Neon DB + keys + Vercel deploy
# create your Grok Bot webhook routine, then:
GROK_WEBHOOK_URL='https://...' GROK_WEBHOOK_AUTH='Bearer ...' ./set-webhook.sh
./smoke-test.sh

setup.sh is non-interactive except for browser sign-ins, and safe to re-run (it reuses existing projects and keys):

  1. Installs vercel and neonctl CLIs if missing (npm i -g --prefix ~/.local).

  2. If you're not signed in, runs vercel login / neonctl auth and prints the URL to open. No account? Both are free: neon.tech and vercel.com — GitHub or Google sign-in works.

  3. Creates a Neon project muse-relay (region aws-us-east-2) and takes its pooled connection string. Tables are created automatically on the first request — no SQL to run.

  4. Generates random MUSE_KEY, GROK_KEY, WEBHOOK_SECRET.

  5. Creates/links the Vercel project, sets env vars via stdin (never echoed), deploys --prod, checks /health, and turns off Vercel Deployment Protection if it blocks public calls.

  6. Writes everything to ~/secrets/muse-relay.env (chmod 600).

Overrides: PROJECT_NAME, NEON_REGION, VERCEL_SCOPE (team slug), DATABASE_URL (use an existing Postgres and skip Neon), MUSE_RELAY_ENV_FILE.

Related MCP server: Muse-Chat-MCP

Env vars

On Vercel (production):

Name

Required

Purpose

DATABASE_URL

yes

Neon pooled Postgres URL

MUSE_KEY

yes

Bearer key Muse sends on /api/v1/*

GROK_KEY

yes

Bearer key Grok Bot sends on /mcp

WEBHOOK_SECRET

yes

HMAC secret for X-Relay-Signature

GROK_WEBHOOK_URL

no

Grok Bot routine webhook URL (push on new Muse msg)

GROK_WEBHOOK_AUTH

no

Sent verbatim as the webhook Authorization header

MUSE_WEBHOOK_URL

no

POSTed on each new Grok→Muse message (event grok.message.created) so something can wake Muse

MUSE_WEBHOOK_AUTH

no

Sent verbatim as Authorization on Muse webhook calls

PUBLIC_BASE_URL

no

Base URL shown in docs/openapi (setup sets it)

MAX_FILE_BYTES, MAX_TOTAL_STORAGE_BYTES, POLL_INTERVAL_MS

no

Tuning (defaults 3 MB, 400 MB, 1500 ms)

Local ~/secrets/muse-relay.env: MUSE_RELAY_URL, MUSE_RELAY_GROK_KEY, MUSE_RELAY_MUSE_KEY, MUSE_RELAY_WEBHOOK_SECRET, MUSE_RELAY_DATABASE_URL.

Grok side

1. MCP connector. Add a local (stdio) MCP server to Grok Bot with this command. It reads the key from the secrets file, so the key never appears in chat:

bash -c 'set -a; . ~/secrets/muse-relay.env; set +a; exec npx -y mcp-remote "$MUSE_RELAY_URL/mcp" --transport http-only --header "Authorization:Bearer $MUSE_RELAY_GROK_KEY"'

Tools: send_to_muse, check_muse_messages (supports wait_seconds ≤ 55), get_thread, get_attachment, list_threads, mark_read. Transport is streamable HTTP, stateless JSON (no SSE).

2. Wake routine. Create a webhook-triggered routine on Grok Bot (e.g. "New Muse message": check_muse_messages, answer in the same thread with send_to_muse, ask me before anything sensitive). Copy its webhook URL and Authorization header into env vars and run ./set-webhook.sh. Payload: POST {event:"muse.message.created", message:{id, cursor, thread_id, sender, text, created_at, attachments}} with headers X-Relay-Timestamp, X-Relay-Signature: sha256=HMAC(secret, "<ts>.<body>"), X-Relay-Secret. Delivery is single-shot, so the routine should also catch up with check_muse_messages each time it wakes.

Muse side — paste into Muse

Give Muse its key (MUSE_RELAY_MUSE_KEY) through Muse's own secret/credential setting if it has one, then paste:

You have a private relay to my Grok Bot at https://YOUR-RELAY.vercel.app
Read https://YOUR-RELAY.vercel.app/openapi.json. Authenticate every call with
"Authorization: Bearer <MUSE_KEY>".
- To ask Grok something, use POST /api/v1/ask {"text": "...", "wait_seconds": 240}.
  It holds the request open and returns Grok's reply directly (usually < 1 min).
  Use a client timeout of at least 255 s. If it returns timed_out:true, keep waiting
  with GET /api/v1/messages?thread_id=<thread_id>&since=<next_cursor>&wait=240.
- Files: attachments [{filename, content_type, content_base64}], max 5 files and
  3 MB per message. Download incoming files with GET /api/v1/files/:id.
- Check GET /api/v1/messages every 15 minutes for messages Grok starts.
- Don't hold listeners open around the clock: the relay runs on free Vercel/Neon
  limits. Long-poll only while you're waiting on an answer.

Free-tier limits & cost

  • Vercel Hobby: functions are billed by active CPU / memory time. Occasional /ask calls are effectively free. Back-to-back 24/7 long-polling would use several times the monthly Hobby allowance — don't.

  • Neon free: 0.5 GB storage, limited compute hours; the DB auto-suspends when idle. Every long-poll keeps compute awake (polls every 1.5 s).

  • Relay caps: 5 files and 3 MB decoded per message (HTTP 413 over), 20 000 chars of text, 400 MB total attachment storage (HTTP 507 over). No auto-cleanup — delete old threads in Neon's SQL editor (DELETE FROM threads WHERE updated_at < now() - interval '30 days'; cascades).

Security notes

  • Two separate random 256-bit keys: Muse's key can't call MCP, Grok's key can't use the Muse REST API (either can download files). Rotate by editing the env var on Vercel and redeploying.

  • Keep ~/secrets/muse-relay.env chmod 600 and never paste values into chat; the scripts never print them.

  • Webhook calls are HMAC-signed; verify X-Relay-Signature if your receiver can.

  • Anything Muse sends is untrusted input to Grok Bot. Have your routine ask you before sending messages, spending money, or sharing data on Muse's behalf.

  • The production URL must be public for Muse to reach it; setup turns off Vercel Authentication (Deployment Protection). Fix by hand if needed: Vercel → project → Settings → Deployment Protection → Vercel Authentication: Disabled.

API reference

Live docs at /docs (also /llms.txt) and /openapi.json on your deployment. Endpoints: GET /health, POST /api/v1/ask, GET|POST /api/v1/messages, POST /api/v1/messages/read, GET /api/v1/threads, GET /api/v1/threads/:id, GET /api/v1/files/:id, POST /mcp.

License

MIT

Waking Muse on new messages (no polling by the AI)

Muse has no public inbound webhook. Two event-driven options:

  1. Muse hook (recommended). Ask Muse to create a lightweight, non-AI hook that runs every 60 seconds and calls GET /api/v1/signal with the Muse key. It returns {unread, latest_cursor, has_unread}. The hook exits silently when nothing changed and wakes Muse only when has_unread is true. Muse handles the messages, marks them read, and goes back to sleep.

  2. Push via MUSE_WEBHOOK_URL. Set it to any catch hook (Zapier, n8n) that can reach Muse; the relay POSTs every Grok→Muse message there.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    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
    3
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables a single owner to receive WhatsApp messages and attachments in a ChatGPT MCP Events client and to send creator-bound text or file replies through OAuth-secured MCP tools. It also supports reading unanswered messages, attachment parts, and delivery/recovery status without any hosted AI model or API key.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Lets Claude Desktop, Claude Code, Cursor, and other MCP clients send messages to any external AI bot over an HTTP webhook and fetch the bot's answer back into the chat. Replies can arrive in the webhook response body, by polling a reply URL, over an SSE stream, or by posting to a local inbox, with tools for sending, reading, and waiting on threaded replies.
    7
    4,971 npm
    MIT