v0.26.0+:
gbrain serve --httpships full OAuth 2.1 (client credentials, auth code + PKCE, refresh rotation, optional DCR), an embedded React admin dashboard at/admin, scoped operations, and a live SSE activity feed. Pre-v0.26 legacy bearer tokens still work —verifyAccessTokenfalls back to theaccess_tokenstable and grandfathers tokens toread+write+admin. Postgres-only for the legacy fallback (theaccess_tokenstable is Postgres-only); OAuth tables work on both PGLite and Postgres. See SECURITY.md for env vars and tunable defaults.
Access your brain from any device, any AI client. GBrain ships two transports:
gbrain serve (stdio) for local agents, and gbrain serve --http (v0.26.0+)
for remote clients over OAuth 2.1.
gbrain serveWorks with Claude Code, Cursor, Windsurf, and any MCP client that supports stdio. No server, no tunnel, no token needed. Works on both PGLite and Postgres engines.
gbrain serve --http --port 3131
ngrok http 3131 --url your-brain.ngrok.app
gbrain serve --http --port 3131 --public-url https://your-brain.ngrok.appBuilt-in HTTP transport with OAuth 2.1, scoped operations, an admin dashboard
at /admin, and a live SSE activity feed. Zero external dependencies. This is
the only path that works with ChatGPT (OAuth 2.1 + PKCE is required by the
ChatGPT MCP connector). Pass --public-url whenever the server is reachable
at anything other than http://localhost:<port> so the OAuth issuer in
discovery metadata matches what clients hit (RFC 8414 §3.3).
Supported clients:
- ChatGPT — requires OAuth 2.1 + PKCE. Works natively with
--http. - Claude Desktop / Cowork — OAuth 2.1 or legacy bearer tokens.
- Perplexity — OAuth 2.1 client credentials grant.
- Claude Code, Cursor, Windsurf — can use OAuth or legacy bearer.
See the OAuth 2.1 setup section below.
Your AI client (Claude Desktop, Perplexity, etc.)
→ ngrok tunnel (https://YOUR-DOMAIN.ngrok.app)
→ gbrain serve --http (built-in transport with bearer auth)
→ Postgres (pooler connection or self-hosted)
This requires:
- A Postgres-backed brain (the
access_tokenstable only exists on Postgres; runninggbrain serve --httpagainst a PGLite install fails fast at startup) - A machine running
gbrain serve --http - A public tunnel (ngrok, Tailscale, or cloud host)
- A bearer token created via
gbrain auth create <name>
Pre-v1.0 tokens are grandfathered as read+write+admin scopes when you upgrade
to the HTTP server, so no migration is required.
gbrain serve --http --port 3131On first start, the server prints an admin bootstrap token to stderr:
Admin bootstrap token: 3a1f9c...
Open http://localhost:3131/admin and paste it to log in.
Save this token. Open http://localhost:3131/admin and paste it to access the
dashboard. The dashboard shows live activity, registered clients, request logs,
and per-client config export.
v0.26.9+:
mcp_request_log.paramsand the live SSE activity feed default to a redacted summary{redacted, kind, declared_keys, unknown_key_count, approx_bytes}. Declared param keys are kept (intersected against the operation's spec); unknown keys are counted but never named, and byte sizes round up to 1KB so size-probe attacks can't binary-search secret content. Operators on a personal laptop who want raw payloads back can passgbrain serve --http --log-full-params(loud stderr warning fires at startup). Multi-tenant deployments should leave it on the redacted default.
Register clients from the /admin dashboard:
- Click Register client.
- Enter a name (e.g.
perplexity,chatgpt). - Pick scopes:
read,write,admin(checkboxes). - Pick grant type:
client_credentialsfor machine-to-machine (Perplexity, Claude Desktop bearer mode) orauthorization_codefor browser-based clients with PKCE (ChatGPT). - For
authorization_codeclients, paste the redirect URI. - Hit Register. The credential-reveal modal shows the
client_id(andclient_secretfor confidential clients) once. Copy or Download JSON immediately — secrets are hashed on storage and never shown again.
Or from the CLI — faster for scripting:
gbrain auth register-client perplexity \
--grant-types client_credentials \
--scopes "read write"v0.34 — source-scoped clients. Multi-source brains can scope a client's
write authority to one source and its read scope to a curated set with the
new --source and --federated-read flags:
gbrain auth register-client dept-x-agent \
--grant-types client_credentials \
--scopes "read write" \
--source dept-x \
--federated-read dept-x,shared,parent-canon--source controls the write authority — put_page / add_link / etc only
land in dept-x. --federated-read controls the read axis independently;
queries return rows from any of the listed sources. Omit both flags for the
v0.33-compatible super-client shape. Pre-v0.34 clients are backfilled to
source_id='default' on gbrain upgrade.
Host-repo wrappers can register programmatically:
await oauthProvider.registerClientManual(
'perplexity',
['client_credentials'],
'read write',
[], // redirect_uris, empty for CC
);For self-service client registration (Dynamic Client Registration, RFC 7591),
start the server with --enable-dcr. DCR is off by default.
v0.34 — bind explicitly. gbrain serve --http defaults to 127.0.0.1.
To accept connections from the ngrok tunnel (or any non-loopback source),
restart with --bind:
gbrain serve --http --port 3131 --bind 0.0.0.0 --public-url https://your-brain.ngrok.appWhen --public-url is set without --bind, a stderr WARN fires at
startup so the misconfiguration ("the tunnel is up but my agent gets
ECONNREFUSED") is loud.
brew install ngrok
ngrok config add-authtoken YOUR_TOKEN
ngrok http 3131 --url your-brain.ngrok.appYour OAuth issuer URL becomes https://your-brain.ngrok.app. The MCP SDK's
router exposes the spec-compliant discovery endpoint at
/.well-known/oauth-authorization-server.
Every operation is tagged read | write | admin. Four operations are
localOnly and rejected over HTTP regardless of scope: sync_brain,
file_upload, file_list, file_url. Remote agents cannot reach local
filesystem surface area.
| Scope | What it allows |
|---|---|
read |
search, query, get_page, list_pages, graph traversal |
write |
put_page, delete_page, add_link, add_timeline_entry |
admin |
Client management, token revocation, sweep, local-only ops |
Keep using pre-v0.26 bearer tokens if you aren't ready to migrate. They
grandfather to read+write+admin scopes on the HTTP server.
See the ngrok-tunnel recipe for full setup. Quick version:
brew install ngrok
ngrok config add-authtoken YOUR_TOKEN
ngrok http 8787 --url your-brain.ngrok.app # Hobby tier for fixed domain# Create a token for each client
gbrain auth create "claude-desktop"
# List all tokens
gbrain auth list
# Revoke a token
gbrain auth revoke "claude-desktop"Tokens are per-client. Create one for each device/app. Revoke individually if compromised. Tokens are stored SHA-256 hashed in your database.
- ChatGPT: setup guide (OAuth 2.1 + PKCE, requires
gbrain serve --http) - Claude Code: setup guide
- Claude Desktop: setup guide (must use GUI, not JSON config)
- Claude Cowork: setup guide
- Perplexity: setup guide
gbrain auth test \
https://YOUR-DOMAIN.ngrok.app/mcp \
--token YOUR_TOKENAll 30 GBrain operations are available remotely, including sync_brain and
file_upload (no timeout limits with self-hosted server).
Security note on file_upload: remote MCP callers are confined to the working
directory where gbrain serve was launched. Symlinks, .. traversal, and absolute
paths outside cwd are rejected. Page slugs and filenames are allowlist-validated
(alphanumeric + hyphens; no control chars, RTL overrides, or backslashes). Local
CLI callers (gbrain file upload ...) keep unrestricted filesystem access since
the user owns the machine.
See ALTERNATIVES.md for a comparison of ngrok, Tailscale Funnel, and cloud hosts (Fly.io, Railway).
"missing_auth" error
Include the Authorization header: Authorization: Bearer YOUR_TOKEN
"invalid_token" error
Run gbrain auth list to see active tokens.
"service_unavailable" error Database connection failed. Check your Supabase dashboard for outages.
Claude Desktop doesn't connect
Remote servers must be added via Settings > Integrations, NOT
claude_desktop_config.json. See CLAUDE_DESKTOP.md.
| Operation | Typical Latency | Notes |
|---|---|---|
| get_page | < 100ms | Single DB query |
| list_pages | < 200ms | DB query with filters |
| search (keyword) | 100-300ms | Full-text search |
| query (hybrid) | 1-3s | Embedding + vector + keyword + RRF |
| put_page | 100-500ms | Write + trigger search_vector update |
| get_stats | < 100ms | Aggregate query |
Note: gbrain serve --http shipped in v0.26.0 with OAuth 2.1 + admin
dashboard baked into the binary. The custom HTTP wrapper pattern (see
voice recipe) is still supported for
teams that need bespoke middleware, but for most remote deployments the
built-in server is the recommended path.