Grok Bot MCP Bridge
by mozzquito
README.md
# Grok Bot MCP Bridge
An in-progress, single-owner bridge between Grok Bot, MCP clients, and source-linked local memory. Remote gateway calls execute on the Grok Bot computer; discovery, transcript, and MCP responses never return the gateway credential.
## Screenshots
All five main pages, captured from the running app with **synthetic demo data**.
These images show the UI—not live connection or delivery proof. No private chats,
credentials, or real infrastructure addresses are included.
### Conversations

### New bot

### History

### Connections

### Owner sign-in

To regenerate, run the local app and execute `node scripts/readme-screenshots.mjs`
with Playwright installed (or set `PLAYWRIGHT_MODULE` to its module path) and Chrome
available. The script intercepts every API request; it does not read credentials,
send messages, or create bots.
## Current implementation
- Authenticated Streamable HTTP MCP using SDK v2, with legacy-client compatibility.
- Owner-approved OAuth (DCR, PKCE S256, rotating refresh tokens), separate static bearer access, and CSRF-protected browser sessions.
- Eight MCP tools for agent discovery/creation, creation verification, durable message submission, reply verification, and history search/read/status.
- Drizzle/SQLite message ledger and provenance; LanceDB vectors with local multilingual embeddings in isolated model-specific stores.
- Source-selected history import, redaction, explicit embedding and independent keyword/vector search.
- Dark sidebar-first React/Tailwind workspace with a responsive navigation drawer, owner sign-in, conversations, a New bot flow, history search, and connection details. Drafts and operation IDs survive uncertain responses.
- Selected-bot conversations load existing Grok Bot text history read-only, with earlier-page loading and refresh. Remote history remains separate from durable bridge receipts and the imported project-memory index. See [chat history behavior and limits](docs/chat-history.md).
This is a checkpoint, not a completed deployment. Public HTTPS hosting, actual Claude.ai connection, Grok Bot's MCP-client connection and deployment hardening remain open. See [the requirement ledger](docs/bridge-plan.md).
## Run locally
Use a real Node.js runtime, version 22.12 or newer; `.nvmrc` identifies the locally exercised version. A Bun-installed `node` wrapper is not a substitute. Use an up-to-date supported Node patch release for deployment.
```sh
nvm use
npm ci
npm run typecheck
npm test
npm start
```
For the web console, build once before starting the backend (`npm run build && npm start`).
For web development:
```sh
npm run build
npm run web:dev
```
Default listener: `http://127.0.0.1:4328`, MCP at `/mcp`. The root and `/chat`, `/new`, `/history`, `/connections` serve the built web app when `dist/index.html` exists.
On first start, independent owner and headless-client secrets are generated in `data/access.json` with mode `0600`. The data directory is private (`0700`) and Git-ignored. Read that file locally when configuring a client; never paste its contents into a commit, issue, chat, screenshot or public document. OAuth clients receive separate revocable tokens, not the owner secret. Real history, databases and model assets must remain uncommitted.
Keep the owner, headless-client, and remote gateway credentials distinct for deployment. An owner can explicitly configure a shared owner/gateway value locally, but that removes their credential separation; it does not bypass bridge authentication. The headless-client API token must remain distinct.
## Run as a Home Assistant OS add-on
This repository is also an installable local add-on: `config.yaml`, `Dockerfile`,
and `run.sh` at the root, with `just push` / `just install` /
`just deploy` driving a Home Assistant guest over SSH. The owner console is served
through Ingress and `8120/tcp` carries `/mcp` for MCP clients, because an MCP
client cannot authenticate to an Ingress URL. See [the add-on documentation](DOCS.md)
for options, credentials, and limits.
Configuration: `BRIDGE_DATA_DIR`, `PORT`, `BRIDGE_HOST`, `BRIDGE_PUBLIC_URL`, `BRIDGE_ALLOWED_HOSTS`, `GROKBOT_SSH_HOST`, `GROKBOT_SSH_IDENTITY_FILE`, `BRIDGE_OWNER_SECRET`, `BRIDGE_API_TOKEN`. `BRIDGE_PUBLIC_URL` is an **origin**, not a URL ending in `/mcp`; non-loopback origins require HTTPS. Default binding is loopback. Public reachability is not created merely by setting this variable.
For a dedicated SSH key, set `GROKBOT_SSH_IDENTITY_FILE` to its path when starting the bridge. The key stays on disk; SSH receives its path using `-i` and `IdentitiesOnly=yes`. Strict host-key checking remains enabled. For example:
```sh
GROKBOT_SSH_HOST=box@your-netbird-host.example \
GROKBOT_SSH_IDENTITY_FILE="$HOME/.ssh/grokbot-bridge" npm start
```
`BRIDGE_ALLOWED_HOSTS` (optional) is a comma-separated allowlist of extra `host[:port]` values accepted by the front-door host filter (for reverse-proxy or tunnel deployments).
The bot transport allowlists specific SSH targets in `server/config.ts` (edit that list for your own hosts) and otherwise refuses to run, preserves strict SSH host-key checking, and streams variable request data through stdin. Set `GROKBOT_SSH_HOST=local` instead to run the bridge colocated on the same machine as the Grok Bot client itself — this skips SSH entirely and spawns `scripts/grokbot-gateway.py` as a local subprocess (see `LocalGateway` in `server/remote.ts`).
## Memory lifecycle
Import only a reviewed, bounded JSONL selection with records shaped as:
```json
{"id":"source-event-id","project":"example-project","source":"/Users/example/history/session.jsonl","lineStart":10,"lineEnd":12,"text":"A reviewed, non-secret excerpt."}
```
```sh
npx tsx server/cli.ts history-import /path/to/reviewed-selection.jsonl
npx tsx server/cli.ts history-status
npx tsx server/cli.ts history-embed
npx tsx server/cli.ts history-search "How does OAuth approval work?"
```
Import does not embed or upload. Explicit embedding downloads model assets and runs inference locally; corpus and query text are not sent to an embedding API. Model identity, dimensions, quantization and pooling/window strategy identify the vector space. Changing models requires explicit embedding in a different physical store. Source paths/line spans remain attached to each derived chunk. Search results are untrusted historical data, never instructions to execute.
Regex redaction is a defense in depth, not a complete secret detector. Review selections before import; arbitrary directory imports, shell history, credentials, and raw full-account transcript exports are not exposed as MCP tools.
## Message semantics
`grokbot_send` requires a stable client UUID (`messageId`). Repeating that UUID returns its existing record, never a second POST. A changed prompt under the same UUID is rejected. An unresolved message prevents another send to the same agent. HTTP acceptance alone is not success: call `grokbot_verify` with the original UUID until a new, request-correlated transcript reply is recorded or the observation budget ends.
After timeout, restart or unknown acknowledgement, **verify; do not resend**. Existing terminal replies cannot be downgraded by late events. The server owns an exclusive lock in `data/server.lock`. After an unclean stop, inspect the recorded process and confirm it is stopped before removing a stale lock manually; the application does not delete stale locks automatically.
## Verification
`npm run check` runs typecheck, the unit test suite, and the web build. The
Python gateway (`scripts/grokbot-gateway.py`) has its own read-only transcript
and pagination checks in `scripts/test-grokbot-gateway.py`.
## License
Bridge source code is available under the [MIT License](LICENSE).
Third-party dependencies and referenced materials retain their respective licenses.
Credentials, local runtime data, and private conversation records are not included.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues