Skip to main content
Glama

vibedev-bridge

A local MCP server that gives web-based AI agents (claude.ai, ChatGPT, Grok — experimental: Gemini, plus Postman's AI agent) read/edit access to your machine's files and a shell allowlist, over HTTPS through a swappable public edge.

  • Transport: Streamable HTTP MCP behind OAuth 2.1

  • Default edge: Tailscale Funnel — bring-your-own Cloudflare named tunnel or any stable HTTPS origin also supported

  • Platforms: Windows · Linux · macOS (Node.js 22)

  • npm: private/unpublished — run from source

Why

Web AI subscriptions (Claude Pro, ChatGPT Plus…) are far cheaper than per-token API use for everyday work, but an agent without access to your files can only talk. The official desktop apps tie local access to a device ID and one login at a time; with a remote MCP server you instead get:

  • Web-quota file and shell access directly from the browser

  • Multi-account flexibility — switch browser profiles, point every account at the same machine

  • Fail-safe execution — the shell tool is a hand-curated allowlist, not a blocklist (Security)

Typical scenarios: at your desk use a native CLI (fastest). Away from the desk — mobile/web/another machine — use this to check jobs, read logs, pull code or clean temp files. Combined with Grok's scheduled prompts it also runs as a headless cloud-triggered local node.

Related MCP server: universal-dev-mcp

Install & run

git clone https://github.com/hoan9an/vibedev-bridge.git
cd vibedev-bridge
npm install
# Development mode (~/.vibedev/mcpsv-dev, ports 9997/9996)
npm run dev

# Production mode (~/.vibedev/mcpsv, ports 9999/9998)
npm start

npm start (foreground; Ctrl+C to stop) handles everything:

  • Passphrase and OAuth client ID/secret generated once under ~/.vibedev/mcpsv/, reused on later runs

  • Funnel: checks tailscale funnel status; if port 9999 is not Funnel-enabled yet, runs tailscale funnel --bg 9999 (idempotent)

  • Prints the four values you need for the connectors: MCP URL, Client ID, Client Secret, Passphrase

  • Opens the control panel at http://127.0.0.1:9998/?t=<token> — sections: 0 Setup (ingress picker) → 1 Connectors2 Install vibedev-rules3 Instructions4 Browser utilities5 Folders6 Shell allowlist

Nothing is installed system-wide, no background daemon is created, and no admin rights are required. Closing the terminal stops the server.

Allowed folders

The default allowed root is your home directory. Add/remove absolute paths in panel section 5 — saves take effect on the next tool call, no restart. Beyond the configured roots, the tools are also granted ~/.vibedev (where vibedev-rules deploys) and ~/.claude, so web agents can read your native CLAUDE.md and the rule corpus the way Claude Code does. ~/.claude is granted at folder level (known tradeoff — session tokens inside it are reachable; the panel row is locked, edit ~/.vibedev/mcpsv/setting.json directly if you want it removed).

Connecting

All clients use the same MCP URL and the same passphrase consent screen; only how they authenticate differs.

Claude web (claude.ai) — primary

  1. claude.ai → Settings → Connectors → Add custom connector

  2. Paste the Remote MCP server URL (https://your-machine.ts.net/mcp)

  3. Advanced settings → paste Client ID + Client Secret printed by npm start

  4. Click Connect → enter the passphrase on the local consent page

ChatGPT — needs Developer mode

  1. Enable Developer mode (Settings → Security and login)

  2. Add a custom connector with the same MCP URL

  3. Same passphrase on the consent page

ChatGPT self-registers via RFC 7591 DCR (POST /register, PKCE, no secret). Do not paste Claude's credentials — each client binds to its own registration.

Grok

Self-registers via the same DCR path — paste only the MCP URL, no Client ID. Its redirect URI is allowlisted; if Grok ever moves it, the server logs register REJECTED (redirect_uri not allowlisted) with the new value to re-allowlist.

Gemini (experimental)

Same confidential-client flow as Claude (client ID + secret). The OAuth handshake works, but tool discovery/drive is unreliable in testing — treat Claude and Grok as the dependable clients today.

Postman (AI agent)

No OAuth redirect and no persistent system prompt on Postman's side:

  1. Panel → Postman tab → copy the filled JSON (live MCP URL + minted token)

  2. Postman → Settings → Connected Accounts → add MCP server → paste the JSON

  3. Paste the panel's prompt at the start of each chat

The Postman tab also hosts a Launch button that attaches a CDP-driven control daemon to the Postman desktop app (auto-clicking Approve/Run, toggling Thinking/Auto-run, opening a new window). It starts only when you click Launch — never at boot. Its injected overlay is the VibeSoft MCP for Postman panel; external links (the vibedev-bridge and vibedev-rules repos) open in your OS default browser.

Official tool suite (39 tools)

  • Chromium control: vibe__chrome_profiles vibe__chrome_launch vibe__chrome_tabs vibe__chrome_interact vibe__chrome_probe_ai vibe__chrome_stop

  • DevTools / CDP: vibe__devtools_targets vibe__devtools_eval vibe__devtools_screenshot

  • System: vibe__notify_user vibe__clipboard_read vibe__clipboard_write

  • HTTP: vibe__local_fetch (SSRF-protected localhost/LAN)

  • Background tasks: vibe__task_start vibe__task_manage

  • Filesystem: vibe__read_text_file vibe__write_file vibe__edit_file vibe__create_directory vibe__move_file vibe__get_file_info vibe__list_allowed_directories

  • Search & shell: vibe__find_path vibe__search_content vibe__run_cmd

  • Ports & dev servers: vibe__port_status vibe__kill_port

  • Git: vibe__git_status vibe__git_diff vibe__git_log

  • SQLite: vibe__sqlite_schema vibe__sqlite_query

  • Agents & context: vibe__agy_run vibe__kiro_read vibe__vibedev-rules_context

  • Postman: vibe__postman_status vibe__postman_eval vibe__postman_rename_conversation vibe__postman_panel_fullwidth

Requirements

  • Node.js 22 — Windows, Linux or macOS

  • Windows only: Git for Windows on PATH — the shell/search tools shell out to Unix binaries (grep, find, …); usr/bin ships what's needed. Prerequisite, not a code dependency.

  • Tailscale (default edge, one-time): install, sign in, and enable Funnel for your tailnet once (login.tailscale.com/f/funnel) — free on every plan. npm start enables port 9999 automatically after that.

Architecture

Claude web / ChatGPT / Grok
      │  HTTPS + OAuth 2.1 (Claude: pre-registered client · others: DCR self-register)
      ▼
Tailscale Funnel        (https://your-machine.ts.net)
      │
      ▼
gatekeeper.js  — public port 9999
      │   /.well-known/oauth-* + openid-configuration (discovery)
      │   /authorize, /token   minimal authorization server (oauth.js)
      │   /register            RFC 7591 dynamic client registration
      │   /mcp                 Bearer-token protected → streamable-bridge.js (Streamable HTTP)
      ▼
tools-server.js — one shared in-process McpServer (InMemoryTransport) mounting:
      filesystem · search · shell (allowlisted) · agy · kiro · rule-context · chrome/CDP ·
      postman · fetch · task · port · git · system · sqlite
panel.js       — loopback-only control panel (:9998), token-gated, never exposed

The ingress is swappable: Tailscale Funnel (default) → your own PUBLIC_ORIGIN → a Cloudflare named tunnel (--tunnel <cred.json> --origin <host>). Precedence follows that order; OAuth and tools are unchanged either way. The panel (section 0) also accepts a cloudflared credentials JSON for no-CLI setups.

Funnel troubleshooting: a "Couldn't connect" while tailscale funnel status says "on" is usually a serve-config sync failure to Tailscale's edge, not a code bug. Don't test with a bare curl https://<host> from the tailnet-joined machine (the mesh shortcut hides the failure) — test the public path:

dig @8.8.8.8 <host> A +short
curl --resolve <host>:443:<IP> https://<host>/.well-known/oauth-authorization-server

A TLS error there → re-run tailscale funnel --bg 9999 to force a re-push. Avoid toggling Funnel repeatedly (Let's Encrypt rate limits).

Configuration

Copy .env.example to .env for overrides — PUBLIC_ORIGIN, GATEKEEPER_PORT, PANEL_PORT, MCP_DATA_DIR, MCP_REQUEST_TIMEOUT_MS. Boot falls back to defaults silently without the file.

Directory layout

vibedev-bridge/
├── bin/vibedev-bridge.js          # global CLI entry (npm package stays private)
├── scripts/
│   ├── start.js                   # single process: gatekeeper + panel + warm tools server
│   ├── gatekeeper.js / oauth.js   # public edge: OAuth server + /mcp proxy
│   ├── streamable-bridge.js       # Streamable HTTP shim → in-process MCP server
│   ├── tools-server.js            # mounts every tool register() module
│   ├── filesystem-mcp.js · search-mcp.js · shell-mcp.js (+ allowlist.js)
│   ├── chrome-mcp.js · chrome-profile.js · cdp-mcp.js · cdp-engine.js
│   ├── postman-mcp.js · rule-context{,-mcp}.js · fetch-mcp.js · task-mcp.js
│   ├── port-mcp.js · git-mcp.js · system-mcp.js · sqlite-mcp.js · agy-mcp.js · kiro-mcp.js
│   ├── panel.js · config-page.js  # loopback control panel
│   ├── vibe-pmcontrol/            # CDP-driven Postman desktop control daemon
│   ├── roots.js · log.js · http.js · html.js · open-browser.js · userdata.js
│   └── update-check.js            # local-only version snapshot, no remote check
├── test/                          # suite (npm test)
└── public/                        # panel CSS/JS + images

User data lives outside the repo at ~/.vibedev/mcpsv/ (settings, tokens, passphrase, DCR clients — all 0600), the same convention as ~/.aws / ~/.docker. A clone never produces a diff from panel edits.

Security

  • Whitelist, not blocklist. Only allowlisted commands run; the default set is read-only (flag-rich binaries whose own flags escape read-only — e.g. find -delete — stay out). Adding commands is a deliberate panel edit, and any command you add runs under your responsibility.

  • OAuth 2.1 over token-in-URL. One pre-issued confidential client (Claude) + DCR public clients (ChatGPT/Grok); tokens bound to their issuing client ID. Details: docs/ref/security-model.md.

  • Single public entry point (gatekeeper.js); the panel binds 127.0.0.1 only, is token-gated per request, and is never exposed.

  • Tokens persist in ~/.vibedev/mcpsv/tokens.json (0600) — a connector is long-lived file access, not a login. Revoke by deleting tokens.json (or oauth-dcr-clients.json) and restarting.

Whitelist rationale

Fail-safe by default (unknown commands blocked), minimal attack surface, subcommand granularity (git scoped to status/log/diff/show), neutralized prompt-injection escalation (nothing unlisted to reach for), read-only by construction. Distinct from Desktop Commander's local blocklist approach by design.

Notes

  • Connector icon: claude.ai queries Google's favicon service with the tailnet apex domain, which has no public DNS record — a default letter icon is what you'll see. The gatekeeper still serves a valid /favicon.ico; the browser just never asks this server for it.

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers