feat: accept the HTTPS /mcp/<uuid> connector URL in --remote (#145) - #146
Closed
dzianisv wants to merge 2 commits into
Closed
feat: accept the HTTPS /mcp/<uuid> connector URL in --remote (#145)#146dzianisv wants to merge 2 commits into
dzianisv wants to merge 2 commits into
Conversation
dzianisv
force-pushed
the
fix/135-relay-lifecycle
branch
from
August 14, 2026 17:48
848f1c8 to
77f87aa
Compare
Users are shown one canonical connector credential in the extension (https://relay.api.vibebrowser.app/mcp/<uuid>). That string could be pasted into Claude/ChatGPT connectors but not into the CLI, which forced users to learn a second transport URL for the same bearer capability. `--remote` (start, openclaw, browser CLI) and the MCP `set_remote` tool now accept it, deriving the relay target deterministically through the single shared normalizer `parseRemoteTarget`: https://host[/prefix]/mcp/<uuid> -> wss://host[/prefix] + <uuid> http://<loopback>[/prefix]/mcp/<uuid> -> ws://<loopback>[/prefix] + <uuid> Bare UUID and ws(s) relay URL forms are unchanged. All #136 hardening is preserved: valid UUID only, no credentials/query/ fragment, no non-loopback plaintext relay transport, and no bearer value in errors, logs, help text, or CLI output. Generic HTTP(S) URLs without the exact /mcp/<uuid> suffix are rejected. Tests: connector normalization matrix (self-hosted path prefixes, ports, loopback forms), malformed/hostile URL rejections with leak assertions, a live set_remote connect over the connector form, a browser-CLI status run through an http connector URL, and a packaged-CLI help gate. Refs #145, #130 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dzianisv
force-pushed
the
feat/cli-http-mcp-remote
branch
from
August 14, 2026 17:55
3bebf68 to
461d953
Compare
…o 0.3.2 npm already serves @vibebrowser/mcp@0.3.3 and @vibebrowser/cli@0.3.1, so merging #146 as-is would be a no-op for the publish workflow. Bump both packages and sync every mirrored version reference the plugin-bundle contract test asserts against package.json (server.json, mcpb/manifest.json, plugin.json, .mcp.json pin, marketplace.json). package-lock.json was regenerated via `npm version --no-git-tag-version`; no dependency changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dzianisv
added a commit
that referenced
this pull request
Aug 14, 2026
…o 0.3.2 npm already serves @vibebrowser/mcp@0.3.3 and @vibebrowser/cli@0.3.1, so merging #146 as-is would be a no-op for the publish workflow. Bump both packages and sync every mirrored version reference the plugin-bundle contract test asserts against package.json (server.json, mcpb/manifest.json, plugin.json, .mcp.json pin, marketplace.json). package-lock.json was regenerated via `npm version --no-git-tag-version`; no dependency changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dzianisv
added a commit
that referenced
this pull request
Aug 14, 2026
…147) * feat: accept the HTTPS /mcp/<uuid> connector URL in --remote (#145) Users are shown one canonical connector credential in the extension (https://relay.api.vibebrowser.app/mcp/<uuid>). That string could be pasted into Claude/ChatGPT connectors but not into the CLI, which forced users to learn a second transport URL for the same bearer capability. `--remote` (start, openclaw, browser CLI) and the MCP `set_remote` tool now accept it, deriving the relay target deterministically through the single shared normalizer `parseRemoteTarget`: https://host[/prefix]/mcp/<uuid> -> wss://host[/prefix] + <uuid> http://<loopback>[/prefix]/mcp/<uuid> -> ws://<loopback>[/prefix] + <uuid> Bare UUID and ws(s) relay URL forms are unchanged. All #136 hardening is preserved: valid UUID only, no credentials/query/ fragment, no non-loopback plaintext relay transport, and no bearer value in errors, logs, help text, or CLI output. Generic HTTP(S) URLs without the exact /mcp/<uuid> suffix are rejected. Tests: connector normalization matrix (self-hosted path prefixes, ports, loopback forms), malformed/hostile URL rejections with leak assertions, a live set_remote connect over the connector form, a browser-CLI status run through an http connector URL, and a packaged-CLI help gate. Refs #145, #130 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(release): bump @vibebrowser/mcp to 0.3.4 and @vibebrowser/cli to 0.3.2 npm already serves @vibebrowser/mcp@0.3.3 and @vibebrowser/cli@0.3.1, so merging #146 as-is would be a no-op for the publish workflow. Bump both packages and sync every mirrored version reference the plugin-bundle contract test asserts against package.json (server.json, mcpb/manifest.json, plugin.json, .mcp.json pin, marketplace.json). package-lock.json was regenerated via `npm version --no-git-tag-version`; no dependency changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(remote): redact every UUID path segment from remote targets A malformed-but-parseable connector URL such as https://host/mcp/<u1>/mcp/<u2> parses to relay base wss://host/mcp/<u1> and uuid <u2>. redactRemoteTarget only masked the full target and the final path segment, so <u1> leaked through any message that echoed the derived relay base. Redact every UUID-shaped path segment (raw and percent-decoded), while preserving full-target redaction, verbatim final-segment redaction and case-insensitive matching. Adds deterministic e2e-remote-lifecycle regressions for double-/mcp/ redaction, loopback-bypass hostnames rejecting plaintext, numeric loopback canonicalization, and encoded/path-confusion accept/reject outcomes. All UUIDs used are synthetic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #136 (
fix/135-relay-lifecycle) — review that first; this PR's diff is only the last commit.Closes #145. Parent: #130.
Problem
The extension shows one canonical connector credential:
Claude/ChatGPT accept it directly, but the CLI required either a bare UUID or a separate
wss://relay.api.vibebrowser.app/<uuid>value — two transport URLs for the same bearer capability.Change
--remote(start,openclaw, browser CLI) and the MCPset_remotetool now accept the connector URL, normalized through the one shared entry pointparseRemoteTargetinsrc/connection.ts:--remoteinputhttps://host[/prefix]/mcp/<uuid>wss://host[/prefix]+<uuid>http://<loopback>[/prefix]/mcp/<uuid>ws://<loopback>[/prefix]+<uuid><uuid><uuid>ws(s)://host[/prefix]/<uuid>ws(s)://host[/prefix]+<uuid>Security
All hardening from #136 is preserved and re-asserted by tests:
http:///ws://) relay transport rejected/mcp/<uuid>suffix rejectedredactRemoteTargetstill redacts both the full input and the UUIDVerified against bypass vectors:
%2F-encoded separators rejected;..and//normalized by WHATWGURL; uppercase/MCP/rejected; default ports normalized;[::1]treated as loopback.Only the documented non-routable placeholder
00000000-0000-0000-0000-000000000000and the repo's pre-existing fabricated test constants appear in the diff. No real credential.Tests
scripts/e2e-remote-lifecycle.mjs: connector normalization matrix (self-hosted path prefixes, non-default ports, all loopback forms), 11 malformed/hostile URL rejections each asserting no UUID/credential/host leak in the message, a liveset_remoteconnect over the connector form against a fake relay, and aset_remoterejection of a generic HTTP URLscripts/e2e-browser-cli.mjs: browser CLIstatusdriven through anhttp://.../mcp/<uuid>connector URL, asserting identical structured output to the ws form with the session id redactedscripts/e2e-cli-package-smoke.mjs: newCLI_PACK_GATE:REMOTE_HELP_OKgate proving the packaged CLI's--helpadvertises the connector formnpm run buildand fullnpm test(12 gates) pass.Docs
README,
packages/cli/README.md,docs/openclaw-local-browser.md, andopenclaw/vibebrowser/SKILL.mdnow lead with the connector URL, list UUID andws(s)://as advanced/compatibility forms, document the self-hosted prefix and loopback derivations, and state the rejection rules. Duplicated two-variable example blocks were collapsed to a singleVIBE_REMOTE_URLform.Release readiness (commit
b731023)npm already serves
@vibebrowser/mcp@0.3.3and@vibebrowser/cli@0.3.1, so this branch was code-complete but unpublishable. Both packages are now bumped:@vibebrowser/mcp(root)@vibebrowser/cli(packages/cli)package-lock.jsonregenerated withnpm version --no-git-tag-version(root +-w @vibebrowser/cli). Diff is version fields only: no dependency changes (3 lines).test:e2e:plugin-bundleversion-consistency contract stays green:server.json(version+packages[0].version),mcpb/manifest.json,plugins/vibe-browser/.claude-plugin/plugin.json, the@vibebrowser/mcp@<version>pin inplugins/vibe-browser/.mcp.json, and.claude-plugin/marketplace.json..github/workflows/publish.ymlneeds no edit: itscheck_packagestep compares eachpackage.jsonversion against the live npm version and publishes only on a change. Both packages now differ from npm, so both will publish after merge through the existing publish workflow.Deprecate broken @vibebrowser/cli@0.3.0step is gated oncli_current == '0.3.1'and will now skip. That is correct:@vibebrowser/cli@0.3.0is already deprecated on npm with the exact expected message (npm view @vibebrowser/cli@0.3.0 deprecated->Broken package: missing runtime file. Use 0.3.1 or later.).Release verification results
npm run buildtsc+prepare-cli-package.mjs)npm run test:e2e:cli-packageCLI_PACK_GATE:PACK_OK:vibebrowser-cli-0.3.2.tgz,INSTALL_OK,HELP_OK,REMOTE_HELP_OK,PASSnpm run test:e2e:plugin-bundle(version/publish contract)e2e ok - 13 checks passed, incl. "plugin .mcp.json pins the version this repo actually publishes", "marketplace entry resolves to the real plugin directory and version", and a live MCP handshake reportingvibebrowser-mcp 0.3.4npm test(full suite, 14 gates)Not merged. Nothing published from this branch - publishing happens only via the
publish.ymlworkflow on push tomain.Not merged, not published.