@reclaimprotocol/agent 0.1.23 → 0.1.25
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 +56 -20
- package/lib/authoring/backend.d.ts +5 -4
- package/lib/authoring/tools.js +30 -30
- package/lib/cdp/capture-engine.js +8 -7
- package/lib/cdp/claims.d.ts +21 -0
- package/lib/cdp/claims.js +129 -0
- package/lib/cdp/container.d.ts +85 -0
- package/lib/cdp/container.js +481 -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/tunnel.d.ts +26 -0
- package/lib/live/tunnel.js +160 -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 +102 -38
- package/lib/mcp/start.js +62 -6
- package/lib/mcp/tools/agent/analyze.js +5 -1
- package/lib/mcp/tools/agent/attach.d.ts +29 -2
- package/lib/mcp/tools/agent/attach.js +310 -24
- package/lib/mcp/tools/agent/build.d.ts +18 -8
- package/lib/mcp/tools/agent/build.js +30 -12
- 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/index.d.ts +1 -2
- package/lib/mcp/tools/agent/index.js +1 -1
- package/lib/mcp/tools/agent/live-view.d.ts +17 -0
- package/lib/mcp/tools/agent/live-view.js +146 -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 +4 -2
- package/lib/mcp/tools/agent/publish.js +47 -77
- package/lib/mcp/tools/agent/session.d.ts +16 -1
- package/lib/mcp/tools/agent/session.js +32 -7
- package/lib/mcp/tools/authenticate/authenticate.js +26 -13
- package/lib/mcp/tools/mode/mode.d.ts +1 -1
- package/lib/mcp/tools/mode/mode.js +10 -22
- package/lib/old/client.d.ts +1 -1
- package/lib/old/client.js +1 -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 +3 -2
- package/lib/old/to-register.js +1 -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/publish.d.ts +1 -1
- package/lib/old/tools/publish.js +90 -131
- 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 +1 -1
- package/lib/proof/page-replay.js +1 -1
- package/lib/proof/pod-prover.d.ts +47 -0
- package/lib/proof/pod-prover.js +155 -0
- package/lib/provider/dom-xpath.js +11 -9
- package/lib/provider/draft.d.ts +10 -7
- package/lib/provider/draft.js +11 -9
- 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 +13 -12
- package/lib/provider/secrets.d.ts +3 -3
- package/lib/provider/secrets.js +3 -3
- package/lib/provider/to-version.d.ts +7 -6
- package/lib/provider/to-version.js +3 -3
- package/lib/tools/registry.d.ts +5 -5
- package/lib/tools/registry.js +5 -5
- package/package.json +3 -3
- package/samples/demo-server/README.md +7 -6
- package/skill/SKILL.builder.md +356 -189
- package/skill/SKILL.common.md +400 -97
- package/skill/SKILL.old.md +340 -155
- package/skill/builder-mode.md +60 -17
- package/skill/hash-validation.md +170 -0
- package/skill/interception.md +236 -0
- package/skill/js-sdk-integration.md +13 -7
- package/skill/old-mode.md +62 -21
- package/skill/user-script.md +61 -0
- package/src/authoring/backend.ts +5 -4
- package/src/authoring/tools.ts +31 -30
- package/src/cdp/capture-engine.ts +8 -7
- package/src/cdp/claims.ts +153 -0
- package/src/cdp/container.ts +593 -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/tunnel.ts +208 -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 +122 -48
- package/src/mcp/start.ts +69 -5
- package/src/mcp/tools/agent/analyze.ts +5 -1
- package/src/mcp/tools/agent/attach.ts +367 -26
- package/src/mcp/tools/agent/build.ts +35 -16
- 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/index.ts +6 -2
- package/src/mcp/tools/agent/live-view.ts +182 -0
- package/src/mcp/tools/agent/pod-proof.ts +90 -0
- package/src/mcp/tools/agent/propose.ts +4 -2
- package/src/mcp/tools/agent/publish.ts +52 -77
- package/src/mcp/tools/agent/session.ts +33 -6
- package/src/mcp/tools/authenticate/authenticate.ts +28 -13
- package/src/mcp/tools/mode/mode.ts +10 -22
- package/src/old/client.ts +2 -2
- package/src/old/instructions.ts +4 -10
- package/src/old/login-cdp.ts +50 -6
- package/src/old/to-register.ts +3 -2
- 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/publish.ts +95 -131
- 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 +1 -1
- package/src/proof/pod-prover.ts +231 -0
- package/src/provider/dom-xpath.ts +11 -9
- package/src/provider/draft.ts +13 -10
- package/src/provider/injection-doc.ts +37 -24
- package/src/provider/match-redaction-warning.ts +3 -3
- package/src/provider/matcher.ts +13 -12
- package/src/provider/secrets.ts +3 -3
- package/src/provider/to-version.ts +11 -9
- package/src/tools/registry.ts +5 -5
- package/skill/injection-api.md +0 -364
|
@@ -466,7 +466,7 @@ export const MCP_TOOLS = {
|
|
|
466
466
|
}),
|
|
467
467
|
},
|
|
468
468
|
"CreateProvider": {
|
|
469
|
-
description: "Create a provider\n\nCreate a new Reclaim provider. Use this only after `providers` returned nothing useful for the domain. The caller must be an active member of the target organization.\nCreates a new provider in the specified organization. `visibility` is coerced to `PRIVATE` at creation regardless of what's sent; the author may toggle to `PUBLIC` later via `PATCH /providers/{id}`. While `PRIVATE`, versions go
|
|
469
|
+
description: "Create a provider\n\nCreate a new Reclaim provider. Use this only after `providers` returned nothing useful for the domain. The caller must be an active member of the target organization.\nCreates a new provider in the specified organization. `visibility` is coerced to `PRIVATE` at creation regardless of what's sent; the author may toggle to `PUBLIC` later via `PATCH /providers/{id}`. While `PRIVATE`, versions go live freely; once `PUBLIC`, non-admin versions need admin review. See `Provider.visibility`.\nThe server also seeds an initial `0.1.0` version on the `draft` branch in the same transaction so the provider is immediately editable. Its `initialUrl` defaults to `https://<domain>`; all other version fields fall back to their schema-declared defaults (a `structured` verificationType, empty requests, empty web settings). `Provider.latestVersion` stays `null` until the draft is promoted to the live channel.",
|
|
470
470
|
inputSchema: toZod({
|
|
471
471
|
"type": "object",
|
|
472
472
|
"properties": {
|
|
@@ -497,7 +497,7 @@ export const MCP_TOOLS = {
|
|
|
497
497
|
"format": "uuid"
|
|
498
498
|
},
|
|
499
499
|
"domain": {
|
|
500
|
-
"description": "Canonical root domain (
|
|
500
|
+
"description": "Canonical root domain (for example, `github.com`). No scheme, no port, no path.",
|
|
501
501
|
"type": "string",
|
|
502
502
|
"format": "hostname",
|
|
503
503
|
"minLength": 1,
|
|
@@ -558,12 +558,12 @@ export const MCP_TOOLS = {
|
|
|
558
558
|
"brandUrl": {
|
|
559
559
|
"type": "string",
|
|
560
560
|
"format": "uri",
|
|
561
|
-
"description": "Canonical homepage of the brand (
|
|
561
|
+
"description": "Canonical homepage of the brand (for example, `https://google.com`). Used in brand-link cards and JSON-LD.",
|
|
562
562
|
"maxLength": 2000
|
|
563
563
|
},
|
|
564
564
|
"primaryDataPoint": {
|
|
565
565
|
"type": "string",
|
|
566
|
-
"description": "Headline data point — the single most-important variable this provider can verify (
|
|
566
|
+
"description": "Headline data point — the single most-important variable this provider can verify (for example, `subscriber count`). Used in the provider's SEO title.",
|
|
567
567
|
"maxLength": 200
|
|
568
568
|
},
|
|
569
569
|
"dataPoints": {
|
|
@@ -670,10 +670,11 @@ export const MCP_TOOLS = {
|
|
|
670
670
|
},
|
|
671
671
|
"branch": {
|
|
672
672
|
"type": "string",
|
|
673
|
-
"description": "Branch (lifecycle stage) of this provider version.\n\n- `ai`: changes authored by the AI assistant live on this branch.\n\n- `draft`: a human is actively editing the version.\n\n- `in_review`: the author has submitted the version to be made\n public and it is awaiting review. On approval the branch tag\n is cleared (the version is promoted to the live channel and becomes\n public).\n\n- `rejected`: review concluded with a rejection. When the author\n addresses the feedback the branch transitions back to\n `in_review`.",
|
|
673
|
+
"description": "Branch (lifecycle stage) of this provider version.\n\n- `ai`: changes authored by the AI assistant live on this branch.\n\n- `draft`: a human is actively editing the version.\n\n- `fixed`: a proven AI repair. It remains pinned to its explicit\n version and does not replace the live trunk version.\n\n- `in_review`: the author has submitted the version to be made\n public and it is awaiting review. On approval the branch tag\n is cleared (the version is promoted to the live channel and becomes\n public).\n\n- `rejected`: review concluded with a rejection. When the author\n addresses the feedback the branch transitions back to\n `in_review`.",
|
|
674
674
|
"enum": [
|
|
675
675
|
"ai",
|
|
676
676
|
"draft",
|
|
677
|
+
"fixed",
|
|
677
678
|
"in_review",
|
|
678
679
|
"rejected"
|
|
679
680
|
]
|
|
@@ -811,7 +812,7 @@ export const MCP_TOOLS = {
|
|
|
811
812
|
"items": {
|
|
812
813
|
"type": "object",
|
|
813
814
|
"additionalProperties": false,
|
|
814
|
-
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (
|
|
815
|
+
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (that is, \"HTTP/1.1 200 OK\")",
|
|
815
816
|
"properties": {
|
|
816
817
|
"xPath": {
|
|
817
818
|
"type": "string",
|
|
@@ -819,7 +820,7 @@ export const MCP_TOOLS = {
|
|
|
819
820
|
},
|
|
820
821
|
"jsonPath": {
|
|
821
822
|
"type": "string",
|
|
822
|
-
"description": "expect a JSON response, retrieve the item at this path using dot notation for
|
|
823
|
+
"description": "expect a JSON response, retrieve the item at this path using dot notation, for example 'email.addresses.0'."
|
|
823
824
|
},
|
|
824
825
|
"regex": {
|
|
825
826
|
"type": "string",
|
|
@@ -964,7 +965,7 @@ export const MCP_TOOLS = {
|
|
|
964
965
|
"items": {
|
|
965
966
|
"type": "object",
|
|
966
967
|
"additionalProperties": false,
|
|
967
|
-
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (
|
|
968
|
+
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (that is, \"HTTP/1.1 200 OK\")",
|
|
968
969
|
"properties": {
|
|
969
970
|
"xPath": {
|
|
970
971
|
"type": "string",
|
|
@@ -972,7 +973,7 @@ export const MCP_TOOLS = {
|
|
|
972
973
|
},
|
|
973
974
|
"jsonPath": {
|
|
974
975
|
"type": "string",
|
|
975
|
-
"description": "expect a JSON response, retrieve the item at this path using dot notation for
|
|
976
|
+
"description": "expect a JSON response, retrieve the item at this path using dot notation, for example 'email.addresses.0'."
|
|
976
977
|
},
|
|
977
978
|
"regex": {
|
|
978
979
|
"type": "string",
|
|
@@ -1029,8 +1030,8 @@ export const MCP_TOOLS = {
|
|
|
1029
1030
|
"properties": {
|
|
1030
1031
|
"geoLocation": {
|
|
1031
1032
|
"type": "string",
|
|
1032
|
-
"description": "Geographic location
|
|
1033
|
-
"maxLength":
|
|
1033
|
+
"description": "Geographic location the verification should appear to originate from: a 2-letter ISO country code, or a parameter the attestor resolves at proof time. `{{DYNAMIC_GEO}}` and `{{DYNAMIC_GEO_SECRET}}` are the Verification Client's standard names for the end-user's own country — the `_SECRET` one is delivered as a secret param, so the attestor never learns which country the proof egressed from.",
|
|
1034
|
+
"maxLength": 64,
|
|
1034
1035
|
"default": "{{DYNAMIC_GEO}}"
|
|
1035
1036
|
},
|
|
1036
1037
|
"clientOptions": {
|
|
@@ -1438,7 +1439,7 @@ export const MCP_TOOLS = {
|
|
|
1438
1439
|
}),
|
|
1439
1440
|
},
|
|
1440
1441
|
"DeleteProviderVersion": {
|
|
1441
|
-
description: "Delete a provider version\n\nSoft-archives a version on the `draft`, `ai`, or `rejected` branch — sets `status` to `ARCHIVED` so history is preserved.
|
|
1442
|
+
description: "Delete a provider version\n\nSoft-archives a version on the `draft`, `ai`, or `rejected` branch — sets `status` to `ARCHIVED` so history is preserved. `fixed`, trunk (live), and `in_review` versions cannot be archived this way; archive the parent provider instead. Supports optimistic concurrency via `If-Match`.",
|
|
1442
1443
|
inputSchema: toZod({
|
|
1443
1444
|
"type": "object",
|
|
1444
1445
|
"properties": {
|
|
@@ -1774,7 +1775,7 @@ export const MCP_TOOLS = {
|
|
|
1774
1775
|
}),
|
|
1775
1776
|
},
|
|
1776
1777
|
"GetProviderVersion": {
|
|
1777
|
-
description: "Get a specific provider version",
|
|
1778
|
+
description: "Get a specific provider version\n\nFetches one exact canonical version. Trunk is public when the provider is public. Non-trunk versions are visible to admins and members of the provider's organization. A member of the organization that paid for a successful AI repair may also read only the exact `fixed` version created by that repair.",
|
|
1778
1779
|
inputSchema: toZod({
|
|
1779
1780
|
"type": "object",
|
|
1780
1781
|
"properties": {
|
|
@@ -2151,7 +2152,7 @@ export const MCP_TOOLS = {
|
|
|
2151
2152
|
}),
|
|
2152
2153
|
},
|
|
2153
2154
|
"ListProviderVersions": {
|
|
2154
|
-
description: "List a provider's versions\n\nLists versions visible to the caller. Non-public branches (`ai`, `draft`, `in_review`, `rejected`) are only visible to members of the provider's owning organization.",
|
|
2155
|
+
description: "List a provider's versions\n\nLists versions visible to the caller. Non-public branches (`ai`, `draft`, `fixed`, `in_review`, `rejected`) are only visible to members of the provider's owning organization.",
|
|
2155
2156
|
inputSchema: toZod({
|
|
2156
2157
|
"type": "object",
|
|
2157
2158
|
"properties": {
|
|
@@ -2306,7 +2307,7 @@ export const MCP_TOOLS = {
|
|
|
2306
2307
|
}),
|
|
2307
2308
|
},
|
|
2308
2309
|
"Providers": {
|
|
2309
|
-
description: "Search providers\n\nSearch
|
|
2310
|
+
description: "Search providers\n\nSearch Reclaim providers by domain or data point. A provider is the recipe an end-user follows to prove something about themselves, such as \"I have N followers on Twitter\".\nCall this BEFORE `create_provider` — most popular domains already have a public provider you can reuse, and creating another one just stacks duplicates.\nReturns a paginated list of the providers the caller can see: public providers to everyone, private providers only to members of the owning organization.",
|
|
2310
2311
|
inputSchema: toZod({
|
|
2311
2312
|
"type": "object",
|
|
2312
2313
|
"properties": {
|
|
@@ -2677,7 +2678,7 @@ export const MCP_TOOLS = {
|
|
|
2677
2678
|
"properties": {
|
|
2678
2679
|
"notes": {
|
|
2679
2680
|
"type": "string",
|
|
2680
|
-
"description": "Optional note from the author to reviewers (changelog, areas to focus on,
|
|
2681
|
+
"description": "Optional note from the author to reviewers (changelog, areas to focus on, and so on).",
|
|
2681
2682
|
"maxLength": 10000
|
|
2682
2683
|
}
|
|
2683
2684
|
}
|
|
@@ -2840,6 +2841,13 @@ export const MCP_TOOLS = {
|
|
|
2840
2841
|
"minLength": 1,
|
|
2841
2842
|
"maxLength": 200
|
|
2842
2843
|
},
|
|
2844
|
+
"region": {
|
|
2845
|
+
"type": "string",
|
|
2846
|
+
"nullable": true,
|
|
2847
|
+
"description": "Confirm or override the provider's region. Send `null` to clear it so the provider applies to every region. See `Provider.region`.",
|
|
2848
|
+
"pattern": "^[a-z]{2}(-[a-z]{2})?$",
|
|
2849
|
+
"maxLength": 5
|
|
2850
|
+
},
|
|
2843
2851
|
"title": {
|
|
2844
2852
|
"type": "string",
|
|
2845
2853
|
"minLength": 1,
|
|
@@ -2892,12 +2900,12 @@ export const MCP_TOOLS = {
|
|
|
2892
2900
|
"brandUrl": {
|
|
2893
2901
|
"type": "string",
|
|
2894
2902
|
"format": "uri",
|
|
2895
|
-
"description": "Canonical homepage of the brand (
|
|
2903
|
+
"description": "Canonical homepage of the brand (for example, `https://google.com`). Used in brand-link cards and JSON-LD.",
|
|
2896
2904
|
"maxLength": 2000
|
|
2897
2905
|
},
|
|
2898
2906
|
"primaryDataPoint": {
|
|
2899
2907
|
"type": "string",
|
|
2900
|
-
"description": "Headline data point — the single most-important variable this provider can verify (
|
|
2908
|
+
"description": "Headline data point — the single most-important variable this provider can verify (for example, `subscriber count`). Used in the provider's SEO title.",
|
|
2901
2909
|
"maxLength": 200
|
|
2902
2910
|
},
|
|
2903
2911
|
"dataPoints": {
|
|
@@ -2933,7 +2941,7 @@ export const MCP_TOOLS = {
|
|
|
2933
2941
|
}),
|
|
2934
2942
|
},
|
|
2935
2943
|
"UpdateProviderVersion": {
|
|
2936
|
-
description: "Update a provider version\n\nMutable only while the version is on the `draft` or `rejected` branch. Versions on `in_review
|
|
2944
|
+
description: "Update a provider version\n\nMutable only while the version is on the `draft` or `rejected` branch. Versions on `fixed`, `in_review`, or the live channel reject all writes here. Caller must be a member of the provider's owning organization. Supports optimistic concurrency via `If-Match`.",
|
|
2937
2945
|
inputSchema: toZod({
|
|
2938
2946
|
"type": "object",
|
|
2939
2947
|
"properties": {
|
|
@@ -2975,7 +2983,7 @@ export const MCP_TOOLS = {
|
|
|
2975
2983
|
"body": {
|
|
2976
2984
|
"type": "object",
|
|
2977
2985
|
"additionalProperties": false,
|
|
2978
|
-
"description": "Partial update of a provider version. Mutable only while the version is on the `draft` or `rejected` branch; versions on `in_review
|
|
2986
|
+
"description": "Partial update of a provider version. Mutable only while the version is on the `draft` or `rejected` branch; versions on `fixed`, `in_review`, or the live channel reject all writes here. The semver does not change on update — `build_number` increments instead, giving callers a monotonic revision counter without touching the (major, minor, patch) PK. `verificationType` and `prompt` may be updated; omit either to carry the prior build's value forward.",
|
|
2979
2987
|
"properties": {
|
|
2980
2988
|
"initialUrl": {
|
|
2981
2989
|
"type": "string",
|
|
@@ -3114,7 +3122,7 @@ export const MCP_TOOLS = {
|
|
|
3114
3122
|
"items": {
|
|
3115
3123
|
"type": "object",
|
|
3116
3124
|
"additionalProperties": false,
|
|
3117
|
-
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (
|
|
3125
|
+
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (that is, \"HTTP/1.1 200 OK\")",
|
|
3118
3126
|
"properties": {
|
|
3119
3127
|
"xPath": {
|
|
3120
3128
|
"type": "string",
|
|
@@ -3122,7 +3130,7 @@ export const MCP_TOOLS = {
|
|
|
3122
3130
|
},
|
|
3123
3131
|
"jsonPath": {
|
|
3124
3132
|
"type": "string",
|
|
3125
|
-
"description": "expect a JSON response, retrieve the item at this path using dot notation for
|
|
3133
|
+
"description": "expect a JSON response, retrieve the item at this path using dot notation, for example 'email.addresses.0'."
|
|
3126
3134
|
},
|
|
3127
3135
|
"regex": {
|
|
3128
3136
|
"type": "string",
|
|
@@ -3264,7 +3272,7 @@ export const MCP_TOOLS = {
|
|
|
3264
3272
|
"items": {
|
|
3265
3273
|
"type": "object",
|
|
3266
3274
|
"additionalProperties": false,
|
|
3267
|
-
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (
|
|
3275
|
+
"description": "Which portions to select from a response. These are selected in order, xpath => jsonPath => regex * These redactions are done client side and only the selected portions are sent to the attestor. The attestor will only be able to see the selected portions alongside the first line of the HTTP response (that is, \"HTTP/1.1 200 OK\")",
|
|
3268
3276
|
"properties": {
|
|
3269
3277
|
"xPath": {
|
|
3270
3278
|
"type": "string",
|
|
@@ -3272,7 +3280,7 @@ export const MCP_TOOLS = {
|
|
|
3272
3280
|
},
|
|
3273
3281
|
"jsonPath": {
|
|
3274
3282
|
"type": "string",
|
|
3275
|
-
"description": "expect a JSON response, retrieve the item at this path using dot notation for
|
|
3283
|
+
"description": "expect a JSON response, retrieve the item at this path using dot notation, for example 'email.addresses.0'."
|
|
3276
3284
|
},
|
|
3277
3285
|
"regex": {
|
|
3278
3286
|
"type": "string",
|
|
@@ -3329,8 +3337,8 @@ export const MCP_TOOLS = {
|
|
|
3329
3337
|
"properties": {
|
|
3330
3338
|
"geoLocation": {
|
|
3331
3339
|
"type": "string",
|
|
3332
|
-
"description": "Geographic location
|
|
3333
|
-
"maxLength":
|
|
3340
|
+
"description": "Geographic location the verification should appear to originate from: a 2-letter ISO country code, or a parameter the attestor resolves at proof time. `{{DYNAMIC_GEO}}` and `{{DYNAMIC_GEO_SECRET}}` are the Verification Client's standard names for the end-user's own country — the `_SECRET` one is delivered as a secret param, so the attestor never learns which country the proof egressed from.",
|
|
3341
|
+
"maxLength": 64,
|
|
3334
3342
|
"default": "{{DYNAMIC_GEO}}"
|
|
3335
3343
|
},
|
|
3336
3344
|
"clientOptions": {
|
package/src/mcp/api/to-zod.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { JSONSchema } from 'zod/v4/core'
|
|
|
6
6
|
*
|
|
7
7
|
* The generator (`packages/app/scripts/mcp-tools-gen.ts`) inlines `$ref`s it
|
|
8
8
|
* walks through `properties`/`items`, but it does NOT recurse into `allOf` /
|
|
9
|
-
* `anyOf` / `oneOf`. So a schema composed with `allOf` (
|
|
9
|
+
* `anyOf` / `oneOf`. So a schema composed with `allOf` (for example,
|
|
10
10
|
* `RequestSelectionTemplate =
|
|
11
11
|
* allOf[ RequestSelection, { multiple, required } ]`,
|
|
12
12
|
* surfaced by the proof tools' `allowedJsRequests`) can carry a dangling
|
package/src/mcp/api/tools.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { MCP_TOOLS } from './operations.gen.ts'
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* The generated `MCP_TOOLS` are keyed by OpenAPI `operationId` (PascalCase,
|
|
12
|
-
*
|
|
12
|
+
* For example, `GetMe`). MCP tools are conventionally snake_case, matching the
|
|
13
13
|
* hand-written tools in this server. Convert the public tool name here while
|
|
14
14
|
* still dispatching to the API with the original operationId — doing this in
|
|
15
15
|
* the (non-generated) registration keeps it from being reverted on regen.
|
package/src/mcp/instructions.ts
CHANGED
|
@@ -1,66 +1,140 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* The authoring documentation, assembled from `skill/*.md` at module load.
|
|
3
|
+
*
|
|
4
|
+
* Two things are served from here:
|
|
5
|
+
* - the always-on MCP server `instructions` (one file per backend mode) —
|
|
6
|
+
* deliberately small, since every client pays for them on every turn;
|
|
7
|
+
* - the deep authoring guide, split into TOPICS and served on demand by the
|
|
8
|
+
* `how_it_works` tool. Nothing here is inlined into a tool schema: a doc
|
|
9
|
+
* embedded in an input-schema description is paid for on every request
|
|
10
|
+
* whether or not it's ever relevant.
|
|
11
|
+
*
|
|
12
|
+
* The prose lives in markdown (published via package.json's `files`) so it
|
|
13
|
+
* can be edited without touching code. Paths resolve identically from
|
|
14
|
+
* `src/mcp` (dev) and `lib/mcp` (published) — both are two levels below the
|
|
15
|
+
* package root.
|
|
16
|
+
*
|
|
17
|
+
* Assembly has three steps:
|
|
18
|
+
* 1. `<!-- common: name -->` splices a shared block out of `SKILL.common.md`
|
|
19
|
+
* (delimited there by `<!-- section: name -->`), so the two mode guides
|
|
20
|
+
* don't drift on the ~60% of prose that is identical.
|
|
21
|
+
* 2. `%CTX%` expands to the mode's consumer-param namespace — `context.` on
|
|
22
|
+
* the builder, `context_` on old-devtools. That is the only textual
|
|
23
|
+
* difference across most shared blocks, so tokenizing it keeps them
|
|
24
|
+
* shared.
|
|
25
|
+
* 3. `<!-- topic: name -->` splits the result into the units `how_it_works`
|
|
26
|
+
* serves. Backend-independent topics come from their own files instead.
|
|
8
27
|
*/
|
|
9
28
|
import assert from 'node:assert'
|
|
10
29
|
import { readFileSync } from 'node:fs'
|
|
11
30
|
import { fileURLToPath } from 'node:url'
|
|
12
31
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'utf8'
|
|
16
|
-
|
|
32
|
+
function readSkill(file: string): string {
|
|
33
|
+
const url = new URL(`../../skill/${file}`, import.meta.url)
|
|
34
|
+
return readFileSync(fileURLToPath(url), 'utf8')
|
|
35
|
+
// Strip any leading frontmatter defensively.
|
|
36
|
+
.replace(/^---\n[\s\S]*?\n---\n/, '')
|
|
37
|
+
.trim()
|
|
38
|
+
}
|
|
17
39
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* identical regardless of backend, "never do" rules, common troubleshooting).
|
|
21
|
-
* That shared text lives once in `skill/SKILL.common.md`, split into named
|
|
22
|
-
* `<!-- section: name -->`-delimited blocks; each mode file splices a block
|
|
23
|
-
* back in at `<!-- common: name -->`. Parsed once at module load.
|
|
24
|
-
*/
|
|
25
|
-
const COMMON_SECTIONS = parseCommonSections(
|
|
26
|
-
readFileSync(
|
|
27
|
-
fileURLToPath(new URL('../../skill/SKILL.common.md', import.meta.url)),
|
|
28
|
-
'utf8',
|
|
29
|
-
),
|
|
30
|
-
)
|
|
40
|
+
export const BUILDER_MODE_INSTRUCTIONS = readSkill('builder-mode.md')
|
|
41
|
+
export const OLD_MODE_INSTRUCTIONS = readSkill('old-mode.md')
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
43
|
+
/** Split `<!-- marker: name -->`-delimited blocks, keeping document order. */
|
|
44
|
+
function splitBlocks(text: string, marker: string): Map<string, string> {
|
|
45
|
+
const blocks = new Map<string, string>()
|
|
46
|
+
const re = new RegExp(
|
|
47
|
+
`<!-- ${marker}: (\\S+) -->\\n([\\s\\S]*?)(?=\\n<!-- ${marker}: |$)`,
|
|
48
|
+
'g',
|
|
49
|
+
)
|
|
35
50
|
for(const match of text.matchAll(re)) {
|
|
36
|
-
// Trim blank LINES only, not inline indentation — some
|
|
51
|
+
// Trim blank LINES only, not inline indentation — some blocks are
|
|
37
52
|
// list-continuation text that's intentionally indented on its first line.
|
|
38
|
-
|
|
53
|
+
blocks.set(match[1], match[2].replace(/^\n+/, '').replace(/\n+$/, ''))
|
|
39
54
|
}
|
|
40
55
|
|
|
41
|
-
return
|
|
56
|
+
return blocks
|
|
42
57
|
}
|
|
43
58
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
const COMMON_SECTIONS = splitBlocks(readSkill('SKILL.common.md'), 'section')
|
|
60
|
+
|
|
61
|
+
/** Topics that read the same on both backends, each its own file. */
|
|
62
|
+
const SHARED_TOPIC_FILES: Record<string, string> = {
|
|
63
|
+
'user-script': 'user-script.md',
|
|
64
|
+
'interception': 'interception.md',
|
|
65
|
+
'hash-validation': 'hash-validation.md',
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** One line per topic, shown in the `how_it_works` index so a caller can pick
|
|
69
|
+
* the right one without fetching several. Keyed across both modes; only the
|
|
70
|
+
* topics a mode actually has are listed back to it. */
|
|
71
|
+
const TOPIC_SUMMARIES: Record<string, string> = {
|
|
72
|
+
'overview': 'Terminology, your stance, and the whole loop at a glance.',
|
|
73
|
+
'auth': 'Signing in to the backend, and which token authorizes what.',
|
|
74
|
+
'browser': 'Choosing a browser source (local Chrome, the Reclaim runtime in '
|
|
75
|
+
+ 'Docker, a remote Popcorn browser, or a custom CDP endpoint), '
|
|
76
|
+
+ 'geolocation, live view, and launch troubleshooting.',
|
|
77
|
+
'capture': 'Tabs, login detection, driving the page, and picking an '
|
|
78
|
+
+ 'authenticated request to prove.',
|
|
79
|
+
'draft': 'The OPRF/privacy decision, propose_provider, and the canonical '
|
|
80
|
+
+ 'drafted shape.',
|
|
81
|
+
'params': 'Extracted vs consumer-supplied vs secret params, the URL '
|
|
82
|
+
+ 'character budget, and runtime resolution.',
|
|
83
|
+
'prove': 'replay_request, the mandatory auth-bound check, run_proof, and '
|
|
84
|
+
+ 'diagnosing failures.',
|
|
85
|
+
'publish': 'Creating/reusing a provider, versions, multi-request providers, '
|
|
86
|
+
+ 'and going live.',
|
|
87
|
+
'discover': 'Finding the right providers for a dev\'s app and creating a '
|
|
88
|
+
+ 'verification session.',
|
|
89
|
+
'user-script': 'Authoring jsUserScripts / customInjection to drive '
|
|
90
|
+
+ 'login-gated pages.',
|
|
91
|
+
'interception': 'injectionType / interceptorType, live interception, the '
|
|
92
|
+
+ 'document-replay flag, and what to do when a site won\'t load or '
|
|
93
|
+
+ 'won\'t let the user sign in.',
|
|
94
|
+
'hash-validation': 'bodySniff, and how verifyProof({ providerId }) gates on '
|
|
95
|
+
+ 'the declared spec hash.',
|
|
96
|
+
'credentials': 'The eth proof-owner key run_proof signs with.',
|
|
97
|
+
'never-do': 'The short list of things that always break a provider.',
|
|
98
|
+
'troubleshooting': 'Expired drafts, browser problems, and where to look '
|
|
99
|
+
+ 'next.',
|
|
100
|
+
}
|
|
57
101
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
102
|
+
export interface Guide {
|
|
103
|
+
/** Topic name → its markdown, in document order. */
|
|
104
|
+
topics: Map<string, string>
|
|
105
|
+
/** `{ topic, summary }` for every topic this mode has. */
|
|
106
|
+
index: Array<{ topic: string, summary: string }>
|
|
107
|
+
/** Every topic concatenated — the whole guide, as it used to be served. */
|
|
108
|
+
full: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildGuide(file: string, ctxPrefix: string): Guide {
|
|
112
|
+
const raw = readSkill(file)
|
|
113
|
+
.replace(/<!-- common: (\S+) -->/g, (_whole, name: string) => {
|
|
114
|
+
const section = COMMON_SECTIONS.get(name)
|
|
115
|
+
assert(section, `${file}: no SKILL.common.md section named "${name}"`)
|
|
116
|
+
return section
|
|
117
|
+
})
|
|
118
|
+
.replaceAll('%CTX%', ctxPrefix)
|
|
119
|
+
|
|
120
|
+
const topics = splitBlocks(raw, 'topic')
|
|
121
|
+
assert(topics.size, `${file}: no <!-- topic: … --> sections found`)
|
|
122
|
+
for(const [name, path] of Object.entries(SHARED_TOPIC_FILES)) {
|
|
123
|
+
topics.set(name, readSkill(path))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const index = [...topics.keys()].map((topic) => {
|
|
127
|
+
const summary = TOPIC_SUMMARIES[topic]
|
|
128
|
+
assert(summary, `${file}: no TOPIC_SUMMARIES entry for "${topic}"`)
|
|
129
|
+
return { topic, summary }
|
|
62
130
|
})
|
|
131
|
+
|
|
132
|
+
return { topics, index, full: [...topics.values()].join('\n\n') }
|
|
63
133
|
}
|
|
64
134
|
|
|
65
|
-
export const
|
|
66
|
-
export const
|
|
135
|
+
export const GUIDE_BUILDER = buildGuide('SKILL.builder.md', 'context.')
|
|
136
|
+
export const GUIDE_OLD = buildGuide('SKILL.old.md', 'context_')
|
|
137
|
+
|
|
138
|
+
export function guideFor(oldMode: boolean): Guide {
|
|
139
|
+
return oldMode ? GUIDE_OLD : GUIDE_BUILDER
|
|
140
|
+
}
|
package/src/mcp/start.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
resolveOldMode,
|
|
12
12
|
sdkApiUrl,
|
|
13
13
|
} from '../consts.ts'
|
|
14
|
+
import { LOGGER } from '../logger.ts'
|
|
14
15
|
import { ReclaimOldClient } from '../old/client.ts'
|
|
15
16
|
import { resolveInitialIdentity } from '../old/identity.ts'
|
|
16
17
|
import { OLD_MODE_INSTRUCTIONS } from '../old/instructions.ts'
|
|
@@ -19,6 +20,7 @@ import { buildOldBackendTools } from '../old/tools/build.ts'
|
|
|
19
20
|
import { NAME, VERSION } from '../pkg.ts'
|
|
20
21
|
import { registerTools } from './api/tools.ts'
|
|
21
22
|
import {
|
|
23
|
+
type AgentState,
|
|
22
24
|
buildAgentState,
|
|
23
25
|
buildAgentTools,
|
|
24
26
|
buildBuilderAuthenticationTools,
|
|
@@ -27,6 +29,7 @@ import {
|
|
|
27
29
|
buildLocalCredentialTools,
|
|
28
30
|
buildModeTools,
|
|
29
31
|
buildVerificationTools,
|
|
32
|
+
disposeAgentState,
|
|
30
33
|
readSession,
|
|
31
34
|
} from './tools/index.ts'
|
|
32
35
|
import { BUILDER_MODE_INSTRUCTIONS } from './instructions.ts'
|
|
@@ -52,6 +55,8 @@ export async function startMcpServer() {
|
|
|
52
55
|
// deployments — set RECLAIM_AGENT_DISABLED=1 to register only the API
|
|
53
56
|
// surface.
|
|
54
57
|
const agentToolsEnabled = !agentDisabled()
|
|
58
|
+
/** The agent state this server registered, for shutdown to release. */
|
|
59
|
+
let agentState: AgentState | undefined
|
|
55
60
|
const builderClient = new ReclaimClient({
|
|
56
61
|
baseUrl: apiUrl(),
|
|
57
62
|
// Builder access is orthogonal to publishing mode. A legacy-devtools
|
|
@@ -75,8 +80,9 @@ export async function startMcpServer() {
|
|
|
75
80
|
})
|
|
76
81
|
const sdkClient = new ReclaimSdkClient({ baseUrl: sdkApiUrl() })
|
|
77
82
|
// Shared with buildAgentTools below so the old-mode publish tool can see
|
|
78
|
-
// the live attach state (
|
|
79
|
-
|
|
83
|
+
// the live attach state (for example, to flag a still-open browser
|
|
84
|
+
// session).
|
|
85
|
+
agentState = buildAgentState()
|
|
80
86
|
|
|
81
87
|
registerToolList(server, buildBuilderAuthenticationTools(builderClient))
|
|
82
88
|
registerToolList(server, buildBuilderOrganizationTools(builderClient))
|
|
@@ -105,8 +111,8 @@ export async function startMcpServer() {
|
|
|
105
111
|
// Register credential tools for ETH credential management.
|
|
106
112
|
registerToolList(server, buildCredentialTools(client))
|
|
107
113
|
|
|
108
|
-
// Higher-level verification orchestrations (
|
|
109
|
-
// Authenticates with RECLAIM_ORG_SECRET, not the session client.
|
|
114
|
+
// Higher-level verification orchestrations (for example, fetch + decrypt
|
|
115
|
+
// result). Authenticates with RECLAIM_ORG_SECRET, not the session client.
|
|
110
116
|
registerToolList(server, buildVerificationTools())
|
|
111
117
|
|
|
112
118
|
// Add auto-generated tools with snake_case wrappers
|
|
@@ -114,10 +120,68 @@ export async function startMcpServer() {
|
|
|
114
120
|
registerTools(server, client)
|
|
115
121
|
|
|
116
122
|
if(agentToolsEnabled) {
|
|
117
|
-
|
|
123
|
+
agentState = buildAgentState()
|
|
124
|
+
registerToolList(server, buildAgentTools(client, client, agentState))
|
|
118
125
|
}
|
|
119
126
|
}
|
|
120
127
|
|
|
128
|
+
// Anything the session holds has to be released when the session ends, and
|
|
129
|
+
// the session can end without a single tool call: the developer closes their
|
|
130
|
+
// agent, the client kills the server, stdin drops. Nothing ran here before,
|
|
131
|
+
// which left a container up and — worse — a public tunnel still pointing at a
|
|
132
|
+
// live browser after the session that made it was gone.
|
|
133
|
+
if(agentToolsEnabled) {
|
|
134
|
+
installShutdownHooks(() => agentState)
|
|
135
|
+
}
|
|
136
|
+
|
|
121
137
|
const transport = new StdioServerTransport()
|
|
122
138
|
await server.connect(transport)
|
|
123
139
|
}
|
|
140
|
+
|
|
141
|
+
/** How long teardown gets before the process leaves anyway. */
|
|
142
|
+
const SHUTDOWN_GRACE_MS = 10_000
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Release the browser on every way out we can observe.
|
|
146
|
+
*
|
|
147
|
+
* `SIGTERM`/`SIGINT` is how a client stops us; stdin ending is how a stdio
|
|
148
|
+
* transport says the other side is gone. A `SIGKILL` cannot be caught at all,
|
|
149
|
+
* which is why `reapOrphanedContainers` exists as the backstop.
|
|
150
|
+
*/
|
|
151
|
+
function installShutdownHooks(state: () => AgentState | undefined): void {
|
|
152
|
+
let shuttingDown = false
|
|
153
|
+
const shutdown = (reason: string) => {
|
|
154
|
+
if(shuttingDown) {
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
shuttingDown = true
|
|
159
|
+
const current = state()
|
|
160
|
+
if(!current) {
|
|
161
|
+
process.exit(0)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
LOGGER.info({ reason }, 'releasing the browser before exit')
|
|
165
|
+
// Bounded: a wedged `docker stop` must not keep the process alive, but
|
|
166
|
+
// nor should we skip cleanup that would have finished in a second.
|
|
167
|
+
const timer = setTimeout(() => {
|
|
168
|
+
LOGGER.warn({ reason }, 'teardown timed out; exiting anyway')
|
|
169
|
+
process.exit(0)
|
|
170
|
+
}, SHUTDOWN_GRACE_MS)
|
|
171
|
+
timer.unref()
|
|
172
|
+
void disposeAgentState(current)
|
|
173
|
+
.catch((err: unknown) => {
|
|
174
|
+
LOGGER.warn({ err }, 'teardown failed')
|
|
175
|
+
})
|
|
176
|
+
.finally(() => {
|
|
177
|
+
clearTimeout(timer)
|
|
178
|
+
process.exit(0)
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
process.once('SIGTERM', () => shutdown('SIGTERM'))
|
|
183
|
+
process.once('SIGINT', () => shutdown('SIGINT'))
|
|
184
|
+
// The transport's own end of the conversation.
|
|
185
|
+
process.stdin.once('end', () => shutdown('stdin ended'))
|
|
186
|
+
process.stdin.once('close', () => shutdown('stdin closed'))
|
|
187
|
+
}
|
|
@@ -7,7 +7,11 @@ export function analyzeTool(captures: CaptureStore): RegisteredTool {
|
|
|
7
7
|
{
|
|
8
8
|
name: 'analyze_request_constraints',
|
|
9
9
|
description:
|
|
10
|
-
'Flag
|
|
10
|
+
'Flag provider-authoring concerns for one captured request — signed '
|
|
11
|
+
+ 'request, CSRF dependency, bot challenge, short-lived token, '
|
|
12
|
+
+ 'GraphQL. Call it on each top candidate from '
|
|
13
|
+
+ 'find_requests_containing before drafting, and relay the returned '
|
|
14
|
+
+ '`concerns` to the developer verbatim.',
|
|
11
15
|
inputSchema: {
|
|
12
16
|
type: 'object',
|
|
13
17
|
properties: {
|