@reclaimprotocol/agent 0.1.22 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -20
- package/lib/authoring/backend.d.ts +13 -10
- package/lib/authoring/tools.js +106 -9
- package/lib/cdp/browser-proxy.d.ts +78 -0
- package/lib/cdp/browser-proxy.js +186 -0
- package/lib/cdp/capture-engine.js +8 -7
- package/lib/cdp/client.d.ts +10 -0
- package/lib/cdp/geo.d.ts +10 -0
- package/lib/cdp/geo.js +36 -0
- package/lib/cdp/index.d.ts +1 -0
- package/lib/cdp/index.js +1 -0
- package/lib/live/cloudflared.d.ts +15 -0
- package/lib/live/cloudflared.js +268 -0
- package/lib/live/page.d.ts +20 -0
- package/lib/live/page.js +134 -0
- package/lib/live/tunnel.d.ts +23 -0
- package/lib/live/tunnel.js +120 -0
- package/lib/live/viewer.d.ts +28 -0
- package/lib/live/viewer.js +232 -0
- package/lib/mcp/api/operations.gen.js +34 -26
- package/lib/mcp/api/to-zod.d.ts +1 -1
- package/lib/mcp/api/to-zod.js +1 -1
- package/lib/mcp/api/tools.js +1 -1
- package/lib/mcp/instructions.d.ts +15 -2
- package/lib/mcp/instructions.js +101 -38
- package/lib/mcp/start.js +4 -3
- package/lib/mcp/tools/agent/analyze.js +5 -1
- package/lib/mcp/tools/agent/attach.d.ts +8 -1
- package/lib/mcp/tools/agent/attach.js +166 -22
- package/lib/mcp/tools/agent/build.d.ts +13 -8
- package/lib/mcp/tools/agent/build.js +22 -11
- package/lib/mcp/tools/agent/capture.js +5 -1
- package/lib/mcp/tools/agent/eval.js +3 -1
- package/lib/mcp/tools/agent/find.js +6 -5
- package/lib/mcp/tools/agent/how-it-works.d.ts +15 -7
- package/lib/mcp/tools/agent/how-it-works.js +57 -17
- package/lib/mcp/tools/agent/live-view.d.ts +21 -0
- package/lib/mcp/tools/agent/live-view.js +153 -0
- package/lib/mcp/tools/agent/pod-proof.d.ts +8 -0
- package/lib/mcp/tools/agent/pod-proof.js +64 -0
- package/lib/mcp/tools/agent/propose.js +29 -3
- package/lib/mcp/tools/agent/proxy.d.ts +3 -0
- package/lib/mcp/tools/agent/proxy.js +199 -0
- package/lib/mcp/tools/agent/publish.js +49 -77
- package/lib/mcp/tools/agent/session.d.ts +2 -1
- package/lib/mcp/tools/agent/session.js +26 -7
- package/lib/mcp/tools/agent/shared.js +17 -8
- package/lib/mcp/tools/authenticate/authenticate.d.ts +11 -0
- package/lib/mcp/tools/authenticate/authenticate.js +143 -121
- package/lib/mcp/tools/authenticate/builder-access.d.ts +8 -3
- package/lib/mcp/tools/authenticate/builder-access.js +8 -3
- package/lib/mcp/tools/mode/mode.d.ts +1 -1
- package/lib/mcp/tools/mode/mode.js +26 -7
- package/lib/old/client.d.ts +9 -0
- package/lib/old/client.js +19 -1
- package/lib/old/instructions.d.ts +9 -1
- package/lib/old/instructions.js +4 -6
- package/lib/old/login-cdp.d.ts +2 -2
- package/lib/old/login-cdp.js +46 -6
- package/lib/old/to-register.d.ts +20 -8
- package/lib/old/to-register.js +7 -1
- package/lib/old/tools/authenticate.js +9 -1
- package/lib/old/tools/get-provider-info.js +6 -5
- package/lib/old/tools/issue-app-credentials.js +3 -2
- package/lib/old/tools/me-providers.js +3 -1
- package/lib/old/tools/publish.d.ts +1 -1
- package/lib/old/tools/publish.js +132 -129
- package/lib/old/tools/update-provider-metadata.d.ts +1 -1
- package/lib/old/tools/update-provider-metadata.js +1 -1
- package/lib/old/tools/verify-sdk-setup.js +1 -1
- package/lib/proof/attestor.d.ts +3 -3
- package/lib/proof/debug-response-dump.js +4 -4
- package/lib/proof/index.d.ts +1 -0
- package/lib/proof/index.js +1 -0
- package/lib/proof/page-replay.d.ts +36 -0
- package/lib/proof/page-replay.js +76 -0
- package/lib/proof/pod-prover.d.ts +47 -0
- package/lib/proof/pod-prover.js +155 -0
- package/lib/proof/replay.d.ts +28 -0
- package/lib/proof/replay.js +39 -18
- package/lib/provider/dom-xpath.js +11 -9
- package/lib/provider/draft.d.ts +13 -8
- package/lib/provider/draft.js +47 -13
- package/lib/provider/injection-doc.d.ts +23 -1
- package/lib/provider/injection-doc.js +34 -21
- package/lib/provider/match-redaction-warning.d.ts +2 -2
- package/lib/provider/match-redaction-warning.js +3 -3
- package/lib/provider/matcher.js +122 -12
- package/lib/provider/secrets.d.ts +3 -3
- package/lib/provider/secrets.js +3 -3
- package/lib/provider/to-version.d.ts +12 -9
- package/lib/provider/to-version.js +16 -4
- package/lib/tools/registry.d.ts +5 -5
- package/lib/tools/registry.js +5 -5
- package/package.json +4 -3
- package/samples/demo-server/README.md +7 -6
- package/skill/SKILL.builder.md +356 -189
- package/skill/SKILL.common.md +314 -79
- package/skill/SKILL.old.md +340 -155
- package/skill/builder-mode.md +58 -17
- package/skill/hash-validation.md +170 -0
- package/skill/interception.md +235 -0
- package/skill/js-sdk-integration.md +13 -7
- package/skill/old-mode.md +53 -12
- package/skill/user-script.md +61 -0
- package/src/authoring/backend.ts +13 -10
- package/src/authoring/tools.ts +128 -9
- package/src/cdp/capture-engine.ts +8 -7
- package/src/cdp/client.ts +8 -0
- package/src/cdp/geo.ts +52 -0
- package/src/cdp/index.ts +1 -0
- package/src/consts.ts +1 -0
- package/src/live/cloudflared.ts +348 -0
- package/src/live/page.ts +145 -0
- package/src/live/tunnel.ts +157 -0
- package/src/live/viewer.ts +293 -0
- package/src/mcp/api/operations.gen.ts +34 -26
- package/src/mcp/api/to-zod.ts +1 -1
- package/src/mcp/api/tools.ts +1 -1
- package/src/mcp/instructions.ts +121 -48
- package/src/mcp/start.ts +4 -3
- package/src/mcp/tools/agent/analyze.ts +5 -1
- package/src/mcp/tools/agent/attach.ts +194 -22
- package/src/mcp/tools/agent/build.ts +26 -15
- package/src/mcp/tools/agent/capture.ts +5 -1
- package/src/mcp/tools/agent/eval.ts +4 -1
- package/src/mcp/tools/agent/find.ts +6 -5
- package/src/mcp/tools/agent/how-it-works.ts +62 -21
- package/src/mcp/tools/agent/live-view.ts +198 -0
- package/src/mcp/tools/agent/pod-proof.ts +90 -0
- package/src/mcp/tools/agent/propose.ts +31 -3
- package/src/mcp/tools/agent/publish.ts +54 -78
- package/src/mcp/tools/agent/session.ts +26 -5
- package/src/mcp/tools/agent/shared.ts +19 -8
- package/src/mcp/tools/authenticate/authenticate.ts +167 -165
- package/src/mcp/tools/authenticate/builder-access.ts +8 -3
- package/src/mcp/tools/mode/mode.ts +28 -7
- package/src/old/client.ts +30 -1
- package/src/old/instructions.ts +4 -10
- package/src/old/login-cdp.ts +50 -6
- package/src/old/to-register.ts +28 -8
- package/src/old/tools/authenticate.ts +9 -1
- package/src/old/tools/get-provider-info.ts +6 -5
- package/src/old/tools/issue-app-credentials.ts +3 -2
- package/src/old/tools/me-providers.ts +3 -1
- package/src/old/tools/publish.ts +140 -130
- package/src/old/tools/update-provider-metadata.ts +1 -1
- package/src/old/tools/verify-sdk-setup.ts +1 -1
- package/src/proof/attestor.ts +3 -3
- package/src/proof/debug-response-dump.ts +4 -4
- package/src/proof/index.ts +8 -0
- package/src/proof/page-replay.ts +131 -0
- package/src/proof/pod-prover.ts +231 -0
- package/src/proof/replay.ts +60 -19
- package/src/provider/dom-xpath.ts +11 -9
- package/src/provider/draft.ts +56 -13
- package/src/provider/injection-doc.ts +37 -24
- package/src/provider/match-redaction-warning.ts +3 -3
- package/src/provider/matcher.ts +151 -10
- package/src/provider/secrets.ts +3 -3
- package/src/provider/to-version.ts +30 -13
- package/src/tools/registry.ts +5 -5
- package/skill/injection-api.md +0 -335
package/skill/SKILL.old.md
CHANGED
|
@@ -1,177 +1,362 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
|
|
1
|
+
<!-- topic: overview -->
|
|
2
|
+
# Authoring a Reclaim provider (old-devtools backend)
|
|
3
|
+
|
|
4
|
+
<!-- common: terminology -->
|
|
5
|
+
|
|
6
|
+
## The loop, at a glance
|
|
7
|
+
|
|
8
|
+
Copy this checklist and check off each step as you finish it. Read the linked
|
|
9
|
+
topic before a step you aren't already fluent in.
|
|
10
|
+
|
|
11
|
+
- [ ] 1. `reclaim_authenticate` once. → topic `auth`
|
|
12
|
+
- [ ] 2. `attach_browser` — pick a browser source with the developer.
|
|
13
|
+
→ topic `browser`
|
|
14
|
+
- [ ] 3. `list_tabs` → `start_capture(tabId)` ⇒ **`captureId`**, your handle for
|
|
15
|
+
everything below. → topic `capture`
|
|
16
|
+
- [ ] 4. Drive the page: `navigate`, `wait_for_page`, `eval_in_page`,
|
|
17
|
+
`get_cookies`. Detect login, land on the page showing the value, trigger
|
|
18
|
+
the request. → topic `capture`
|
|
19
|
+
- [ ] 5. `find_requests_containing` → `analyze_request_constraints` → pick an
|
|
20
|
+
**authenticated** request. → topic `capture`
|
|
21
|
+
- [ ] 6. `propose_provider(captureId, requestId, …)` ⇒ **`draftId`** (recipe +
|
|
22
|
+
captured secrets, held server-side — secrets never enter the transcript).
|
|
23
|
+
→ topic `draft`
|
|
24
|
+
- [ ] 7. Parameterize user-specific URL segments; mark secrets. → topic `params`
|
|
25
|
+
- [ ] 8. `replay_request(captureId, draftId)`, then again with
|
|
26
|
+
`withoutSecrets: true`. → topic `prove`
|
|
27
|
+
- [ ] 9. `run_proof(captureId, draftId, ownerAddress)`.
|
|
28
|
+
→ topics `prove`, `credentials`
|
|
29
|
+
- [ ] 10. `create_provider_version_from_capture`. → topic `publish`
|
|
30
|
+
|
|
31
|
+
Multi-request provider? Run steps 6–9 once per request, then publish every
|
|
32
|
+
proven draft in one call. See topic `publish`.
|
|
33
|
+
|
|
34
|
+
**This mode's limits.** Only GET/POST requests can be captured into providers.
|
|
35
|
+
There is no organization management, credential-linking, or public-review
|
|
36
|
+
workflow — the narrow `authenticate_builder` / `list_builder_organizations`
|
|
37
|
+
exception exists only to allocate Builder-hosted authoring browsers.
|
|
38
|
+
`get_me_providers` is the only provider-listing tool here.
|
|
39
|
+
|
|
40
|
+
**Diagnosing a session:** `session_analytics_logs` fetches a verification
|
|
41
|
+
session's analytics logs by id (matches, claims, failures).
|
|
42
|
+
|
|
43
|
+
<!-- topic: auth -->
|
|
3
44
|
## Getting authenticated
|
|
4
45
|
|
|
5
|
-
Call `reclaim_authenticate({})` with no arguments. It opens the Reclaim
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<!--
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
Call `reclaim_authenticate({})` with no arguments. It opens the Reclaim
|
|
47
|
+
dashboard in Chrome, waits for the developer to sign in, reads the token from
|
|
48
|
+
the page and closes the tab — a still-valid cached identity is reused first, so
|
|
49
|
+
it's often instant. Tell the developer once: _"A browser window is opening the
|
|
50
|
+
Reclaim dashboard — please sign in and I'll continue automatically."_
|
|
51
|
+
|
|
52
|
+
- Force a fresh login: `reclaim_authenticate({ useBrowser: true })`.
|
|
53
|
+
- Skip the browser: `reclaim_authenticate({ token: "<firebase-id-token>" })`, or
|
|
54
|
+
`reclaim_authenticate({ ethAddress: "0x…" })` for a provisioned eth user.
|
|
55
|
+
- Tokens are short-lived (~1h). Any later 401 → call `reclaim_authenticate({})`
|
|
56
|
+
again.
|
|
57
|
+
|
|
58
|
+
### Two independent auth systems — don't confuse them
|
|
59
|
+
|
|
60
|
+
`reclaim_authenticate` and `authenticate_builder` log into DIFFERENT backends
|
|
61
|
+
and are NOT interchangeable.
|
|
62
|
+
|
|
63
|
+
- **`reclaim_authenticate`** authorizes everything in this mode:
|
|
64
|
+
`create_provider_version_from_capture`, `get_me_providers`, and the rest.
|
|
65
|
+
- **`authenticate_builder`** covers exactly two Builder-exclusive features:
|
|
66
|
+
allocating a Popcorn remote browser (`attach_browser mode="builder"`) and
|
|
67
|
+
`list_builder_organizations`. It authorizes nothing else.
|
|
68
|
+
|
|
69
|
+
`get_devtools_mode` reports the presence of both. If a publish or
|
|
70
|
+
`get_me_providers` call fails with an auth error even though
|
|
71
|
+
`reclaim_authenticate` ran earlier, the old-devtools token has expired — re-run
|
|
72
|
+
it. Don't assume `authenticate_builder` fixes it.
|
|
73
|
+
|
|
74
|
+
<!-- topic: browser -->
|
|
75
|
+
<!-- common: browser -->
|
|
76
|
+
|
|
77
|
+
<!-- topic: capture -->
|
|
78
|
+
## Capture
|
|
79
|
+
|
|
80
|
+
1. **Attach** — topic `browser`.
|
|
81
|
+
|
|
82
|
+
2. **Pick a tab and start the capture.** `list_tabs`, then
|
|
83
|
+
`start_capture(tabId)` ⇒ a **`captureId`**: the session handle every browser
|
|
84
|
+
and inspect tool takes as its first argument (`navigate`, `eval_in_page`,
|
|
85
|
+
`wait_for_page`, `get_cookies`, `list_requests`, `find_requests_containing`,
|
|
86
|
+
`propose_provider`). If a tab is already on the right origin use it,
|
|
87
|
+
otherwise the first is usually fine. Capturing from the start is harmless —
|
|
88
|
+
it also records the login navigation. Then `navigate(captureId, url)` to
|
|
89
|
+
the site you inferred from the developer's request ("GitHub username" →
|
|
90
|
+
`https://github.com`). Don't ask the developer to navigate.
|
|
91
|
+
|
|
92
|
+
3. <!-- common: login-detect -->
|
|
93
|
+
|
|
94
|
+
4. **Navigate to the page that displays the value.** Construct the URL from what
|
|
95
|
+
you know about the site; eval for anything you need (for example, GitHub's
|
|
96
|
+
`meta[name="user-login"]`'s `content`), then `navigate(captureId, url)`.
|
|
97
|
+
|
|
98
|
+
5. **Trigger the request.** Capture has been live since step 2, so make the
|
|
99
|
+
call fire: `eval_in_page(captureId, "location.reload()")`, or click an
|
|
100
|
+
element / hit a SPA route programmatically. Don't ask the developer to click.
|
|
101
|
+
|
|
102
|
+
6. <!-- common: identify-value -->
|
|
103
|
+
|
|
104
|
+
7. <!-- common: find-request -->
|
|
105
|
+
|
|
106
|
+
<!-- topic: draft -->
|
|
107
|
+
## Draft the provider
|
|
108
|
+
|
|
109
|
+
<!-- common: oprf -->
|
|
110
|
+
|
|
111
|
+
**Call `propose_provider`.** It returns a **`draftId`** — the handle for
|
|
112
|
+
`replay_request` and `run_proof` — plus the secret-free `provider` and
|
|
113
|
+
`secretRefs`. The recipe **and the captured secret values** live server-side
|
|
114
|
+
under that `draftId`; the secrets never enter the transcript, so you carry the
|
|
115
|
+
`draftId`, not the provider JSON, into replay/prove.
|
|
116
|
+
|
|
117
|
+
**Extracting MORE THAN ONE value?** Prefer a **single request whose response
|
|
118
|
+
contains all of them** and draft them together — one `responseMatches` +
|
|
119
|
+
`responseRedactions` pair per value. Find that request by running
|
|
120
|
+
`find_requests_containing` for each value and picking a `requestId` common to
|
|
121
|
+
all. Then pass a `targets` array, each entry with its `value` (exactly as it
|
|
122
|
+
appears) and a distinct `name`:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
propose_provider(captureId, requestId, name, targets: [
|
|
126
|
+
{ value: "Scratch-net", name: "username" },
|
|
127
|
+
{ value: "Alex", name: "name" },
|
|
128
|
+
])
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The shorthand `propose_provider(captureId, requestId, target, name, hash?)`
|
|
132
|
+
still works for one target.
|
|
133
|
+
|
|
134
|
+
**Inspect what comes back:**
|
|
135
|
+
|
|
136
|
+
- Is the right header marked secret? (cookies, `Authorization`, `X-*` tokens)
|
|
137
|
+
- Is `responseMatches[0].value` a `contains` with a `{{name}}` template matching
|
|
138
|
+
the captured value's structural context?
|
|
139
|
+
- Is `paramValues[name]` the original captured value?
|
|
140
|
+
- Does each `responseRedactions` entry carry an `xPath`/`jsonPath` anchor
|
|
141
|
+
**plus** a named-capture `regex` isolating the value? (With `hash`, the regex
|
|
142
|
+
also carries `hash: oprf-…`.)
|
|
143
|
+
|
|
144
|
+
**Provenance — match the structure, never the bare value.** The `contains`
|
|
145
|
+
template and the redaction regex are always anchored on the value's surrounding
|
|
146
|
+
context — the JSON key (`"login":"{{username}}"`) or the enclosing element —
|
|
147
|
+
never `{{username}}` alone. That ties the proof to *where the value legitimately
|
|
148
|
+
appears*; a bare-value match would let a user surface the same string from any
|
|
149
|
+
field they control. The synthesizer does this for you.
|
|
150
|
+
|
|
151
|
+
**Canonical drafted shape** (no hash):
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"responseMatches": [
|
|
156
|
+
{ "type": "contains", "value": "\"login\":\"{{username}}\"" }
|
|
157
|
+
],
|
|
158
|
+
"responseRedactions": [
|
|
159
|
+
{
|
|
160
|
+
"xPath": "//script[@id=\"client-env\"]",
|
|
161
|
+
"regex": "\"login\":\"(?<username>[A-Za-z0-9_-]+)\""
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"paramValues": { "username": "Scratch-net" }
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
With `hash: 'oprf-raw'`, the redaction gains `"hash": "oprf-raw"`. Nothing else
|
|
169
|
+
changes.
|
|
64
170
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"responseMatches": [
|
|
70
|
-
{ "type": "contains", "value": "\"login\":\"{{username}}\"" }
|
|
71
|
-
],
|
|
72
|
-
"responseRedactions": [{ "xPath": "//script[@id=\"client-env\"]" }],
|
|
73
|
-
"paramValues": { "username": "Scratch-net" }
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
**Canonical drafted shape** (with `hash: 'oprf-raw'`):
|
|
171
|
+
<!-- common: rewrite-shape-block -->
|
|
78
172
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"responseMatches": [
|
|
82
|
-
{ "type": "contains", "value": "\"login\":\"{{username}}\"" }
|
|
83
|
-
],
|
|
84
|
-
"responseRedactions": [
|
|
85
|
-
{
|
|
86
|
-
"xPath": "//script[@id=\"client-env\"]",
|
|
87
|
-
"regex": "\"login\":\"(?<username>[A-Za-z0-9_-]+)\"",
|
|
88
|
-
"hash": "oprf-raw"
|
|
89
|
-
}
|
|
90
|
-
],
|
|
91
|
-
"paramValues": { "username": "Scratch-net" }
|
|
92
|
-
}
|
|
93
|
-
```
|
|
173
|
+
<!-- topic: params -->
|
|
174
|
+
## Parameters: extracted, consumer-supplied, and secret
|
|
94
175
|
|
|
95
|
-
|
|
176
|
+
**Parameterize user-specific URL segments** so the provider isn't pinned to one
|
|
177
|
+
user. The matcher already puts the *captured* value in `paramValues`. If the URL
|
|
178
|
+
*also* carries user-identifying segments, those are **consumer-supplied context
|
|
179
|
+
params** — their values come from the consumer at verification time, not from
|
|
180
|
+
extraction.
|
|
96
181
|
|
|
97
|
-
|
|
182
|
+
Replace them with `{{context_<name>}}` and add
|
|
183
|
+
`paramValues: { …, "context_username": "Scratch-net" }`. **This backend does not
|
|
184
|
+
support the dotted `{{context.<name>}}` form the Builder uses**, and there is no
|
|
185
|
+
`requiredContext` declaration here — the convention is the whole mechanism.
|
|
98
186
|
|
|
99
|
-
-
|
|
100
|
-
- Query parameters with user-specific values → same treatment.
|
|
187
|
+
- Query params with user-specific values → same treatment.
|
|
101
188
|
- Generic segments (`/api/v3`, `/users`, `/repos`) stay literal.
|
|
102
|
-
-
|
|
189
|
+
- No user-identifying segments (for example, `/settings/profile`) → leave it
|
|
190
|
+
alone.
|
|
103
191
|
|
|
104
|
-
|
|
192
|
+
<!-- common: secrets -->
|
|
105
193
|
|
|
106
|
-
|
|
194
|
+
The `context_` prefix is a naming convention (consumer-supplied vs
|
|
195
|
+
extracted-from-traffic). The attestor itself only looks up `{{whatever}}` in
|
|
196
|
+
`paramValues`/`secretParams.paramValues` and doesn't care about the prefix.
|
|
107
197
|
|
|
108
198
|
<!-- common: no-rename-param -->
|
|
109
199
|
|
|
110
|
-
`propose_provider` returns `verificationWarnings` for
|
|
111
|
-
|
|
112
|
-
|
|
200
|
+
`propose_provider` returns `verificationWarnings` for calls only an author can
|
|
201
|
+
make (currently: a captured value baked literally into the URL, needing the
|
|
202
|
+
`{{context_<name>}}`-vs-bare-vs-recapture decision). Advisory, never blocking —
|
|
203
|
+
**surface each one verbatim** and resolve it before publishing.
|
|
113
204
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- `matchesOriginal: false` with stable diff (timestamps etc.) → tighten the matcher and retry.
|
|
205
|
+
<!-- topic: prove -->
|
|
206
|
+
## Replay, then prove
|
|
117
207
|
|
|
118
|
-
**
|
|
208
|
+
**1. Replay.** `replay_request(captureId, draftId)`:
|
|
119
209
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
210
|
+
- `matchesOriginal: true` → proceed.
|
|
211
|
+
- `false` with `hints` mentioning auth/csrf → re-trigger the action yourself
|
|
212
|
+
(navigate or reload with the tools) and redraft. Don't ask the developer to
|
|
213
|
+
redo it.
|
|
214
|
+
- `false` with a stable diff (timestamps, and so on) → tighten the matcher
|
|
215
|
+
and retry.
|
|
216
|
+
|
|
217
|
+
**2. The authentication-bound check — mandatory.**
|
|
218
|
+
`replay_request(captureId, draftId, withoutSecrets: true)` re-issues the request
|
|
219
|
+
with no secrets/cookies, as an anonymous visitor.
|
|
220
|
+
|
|
221
|
+
- FAILS to extract (401/403/redirect, or the value is gone) → the endpoint is
|
|
222
|
+
auth-bound. Good: the proof genuinely means "the holder of these secrets saw
|
|
223
|
+
this value."
|
|
224
|
+
- STILL extracts the value → the endpoint is **PUBLIC**; the proof binds to
|
|
225
|
+
nobody. **Do NOT prove it.** Find a request whose response depends on the
|
|
226
|
+
session and re-check. If the value only ever appears on public responses, tell
|
|
227
|
+
the developer it can't be proven as an identity claim.
|
|
228
|
+
|
|
229
|
+
**3. Prove.** `run_proof(captureId, draftId, ownerAddress)`. On
|
|
230
|
+
`verified: true` the full claim is written to
|
|
231
|
+
`~/.reclaim/claims/<timestamp>.json` and you get
|
|
232
|
+
`{verified, extractedValue, extractedParameters, identifier, owner, claimPath, claim}`.
|
|
233
|
+
`claim` is display-ready (huge `request` payload stripped, byte arrays base64'd)
|
|
234
|
+
— **show it to the developer as a fenced JSON block at the end**, with the
|
|
235
|
+
provider JSON. That's the final result.
|
|
236
|
+
|
|
237
|
+
**`errorKind: "missing-owner-key"`** → no eth proof-owner key yet. Tell the
|
|
238
|
+
developer what's happening and drive the bootstrap yourself — see topic
|
|
239
|
+
`credentials`. No restart needed, and the existing `draftId` stays valid.
|
|
126
240
|
|
|
127
241
|
<!-- common: prove-tail -->
|
|
128
242
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
243
|
+
<!-- topic: publish -->
|
|
244
|
+
## Publish
|
|
245
|
+
|
|
246
|
+
`provider` is the JSON from the draft step with the `params` URL
|
|
247
|
+
parameterization applied. `initialUrl` is the page where the user logs in / the
|
|
248
|
+
value is displayed (for example, `https://github.com/Syed`) — **not** the API
|
|
249
|
+
endpoint URL inside the provider. It maps to the provider's `loginUrl`.
|
|
250
|
+
|
|
251
|
+
Call `create_provider_version_from_capture`:
|
|
252
|
+
|
|
253
|
+
- **New provider:** omit `providerId`. Registers a new provider at version
|
|
254
|
+
1.0.0. Pass `provider`, `initialUrl`, optionally `description`,
|
|
255
|
+
`geoLocation`, `providerType` (`PRIVATE` default | `PUBLIC`).
|
|
256
|
+
⚠️ Re-running without `providerId` registers ANOTHER provider — that's how
|
|
257
|
+
duplicates appear. Check `get_me_providers` first.
|
|
258
|
+
- **New version of an existing provider:** pass its `providerId`; the patch is
|
|
259
|
+
auto-bumped above the highest existing version. Pass `notes` (≥10 chars).
|
|
260
|
+
- **Multi-request provider** (landing call + details call, a
|
|
261
|
+
CSRF-preflight/refresh-token chain, …): run capture→draft→replay→prove ONCE
|
|
262
|
+
PER REQUEST, then pass `providers: [draftA, draftB, …]` instead of the single
|
|
263
|
+
`provider`. Each becomes a parallel `requestData` entry on the SAME version
|
|
264
|
+
and **all** are required at verification time.
|
|
265
|
+
- **Login/navigation-gated data:** supply `customInjection` (plain page JS) and
|
|
266
|
+
`allowedInjectedRequestData` (extra requests the script may fire).
|
|
267
|
+
→ topic `user-script`. Before populating `allowedInjectedRequestData` for a
|
|
268
|
+
`verifyProof({ providerId })` use case, read topic `hash-validation`.
|
|
269
|
+
|
|
270
|
+
**Ownership — you can only add a version to a provider YOU own.** The
|
|
271
|
+
`providerId` must come from `get_me_providers`. Versioning a public provider you
|
|
272
|
+
don't own fails with a permission error; that's expected. To publish your own
|
|
273
|
+
version of such a site, re-run **without** `providerId` to register your own
|
|
274
|
+
copy. If versioning a provider you *do* own fails, confirm you authenticated as
|
|
275
|
+
the account that created it.
|
|
276
|
+
|
|
277
|
+
**Before adding a version to an existing provider, read the current one with
|
|
278
|
+
`get_provider_info(providerId)` — this is not optional.** This backend has no
|
|
279
|
+
partial-patch endpoint: every version replaces the WHOLE `providerConfig` with
|
|
280
|
+
exactly what you pass in THIS call, and the tool carries **nothing** forward.
|
|
281
|
+
Any field you want to survive must be re-supplied here — `customInjection`,
|
|
282
|
+
`userAgent`, `pageTitle`, `allowedInjectedRequestData`, `stepsToFollow`,
|
|
283
|
+
`useIncognitoWebview`, `extensionConfig`, and `requestData` (through
|
|
284
|
+
`provider`/`providers`). Anything omitted is published blank. So to change one
|
|
285
|
+
field: read the live config, then pass the full desired config (existing values
|
|
286
|
+
plus your change) back in.
|
|
287
|
+
|
|
288
|
+
`allowedInjectedRequestData`, `useIncognitoWebview` and `extensionConfig` take
|
|
289
|
+
effect on add-version only — the register endpoint ignores them, so on a fresh
|
|
290
|
+
register the tool automatically follows up with an add-version call that
|
|
291
|
+
applies them.
|
|
292
|
+
|
|
293
|
+
**Related tools:**
|
|
294
|
+
|
|
295
|
+
- `update_provider_metadata(providerId, {…})` — rename, redescribe, retag, flip
|
|
296
|
+
`providerType`, toggle `isActive`, **without** creating a version. A genuine
|
|
297
|
+
partial update; don't route a pure metadata edit through a new version.
|
|
298
|
+
- `get_provider_info(providerId, versionNumber?)` — look up ANY published
|
|
299
|
+
provider (not just yours) and see exactly what the live verification client
|
|
300
|
+
would fetch. Reads the public production SDK backend directly, no auth.
|
|
301
|
+
|
|
302
|
+
There's no create-then-version step and no org / public-review workflow here.
|
|
303
|
+
When done, tell the developer the version is live and that they can integrate
|
|
304
|
+
using the `providerId`.
|
|
305
|
+
|
|
306
|
+
**The browser is still open.** The response's `_notes` says so. Surface it and
|
|
307
|
+
ask whether the developer wants to keep the session for further edits — call
|
|
308
|
+
`dispose_browser` only once they confirm. Never close it unprompted; a
|
|
309
|
+
`builder`-mode session is quota-accounted.
|
|
310
|
+
|
|
311
|
+
<!-- topic: never-do -->
|
|
148
312
|
## Things to never do
|
|
149
313
|
|
|
150
314
|
<!-- common: never-do-common -->
|
|
151
|
-
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<!--
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
315
|
+
- Never request `hash` for a target whose value also appears in the request URL
|
|
316
|
+
(topic `draft`), and never `hash` a free-form target — `propose_provider`
|
|
317
|
+
throws either way; retrying won't help.
|
|
318
|
+
|
|
319
|
+
<!-- topic: credentials -->
|
|
320
|
+
<!-- common: credentials -->
|
|
321
|
+
|
|
322
|
+
<!-- topic: troubleshooting -->
|
|
323
|
+
## Troubleshooting
|
|
324
|
+
|
|
325
|
+
**`unknown draftId` / `no capture`.** The draft is bound to its capture, held in
|
|
326
|
+
the MCP server process. Anything that restarts the server (Claude Code restart,
|
|
327
|
+
`reset_session`, reboot) drops every capture and its drafts. The fix is always
|
|
328
|
+
`start_capture` → interact → `propose_provider` for a fresh `draftId`. Don't ask
|
|
329
|
+
the developer to "re-enter the value" — walk them back through capture.
|
|
330
|
+
|
|
331
|
+
**Replaying as an anonymous visitor.** Pass `withoutSecrets: true` to
|
|
332
|
+
`replay_request`; the draft still holds the captured secrets, so you never
|
|
333
|
+
re-supply them.
|
|
334
|
+
|
|
335
|
+
**Auth errors on publish / `get_me_providers`** → the old-devtools token
|
|
336
|
+
expired. Re-run `reclaim_authenticate` (topic `auth`), not
|
|
337
|
+
`authenticate_builder`.
|
|
338
|
+
|
|
339
|
+
**`reclaim_authenticate` seems to hang.** On a FRESH Chrome profile the
|
|
340
|
+
dashboard is a large cold download, so the login form can take tens of seconds
|
|
341
|
+
to become usable — that time comes out of the sign-in budget. Tell the
|
|
342
|
+
developer it is loading and that the window is waiting for them, and DON'T
|
|
343
|
+
re-run the tool while it is still waiting: a second call restarts the whole
|
|
344
|
+
wait and is what turns a slow load into an apparent multi-minute hang. If it
|
|
345
|
+
does time out, the error says whether the page ever became interactive —
|
|
346
|
+
"never became interactive" means the load, not the human.
|
|
347
|
+
|
|
348
|
+
**Site won't load, won't let the user sign in, or breaks right after
|
|
349
|
+
sign-in.** Check WHICH client the session targets first: on `builder` (the
|
|
350
|
+
default) and `portals` interception happens over CDP, so it is never the
|
|
351
|
+
cause — look for a captcha instead. On `inapp-sdk`, `verifier-app`, or the
|
|
352
|
+
browser extension, suspect interception before the recipe, and bisect: FIRST
|
|
353
|
+
turn
|
|
354
|
+
document replay off and keep the interceptor (`disableRequestReplay: true`, or
|
|
355
|
+
`isDocumentRequestReplayEnabled: false` on builder) — often that alone is what
|
|
356
|
+
breaks the page, and it's the smallest change. Only if that doesn't help, turn
|
|
357
|
+
interception off entirely (`injectionType: NONE`, or omit
|
|
358
|
+
`interceptorOptions`). Full checklist and remedies: topic `interception`.
|
|
359
|
+
|
|
360
|
+
**Proof failures / attestor errors** → topic `prove`.
|
|
361
|
+
**Browser won't launch or attach** → topic `browser`.
|
|
362
|
+
**Missing signing key** → topic `credentials`.
|