@checkbox-site/mcp 0.2.5 → 0.2.6
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/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/tools.d.ts +21 -0
- package/dist/tools.js +51 -15
- package/package.json +2 -2
package/dist/server.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { KeyContext } from './permissions.ts';
|
|
|
5
5
|
import { type IssuedKeys, type ToolContext, type ToolDef } from './tools.ts';
|
|
6
6
|
export declare const SERVER_NAME = "checkbox";
|
|
7
7
|
/** Kept equal to packages/mcp/package.json "version" (@checkbox-site/mcp); mcp.test.ts checks it. */
|
|
8
|
-
export declare const SERVER_VERSION = "0.2.
|
|
8
|
+
export declare const SERVER_VERSION = "0.2.6";
|
|
9
9
|
export declare const DEFAULT_MCP_URL = "https://app.checkbox.site/mcp";
|
|
10
10
|
/** The coverage phrase used across Checkbox (the API docs tests check the count against the rules catalog). */
|
|
11
11
|
export declare const COVERAGE_PHRASE = "federal law, 27 states, DC and New York City";
|
package/dist/server.js
CHANGED
|
@@ -9,7 +9,7 @@ import { likelyMisspelling, unknownArgumentsMessage, unknownKeysParams } from ".
|
|
|
9
9
|
import { outdatedNotice } from "./version-check.js";
|
|
10
10
|
export const SERVER_NAME = 'checkbox';
|
|
11
11
|
/** Kept equal to packages/mcp/package.json "version" (@checkbox-site/mcp); mcp.test.ts checks it. */
|
|
12
|
-
export const SERVER_VERSION = '0.2.
|
|
12
|
+
export const SERVER_VERSION = '0.2.6';
|
|
13
13
|
export const DEFAULT_MCP_URL = 'https://app.checkbox.site/mcp';
|
|
14
14
|
/** The coverage phrase used across Checkbox (the API docs tests check the count against the rules catalog). */
|
|
15
15
|
export const COVERAGE_PHRASE = 'federal law, 27 states, DC and New York City';
|
package/dist/tools.d.ts
CHANGED
|
@@ -133,6 +133,12 @@ export declare function clipWords(v: unknown, n: number): unknown;
|
|
|
133
133
|
export declare function unverifiedScanNote(u: unknown): string | null;
|
|
134
134
|
/** Round 20: one line with the plans Checkbox judges the site against (setup's site_plans), so no second call is needed. */
|
|
135
135
|
export declare function sitePlansNote(plans: unknown): string | null;
|
|
136
|
+
/**
|
|
137
|
+
* Round 33 (pilot 32 item 22, new-app: setup_checkbox answered with about 30 KB on the first call): the first setup
|
|
138
|
+
* response leaves out what the agent does not need yet. The go-live steps become their one-line summary (get_compliance_plan
|
|
139
|
+
* and complete_setup carry them in full), and once the Stripe key is stored its permission checklist is dropped. Pure.
|
|
140
|
+
*/
|
|
141
|
+
export declare function compactSetupDoc<T>(doc: T): T;
|
|
136
142
|
/**
|
|
137
143
|
* Pilot round 9 (nextjs): setup_checkbox still showed `insurable: false` and `score: 26.8` next to the status label.
|
|
138
144
|
* The API keeps both (deprecated) for backward compatibility; agents see only the one status.
|
|
@@ -211,6 +217,21 @@ interface PrecheckLite {
|
|
|
211
217
|
}
|
|
212
218
|
/** Audit: the pre-check's per-check results, one compact line each (agents only saw the overall verdict). */
|
|
213
219
|
export declare function precheckLines(pre: PrecheckLite | null | undefined, max?: number): string[];
|
|
220
|
+
interface FinalCheckLite {
|
|
221
|
+
check_id: string;
|
|
222
|
+
observed: string;
|
|
223
|
+
detail?: string;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Round 33 (pilot 32 item 10, new-app: the PASSED_WITH_NOTES text listed the stale pre-check bullets (needs_review)
|
|
227
|
+
* while the final checks lived only in the JSON): a finished verification is summarized from its FINAL checks; the
|
|
228
|
+
* pre-check lines show only while it is pending or when it has no final checks. Pure, exported for tests.
|
|
229
|
+
*/
|
|
230
|
+
export declare function verificationLines(v: {
|
|
231
|
+
status: string;
|
|
232
|
+
precheck?: PrecheckLite | null;
|
|
233
|
+
checks?: FinalCheckLite[] | null;
|
|
234
|
+
}, max?: number): string[];
|
|
214
235
|
/** createTestRun body from the tool's arguments (top-level shortcuts merged into `stripe`). Exported for tests. */
|
|
215
236
|
export declare function startTestRunBody(args: Record<string, unknown>): Record<string, unknown>;
|
|
216
237
|
interface ScheduledNotice {
|
package/dist/tools.js
CHANGED
|
@@ -461,10 +461,29 @@ async function setupOverOAuth(api, session, ctx) {
|
|
|
461
461
|
data: (() => {
|
|
462
462
|
const doc = { ...session, ...(fresh ?? {}) };
|
|
463
463
|
const keys = labelledPublicKeys(doc.install?.snippet_key, doc.publishable_key);
|
|
464
|
-
return withoutLegacyScore({ ...doc, ...(keys.length ? { public_keys: keys } : {}), ...(firstCheck ? { first_check: firstCheck } : {}) });
|
|
464
|
+
return compactSetupDoc(withoutLegacyScore({ ...doc, ...(keys.length ? { public_keys: keys } : {}), ...(firstCheck ? { first_check: firstCheck } : {}) }));
|
|
465
465
|
})(),
|
|
466
466
|
};
|
|
467
467
|
}
|
|
468
|
+
/**
|
|
469
|
+
* Round 33 (pilot 32 item 22, new-app: setup_checkbox answered with about 30 KB on the first call): the first setup
|
|
470
|
+
* response leaves out what the agent does not need yet. The go-live steps become their one-line summary (get_compliance_plan
|
|
471
|
+
* and complete_setup carry them in full), and once the Stripe key is stored its permission checklist is dropped. Pure.
|
|
472
|
+
*/
|
|
473
|
+
export function compactSetupDoc(doc) {
|
|
474
|
+
if (!doc || typeof doc !== 'object')
|
|
475
|
+
return doc;
|
|
476
|
+
const d = { ...doc };
|
|
477
|
+
const g = d.go_live;
|
|
478
|
+
if (g && typeof g === 'object' && Array.isArray(g.steps))
|
|
479
|
+
d.go_live = { summary: g.summary ?? null, steps: g.steps.length, full: 'get_compliance_plan (go_live) or complete_setup' };
|
|
480
|
+
const st = d.stripe;
|
|
481
|
+
if (st && st.test_credential_stored === true && st.restricted_key && Array.isArray(st.restricted_key.permissions)) {
|
|
482
|
+
const { permissions: _p, ...rk } = st.restricted_key;
|
|
483
|
+
d.stripe = { ...st, restricted_key: rk };
|
|
484
|
+
}
|
|
485
|
+
return d;
|
|
486
|
+
}
|
|
468
487
|
/**
|
|
469
488
|
* Pilot round 9 (nextjs): setup_checkbox still showed `insurable: false` and `score: 26.8` next to the status label.
|
|
470
489
|
* The API keeps both (deprecated) for backward compatibility; agents see only the one status.
|
|
@@ -647,7 +666,7 @@ const setupCheckbox = {
|
|
|
647
666
|
notes: [
|
|
648
667
|
'Tell the human exactly one line, e.g. "Open <link> and click Approve to connect Checkbox (free, no card)." Do not ask them to copy keys.',
|
|
649
668
|
// Round 32 (pilot 31 item 13): the Stripe key box and the restricted key in the same message (one approval).
|
|
650
|
-
`${args.billing_platform === 'stripe' ? 'In the same message' : 'If the site sells through Stripe, in the same message'}, ask them to tick “Let your agent store a Stripe test-mode key” on that page and, if the project has no rk_test_ key yet, to create a restricted key in Stripe Test mode (https://dashboard.stripe.com/test/apikeys → Create restricted key, with the permissions the approval page lists) and put it in the project's env file (never in the chat): one approval then covers the key and the test subscription.`,
|
|
669
|
+
`${args.billing_platform === 'stripe' ? 'In the same message' : 'If the site sells through Stripe, in the same message'}, ask them to tick the box “Let your agent store a Stripe test-mode restricted key for this project” on that page and, if the project has no rk_test_ key yet, to create a restricted key in Stripe Test mode (https://dashboard.stripe.com/test/apikeys → Create restricted key, with the permissions the approval page lists) and put it in the project's env file (never in the chat): one approval then covers the key and the test subscription.`,
|
|
651
670
|
`Then call setup_checkbox again with device_code "${auth.device_code}" AND the same facts (site_url, checkout_url, merchant_name, plans, policy URLs): after the approval Checkbox applies them and runs the first checks in that call. Keep the device_code private; it is not shown to the human.`,
|
|
652
671
|
],
|
|
653
672
|
next: { type: 'wait_for_approval', message: `Call setup_checkbox with device_code "${auth.device_code}" to wait for the approval.`, operation_id: 'createDeviceToken' },
|
|
@@ -670,7 +689,7 @@ const setupCheckbox = {
|
|
|
670
689
|
notes,
|
|
671
690
|
data: (() => {
|
|
672
691
|
const keys = labelledPublicKeys(session.install?.snippet_key, session.publishable_key);
|
|
673
|
-
return keys.length ? { ...withoutLegacyScore(session), public_keys: keys } : withoutLegacyScore(session);
|
|
692
|
+
return compactSetupDoc(keys.length ? { ...withoutLegacyScore(session), public_keys: keys } : withoutLegacyScore(session));
|
|
674
693
|
})(),
|
|
675
694
|
};
|
|
676
695
|
},
|
|
@@ -957,6 +976,21 @@ export function precheckLines(pre, max = 12) {
|
|
|
957
976
|
const lines = sorted.slice(0, max).map((c) => `${c.check_id}: ${c.status}${c.reason ? ` — ${untrusted(c.reason, 180)}` : ''}${c.fix ? ` Fix: ${untrusted(c.fix, 200)}` : ''}`);
|
|
958
977
|
return [`Pre-check (${pre?.verdict ?? 'n/a'}), per check:`, ...lines, ...(checks.length > max ? [`and ${checks.length - max} more (data.precheck.checks)`] : [])];
|
|
959
978
|
}
|
|
979
|
+
/**
|
|
980
|
+
* Round 33 (pilot 32 item 10, new-app: the PASSED_WITH_NOTES text listed the stale pre-check bullets (needs_review)
|
|
981
|
+
* while the final checks lived only in the JSON): a finished verification is summarized from its FINAL checks; the
|
|
982
|
+
* pre-check lines show only while it is pending or when it has no final checks. Pure, exported for tests.
|
|
983
|
+
*/
|
|
984
|
+
export function verificationLines(v, max = 12) {
|
|
985
|
+
const checks = v.checks ?? [];
|
|
986
|
+
if (v.status === 'pending' || !checks.length)
|
|
987
|
+
return precheckLines(v.precheck, max);
|
|
988
|
+
const order = { fail: 0, needs_review: 1, missing_data: 1, pass: 2, informational: 2, not_applicable: 3 };
|
|
989
|
+
const sorted = [...checks].sort((a, b) => (order[a.observed] ?? 1) - (order[b.observed] ?? 1));
|
|
990
|
+
const lines = sorted.slice(0, max).map((c) => `${c.check_id}: ${c.observed}${c.detail ? ` — ${untrusted(c.detail, 180)}` : ''}`);
|
|
991
|
+
const pre = v.precheck?.verdict && v.precheck.checks?.length ? [`(The pre-check's estimate, ${v.precheck.verdict}, is superseded by these final checks: data.precheck keeps it.)`] : [];
|
|
992
|
+
return ['Final checks:', ...lines, ...(checks.length > max ? [`and ${checks.length - max} more (data.checks)`] : []), ...pre];
|
|
993
|
+
}
|
|
960
994
|
const verifyTask = {
|
|
961
995
|
name: 'verify_task',
|
|
962
996
|
title: 'Verify a task after applying its change',
|
|
@@ -966,7 +1000,7 @@ const verifyTask = {
|
|
|
966
1000
|
'- page tasks: html = the rendered page HTML (before or after deploy; ≤ ~900 KB). Without it Checkbox fetches the live page.',
|
|
967
1001
|
'- Stripe tasks: stripe_checkout_session = exactly the object your code now passes to stripe.checkout.sessions.create.',
|
|
968
1002
|
'- email tasks: email = { subject, text and/or html } of the new template.',
|
|
969
|
-
'Result: verification status passed / failed (with a diff of expected vs observed) / pending (waiting for the confirming scan). Waits up to `wait` seconds. Then follow next_action (usually get_compliance_plan).
|
|
1003
|
+
'Result: verification status passed / needs_review / failed (with a diff of expected vs observed) / pending (waiting for the confirming scan). Waits up to `wait` seconds. Then follow next_action (usually get_compliance_plan). Status needs_review: nothing failed, but a check is still undecided; it is not done: follow next_action. "informational" checks are notes on Stripe\'s own layout: nothing to change.',
|
|
970
1004
|
].join('\n'),
|
|
971
1005
|
input: {
|
|
972
1006
|
task: z.string().max(100).describe('Task id (task_…).'),
|
|
@@ -1001,7 +1035,7 @@ const verifyTask = {
|
|
|
1001
1035
|
return {
|
|
1002
1036
|
headline: `Verification ${v.id} of ${String(args.task)}: ${statusLine(v.status)}${v.plan_status ? `; plan is now ${planStatusWords(v.plan_status, v.plan_status_label)}` : ''}.${v.checked ? ` Checked: ${untrusted(v.checked, 300)}.` : ''}`,
|
|
1003
1037
|
notes: [
|
|
1004
|
-
...
|
|
1038
|
+
...verificationLines(v),
|
|
1005
1039
|
...((v.status === 'failed' || v.status === 'not_checked') && v.next_action?.type === 'verify_domain'
|
|
1006
1040
|
? ['The domain is not verified yet. Waiting for the human to publish the DNS record / file / meta tag or install the snippet; don\'t retry until they say it\'s done. Nothing to change in the code.']
|
|
1007
1041
|
: v.next_action?.type === 'retry_later'
|
|
@@ -1011,15 +1045,17 @@ const verifyTask = {
|
|
|
1011
1045
|
[v.next_action.description ?? 'Checkbox Notices sends this email: nothing to add to your code. Continue with the next task.']
|
|
1012
1046
|
: v.next_action?.type === 'bcc_then_continue'
|
|
1013
1047
|
? ['The copy is checked; the task closes when the first real email arrives with the BCC. Add the BCC to your sending code and continue with the next task (no need to poll).']
|
|
1014
|
-
: v.status === '
|
|
1015
|
-
? ['
|
|
1016
|
-
: v.status === '
|
|
1017
|
-
? ['
|
|
1018
|
-
: v.status === '
|
|
1019
|
-
? ['
|
|
1020
|
-
: v.status === '
|
|
1021
|
-
? ['
|
|
1022
|
-
:
|
|
1048
|
+
: v.status === 'needs_review'
|
|
1049
|
+
? ['Nothing failed, but a check is still undecided: it is not done. Follow Next (it says what decides it).']
|
|
1050
|
+
: v.status === 'failed'
|
|
1051
|
+
? ['The change did not satisfy the check: read diff (expected vs observed), fix the code, and call verify_task again.']
|
|
1052
|
+
: v.status === 'not_checked'
|
|
1053
|
+
? ['Not checked yet: Checkbox is missing evidence (see next_action), not a code problem. Do not change the code for this; provide what next_action asks for.']
|
|
1054
|
+
: v.status === 'pending_live_check'
|
|
1055
|
+
? ['Live check pending: the email content passes; Checkbox has not seen it sent for a real event yet. Nothing to change in the code: it completes on the first real send (or a proof run).']
|
|
1056
|
+
: v.status === 'pending'
|
|
1057
|
+
? ['Waiting for a confirming observation; call get_verification later (or continue with other tasks).']
|
|
1058
|
+
: []),
|
|
1023
1059
|
...hint,
|
|
1024
1060
|
],
|
|
1025
1061
|
data: v,
|
|
@@ -1076,7 +1112,7 @@ const getVerification = {
|
|
|
1076
1112
|
annotations: { ...ro, title: 'Verification' },
|
|
1077
1113
|
async run(args, { api }) {
|
|
1078
1114
|
const v = await api.request('GET', `/v1/verifications/${enc(String(args.verification))}`, { query: { wait: args.wait ?? 0 } });
|
|
1079
|
-
const notes =
|
|
1115
|
+
const notes = verificationLines(v);
|
|
1080
1116
|
return { headline: `Verification ${v.id}: ${statusLine(v.status)}.`, ...(notes.length ? { notes } : {}), data: v };
|
|
1081
1117
|
},
|
|
1082
1118
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkbox-site/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Checkbox MCP server: auto-renewal law and subscription compliance checks for AI agents (FTC ROSCA, California ARL, New York and other states) on Stripe Checkout params, pricing pages, disclosures and emails. Remote at https://app.checkbox.site/mcp, or local stdio.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"checkbox",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"prepack": "npm run build"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@checkbox-site/node": "^0.2.
|
|
80
|
+
"@checkbox-site/node": "^0.2.6",
|
|
81
81
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
82
82
|
"zod": "^4.6.7"
|
|
83
83
|
}
|