@cookiemunch/mcp 0.1.0 → 0.2.0
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 +11 -6
- package/dist/bin.cjs +555 -135
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2 -2
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-G5TN4KJA.js → chunk-PLBLLTYO.js} +555 -135
- package/dist/chunk-PLBLLTYO.js.map +1 -0
- package/dist/index.cjs +554 -134
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -4
- package/dist/chunk-G5TN4KJA.js.map +0 -1
package/dist/bin.cjs
CHANGED
|
@@ -9,7 +9,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
9
9
|
var import_sdk = require("@cookiemunch/sdk");
|
|
10
10
|
|
|
11
11
|
// src/tools.ts
|
|
12
|
-
var
|
|
12
|
+
var import_zod4 = require("zod");
|
|
13
13
|
|
|
14
14
|
// src/tools-config.ts
|
|
15
15
|
var import_zod = require("zod");
|
|
@@ -549,9 +549,29 @@ function registerPlatformTools(tool, client) {
|
|
|
549
549
|
secretKey: import_zod2.z.string().describe("Its API key, with whatever scope that system needs to export and erase a user."),
|
|
550
550
|
webhookSecret: import_zod2.z.string().optional().describe("Signing secret of its webhook endpoint. Optional: polling closes tasks without it."),
|
|
551
551
|
auto: import_zod2.z.boolean().optional().describe("Open a sub-task automatically when a request reaches fulfilment. Default true."),
|
|
552
|
-
profile: import_zod2.z.record(import_zod2.z.unknown()).describe("How to drive that system: { open, poll, statuses } required, plus optional subjectLookup, auth, idempotencyHeader and webhook. See the connected-systems docs for the shape.")
|
|
552
|
+
profile: import_zod2.z.record(import_zod2.z.unknown()).describe("How to drive that system: { open, poll, statuses } required, plus optional subjectLookup, auth, idempotencyHeader and webhook. See the connected-systems docs for the shape."),
|
|
553
|
+
dryRun: import_zod2.z.boolean().optional().describe("Validate everything and answer the connection that would be created, storing nothing.")
|
|
553
554
|
},
|
|
554
|
-
(a) =>
|
|
555
|
+
(a) => {
|
|
556
|
+
const { dryRun, ...input } = a;
|
|
557
|
+
return dryRun === true ? client.fulfillment.dryRunConnectExecutor(input) : client.fulfillment.connectExecutor(input);
|
|
558
|
+
}
|
|
559
|
+
);
|
|
560
|
+
tool(
|
|
561
|
+
"test_dsar_executor_webhook",
|
|
562
|
+
"Would this webhook delivery from a connected system verify? Runs the receiver's exact check (headers, timestamp tolerance, prefix, HMAC) on headers and a raw body you supply, acts on nothing, and returns { verified, stage, reason } naming the stage that failed. `body` must be the raw request body string, byte for byte. Read-only.",
|
|
563
|
+
{
|
|
564
|
+
id: import_zod2.z.string().describe("The connection id."),
|
|
565
|
+
headers: import_zod2.z.record(import_zod2.z.string()).describe("The delivery headers, e.g. its id, timestamp and signature headers."),
|
|
566
|
+
body: import_zod2.z.string().describe("The raw body exactly as it was signed.")
|
|
567
|
+
},
|
|
568
|
+
(a) => client.fulfillment.testExecutorWebhook(a.id, { headers: a.headers, body: a.body })
|
|
569
|
+
);
|
|
570
|
+
tool(
|
|
571
|
+
"list_dsar_executor_webhook_deliveries",
|
|
572
|
+
"The last 50 deliveries to a connected system's webhook, newest first, each with whether it verified and, if not, the stage and reason. Never includes the secret, the signature or the body (only a short hash and size). Read-only.",
|
|
573
|
+
{ id: import_zod2.z.string().describe("The connection id.") },
|
|
574
|
+
(a) => client.fulfillment.executorWebhookDeliveries(a.id)
|
|
555
575
|
);
|
|
556
576
|
tool(
|
|
557
577
|
"disconnect_dsar_executor",
|
|
@@ -664,10 +684,176 @@ function registerPlatformTools(tool, client) {
|
|
|
664
684
|
);
|
|
665
685
|
}
|
|
666
686
|
|
|
687
|
+
// src/tools-rights-page.ts
|
|
688
|
+
var import_zod3 = require("zod");
|
|
689
|
+
function registerRightsTools(tool, client) {
|
|
690
|
+
const cbid = { cbid: import_zod3.z.string().describe("Site identifier (cbid). Must belong to your org.") };
|
|
691
|
+
const base = {
|
|
692
|
+
baseUpdatedAt: import_zod3.z.union([import_zod3.z.number().int(), import_zod3.z.string(), import_zod3.z.null()]).optional().describe("The draft\u2019s updatedAt from your last read (null if it had none). If someone saved since, the write is refused with 409 draft_conflict and the current draft; omit to overwrite regardless.")
|
|
693
|
+
};
|
|
694
|
+
const baseOpt = (a) => a.baseUpdatedAt !== void 0 ? { baseUpdatedAt: a.baseUpdatedAt } : {};
|
|
695
|
+
tool("get_rights_page", "Read the site\u2019s rights page DRAFT (the default page until first saved), with warnings that would block publishing.", cbid, (a) => client.rightsPage.get(a.cbid));
|
|
696
|
+
tool(
|
|
697
|
+
"update_rights_page",
|
|
698
|
+
"Replace the rights page draft with a full document (theme, sections, form, i18n, seo, customCss). Nothing goes live until publish_rights_page. Prefer patch_rights_page for small changes and preview_rights_page when unsure. Pass baseUpdatedAt (from get_rights_page) to avoid overwriting someone else\u2019s save: a mismatch is 409 draft_conflict with the current draft.",
|
|
699
|
+
{ ...cbid, page: import_zod3.z.record(import_zod3.z.unknown()).describe("The whole RightsPage document (v: 1)."), ...base },
|
|
700
|
+
(a) => client.rightsPage.put(a.cbid, a.page, baseOpt(a))
|
|
701
|
+
);
|
|
702
|
+
tool(
|
|
703
|
+
"patch_rights_page",
|
|
704
|
+
"Change part of the rights page draft: objects merge, arrays (sections, request types, fields) replace whole, null removes a field. baseUpdatedAt works as on update_rights_page (409 draft_conflict).",
|
|
705
|
+
{ ...cbid, patch: import_zod3.z.record(import_zod3.z.unknown()), ...base },
|
|
706
|
+
(a) => client.rightsPage.patch(a.cbid, a.patch, baseOpt(a))
|
|
707
|
+
);
|
|
708
|
+
tool(
|
|
709
|
+
"preview_rights_page",
|
|
710
|
+
'Validate a rights-page write WITHOUT saving: returns the document as it would be stored and any publish warnings. mode "patch" (default) or "put".',
|
|
711
|
+
{ ...cbid, page: import_zod3.z.record(import_zod3.z.unknown()), mode: import_zod3.z.enum(["patch", "put"]).optional() },
|
|
712
|
+
(a) => client.rightsPage.dryRun(a.cbid, a.page, { mode: a.mode ?? "patch" })
|
|
713
|
+
);
|
|
714
|
+
tool("get_published_rights_page", "Read the LIVE rights page document (404 not_published while the site shows the default page).", cbid, (a) => client.rightsPage.getPublished(a.cbid));
|
|
715
|
+
tool(
|
|
716
|
+
"publish_rights_page",
|
|
717
|
+
"Publish the draft as the next version: it goes live at once, to every visitor. Refused unless the page has exactly one form section and an enabled request type. Pass baseUpdatedAt (from get_rights_page) so only the draft you read goes live; without it, whatever the draft holds now is published, including someone else\u2019s later edits. A mismatch is 409 draft_conflict with the current draft.",
|
|
718
|
+
{ ...cbid, ...base },
|
|
719
|
+
(a) => client.rightsPage.publish(a.cbid, baseOpt(a))
|
|
720
|
+
);
|
|
721
|
+
tool("list_rights_page_versions", "Published versions of the rights page, newest first, each with publishedBy, publishedByEmail (null for an API key) and publishedVia.", cbid, (a) => client.rightsPage.versions(a.cbid));
|
|
722
|
+
tool(
|
|
723
|
+
"rollback_rights_page",
|
|
724
|
+
"Publish an earlier version of the rights page again (as a new version): it goes live at once and REPLACES the current draft, so unpublished edits are lost and cannot be recovered (versions hold only published documents). Pass baseUpdatedAt (from get_rights_page) to refuse with 409 draft_conflict if anyone saved the draft since you read it.",
|
|
725
|
+
{ ...cbid, version: import_zod3.z.number().int().min(1), ...base },
|
|
726
|
+
(a) => client.rightsPage.rollback(a.cbid, a.version, baseOpt(a))
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
function registerRightsPageTools(tool, client) {
|
|
730
|
+
const site = import_zod3.z.object({ cbid: import_zod3.z.string().describe("Site identifier (cbid). Must belong to your org.") });
|
|
731
|
+
const host = site.extend({
|
|
732
|
+
hostname: import_zod3.z.string().describe("The custom hostname, e.g. privacy.example.com (unicode or punycode).")
|
|
733
|
+
});
|
|
734
|
+
tool(
|
|
735
|
+
"list_rights_page_domains",
|
|
736
|
+
"List the custom hostnames serving a site's rights page, each with its status (pending_dns, verifying, issuing, active, error), the exact DNS records to create, and the plan's allowance.",
|
|
737
|
+
site.shape,
|
|
738
|
+
(a) => client.rightsPage.listDomains(site.parse(a).cbid)
|
|
739
|
+
);
|
|
740
|
+
tool(
|
|
741
|
+
"add_rights_page_domain",
|
|
742
|
+
"Add a custom hostname for a site's rights page (e.g. privacy.example.com). Returns the DNS records the owner must create: a CNAME to this domain's own <token>.cname.cookiemunch.net (a CNAME to anything else never verifies it), or for an apex / flattened / proxied record the _cookiemunch TXT. Then call verify_rights_page_domain. Plans include Free 0, Starter 1, Pro 5, Scale unlimited.",
|
|
743
|
+
host.shape,
|
|
744
|
+
(a) => {
|
|
745
|
+
const { cbid, hostname } = host.parse(a);
|
|
746
|
+
return client.rightsPage.addDomain(cbid, hostname);
|
|
747
|
+
}
|
|
748
|
+
);
|
|
749
|
+
tool(
|
|
750
|
+
"verify_rights_page_domain",
|
|
751
|
+
"Check a custom hostname now: DNS while it is pending or in error, the HTTPS answer once it is routed. Returns the domain as it now stands; lastError and dnsSeen say what is missing.",
|
|
752
|
+
host.shape,
|
|
753
|
+
(a) => {
|
|
754
|
+
const { cbid, hostname } = host.parse(a);
|
|
755
|
+
return client.rightsPage.verifyDomain(cbid, hostname);
|
|
756
|
+
}
|
|
757
|
+
);
|
|
758
|
+
tool(
|
|
759
|
+
"remove_rights_page_domain",
|
|
760
|
+
"Remove a custom hostname from a site's rights page. It stops being served at once and its certificate is no longer renewed.",
|
|
761
|
+
host.shape,
|
|
762
|
+
async (a) => {
|
|
763
|
+
const { cbid, hostname } = host.parse(a);
|
|
764
|
+
await client.rightsPage.removeDomain(cbid, hostname);
|
|
765
|
+
return { removed: hostname };
|
|
766
|
+
}
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/design-warnings.ts
|
|
771
|
+
function whereText(f) {
|
|
772
|
+
const w = f.where ?? {};
|
|
773
|
+
const bits = [
|
|
774
|
+
f.layer === "banner" ? "first layer" : `${f.layer} layer`,
|
|
775
|
+
w.view ? `view "${w.view}"` : "",
|
|
776
|
+
w.variant && w.variant !== "base" ? `variant ${w.variant}` : "",
|
|
777
|
+
w.theme === "dark" ? "dark theme" : "",
|
|
778
|
+
w.breakpoint === "mobile" ? "mobile" : "",
|
|
779
|
+
w.language ? `language ${w.language}` : "",
|
|
780
|
+
w.url ? w.url : ""
|
|
781
|
+
].filter(Boolean);
|
|
782
|
+
return bits.join(", ");
|
|
783
|
+
}
|
|
784
|
+
function styleText(s) {
|
|
785
|
+
const parts = [
|
|
786
|
+
s.background ? `background ${s.background}` : "",
|
|
787
|
+
s.color ? `text ${s.color}` : "",
|
|
788
|
+
s.borderColor ? `border ${s.borderWidth ?? 1}px ${s.borderColor}` : "",
|
|
789
|
+
s.fontSize ? `font ${s.fontSize}px` : "",
|
|
790
|
+
s.fontWeight ? `weight ${s.fontWeight}` : "",
|
|
791
|
+
s.width && s.height ? `${Math.round(s.width)}\xD7${Math.round(s.height)}px` : ""
|
|
792
|
+
].filter(Boolean);
|
|
793
|
+
return parts.join(", ");
|
|
794
|
+
}
|
|
795
|
+
var CONTEXT_TEXT = {
|
|
796
|
+
saved: "The config was saved as sent; this is a warning, not an error.",
|
|
797
|
+
preview: "Nothing was saved: this is a preview of the write.",
|
|
798
|
+
lint: "Nothing was saved: this is a lint of a proposed config.",
|
|
799
|
+
read: "This describes the config as it is stored now; nothing was changed.",
|
|
800
|
+
scan: "This was measured on the live site by the last cookie scan; fix the banner, then scan again."
|
|
801
|
+
};
|
|
802
|
+
function designContext(tool, value) {
|
|
803
|
+
const v = value && typeof value === "object" ? value : {};
|
|
804
|
+
if (tool === "lint_banner_config") return "lint";
|
|
805
|
+
if (v.dryRun === true || tool.startsWith("preview_")) return "preview";
|
|
806
|
+
if (v.buttonParity && typeof v.buttonParity === "object") return "scan";
|
|
807
|
+
if (/^(update|patch|set|edit|create|assign|apply)_/.test(tool)) return "saved";
|
|
808
|
+
return "read";
|
|
809
|
+
}
|
|
810
|
+
function designWarningText(findings, suggested, context = "read") {
|
|
811
|
+
if (!Array.isArray(findings) || findings.length === 0) return "";
|
|
812
|
+
const warnings = findings.filter((f) => f.severity === "warning");
|
|
813
|
+
const notices = findings.filter((f) => f.severity !== "warning");
|
|
814
|
+
const lines = [];
|
|
815
|
+
if (warnings.length) {
|
|
816
|
+
lines.push(
|
|
817
|
+
`Design warning: the Accept button is more prominent than Reject (${warnings.length} issue${warnings.length === 1 ? "" : "s"}). Regulators treat this as a dark pattern (EDPB Guidelines 03/2022, the EDPB cookie banner taskforce, CNIL). Make both buttons the same style. ${CONTEXT_TEXT[context]}`
|
|
818
|
+
);
|
|
819
|
+
for (const f of warnings) lines.push(`- [${f.code}] (${whereText(f)}) ${f.detail} Fix: ${f.fix}`);
|
|
820
|
+
}
|
|
821
|
+
if (notices.length) {
|
|
822
|
+
lines.push(
|
|
823
|
+
`Design notice: ${notices.length} thing${notices.length === 1 ? "" : "s"} to check about how Reject compares with Accept.` + (warnings.length ? "" : ` ${CONTEXT_TEXT[context]}`)
|
|
824
|
+
);
|
|
825
|
+
for (const f of notices) lines.push(`- [${f.code}] (${whereText(f)}) ${f.detail} Fix: ${f.fix}`);
|
|
826
|
+
}
|
|
827
|
+
const fixes = suggested && suggested.length ? suggested : findings.filter((f) => f.accept && f.reject).slice(0, 1).map((f) => ({ ...f.accept, layer: f.layer, view: f.where?.view }));
|
|
828
|
+
for (const s of fixes) {
|
|
829
|
+
const style = styleText(s);
|
|
830
|
+
if (style) {
|
|
831
|
+
lines.push(
|
|
832
|
+
`Suggested fix: style Reject all${s.view ? ` in view "${s.view}"` : ""} with ${style} \u2014 the same as Accept all. In a flow design, give the Reject button the same \`variant\` and size as the Accept button.`
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return lines.join("\n");
|
|
837
|
+
}
|
|
838
|
+
function withDesignWarnings(value, body, tool = "") {
|
|
839
|
+
if (!value || typeof value !== "object") return body;
|
|
840
|
+
const nested = value.buttonParity;
|
|
841
|
+
const v = nested && typeof nested === "object" ? nested : value;
|
|
842
|
+
if (!Array.isArray(v.designWarnings) || v.designWarnings.length === 0) return body;
|
|
843
|
+
const head = designWarningText(
|
|
844
|
+
v.designWarnings,
|
|
845
|
+
Array.isArray(v.suggestedReject) ? v.suggestedReject : void 0,
|
|
846
|
+
designContext(tool, value)
|
|
847
|
+
);
|
|
848
|
+
return head ? `${head}
|
|
849
|
+
|
|
850
|
+
${body}` : body;
|
|
851
|
+
}
|
|
852
|
+
|
|
667
853
|
// src/tools.ts
|
|
668
|
-
function text(value) {
|
|
854
|
+
function text(value, tool = "") {
|
|
669
855
|
const body = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
670
|
-
return { content: [{ type: "text", text: body }] };
|
|
856
|
+
return { content: [{ type: "text", text: withDesignWarnings(value, body, tool) }] };
|
|
671
857
|
}
|
|
672
858
|
function fail(err) {
|
|
673
859
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -677,16 +863,16 @@ function registerTools(server, client) {
|
|
|
677
863
|
const tool = (name, description, inputSchema, run) => {
|
|
678
864
|
server.registerTool(name, { description, inputSchema }, async (args) => {
|
|
679
865
|
try {
|
|
680
|
-
return text(await run(args));
|
|
866
|
+
return text(await run(args), name);
|
|
681
867
|
} catch (err) {
|
|
682
868
|
return fail(err);
|
|
683
869
|
}
|
|
684
870
|
});
|
|
685
871
|
};
|
|
686
|
-
const cbid = { cbid:
|
|
872
|
+
const cbid = { cbid: import_zod4.z.string().describe("Site identifier (cbid). Must belong to your org.") };
|
|
687
873
|
const range = {
|
|
688
|
-
from:
|
|
689
|
-
to:
|
|
874
|
+
from: import_zod4.z.number().optional().describe("Epoch-ms lower bound."),
|
|
875
|
+
to: import_zod4.z.number().optional().describe("Epoch-ms upper bound.")
|
|
690
876
|
};
|
|
691
877
|
tool(
|
|
692
878
|
"whoami",
|
|
@@ -704,19 +890,19 @@ function registerTools(server, client) {
|
|
|
704
890
|
tool(
|
|
705
891
|
"get_site",
|
|
706
892
|
"One site: its domain, cbid and verification status. Read-only.",
|
|
707
|
-
{ cbid:
|
|
893
|
+
{ cbid: import_zod4.z.string() },
|
|
708
894
|
(a) => client.sites.get(a.cbid)
|
|
709
895
|
);
|
|
710
896
|
tool(
|
|
711
897
|
"get_site_banner",
|
|
712
898
|
"Which banner design a site uses, or bannerId null when none is assigned. Read-only.",
|
|
713
|
-
{ cbid:
|
|
899
|
+
{ cbid: import_zod4.z.string() },
|
|
714
900
|
(a) => client.sites.banner(a.cbid)
|
|
715
901
|
);
|
|
716
902
|
tool(
|
|
717
903
|
"get_privacy_policy",
|
|
718
904
|
"Generate the site's privacy and cookie policy as Markdown, naming the org's data controller. Needs a contact email: the one given, else the org controller's, else the owner's. Read-only \u2014 nothing is published.",
|
|
719
|
-
{ cbid:
|
|
905
|
+
{ cbid: import_zod4.z.string(), contactEmail: import_zod4.z.string().optional(), effectiveDate: import_zod4.z.string().optional().describe("YYYY-MM-DD; defaults to today."), jurisdictions: import_zod4.z.array(import_zod4.z.string()).optional() },
|
|
720
906
|
(a) => client.sites.policy(a.cbid, {
|
|
721
907
|
...a.contactEmail ? { contactEmail: a.contactEmail } : {},
|
|
722
908
|
...a.effectiveDate ? { effectiveDate: a.effectiveDate } : {},
|
|
@@ -726,7 +912,7 @@ function registerTools(server, client) {
|
|
|
726
912
|
tool(
|
|
727
913
|
"set_ad_personalization",
|
|
728
914
|
"Add or remove the separate 'personalised ads' choice on the site's live banner. With it on, accepting marketing no longer implies personalised ads unless `default` is true.",
|
|
729
|
-
{ cbid:
|
|
915
|
+
{ cbid: import_zod4.z.string(), enabled: import_zod4.z.boolean(), default: import_zod4.z.boolean().optional(), label: import_zod4.z.string().optional() },
|
|
730
916
|
(a) => client.sites.setAdPersonalization(a.cbid, {
|
|
731
917
|
enabled: a.enabled,
|
|
732
918
|
...a.default !== void 0 ? { default: a.default } : {},
|
|
@@ -737,11 +923,11 @@ function registerTools(server, client) {
|
|
|
737
923
|
"analyze_session",
|
|
738
924
|
"Analyse a captured browsing session against the consent it ran under: which trackers fired after the visitor opted out, and what personal data left the page. Read-only.",
|
|
739
925
|
{
|
|
740
|
-
cbid:
|
|
741
|
-
har:
|
|
742
|
-
requests:
|
|
743
|
-
consent:
|
|
744
|
-
gpc:
|
|
926
|
+
cbid: import_zod4.z.string(),
|
|
927
|
+
har: import_zod4.z.unknown().optional().describe("A HAR export of the session."),
|
|
928
|
+
requests: import_zod4.z.array(import_zod4.z.unknown()).optional().describe("Or the requests directly."),
|
|
929
|
+
consent: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.boolean()).optional(),
|
|
930
|
+
gpc: import_zod4.z.boolean().optional()
|
|
745
931
|
},
|
|
746
932
|
(a) => client.sites.analyzeSession(a.cbid, {
|
|
747
933
|
...a.har !== void 0 ? { har: a.har } : {},
|
|
@@ -753,39 +939,62 @@ function registerTools(server, client) {
|
|
|
753
939
|
tool(
|
|
754
940
|
"create_site",
|
|
755
941
|
"Create a new site. The cbid is auto-generated if you omit it.",
|
|
756
|
-
{ domain:
|
|
942
|
+
{ domain: import_zod4.z.string().describe("The site domain, e.g. example.com."), cbid: import_zod4.z.string().optional().describe("Optional explicit cbid.") },
|
|
757
943
|
(a) => client.sites.create({ domain: a.domain, ...typeof a.cbid === "string" ? { cbid: a.cbid } : {} })
|
|
758
944
|
);
|
|
759
945
|
tool(
|
|
760
946
|
"create_sites_bulk",
|
|
761
947
|
"Create up to 100 sites in one call. Partial success: each item reports ok or its own error, and a bad or duplicate item fails only itself.",
|
|
762
948
|
{
|
|
763
|
-
sites:
|
|
949
|
+
sites: import_zod4.z.array(import_zod4.z.object({ domain: import_zod4.z.string(), cbid: import_zod4.z.string().optional(), platform: import_zod4.z.string().optional() })).min(1).max(100)
|
|
764
950
|
},
|
|
765
951
|
(a) => client.sites.createBulk(a.sites)
|
|
766
952
|
);
|
|
767
953
|
tool("get_site_config", "Get the banner/consent configuration for a site.", { ...cbid }, (a) => client.sites.getConfig(a.cbid));
|
|
768
954
|
tool(
|
|
769
955
|
"update_site_config",
|
|
770
|
-
"Replace (overwrite) the banner/consent configuration for a site via PUT. This is destructive, not a merge: any top-level SiteConfig field you omit from `config` reverts to its default rather than keeping its current value. To change one setting, use patch_site_config instead \u2014 it merges server-side. Prefer the narrower set_* tools (set_blocking, set_banner_basics, etc.) when they cover your change.",
|
|
771
|
-
{
|
|
772
|
-
|
|
956
|
+
"Replace (overwrite) the banner/consent configuration for a site via PUT. This is destructive, not a merge: any top-level SiteConfig field you omit from `config` reverts to its default rather than keeping its current value \u2014 unless keepUnspecified is true, in which case omitted top-level fields keep their stored value and only the fields you send are replaced (each whole). A top-level field sent as null reverts to its default. To change one setting, use patch_site_config instead \u2014 it merges server-side. Prefer the narrower set_* tools (set_blocking, set_banner_basics, etc.) when they cover your change.",
|
|
957
|
+
{
|
|
958
|
+
...cbid,
|
|
959
|
+
config: import_zod4.z.record(import_zod4.z.unknown()).describe("The full SiteConfig to write, not a patch. Without keepUnspecified, omitted top-level fields are NOT preserved from the current config."),
|
|
960
|
+
keepUnspecified: import_zod4.z.boolean().optional().describe("PUT ?keep=unspecified: keep the stored value of every top-level field `config` omits, instead of reverting it to its default.")
|
|
961
|
+
},
|
|
962
|
+
(a) => a.keepUnspecified === true ? client.sites.putConfig(a.cbid, a.config, { keep: "unspecified" }) : client.sites.putConfig(a.cbid, a.config)
|
|
773
963
|
);
|
|
774
964
|
tool(
|
|
775
965
|
"patch_site_config",
|
|
776
|
-
|
|
777
|
-
{ ...cbid, config:
|
|
966
|
+
`Change part of a site's banner/consent configuration. The patch is a JSON Merge Patch (RFC 7386) over the stored config server-side: any field you omit keeps its current value, and a field set to null is REMOVED (it falls back to its default) \u2014 e.g. { "banner": { "i18n": { "es": null } } } drops the Spanish override. This is the safe way to flip one setting, and it needs no read-modify-write. Use update_site_config only when you genuinely mean to replace the whole document.`,
|
|
967
|
+
{ ...cbid, config: import_zod4.z.record(import_zod4.z.unknown()).describe('The subset of SiteConfig to change, e.g. { "banner": { "showRightsLink": true } }. Everything else is preserved; null removes a field.') },
|
|
778
968
|
(a) => client.sites.patchConfig(a.cbid, a.config)
|
|
779
969
|
);
|
|
780
970
|
tool(
|
|
781
971
|
"preview_site_config",
|
|
782
|
-
'Preview a config change WITHOUT saving it: returns the config as it would be saved, a diff of every field that would change, and any warnings (plan-gated or unrecognised fields). mode "patch" (default) previews patch_site_config; mode "put" previews update_site_config, and its diff lists everything a replace would revert to its default. Use it before any write you are not sure of.',
|
|
972
|
+
'Preview a config change WITHOUT saving it: returns the config as it would be saved, a diff of every field that would change, and any warnings (plan-gated or unrecognised fields). mode "patch" (default) previews patch_site_config; mode "put" previews update_site_config, and its diff lists everything a replace would revert to its default (unless keepUnspecified is true). Use it before any write you are not sure of.',
|
|
973
|
+
{
|
|
974
|
+
...cbid,
|
|
975
|
+
config: import_zod4.z.record(import_zod4.z.unknown()).describe('The patch (or, with mode "put", the full config) to preview.'),
|
|
976
|
+
mode: import_zod4.z.enum(["patch", "put"]).optional().describe("patch (default) merges; put replaces."),
|
|
977
|
+
keepUnspecified: import_zod4.z.boolean().optional().describe('With mode "put": preview update_site_config with keepUnspecified (omitted top-level fields keep their stored value).')
|
|
978
|
+
},
|
|
979
|
+
(a) => client.sites.dryRunConfig(a.cbid, a.config, {
|
|
980
|
+
mode: a.mode ?? "patch",
|
|
981
|
+
...a.keepUnspecified === true ? { keep: "unspecified" } : {}
|
|
982
|
+
})
|
|
983
|
+
);
|
|
984
|
+
tool(
|
|
985
|
+
"lint_banner_config",
|
|
986
|
+
'Check a banner config for consent-button parity WITHOUT saving it: is "Accept all" more prominent than "Reject all" anywhere \u2014 a brighter or more saturated colour, a bigger or bolder button, Reject styled as a link, hidden, below the fold, set apart, missing from the first layer, or worded to guilt-trip? Regulators (EDPB, CNIL) treat that as a dark pattern. Returns findings, a 0\u2013100 score and the reject style that would match Accept. It checks exactly what the write would store: merged over the stored config as patch_site_config would, or with replace: true replaced as update_site_config would. Run it before writing any banner design.',
|
|
783
987
|
{
|
|
784
988
|
...cbid,
|
|
785
|
-
config:
|
|
786
|
-
|
|
989
|
+
config: import_zod4.z.record(import_zod4.z.unknown()).describe("The proposed SiteConfig (or a partial one, or a v2 flow design)."),
|
|
990
|
+
replace: import_zod4.z.boolean().optional().describe("Check what update_site_config (a full replace) would store, instead of what patch_site_config (a merge) would.")
|
|
787
991
|
},
|
|
788
|
-
(a) =>
|
|
992
|
+
async (a) => {
|
|
993
|
+
const r = await client.sites.lintConfig(a.cbid, a.config, a.replace === true ? { replace: true } : {});
|
|
994
|
+
return r.designWarnings.length === 0 ? `No design warnings: Accept all and Reject all have equal weight on every surface checked (score ${r.score}). Nothing was saved.
|
|
995
|
+
|
|
996
|
+
${JSON.stringify(r, null, 2)}` : r;
|
|
997
|
+
}
|
|
789
998
|
);
|
|
790
999
|
tool(
|
|
791
1000
|
"verify_consent_log",
|
|
@@ -802,7 +1011,7 @@ function registerTools(server, client) {
|
|
|
802
1011
|
tool(
|
|
803
1012
|
"get_consent_log",
|
|
804
1013
|
"Get recent anonymised consent records for a site.",
|
|
805
|
-
{ ...cbid, ...range, limit:
|
|
1014
|
+
{ ...cbid, ...range, limit: import_zod4.z.number().optional().describe("Max records to return (default 200).") },
|
|
806
1015
|
(a) => client.consent.log(a.cbid, {
|
|
807
1016
|
from: a.from,
|
|
808
1017
|
to: a.to,
|
|
@@ -812,49 +1021,53 @@ function registerTools(server, client) {
|
|
|
812
1021
|
tool(
|
|
813
1022
|
"get_subject_consent",
|
|
814
1023
|
"One person's consent records across every site in the org \u2014 web, mobile and desktop \u2014 by the subjectId your apps attach. Consent data: needs the consent:read scope. Read-only.",
|
|
815
|
-
{ subjectId:
|
|
1024
|
+
{ subjectId: import_zod4.z.string() },
|
|
816
1025
|
(a) => client.subjects.consent(a.subjectId)
|
|
817
1026
|
);
|
|
818
1027
|
tool("list_dsar", "List all Data Subject Access Requests for your organization.", {}, () => client.dsar.list());
|
|
819
1028
|
tool(
|
|
820
1029
|
"update_dsar_executor",
|
|
821
|
-
"Change a connected system in place \u2014 its profile, address, credential or auto flag. Only what you pass changes; the stored credential is kept unless you give a new one.",
|
|
822
|
-
{
|
|
823
|
-
|
|
1030
|
+
"Change a connected system in place \u2014 its profile, address, credential or auto flag. Only what you pass changes; the stored credential is kept unless you give a new one. With dryRun, answers the connection as it would be and a diff, and changes nothing.",
|
|
1031
|
+
{
|
|
1032
|
+
id: import_zod4.z.string(),
|
|
1033
|
+
patch: import_zod4.z.record(import_zod4.z.unknown()),
|
|
1034
|
+
dryRun: import_zod4.z.boolean().optional().describe("Validate and diff without saving.")
|
|
1035
|
+
},
|
|
1036
|
+
(a) => a.dryRun === true ? client.fulfillment.dryRunUpdateExecutor(a.id, a.patch) : client.fulfillment.updateExecutor(a.id, a.patch)
|
|
824
1037
|
);
|
|
825
1038
|
tool(
|
|
826
1039
|
"get_dsar",
|
|
827
1040
|
"One rights request by id, including its status and the deadline it must be answered by.",
|
|
828
|
-
{ id:
|
|
1041
|
+
{ id: import_zod4.z.string() },
|
|
829
1042
|
(a) => client.dsar.get(a.id)
|
|
830
1043
|
);
|
|
831
1044
|
tool(
|
|
832
1045
|
"erase_dsar_subject",
|
|
833
1046
|
"For a deletion request that is past identity verification: erase the person\u2019s consent records on one site, identified by their consent stamp. Irreversible. The erasure is noted on the request. If the response carries a warning, nothing was cryptographically erased \u2014 tell the user.",
|
|
834
|
-
{ id:
|
|
1047
|
+
{ id: import_zod4.z.string(), cbid: import_zod4.z.string(), stamp: import_zod4.z.string() },
|
|
835
1048
|
(a) => client.dsar.erase(a.id, a.cbid, a.stamp)
|
|
836
1049
|
);
|
|
837
1050
|
tool(
|
|
838
1051
|
"export_dsar_subject",
|
|
839
1052
|
"For an access or portability request that is past identity verification: the person\u2019s consent records on one site, identified by their consent stamp. The export is noted on the request.",
|
|
840
|
-
{ id:
|
|
1053
|
+
{ id: import_zod4.z.string(), cbid: import_zod4.z.string(), stamp: import_zod4.z.string() },
|
|
841
1054
|
(a) => client.dsar.export(a.id, a.cbid, a.stamp)
|
|
842
1055
|
);
|
|
843
1056
|
tool(
|
|
844
1057
|
"get_dsar_response_notice",
|
|
845
1058
|
"The subject-facing response notice for a request, as plain text \u2014 what to send the person. Read-only; nothing is sent.",
|
|
846
|
-
{ id:
|
|
1059
|
+
{ id: import_zod4.z.string() },
|
|
847
1060
|
(a) => client.dsar.response(a.id)
|
|
848
1061
|
);
|
|
849
1062
|
tool(
|
|
850
1063
|
"create_dsar",
|
|
851
1064
|
"Open a new Data Subject Access Request.",
|
|
852
1065
|
{
|
|
853
|
-
type:
|
|
854
|
-
subjectEmail:
|
|
855
|
-
regulation:
|
|
856
|
-
note:
|
|
857
|
-
test:
|
|
1066
|
+
type: import_zod4.z.enum(["access", "deletion", "rectification", "portability", "opt-out"]).describe("DSAR right being exercised."),
|
|
1067
|
+
subjectEmail: import_zod4.z.string().describe("The data subject\u2019s email."),
|
|
1068
|
+
regulation: import_zod4.z.enum(["gdpr", "ccpa"]).describe("Governing regulation."),
|
|
1069
|
+
note: import_zod4.z.string().optional().describe("Optional free-text note."),
|
|
1070
|
+
test: import_zod4.z.boolean().optional().describe("Mark it as a test request: kept off the SLA board and deletable afterwards with delete_test_dsar.")
|
|
858
1071
|
},
|
|
859
1072
|
(a) => client.dsar.create({
|
|
860
1073
|
type: a.type,
|
|
@@ -864,21 +1077,43 @@ function registerTools(server, client) {
|
|
|
864
1077
|
...a.test === true ? { test: true } : {}
|
|
865
1078
|
})
|
|
866
1079
|
);
|
|
1080
|
+
tool(
|
|
1081
|
+
"create_rights_link",
|
|
1082
|
+
"Mint a signed, single-use link to a site\u2019s hosted rights page for a person you know is signed in to that site. On the page their email is filled in and locked and the email-code step is skipped; the filed request is recorded as verified by their account. Give the link only to that person. Expires in 15 minutes by default (max 1 hour). Needs dsar:write.",
|
|
1083
|
+
{
|
|
1084
|
+
cbid: import_zod4.z.string().describe("Site identifier (cbid). Must belong to your org."),
|
|
1085
|
+
email: import_zod4.z.string().describe("The signed-in person\u2019s verified email address."),
|
|
1086
|
+
userId: import_zod4.z.string().optional().describe("Your own account id for them; recorded on the request."),
|
|
1087
|
+
rights: import_zod4.z.array(import_zod4.z.enum(["access", "erasure", "rectification", "portability", "restriction", "objection", "opt_out_sale", "opt_out_targeted", "limit_sensitive"])).min(1).optional().describe("Limit the link to these rights. Default: every right the page offers."),
|
|
1088
|
+
ttlSeconds: import_zod4.z.number().int().min(60).max(3600).optional().describe("How long the link works, in seconds (default 900).")
|
|
1089
|
+
},
|
|
1090
|
+
(a) => client.rightsLinks.create(a.cbid, {
|
|
1091
|
+
subject: { email: a.email, ...typeof a.userId === "string" ? { userId: a.userId } : {} },
|
|
1092
|
+
...Array.isArray(a.rights) ? { rights: a.rights } : {},
|
|
1093
|
+
...typeof a.ttlSeconds === "number" ? { ttlSeconds: a.ttlSeconds } : {}
|
|
1094
|
+
})
|
|
1095
|
+
);
|
|
867
1096
|
tool(
|
|
868
1097
|
"delete_test_dsar",
|
|
869
1098
|
"Delete a TEST rights request (one created with test: true), with its tasks and their upstream log. Real requests cannot be deleted and are refused. The deletion is recorded in the audit log.",
|
|
870
|
-
{ id:
|
|
1099
|
+
{ id: import_zod4.z.string().describe("The test request id.") },
|
|
871
1100
|
async (a) => {
|
|
872
1101
|
await client.dsar.delete(a.id);
|
|
873
1102
|
return { deleted: a.id };
|
|
874
1103
|
}
|
|
875
1104
|
);
|
|
1105
|
+
tool(
|
|
1106
|
+
"mark_dsar_test",
|
|
1107
|
+
"Mark a CLOSED rights request (completed or rejected) as a test request, after the fact \u2014 for trial requests filed before test: true existed. An open request is refused (request_not_closed), so a live obligation can never be relabelled. Recorded in the audit log; afterwards delete_test_dsar can remove it. Returns { request, changed }.",
|
|
1108
|
+
{ id: import_zod4.z.string().describe("The closed request id.") },
|
|
1109
|
+
(a) => client.dsar.markTest(a.id)
|
|
1110
|
+
);
|
|
876
1111
|
tool(
|
|
877
1112
|
"advance_dsar",
|
|
878
1113
|
"Advance a DSAR to a new status (received \u2192 verifying \u2192 in_progress \u2192 completed, or rejected).",
|
|
879
1114
|
{
|
|
880
|
-
id:
|
|
881
|
-
toStatus:
|
|
1115
|
+
id: import_zod4.z.string().describe("The DSAR id."),
|
|
1116
|
+
toStatus: import_zod4.z.enum(["received", "verifying", "in_progress", "completed", "rejected"]).describe("Target status.")
|
|
882
1117
|
},
|
|
883
1118
|
(a) => client.dsar.advance(a.id, a.toStatus)
|
|
884
1119
|
);
|
|
@@ -891,7 +1126,7 @@ function registerTools(server, client) {
|
|
|
891
1126
|
tool(
|
|
892
1127
|
"get_receipt",
|
|
893
1128
|
"Fetch the signed consent receipt for a single consent record (by stamp).",
|
|
894
|
-
{ ...cbid, stamp:
|
|
1129
|
+
{ ...cbid, stamp: import_zod4.z.string().describe("The consent record stamp/id.") },
|
|
895
1130
|
(a) => client.consent.receipt(a.cbid, a.stamp)
|
|
896
1131
|
);
|
|
897
1132
|
tool("delete_site", "Delete a site (cbid) and its configuration from your org.", { ...cbid }, async (a) => {
|
|
@@ -903,13 +1138,13 @@ function registerTools(server, client) {
|
|
|
903
1138
|
"create_vendor",
|
|
904
1139
|
"Register a vendor (processor) and compute its risk score.",
|
|
905
1140
|
{
|
|
906
|
-
name:
|
|
907
|
-
category:
|
|
908
|
-
dataShared:
|
|
909
|
-
dpaSigned:
|
|
910
|
-
subprocessors:
|
|
911
|
-
certifications:
|
|
912
|
-
region:
|
|
1141
|
+
name: import_zod4.z.string().describe("Vendor name."),
|
|
1142
|
+
category: import_zod4.z.string().describe("Vendor category, e.g. analytics."),
|
|
1143
|
+
dataShared: import_zod4.z.array(import_zod4.z.string()).describe("Categories of data shared with the vendor."),
|
|
1144
|
+
dpaSigned: import_zod4.z.boolean().describe("Whether a Data Processing Agreement is signed."),
|
|
1145
|
+
subprocessors: import_zod4.z.number().describe("Number of subprocessors."),
|
|
1146
|
+
certifications: import_zod4.z.array(import_zod4.z.string()).describe("Compliance certifications, e.g. ISO27001."),
|
|
1147
|
+
region: import_zod4.z.string().describe("Primary processing region, e.g. EU.")
|
|
913
1148
|
},
|
|
914
1149
|
(a) => client.vendors.create({
|
|
915
1150
|
name: a.name,
|
|
@@ -927,13 +1162,13 @@ function registerTools(server, client) {
|
|
|
927
1162
|
"create_ropa",
|
|
928
1163
|
"Create a Record of Processing Activity (RoPA) entry.",
|
|
929
1164
|
{
|
|
930
|
-
name:
|
|
931
|
-
purpose:
|
|
932
|
-
legalBasis:
|
|
933
|
-
dataCategories:
|
|
934
|
-
recipients:
|
|
935
|
-
retentionDays:
|
|
936
|
-
crossBorderTransfer:
|
|
1165
|
+
name: import_zod4.z.string().describe("Activity name."),
|
|
1166
|
+
purpose: import_zod4.z.string().describe("Purpose of processing."),
|
|
1167
|
+
legalBasis: import_zod4.z.enum(["consent", "contract", "legal-obligation", "vital-interests", "public-task", "legitimate-interests"]).describe("GDPR legal basis."),
|
|
1168
|
+
dataCategories: import_zod4.z.array(import_zod4.z.string()).describe("Categories of personal data."),
|
|
1169
|
+
recipients: import_zod4.z.array(import_zod4.z.string()).describe("Recipients of the data."),
|
|
1170
|
+
retentionDays: import_zod4.z.number().describe("Retention period in days."),
|
|
1171
|
+
crossBorderTransfer: import_zod4.z.boolean().describe("Whether data is transferred across borders.")
|
|
937
1172
|
},
|
|
938
1173
|
(a) => client.ropa.create({
|
|
939
1174
|
name: a.name,
|
|
@@ -979,9 +1214,9 @@ function registerTools(server, client) {
|
|
|
979
1214
|
"create_webhook",
|
|
980
1215
|
"Create a webhook subscription. The response includes the signing secret (shown once).",
|
|
981
1216
|
{
|
|
982
|
-
url:
|
|
983
|
-
events:
|
|
984
|
-
cbid:
|
|
1217
|
+
url: import_zod4.z.string().describe("HTTPS endpoint to deliver events to."),
|
|
1218
|
+
events: import_zod4.z.array(import_zod4.z.string()).describe("Event names to subscribe to, e.g. consent.created."),
|
|
1219
|
+
cbid: import_zod4.z.string().optional().describe("Optional site cbid to scope the subscription to.")
|
|
985
1220
|
},
|
|
986
1221
|
(a) => client.webhooks.create({
|
|
987
1222
|
url: a.url,
|
|
@@ -992,13 +1227,13 @@ function registerTools(server, client) {
|
|
|
992
1227
|
tool(
|
|
993
1228
|
"roll_webhook_secret",
|
|
994
1229
|
"Rotate a webhook subscription\u2019s signing secret. The new secret is returned once; the receiving endpoint must be updated to verify with it.",
|
|
995
|
-
{ id:
|
|
1230
|
+
{ id: import_zod4.z.string() },
|
|
996
1231
|
(a) => client.webhooks.rollSecret(a.id)
|
|
997
1232
|
);
|
|
998
1233
|
tool(
|
|
999
1234
|
"test_webhook",
|
|
1000
1235
|
"Send a signed test event to a webhook subscription now, and report what the endpoint answered.",
|
|
1001
|
-
{ id:
|
|
1236
|
+
{ id: import_zod4.z.string() },
|
|
1002
1237
|
(a) => client.webhooks.test(a.id)
|
|
1003
1238
|
);
|
|
1004
1239
|
tool(
|
|
@@ -1010,18 +1245,18 @@ function registerTools(server, client) {
|
|
|
1010
1245
|
tool(
|
|
1011
1246
|
"replay_webhook_dead_letter",
|
|
1012
1247
|
"Deliver a dead-lettered webhook event again, to the subscription as it is now.",
|
|
1013
|
-
{ id:
|
|
1248
|
+
{ id: import_zod4.z.string() },
|
|
1014
1249
|
(a) => client.webhooks.replayDeadLetter(a.id)
|
|
1015
1250
|
);
|
|
1016
1251
|
tool(
|
|
1017
1252
|
"update_webhook",
|
|
1018
1253
|
"Change a webhook subscription, or pause it with active:false (delivery stops; the subscription is kept). Only the fields given change. cbid: null widens it to every property in the org.",
|
|
1019
1254
|
{
|
|
1020
|
-
id:
|
|
1021
|
-
url:
|
|
1022
|
-
events:
|
|
1023
|
-
cbid:
|
|
1024
|
-
active:
|
|
1255
|
+
id: import_zod4.z.string(),
|
|
1256
|
+
url: import_zod4.z.string().optional(),
|
|
1257
|
+
events: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
1258
|
+
cbid: import_zod4.z.string().nullable().optional(),
|
|
1259
|
+
active: import_zod4.z.boolean().optional()
|
|
1025
1260
|
},
|
|
1026
1261
|
(a) => client.webhooks.update(a.id, {
|
|
1027
1262
|
...a.url !== void 0 ? { url: a.url } : {},
|
|
@@ -1030,20 +1265,20 @@ function registerTools(server, client) {
|
|
|
1030
1265
|
...a.active !== void 0 ? { active: a.active } : {}
|
|
1031
1266
|
})
|
|
1032
1267
|
);
|
|
1033
|
-
tool("delete_webhook", "Delete a webhook subscription by id.", { id:
|
|
1268
|
+
tool("delete_webhook", "Delete a webhook subscription by id.", { id: import_zod4.z.string().describe("The webhook subscription id.") }, async (a) => {
|
|
1034
1269
|
await client.webhooks.delete(a.id);
|
|
1035
1270
|
return { ok: true };
|
|
1036
1271
|
});
|
|
1037
1272
|
tool(
|
|
1038
1273
|
"verify_site",
|
|
1039
1274
|
"Verify that your organization controls a domain by one of three challenge methods (dns / meta / file). Required to unlock consent export and signed receipts.",
|
|
1040
|
-
{ ...cbid, method:
|
|
1275
|
+
{ ...cbid, method: import_zod4.z.enum(["dns", "meta", "file"]).describe("Challenge method: dns (TXT record), meta (HTML tag), or file (/.well-known/cookiemunch-verify.txt).") },
|
|
1041
1276
|
(a) => client.sites.verify(a.cbid, a.method)
|
|
1042
1277
|
);
|
|
1043
1278
|
tool(
|
|
1044
1279
|
"get_verification_challenge",
|
|
1045
1280
|
"Exactly what to publish to prove control of a site\u2019s domain: the DNS TXT record, the meta tag, the file, or installing the embed. Read-only \u2014 publish one, then call verify_site.",
|
|
1046
|
-
{ cbid:
|
|
1281
|
+
{ cbid: import_zod4.z.string() },
|
|
1047
1282
|
(a) => client.sites.verifyChallenge(a.cbid)
|
|
1048
1283
|
);
|
|
1049
1284
|
tool(
|
|
@@ -1055,15 +1290,15 @@ function registerTools(server, client) {
|
|
|
1055
1290
|
tool(
|
|
1056
1291
|
"get_flow",
|
|
1057
1292
|
"Get the v2 banner flow config for a site, including current views, categories, and any lint issues.",
|
|
1058
|
-
{ cbid:
|
|
1293
|
+
{ cbid: import_zod4.z.string().describe("Site identifier (cbid).") },
|
|
1059
1294
|
(a) => client.sites.getFlow(a.cbid)
|
|
1060
1295
|
);
|
|
1061
1296
|
tool(
|
|
1062
1297
|
"edit_flow",
|
|
1063
1298
|
"Apply a batch of structured edit operations to a site's v2 banner flow. All ops are validated server-side and the final config must be lint-clean before it is saved.",
|
|
1064
1299
|
{
|
|
1065
|
-
cbid:
|
|
1066
|
-
operations:
|
|
1300
|
+
cbid: import_zod4.z.string().describe("Site identifier (cbid)."),
|
|
1301
|
+
operations: import_zod4.z.array(import_zod4.z.record(import_zod4.z.unknown())).describe(
|
|
1067
1302
|
'Ordered list of ops. Each must have an "op" field: addView | removeView | addElement | setButtonTransition | addCustomCategory.'
|
|
1068
1303
|
)
|
|
1069
1304
|
},
|
|
@@ -1073,19 +1308,21 @@ function registerTools(server, client) {
|
|
|
1073
1308
|
"set_flow",
|
|
1074
1309
|
"Wholesale replace a site's v2 banner flow with a complete config (e.g. from a template). Validated server-side before it is saved.",
|
|
1075
1310
|
{
|
|
1076
|
-
cbid:
|
|
1077
|
-
config:
|
|
1311
|
+
cbid: import_zod4.z.string().describe("Site identifier (cbid)."),
|
|
1312
|
+
config: import_zod4.z.record(import_zod4.z.unknown()).describe("A full v2 FlowConfig object ({ v:2, flow, categories, ... }).")
|
|
1078
1313
|
},
|
|
1079
1314
|
(a) => client.sites.setFlow(a.cbid, a.config)
|
|
1080
1315
|
);
|
|
1081
1316
|
registerConfigTools(tool, client);
|
|
1082
1317
|
registerPlatformTools(tool, client);
|
|
1318
|
+
registerRightsTools(tool, client);
|
|
1319
|
+
registerRightsPageTools(tool, client);
|
|
1083
1320
|
tool(
|
|
1084
1321
|
"invite_member",
|
|
1085
1322
|
"Invite a person to your organization by email. role must be admin, member, or viewer. The org is derived from the API key \u2014 you cannot invite into a different org.",
|
|
1086
1323
|
{
|
|
1087
|
-
email:
|
|
1088
|
-
role:
|
|
1324
|
+
email: import_zod4.z.string().describe("Email address of the person to invite."),
|
|
1325
|
+
role: import_zod4.z.enum(["admin", "member", "viewer"]).describe("Role to assign: admin, member, or viewer. owner is not assignable via API key.")
|
|
1089
1326
|
},
|
|
1090
1327
|
(a) => client.members.invite(a.email, a.role)
|
|
1091
1328
|
);
|
|
@@ -1093,8 +1330,8 @@ function registerTools(server, client) {
|
|
|
1093
1330
|
"set_member_role",
|
|
1094
1331
|
"Change the role of a member in your organization. The org owner's role cannot be changed.",
|
|
1095
1332
|
{
|
|
1096
|
-
userId:
|
|
1097
|
-
role:
|
|
1333
|
+
userId: import_zod4.z.string().describe("The userId of the member whose role to change."),
|
|
1334
|
+
role: import_zod4.z.enum(["admin", "member", "viewer"]).describe("New role: admin, member, or viewer.")
|
|
1098
1335
|
},
|
|
1099
1336
|
(a) => client.members.setRole(a.userId, a.role)
|
|
1100
1337
|
);
|
|
@@ -1102,7 +1339,7 @@ function registerTools(server, client) {
|
|
|
1102
1339
|
"remove_member",
|
|
1103
1340
|
"Remove a member from your organization. The org owner cannot be removed.",
|
|
1104
1341
|
{
|
|
1105
|
-
userId:
|
|
1342
|
+
userId: import_zod4.z.string().describe("The userId of the member to remove.")
|
|
1106
1343
|
},
|
|
1107
1344
|
async (a) => {
|
|
1108
1345
|
await client.members.remove(a.userId);
|
|
@@ -1113,11 +1350,11 @@ function registerTools(server, client) {
|
|
|
1113
1350
|
"create_brand_kit",
|
|
1114
1351
|
"Create a reusable brand kit (colors, logo, typography) for your organization's consent banners.",
|
|
1115
1352
|
{
|
|
1116
|
-
name:
|
|
1117
|
-
theme:
|
|
1118
|
-
content:
|
|
1119
|
-
logoUrl:
|
|
1120
|
-
customCss:
|
|
1353
|
+
name: import_zod4.z.string().describe("Display name for the brand kit."),
|
|
1354
|
+
theme: import_zod4.z.record(import_zod4.z.unknown()).describe("Theme tokens (colors, fonts, etc.) as a JSON object."),
|
|
1355
|
+
content: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("Optional banner copy overrides."),
|
|
1356
|
+
logoUrl: import_zod4.z.string().optional().describe("Optional URL for your org logo."),
|
|
1357
|
+
customCss: import_zod4.z.string().optional().describe("Optional custom CSS string to inject into the banner.")
|
|
1121
1358
|
},
|
|
1122
1359
|
(a) => client.brandKits.create({
|
|
1123
1360
|
name: a.name,
|
|
@@ -1131,7 +1368,7 @@ function registerTools(server, client) {
|
|
|
1131
1368
|
"delete_brand_kit",
|
|
1132
1369
|
"Delete a brand kit by id. The kit must belong to your organization (cross-org deletes are rejected).",
|
|
1133
1370
|
{
|
|
1134
|
-
id:
|
|
1371
|
+
id: import_zod4.z.string().describe("The brand kit id to delete.")
|
|
1135
1372
|
},
|
|
1136
1373
|
async (a) => {
|
|
1137
1374
|
await client.brandKits.delete(a.id);
|
|
@@ -1142,25 +1379,25 @@ function registerTools(server, client) {
|
|
|
1142
1379
|
"save_preference",
|
|
1143
1380
|
"Save or update the consent preferences for an end-user (by subjectId) within your organization. purposes is a map of purpose-name \u2192 boolean.",
|
|
1144
1381
|
{
|
|
1145
|
-
subjectId:
|
|
1146
|
-
purposes:
|
|
1382
|
+
subjectId: import_zod4.z.string().describe("The end-user identifier (e.g. email or internal user id)."),
|
|
1383
|
+
purposes: import_zod4.z.record(import_zod4.z.boolean()).describe('Map of purpose names to consent values, e.g. { "newsletter": true, "analytics": false }.')
|
|
1147
1384
|
},
|
|
1148
1385
|
(a) => client.preferences.save(a.subjectId, a.purposes)
|
|
1149
1386
|
);
|
|
1150
1387
|
tool(
|
|
1151
1388
|
"get_preference",
|
|
1152
1389
|
"One end-user\u2019s saved preferences, by subjectId. Read-only.",
|
|
1153
|
-
{ subjectId:
|
|
1390
|
+
{ subjectId: import_zod4.z.string() },
|
|
1154
1391
|
(a) => client.preferences.get(a.subjectId)
|
|
1155
1392
|
);
|
|
1156
1393
|
tool(
|
|
1157
1394
|
"issue_api_key",
|
|
1158
1395
|
"Issue a new API key. The secret is returned once and never again. Prefer the least privilege the job needs: `scopes` limits what it can do, `cbids` locks it to specific sites (it then cannot reach anything org-wide), `expiresInDays` retires it. Omitting all three mints a full-access, org-wide, non-expiring key.",
|
|
1159
1396
|
{
|
|
1160
|
-
name:
|
|
1161
|
-
scopes:
|
|
1162
|
-
cbids:
|
|
1163
|
-
expiresInDays:
|
|
1397
|
+
name: import_zod4.z.string().optional(),
|
|
1398
|
+
scopes: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
1399
|
+
cbids: import_zod4.z.array(import_zod4.z.string()).min(1).optional(),
|
|
1400
|
+
expiresInDays: import_zod4.z.number().int().min(1).max(3650).optional()
|
|
1164
1401
|
},
|
|
1165
1402
|
(a) => client.keys.issue({
|
|
1166
1403
|
...a.name ? { name: a.name } : {},
|
|
@@ -1169,36 +1406,80 @@ function registerTools(server, client) {
|
|
|
1169
1406
|
...a.expiresInDays !== void 0 ? { expiresInDays: a.expiresInDays } : {}
|
|
1170
1407
|
})
|
|
1171
1408
|
);
|
|
1172
|
-
tool("revoke_api_key", "Revoke an API key by its prefix. Takes effect immediately; anything using that key stops working.", { prefix:
|
|
1409
|
+
tool("revoke_api_key", "Revoke an API key by its prefix. Takes effect immediately; anything using that key stops working.", { prefix: import_zod4.z.string() }, async (a) => {
|
|
1173
1410
|
await client.keys.revoke(a.prefix);
|
|
1174
1411
|
return { revoked: a.prefix };
|
|
1175
1412
|
});
|
|
1176
1413
|
tool(
|
|
1177
1414
|
"import_cookie_declaration",
|
|
1178
1415
|
"Read a cookie declaration exported from another CMP (OneTrust, Cookiebot, CookieYes, or any CSV/JSON with the same columns) and translate its categories into ours. Nothing is applied \u2014 it comes back for review, with the rows whose category could not be placed listed separately.",
|
|
1179
|
-
{ cbid:
|
|
1416
|
+
{ cbid: import_zod4.z.string(), data: import_zod4.z.string().describe("The exported file, as text (CSV or JSON).") },
|
|
1180
1417
|
(a) => client.sites.importDeclaration(a.cbid, a.data)
|
|
1181
1418
|
);
|
|
1419
|
+
tool(
|
|
1420
|
+
"apply_cookie_import",
|
|
1421
|
+
"Import a cookie declaration exported from another CMP AND declare it: every row whose category mapped to ours and that has a purpose becomes a site declaration; the rest come back in `skipped` with the reason. Cookies the site already declared are kept unless overwrite is true. Prefer import_cookie_declaration first to review.",
|
|
1422
|
+
{ cbid: import_zod4.z.string(), data: import_zod4.z.string().describe("The exported file, as text (CSV or JSON)."), overwrite: import_zod4.z.boolean().optional() },
|
|
1423
|
+
(a) => client.sites.applyImport(a.cbid, a.data, a.overwrite ? { overwrite: true } : void 0)
|
|
1424
|
+
);
|
|
1425
|
+
const declarationShape = {
|
|
1426
|
+
category: import_zod4.z.string().describe("necessary, preferences, statistics, marketing, or one of the site\u2019s categories.custom ids."),
|
|
1427
|
+
purpose: import_zod4.z.string().describe("What the cookie does, as visitors will read it \u2014 and the fallback for any language purposes lacks."),
|
|
1428
|
+
purposes: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.string().max(1e3)).nullable().optional().describe('The purpose in other languages, keyed by BCP-47 tag: {"es": "\u2026", "pt-BR": "\u2026"}. The banner, data-cc="declaration" and cookie-declaration.js draw the visitor\u2019s language. null clears.'),
|
|
1429
|
+
provider: import_zod4.z.string().optional(),
|
|
1430
|
+
expiry: import_zod4.z.string().optional().describe('e.g. "Session", "30 days", "1 year" (the banner localises these forms).'),
|
|
1431
|
+
domain: import_zod4.z.string().optional(),
|
|
1432
|
+
pattern: import_zod4.z.boolean().optional().describe("Treat the name as a prefix wildcard (a trailing * does the same).")
|
|
1433
|
+
};
|
|
1434
|
+
const dryRunArg = import_zod4.z.boolean().optional().describe("Store nothing: answer with the would-be declarations and a diff (added / removed / changed) to check first.");
|
|
1435
|
+
tool(
|
|
1436
|
+
"declare_cookie",
|
|
1437
|
+
'Declare what one of the site\u2019s cookies is. Overrides the scanner, observed visits and the cookie database everywhere the declaration is shown (API, preference modal, data-cc="declaration"). Use for the site\u2019s own cookies the database cannot know. A name ending in * covers every cookie with that prefix.',
|
|
1438
|
+
{ cbid: import_zod4.z.string(), name: import_zod4.z.string(), ...declarationShape, dryRun: dryRunArg },
|
|
1439
|
+
(a) => {
|
|
1440
|
+
const { cbid: cbid2, name, dryRun, ...rest } = a;
|
|
1441
|
+
return client.sites.declareCookie(cbid2, name, rest, dryRun ? { dryRun: true } : void 0);
|
|
1442
|
+
}
|
|
1443
|
+
);
|
|
1444
|
+
tool(
|
|
1445
|
+
"declare_cookies",
|
|
1446
|
+
"Declare many cookies at once. All-or-nothing: one invalid item refuses the whole request and nothing is saved. replace: true also removes every declaration the list does not name.",
|
|
1447
|
+
{ cbid: import_zod4.z.string(), cookies: import_zod4.z.array(import_zod4.z.object({ name: import_zod4.z.string(), ...declarationShape })).max(500), replace: import_zod4.z.boolean().optional(), dryRun: dryRunArg },
|
|
1448
|
+
(a) => {
|
|
1449
|
+
const o = { ...a.replace ? { replace: true } : {}, ...a.dryRun ? { dryRun: true } : {} };
|
|
1450
|
+
return client.sites.declareCookies(a.cbid, a.cookies, Object.keys(o).length ? o : void 0);
|
|
1451
|
+
}
|
|
1452
|
+
);
|
|
1453
|
+
tool(
|
|
1454
|
+
"undeclare_cookie",
|
|
1455
|
+
"Remove a cookie declaration; the scanned/observed classification applies again.",
|
|
1456
|
+
{ cbid: import_zod4.z.string(), name: import_zod4.z.string(), dryRun: dryRunArg },
|
|
1457
|
+
async (a) => {
|
|
1458
|
+
if (a.dryRun) return client.sites.undeclareCookie(a.cbid, a.name, { dryRun: true });
|
|
1459
|
+
await client.sites.undeclareCookie(a.cbid, a.name);
|
|
1460
|
+
return { undeclared: a.name };
|
|
1461
|
+
}
|
|
1462
|
+
);
|
|
1182
1463
|
tool(
|
|
1183
1464
|
"get_blocked_pages",
|
|
1184
1465
|
"Pages where the embed could not load its banner renderer \u2014 the page\u2019s Content Security Policy or Trusted Types policy refused it, so nobody there can be asked for consent. An empty list is healthy. Read-only.",
|
|
1185
|
-
{ cbid:
|
|
1466
|
+
{ cbid: import_zod4.z.string() },
|
|
1186
1467
|
(a) => client.sites.blocked(a.cbid)
|
|
1187
1468
|
);
|
|
1188
1469
|
tool(
|
|
1189
1470
|
"roll_api_key",
|
|
1190
1471
|
"Rotate an API key: returns a new secret once, with the same name, scopes, property lock and expiry. The old secret stops working immediately \u2014 if it is the key this server runs with, this server stops working too until it is reconfigured.",
|
|
1191
|
-
{ prefix:
|
|
1472
|
+
{ prefix: import_zod4.z.string() },
|
|
1192
1473
|
(a) => client.keys.roll(a.prefix)
|
|
1193
1474
|
);
|
|
1194
1475
|
tool(
|
|
1195
1476
|
"update_api_key",
|
|
1196
1477
|
"Rename an API key, or replace its scopes or the properties it is locked to. Only the fields given change; the secret does not.",
|
|
1197
1478
|
{
|
|
1198
|
-
prefix:
|
|
1199
|
-
name:
|
|
1200
|
-
scopes:
|
|
1201
|
-
cbids:
|
|
1479
|
+
prefix: import_zod4.z.string(),
|
|
1480
|
+
name: import_zod4.z.string().optional(),
|
|
1481
|
+
scopes: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
1482
|
+
cbids: import_zod4.z.array(import_zod4.z.string()).min(1).optional()
|
|
1202
1483
|
},
|
|
1203
1484
|
(a) => client.keys.update(a.prefix, {
|
|
1204
1485
|
...a.name !== void 0 ? { name: a.name } : {},
|
|
@@ -1210,31 +1491,170 @@ function registerTools(server, client) {
|
|
|
1210
1491
|
tool(
|
|
1211
1492
|
"update_org",
|
|
1212
1493
|
"Rename your organisation or set its logo. logoUrl: null removes the logo; upload an image with upload_asset to get a URL. Deleting the organisation is not possible here.",
|
|
1213
|
-
{ name:
|
|
1494
|
+
{ name: import_zod4.z.string().min(1).optional(), logoUrl: import_zod4.z.string().nullable().optional() },
|
|
1214
1495
|
(a) => client.org.update({
|
|
1215
1496
|
...a.name !== void 0 ? { name: a.name } : {},
|
|
1216
1497
|
...a.logoUrl !== void 0 ? { logoUrl: a.logoUrl } : {}
|
|
1217
1498
|
})
|
|
1218
1499
|
);
|
|
1500
|
+
tool(
|
|
1501
|
+
"get_mail_provider",
|
|
1502
|
+
"Your own mail provider for rights-request mail (verification codes and other privacy-request mail), if any. Never returns the credential, only its last four characters. `sender` says whether verification codes are mailed through it now (own) or not at all (none) \u2014 there is no shared sender. Read-only.",
|
|
1503
|
+
{},
|
|
1504
|
+
() => client.org.mailProvider.get()
|
|
1505
|
+
);
|
|
1506
|
+
tool(
|
|
1507
|
+
"set_mail_provider",
|
|
1508
|
+
"Connect your own mail provider for rights-request mail \u2014 recommended, so codes come from your own domain. Replaces the stored one. It carries mail only after test_mail_provider succeeds; every save clears that. Omit secret to keep the stored one (same provider only).",
|
|
1509
|
+
{
|
|
1510
|
+
provider: import_zod4.z.enum(["brevo", "sendgrid", "postmark", "resend", "ses", "smtp"]),
|
|
1511
|
+
fromEmail: import_zod4.z.string().describe("An address on a domain your provider has verified."),
|
|
1512
|
+
fromName: import_zod4.z.string().max(100).nullable().optional(),
|
|
1513
|
+
replyTo: import_zod4.z.string().nullable().optional(),
|
|
1514
|
+
secret: import_zod4.z.string().optional().describe("API key (Brevo, SendGrid, Resend), server token (Postmark), secret access key (SES) or SMTP password. Write-only."),
|
|
1515
|
+
ses: import_zod4.z.object({ region: import_zod4.z.string(), accessKeyId: import_zod4.z.string() }).optional().describe("Required for ses."),
|
|
1516
|
+
smtp: import_zod4.z.object({ host: import_zod4.z.string(), port: import_zod4.z.union([import_zod4.z.literal(25), import_zod4.z.literal(465), import_zod4.z.literal(587), import_zod4.z.literal(2525)]), security: import_zod4.z.enum(["tls", "starttls"]), username: import_zod4.z.string() }).optional().describe("Required for smtp. TLS is always required.")
|
|
1517
|
+
},
|
|
1518
|
+
(a) => client.org.mailProvider.set(a)
|
|
1519
|
+
);
|
|
1520
|
+
tool(
|
|
1521
|
+
"test_mail_provider",
|
|
1522
|
+
"Send a test message through your own mail provider (never Cookie Munch\u2019s) and report what it answered. Success marks the configuration verified, after which it carries all rights mail.",
|
|
1523
|
+
{ to: import_zod4.z.string().optional().describe("Recipient. Default: the reply-to, else the from address.") },
|
|
1524
|
+
(a) => client.org.mailProvider.test(a.to)
|
|
1525
|
+
);
|
|
1526
|
+
tool(
|
|
1527
|
+
"remove_mail_provider",
|
|
1528
|
+
"Remove your own mail provider. Rights mail goes back to Cookie Munch\u2019s shared sender, labelled as sending on your site\u2019s behalf.",
|
|
1529
|
+
{},
|
|
1530
|
+
async () => {
|
|
1531
|
+
await client.org.mailProvider.remove();
|
|
1532
|
+
return { removed: true };
|
|
1533
|
+
}
|
|
1534
|
+
);
|
|
1535
|
+
const CAPTCHA_OFF = "Off removes spam protection beyond the hidden spam-trap field, the rate limits and the email code: expect more spam requests. Own keys are recommended.";
|
|
1536
|
+
const captchaInput = {
|
|
1537
|
+
mode: import_zod4.z.enum(["own", "off"]).describe(`own: your own captcha provider keys (recommended). off: no captcha. ${CAPTCHA_OFF}`),
|
|
1538
|
+
provider: import_zod4.z.enum(["turnstile", "hcaptcha", "recaptcha_v2", "recaptcha_v3"]).optional().describe("Required for own."),
|
|
1539
|
+
siteKey: import_zod4.z.string().optional().describe("Required for own: the public site key. List your rights-page hostnames on it at the provider."),
|
|
1540
|
+
secret: import_zod4.z.string().optional().describe("The provider secret key. Write-only; never returned. Omit to keep the stored one (same provider)."),
|
|
1541
|
+
minScore: import_zod4.z.number().min(0.1).max(0.9).optional().describe("reCAPTCHA v3 only. Default 0.5.")
|
|
1542
|
+
};
|
|
1543
|
+
const captchaBody = (a) => ({
|
|
1544
|
+
mode: a.mode,
|
|
1545
|
+
...a.provider !== void 0 ? { provider: a.provider } : {},
|
|
1546
|
+
...a.siteKey !== void 0 ? { siteKey: a.siteKey } : {},
|
|
1547
|
+
...a.secret !== void 0 ? { secret: a.secret } : {},
|
|
1548
|
+
...a.minScore !== void 0 ? { minScore: a.minScore } : {}
|
|
1549
|
+
});
|
|
1550
|
+
tool(
|
|
1551
|
+
"get_rights_captcha",
|
|
1552
|
+
"The captcha on a site\u2019s hosted rights page: its own setting, else the organisation default, else off (`source` says which). Never returns the secret. Read-only.",
|
|
1553
|
+
{ cbid: import_zod4.z.string() },
|
|
1554
|
+
(a) => client.rightsCaptcha.get(a.cbid)
|
|
1555
|
+
);
|
|
1556
|
+
tool(
|
|
1557
|
+
"set_rights_captcha",
|
|
1558
|
+
`Set a site\u2019s rights-page captcha: your own Turnstile, hCaptcha or reCAPTCHA keys (recommended; the provider must accept the secret before it is saved), or off. ${CAPTCHA_OFF} Audited with the old and new mode.`,
|
|
1559
|
+
{ cbid: import_zod4.z.string(), ...captchaInput },
|
|
1560
|
+
(a) => client.rightsCaptcha.set(a.cbid, captchaBody(a))
|
|
1561
|
+
);
|
|
1562
|
+
tool(
|
|
1563
|
+
"remove_rights_captcha",
|
|
1564
|
+
"Remove a site\u2019s own captcha setting: it inherits the organisation default again (or off). Returns the setting now in force.",
|
|
1565
|
+
{ cbid: import_zod4.z.string() },
|
|
1566
|
+
(a) => client.rightsCaptcha.remove(a.cbid)
|
|
1567
|
+
);
|
|
1568
|
+
tool(
|
|
1569
|
+
"get_rights_captcha_default",
|
|
1570
|
+
"The organisation default captcha for its rights pages, used by every site without its own setting. Never returns the secret. Read-only.",
|
|
1571
|
+
{},
|
|
1572
|
+
() => client.org.rightsCaptcha.get()
|
|
1573
|
+
);
|
|
1574
|
+
tool(
|
|
1575
|
+
"set_rights_captcha_default",
|
|
1576
|
+
`Set the organisation default captcha for its rights pages: your own keys (recommended) or off. ${CAPTCHA_OFF}`,
|
|
1577
|
+
captchaInput,
|
|
1578
|
+
(a) => client.org.rightsCaptcha.set(captchaBody(a))
|
|
1579
|
+
);
|
|
1580
|
+
tool(
|
|
1581
|
+
"remove_rights_captcha_default",
|
|
1582
|
+
"Remove the organisation default: sites without their own setting then have no captcha. Returns the setting now in force.",
|
|
1583
|
+
{},
|
|
1584
|
+
() => client.org.rightsCaptcha.remove()
|
|
1585
|
+
);
|
|
1586
|
+
const IDENTITY_NOTE = "The JWKS is fetched and checked before anything is saved. The session token must carry the email and a verified-email claim (default email_verified) set to true (Clerk: add email: {{user.primary_email_address}} to the session token; Clerk documents no claim for whether that address is verified, so either add your own or set trustEmailClaim). oidc_jwt needs an audience or authorizedParties.";
|
|
1587
|
+
const identityInput = {
|
|
1588
|
+
type: import_zod4.z.enum(["clerk", "atlas", "oidc_jwt"]).describe("clerk, atlas (Clerk-shaped), or oidc_jwt (any issuer that signs session JWTs with a published JWKS)."),
|
|
1589
|
+
issuer: import_zod4.z.string().describe("https URL exactly as in the token\u2019s iss (Clerk: your Frontend API URL)."),
|
|
1590
|
+
jwksUrl: import_zod4.z.string().optional().describe("Required for oidc_jwt; clerk/atlas default to <issuer>/.well-known/jwks.json."),
|
|
1591
|
+
audience: import_zod4.z.string().optional().describe("Expected aud. For oidc_jwt an audience or authorizedParties is required (a shared issuer mints tokens for every app)."),
|
|
1592
|
+
authorizedParties: import_zod4.z.array(import_zod4.z.string()).optional().describe("Your own origins (https://www.example.com) the token\u2019s azp must be one of. Required for clerk and atlas; for oidc_jwt when there is no audience."),
|
|
1593
|
+
emailClaim: import_zod4.z.string().optional().describe("Default email."),
|
|
1594
|
+
emailVerifiedClaim: import_zod4.z.string().optional().describe("Default email_verified; must be exactly true."),
|
|
1595
|
+
sessionCookieName: import_zod4.z.string().optional().describe("Default __session: the cookie the hosted page on your custom domain reads."),
|
|
1596
|
+
trustEmailClaim: import_zod4.z.boolean().optional().describe("clerk/atlas only, default false. True: a token without the verified claim is accepted, its email claim taken as verified. Set only if every address your provider puts in that claim is verified.")
|
|
1597
|
+
};
|
|
1598
|
+
const identityBody = (a) => {
|
|
1599
|
+
const out = { type: a.type, issuer: a.issuer };
|
|
1600
|
+
for (const k of ["jwksUrl", "audience", "authorizedParties", "emailClaim", "emailVerifiedClaim", "sessionCookieName", "trustEmailClaim"]) if (a[k] !== void 0) out[k] = a[k];
|
|
1601
|
+
return out;
|
|
1602
|
+
};
|
|
1603
|
+
tool(
|
|
1604
|
+
"get_rights_identity",
|
|
1605
|
+
"The sign-in provider a site\u2019s rights requests are verified with: its own setting, else the organisation default, else none (`source` says which). Read-only.",
|
|
1606
|
+
{ cbid: import_zod4.z.string() },
|
|
1607
|
+
(a) => client.rightsIdentity.get(a.cbid)
|
|
1608
|
+
);
|
|
1609
|
+
tool(
|
|
1610
|
+
"set_rights_identity",
|
|
1611
|
+
`Connect a site\u2019s sign-in provider so a visitor signed in to the site is verified by their session, with no code mail. ${IDENTITY_NOTE} Audited.`,
|
|
1612
|
+
{ cbid: import_zod4.z.string(), ...identityInput },
|
|
1613
|
+
(a) => client.rightsIdentity.set(a.cbid, identityBody(a))
|
|
1614
|
+
);
|
|
1615
|
+
tool(
|
|
1616
|
+
"remove_rights_identity",
|
|
1617
|
+
"Remove a site\u2019s own sign-in provider: it inherits the organisation default again (or none). Returns the setting now in force.",
|
|
1618
|
+
{ cbid: import_zod4.z.string() },
|
|
1619
|
+
(a) => client.rightsIdentity.remove(a.cbid)
|
|
1620
|
+
);
|
|
1621
|
+
tool(
|
|
1622
|
+
"get_rights_identity_default",
|
|
1623
|
+
"The organisation default sign-in provider for its rights requests, used by every site without its own. Read-only.",
|
|
1624
|
+
{},
|
|
1625
|
+
() => client.org.rightsIdentity.get()
|
|
1626
|
+
);
|
|
1627
|
+
tool(
|
|
1628
|
+
"set_rights_identity_default",
|
|
1629
|
+
`Set the organisation default sign-in provider for its rights requests. ${IDENTITY_NOTE}`,
|
|
1630
|
+
identityInput,
|
|
1631
|
+
(a) => client.org.rightsIdentity.set(identityBody(a))
|
|
1632
|
+
);
|
|
1633
|
+
tool(
|
|
1634
|
+
"remove_rights_identity_default",
|
|
1635
|
+
"Remove the organisation default sign-in provider. Returns the setting now in force.",
|
|
1636
|
+
{},
|
|
1637
|
+
() => client.org.rightsIdentity.remove()
|
|
1638
|
+
);
|
|
1219
1639
|
tool(
|
|
1220
1640
|
"get_audit_log",
|
|
1221
1641
|
"The organisation\u2019s audit log, newest first: administrative changes made in the dashboard or through the API, and who made them. Read-only.",
|
|
1222
|
-
{ limit:
|
|
1642
|
+
{ limit: import_zod4.z.number().int().min(1).max(500).optional() },
|
|
1223
1643
|
(a) => client.audit(a.limit)
|
|
1224
1644
|
);
|
|
1225
1645
|
tool(
|
|
1226
1646
|
"upload_asset",
|
|
1227
1647
|
"Upload an image \u2014 a banner logo \u2014 and get its public URL. data is base64 (a data: URL also works); PNG, JPEG, WebP, GIF or SVG, up to 1,000,000 bytes.",
|
|
1228
1648
|
{
|
|
1229
|
-
data:
|
|
1230
|
-
contentType:
|
|
1649
|
+
data: import_zod4.z.string(),
|
|
1650
|
+
contentType: import_zod4.z.enum(["image/png", "image/jpeg", "image/webp", "image/gif", "image/svg+xml"])
|
|
1231
1651
|
},
|
|
1232
1652
|
(a) => client.assets.upload({ data: a.data, contentType: a.contentType })
|
|
1233
1653
|
);
|
|
1234
1654
|
tool(
|
|
1235
1655
|
"delete_asset",
|
|
1236
1656
|
"Delete a stored image by its URL (or file name). Only your own organisation\u2019s images can be named.",
|
|
1237
|
-
{ url:
|
|
1657
|
+
{ url: import_zod4.z.string().describe("The URL upload_asset returned, or just its file name.") },
|
|
1238
1658
|
async (a) => {
|
|
1239
1659
|
await client.assets.delete(a.url);
|
|
1240
1660
|
return { deleted: a.url };
|
|
@@ -1249,18 +1669,18 @@ function registerTools(server, client) {
|
|
|
1249
1669
|
tool(
|
|
1250
1670
|
"get_customer",
|
|
1251
1671
|
"One child org: its controller details and usage. Read-only.",
|
|
1252
|
-
{ id:
|
|
1672
|
+
{ id: import_zod4.z.string() },
|
|
1253
1673
|
(a) => client.reseller.get(a.id)
|
|
1254
1674
|
);
|
|
1255
1675
|
tool(
|
|
1256
1676
|
"provision_customer",
|
|
1257
1677
|
"Create a new child org under this reseller. With `mintKey`, its first API key is returned once. Counts toward the reseller plan\u2019s pooled limits.",
|
|
1258
1678
|
{
|
|
1259
|
-
name:
|
|
1260
|
-
ownerEmail:
|
|
1261
|
-
delegatedAccess:
|
|
1262
|
-
mintKey:
|
|
1263
|
-
keyScopes:
|
|
1679
|
+
name: import_zod4.z.string(),
|
|
1680
|
+
ownerEmail: import_zod4.z.string().optional(),
|
|
1681
|
+
delegatedAccess: import_zod4.z.boolean().optional().describe("Whether this reseller may act inside the child."),
|
|
1682
|
+
mintKey: import_zod4.z.boolean().optional(),
|
|
1683
|
+
keyScopes: import_zod4.z.array(import_zod4.z.string()).optional()
|
|
1264
1684
|
},
|
|
1265
1685
|
(a) => client.reseller.create({
|
|
1266
1686
|
name: a.name,
|
|
@@ -1274,10 +1694,10 @@ function registerTools(server, client) {
|
|
|
1274
1694
|
"update_customer",
|
|
1275
1695
|
"Change a child org\u2019s status, delegated access or DSAR routing. `dsarRouting: null` clears the override.",
|
|
1276
1696
|
{
|
|
1277
|
-
id:
|
|
1278
|
-
status:
|
|
1279
|
-
delegatedAccess:
|
|
1280
|
-
dsarRouting:
|
|
1697
|
+
id: import_zod4.z.string(),
|
|
1698
|
+
status: import_zod4.z.enum(["active", "suspended"]).optional(),
|
|
1699
|
+
delegatedAccess: import_zod4.z.boolean().optional(),
|
|
1700
|
+
dsarRouting: import_zod4.z.enum(["reseller", "child"]).nullable().optional()
|
|
1281
1701
|
},
|
|
1282
1702
|
(a) => client.reseller.update(a.id, {
|
|
1283
1703
|
...a.status ? { status: a.status } : {},
|
|
@@ -1288,7 +1708,7 @@ function registerTools(server, client) {
|
|
|
1288
1708
|
tool(
|
|
1289
1709
|
"suspend_customer",
|
|
1290
1710
|
"Suspend a child org: it stops ingesting consent and its keys stop working, and it can be reactivated with update_customer. Its data is kept. (Permanent deletion is deliberately not available here.)",
|
|
1291
|
-
{ id:
|
|
1711
|
+
{ id: import_zod4.z.string() },
|
|
1292
1712
|
async (a) => {
|
|
1293
1713
|
await client.reseller.deprovision(a.id);
|
|
1294
1714
|
return { suspended: a.id };
|
|
@@ -1297,72 +1717,72 @@ function registerTools(server, client) {
|
|
|
1297
1717
|
tool(
|
|
1298
1718
|
"list_customer_keys",
|
|
1299
1719
|
"A child org's API key prefixes. Never the secrets. Read-only.",
|
|
1300
|
-
{ id:
|
|
1720
|
+
{ id: import_zod4.z.string() },
|
|
1301
1721
|
(a) => client.reseller.listKeys(a.id)
|
|
1302
1722
|
);
|
|
1303
1723
|
tool(
|
|
1304
1724
|
"issue_customer_key",
|
|
1305
1725
|
"Mint an API key for a child org. The secret is returned once. Prefer scopes and a property lock over a full-access key.",
|
|
1306
|
-
{ id:
|
|
1726
|
+
{ id: import_zod4.z.string(), name: import_zod4.z.string().optional(), scopes: import_zod4.z.array(import_zod4.z.string()).optional(), cbids: import_zod4.z.array(import_zod4.z.string()).min(1).optional() },
|
|
1307
1727
|
(a) => client.reseller.mintKey(a.id, {
|
|
1308
1728
|
...a.name ? { name: a.name } : {},
|
|
1309
1729
|
...a.scopes ? { scopes: a.scopes } : {},
|
|
1310
1730
|
...a.cbids ? { cbids: a.cbids } : {}
|
|
1311
1731
|
})
|
|
1312
1732
|
);
|
|
1313
|
-
tool("revoke_customer_key", "Revoke a child org's API key by prefix. Takes effect immediately.", { id:
|
|
1733
|
+
tool("revoke_customer_key", "Revoke a child org's API key by prefix. Takes effect immediately.", { id: import_zod4.z.string(), prefix: import_zod4.z.string() }, async (a) => {
|
|
1314
1734
|
await client.reseller.revokeKey(a.id, a.prefix);
|
|
1315
1735
|
return { revoked: a.prefix };
|
|
1316
1736
|
});
|
|
1317
1737
|
tool(
|
|
1318
1738
|
"erase_subject_data",
|
|
1319
1739
|
"IRREVERSIBLY crypto-erase a data subject's consent records by their consent-receipt stamp (GDPR/CCPA deletion). Destroys the encryption key; the tamper-evident chain stays intact.",
|
|
1320
|
-
{ cbid:
|
|
1740
|
+
{ cbid: import_zod4.z.string(), stamp: import_zod4.z.string() },
|
|
1321
1741
|
(a) => client.consent.eraseSubject(a.cbid, a.stamp)
|
|
1322
1742
|
);
|
|
1323
1743
|
tool(
|
|
1324
1744
|
"export_subject_data",
|
|
1325
1745
|
"Export a data subject's consent records (GDPR access/portability).",
|
|
1326
|
-
{ cbid:
|
|
1746
|
+
{ cbid: import_zod4.z.string(), stamp: import_zod4.z.string() },
|
|
1327
1747
|
(a) => client.consent.exportSubject(a.cbid, a.stamp)
|
|
1328
1748
|
);
|
|
1329
1749
|
tool("list_banners", "List reusable banner designs in your org.", {}, () => client.banners.list());
|
|
1330
1750
|
tool(
|
|
1331
1751
|
"create_banner",
|
|
1332
1752
|
"Create a reusable banner design.",
|
|
1333
|
-
{ name:
|
|
1753
|
+
{ name: import_zod4.z.string(), json: import_zod4.z.record(import_zod4.z.unknown()).describe("A v2 BannerConfig.") },
|
|
1334
1754
|
(a) => client.banners.create({ name: a.name, json: a.json })
|
|
1335
1755
|
);
|
|
1336
|
-
tool("get_banner", "Get a banner design by id.", { id:
|
|
1756
|
+
tool("get_banner", "Get a banner design by id.", { id: import_zod4.z.string() }, (a) => client.banners.get(a.id));
|
|
1337
1757
|
tool(
|
|
1338
1758
|
"update_banner",
|
|
1339
1759
|
"Update a banner design (name and/or config).",
|
|
1340
|
-
{ id:
|
|
1760
|
+
{ id: import_zod4.z.string(), name: import_zod4.z.string().optional(), json: import_zod4.z.record(import_zod4.z.unknown()).optional() },
|
|
1341
1761
|
(a) => client.banners.update(a.id, {
|
|
1342
1762
|
...a.name !== void 0 ? { name: a.name } : {},
|
|
1343
1763
|
...a.json !== void 0 ? { json: a.json } : {}
|
|
1344
1764
|
})
|
|
1345
1765
|
);
|
|
1346
|
-
tool("delete_banner", "Delete a banner design (fails if assigned to sites).", { id:
|
|
1766
|
+
tool("delete_banner", "Delete a banner design (fails if assigned to sites).", { id: import_zod4.z.string() }, async (a) => {
|
|
1347
1767
|
await client.banners.delete(a.id);
|
|
1348
1768
|
return { ok: true };
|
|
1349
1769
|
});
|
|
1350
1770
|
tool(
|
|
1351
1771
|
"get_banner_assignments",
|
|
1352
1772
|
"The sites (cbids) a banner design is currently assigned to. Read-only.",
|
|
1353
|
-
{ id:
|
|
1773
|
+
{ id: import_zod4.z.string() },
|
|
1354
1774
|
(a) => client.banners.assignments(a.id)
|
|
1355
1775
|
);
|
|
1356
1776
|
tool(
|
|
1357
1777
|
"assign_banner",
|
|
1358
1778
|
"Set which sites (cbids) use a banner design.",
|
|
1359
|
-
{ id:
|
|
1779
|
+
{ id: import_zod4.z.string(), cbids: import_zod4.z.array(import_zod4.z.string()) },
|
|
1360
1780
|
(a) => client.banners.setAssignments(a.id, a.cbids)
|
|
1361
1781
|
);
|
|
1362
1782
|
tool(
|
|
1363
1783
|
"publish_banner",
|
|
1364
1784
|
"Publish a design live to all its assigned sites.",
|
|
1365
|
-
{ id:
|
|
1785
|
+
{ id: import_zod4.z.string() },
|
|
1366
1786
|
(a) => client.banners.publish(a.id)
|
|
1367
1787
|
);
|
|
1368
1788
|
}
|
|
@@ -1382,7 +1802,7 @@ async function main() {
|
|
|
1382
1802
|
console.error("COOKIEMUNCH_API_KEY is required.");
|
|
1383
1803
|
process.exit(1);
|
|
1384
1804
|
}
|
|
1385
|
-
const baseUrl = process.env.COOKIEMUNCH_BASE_URL ?? "
|
|
1805
|
+
const baseUrl = process.env.COOKIEMUNCH_BASE_URL ?? "https://api.cookiemunch.net";
|
|
1386
1806
|
const server = createCookieMunchMcp({ apiKey, baseUrl });
|
|
1387
1807
|
const transport = new import_stdio.StdioServerTransport();
|
|
1388
1808
|
await server.connect(transport);
|