A thin Bun proxy that makes obsidian-mcp-server (or any cyanheads-based MCP server) work with Grok's "Bring Your Own MCP" connector feature.
Without this proxy, Grok's connector completes the MCP handshake but never fetches tools, then fails with a vague "Authentication" error after 30 seconds.
1. Immediate notifications/tools/list_changed on SSE open
Grok waits for this notification before calling tools/list. The notification must arrive the instant the SSE channel opens — not waiting for the first backend ping (which can be 30+ seconds away). The proxy emits it immediately using ReadableStream.start().
2. Strips the tasks capability
The cyanheads framework advertises a non-standard tasks capability. Grok's connector doesn't handle it and fails silently.
3. Strips listChanged flags
Removes listChanged: true from all capabilities so Grok fetches tools proactively.
4. Password-gated OAuth server
The MCP server advertises bearer auth required. Grok tries OAuth discovery, can't find an auth server, and gives up. This proxy implements a full OAuth server with a password-protected authorization page. Only someone with your password can get a valid token.
- Bun
- obsidian-mcp-server running locally (default port 3010)
- A Cloudflare Tunnel routing your public domain to
localhost:3012
MCP_HOST=https://vault.yourdomain.com \
MCP_BACKEND=http://localhost:3010 \
PROXY_PASSWORD=your-secret-password \
bun run proxy.tsCreate /Library/LaunchAgents/com.yourname.mcp-proxy.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.yourname.mcp-proxy</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/.bun/bin/bun</string>
<string>run</string>
<string>/path/to/proxy.ts</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>MCP_HOST</key>
<string>https://vault.yourdomain.com</string>
<key>MCP_BACKEND</key>
<string>http://localhost:3010</string>
<key>PROXY_PASSWORD</key>
<string>your-secret-password</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>Then: launchctl load /Library/LaunchAgents/com.yourname.mcp-proxy.plist
- Go to grok.com/connectors → New Connector → Custom
- Enter your public URL:
https://vault.yourdomain.com/mcp - Grok will redirect you to a login page — enter your
PROXY_PASSWORD - Done. Grok stores the token for 90 days.
Obsidian
└── Local REST API plugin (localhost:27124)
└── obsidian-mcp-server (localhost:3010)
└── obsidian-grok-proxy (localhost:3012)
└── Cloudflare Tunnel
└── vault.yourdomain.com/mcp
└── Grok Voice connector
Full debugging story and setup guide: viberpsychosis.com