Repository navigation
feat: add capture_redirect capability - #108
Conversation
Add a `capture_redirect` capability that snapshots the redirect target
URL of the next request the browser makes to a declared (host, path?),
via `chrome.webRequest.onBeforeRedirect`. Single-shot, mirroring
`capture_request_header` but lighter — the only gate is that the watched
host is one of the MCP's declared `domains` (equals-or-subdomain); no
per-entry declared scope is required, and `onBeforeRedirect` needs no
`extraInfoSpec`.
Use case: a Cloudflare-walled endpoint that 302-redirects cross-origin
to a presigned URL. A page-level fetch sees only an opaque cross-origin
redirect, but `onBeforeRedirect` exposes `details.redirectUrl` at the
network layer — so the consumer can capture the presigned target and
fetch it server-side (no CORS off-browser).
- protocol: add 'capture_redirect' to Capability + KNOWN_CAPABILITIES;
CaptureRedirectInit + inner request/response (value = redirect URL);
validateInnerRequest/Response branches.
- server: FetchproxyServer.captureRedirect({host, path?, timeoutMs?}),
with the same bridge-down/lazy-revive handling as captureRequestHeader.
- extension-core: dispatcher branch + handleCaptureRedirectRequest
(host-in-domains gate, onBeforeRedirect listener, 30s default timeout,
double-fire guard).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @chrischall's task in 6m 2s —— View job Review — PR #108
|
| ok: false, | ||
| op: 'capture_redirect', | ||
| error: 'timeout', | ||
| }); | ||
| }, timeoutMs); | ||
| } | ||
|
|
||
| async function handleReadIndexedDbRequest( | ||
| mcpId: string, |
There was a problem hiding this comment.
🟡 Nit — consider clearing the timeout on resolve.
The 30 s timeout fires even after the listener successfully resolves; if (resolved) return makes it a no-op, but you'd avoid the dangling timer (and a tiny memory hold on the listener closure) by clearTimeout-ing in the listener and capturing the handle.
This matches the existing handleCaptureRequestHeaderRequest pattern at line 1717 — also un-cleared — so this is consistent with prior art and arguably out-of-scope for this PR. Flagging only because a small refactor would clean both up at once.
🤖 I have created a release *beep* *boop* --- ## [1.1.0](v1.0.1...v1.1.0) (2026-06-04) ### Features * add capture_redirect capability ([#108](#108)) ([3121dc5](3121dc5)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
What
Adds a new
capture_redirectcapability that snapshots the redirect target URL of the next request the browser makes to a declared(host, path?), viachrome.webRequest.onBeforeRedirect. Single-shot.Mirrors the existing
capture_request_headercapability, but lighter: there's no per-entry declared scope plumbing. The only gate is that the watched host is one of the MCP's declareddomains(equals-or-subdomain).onBeforeRedirectneeds noextraInfoSpec.Why
A Cloudflare-walled endpoint that 302-redirects cross-origin to a presigned URL (e.g. musescore's
score/download/index→ presigned S3) is opaque to a page-levelfetch— the redirect target can't be read cross-origin. ButonBeforeRedirectexposesdetails.redirectUrlat the network layer regardless of CORS, so the consumer can capture the presigned target and fetch it server-side (no CORS off-browser, and the presigned URL carries its own auth so no Cloudflare/TLS binding).Changes
'capture_redirect'added to theCapabilityunion +KNOWN_CAPABILITIES;CaptureRedirectInit {host, path?, timeoutMs?}+ inner request/response (responsevalue= redirect URL);validateInnerRequest/validateInnerResponsebranches.FetchproxyServer.captureRedirect({host, path?, timeoutMs?}): Promise<string>, with the same bridge-down / lazy-revive handling ascaptureRequestHeader.handleCaptureRedirectRequest(host-in-domains gate,onBeforeRedirectlistener filtered onhttps://${host}${path ?? '/*'}, double-fire guard, 30s default timeout).Tests
validate.test.ts: accepts a validcapture_redirectrequest/ok-response; rejects bad host, bad path, unexpected fields, bad timeoutMs, missing/non-string value.convenience.test.ts:captureRedirect()throws when capability undeclared, emits the correct inner-request shape and resolves the URL, threadstimeoutMs, omitspathwhen absent, surfaces timeout as a protocol error.Full suite: 815 tests green.
npm run build --workspacesclean.🤖 Generated with Claude Code