@sakupa/mcp 0.7.26 → 0.7.28
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/bin.js +27 -19
- package/dist/index.js +27 -19
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -129,7 +129,7 @@ var FORBIDDEN_PATH_SEGMENTS = [
|
|
|
129
129
|
var ALLOWED_HIDDEN_PATHS = [".well-known/"];
|
|
130
130
|
|
|
131
131
|
// ../core/dist/domain/version.js
|
|
132
|
-
var SAKUPA_MCP_VERSION = "0.7.
|
|
132
|
+
var SAKUPA_MCP_VERSION = "0.7.28";
|
|
133
133
|
|
|
134
134
|
// ../core/dist/domain/errors.js
|
|
135
135
|
var HTTP_STATUS = {
|
|
@@ -2631,7 +2631,7 @@ NO content was uploaded or changed by this call \u2014 to publish new or edited
|
|
|
2631
2631
|
server.registerTool(
|
|
2632
2632
|
"status",
|
|
2633
2633
|
{
|
|
2634
|
-
description: "Show the current status of this project's Sakupa site: URL, mode (free/paid), expiry,
|
|
2634
|
+
description: "Show the current status of this project's Sakupa site: URL, mode (free/paid), expiry, custom domains, size, last deployment and warnings. For a paid site this tool also automatically returns the complete authoritative billing snapshot; users never need to know or name a separate billing tool to get accurate subscription information.",
|
|
2635
2635
|
outputSchema: STRUCTURED_TOOL_OUTPUT_SCHEMA,
|
|
2636
2636
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
2637
2637
|
inputSchema: { projectDir: projectDirInput }
|
|
@@ -2642,12 +2642,18 @@ NO content was uploaded or changed by this call \u2014 to publish new or edited
|
|
|
2642
2642
|
const site = requireSiteFile(ctx);
|
|
2643
2643
|
const res = await ctx.client.getSiteStatus(site.siteId, site.credential);
|
|
2644
2644
|
noteSiteMode(res.siteId, res.mode);
|
|
2645
|
+
const billing = res.mode === "paid" ? await ctx.client.getBillingStatus(site.siteId, site.credential) : void 0;
|
|
2645
2646
|
const binding = res.pendingDomainBinding ? await describePendingBinding(ctx.client, site.credential, res.pendingDomainBinding) : void 0;
|
|
2646
|
-
return textJson(
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2647
|
+
return textJson(
|
|
2648
|
+
"status_returned",
|
|
2649
|
+
billing ? `Site status with AUTHORITATIVE BILLING SNAPSHOT. When answering any subscription question, use the nested billing object and report the current plan, scheduled renewal or cancellation, effective time, current entitlement, billing period, usage state and one-time carry when present:${binding?.note ?? ""}` : `Site status:${binding?.note ?? ""}`,
|
|
2650
|
+
{
|
|
2651
|
+
...res,
|
|
2652
|
+
projectDir: ctx.projectDir,
|
|
2653
|
+
...billing ? { billing } : {},
|
|
2654
|
+
...binding?.checklist ? { dnsChecklist: binding.checklist } : {}
|
|
2655
|
+
}
|
|
2656
|
+
);
|
|
2651
2657
|
} catch (e) {
|
|
2652
2658
|
return toolError(e);
|
|
2653
2659
|
}
|
|
@@ -2819,7 +2825,7 @@ When the user says the TXT is set, run bind "status". It verifies ownership and
|
|
|
2819
2825
|
server.registerTool(
|
|
2820
2826
|
"billing",
|
|
2821
2827
|
{
|
|
2822
|
-
description: "
|
|
2828
|
+
description: "Return the sole authoritative source for this site's hosting subscription: current plan, next renewal plan or cancellation, effective time, payment state, current paid entitlement, reconciled usage, estimated usage tier, bound custom domains and risks. Owner-only (uses the credential in .sakupa/site.json).",
|
|
2823
2829
|
outputSchema: STRUCTURED_TOOL_OUTPUT_SCHEMA,
|
|
2824
2830
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
2825
2831
|
inputSchema: { projectDir: projectDirInput }
|
|
@@ -2831,15 +2837,20 @@ When the user says the TXT is set, run bind "status". It verifies ownership and
|
|
|
2831
2837
|
const res = await ctx.client.getBillingStatus(site.siteId, site.credential);
|
|
2832
2838
|
noteSiteMode(res.siteId, res.mode);
|
|
2833
2839
|
const lines = [
|
|
2834
|
-
`
|
|
2840
|
+
`AUTHORITATIVE BILLING SNAPSHOT for site ${res.siteId} (mode: ${res.mode})`,
|
|
2835
2841
|
res.permanentUrl ? `Permanent URL: ${res.permanentUrl}` : void 0,
|
|
2836
2842
|
res.plan ? `Current plan: ${res.plan} (JPY ${res.monthlyPriceJpy ?? tierPriceJpy(res.plan)}/month)` : "Current plan: (no subscription yet)",
|
|
2837
2843
|
res.subscriptionStatus ? `Subscription payment state: ${res.subscriptionStatus}` : void 0,
|
|
2838
|
-
res.cancelAtPeriodEnd ? "Renewal: CANCELED \u2014 the site reverts to free at the end of the already-paid month" : res.renewalPlan ? `Next renewal plan: ${res.renewalPlan} (JPY ${res.renewalMonthlyPriceJpy ?? tierPriceJpy(res.renewalPlan)}/month)` + (res.renewalEffectiveAt ? `, effective ${res.renewalEffectiveAt}` : " (unchanged)") : void 0,
|
|
2844
|
+
res.cancelAtPeriodEnd === true ? "Renewal: CANCELED \u2014 the site reverts to free at the end of the already-paid month" : res.renewalPlan ? `Next renewal plan: ${res.renewalPlan} (JPY ${res.renewalMonthlyPriceJpy ?? tierPriceJpy(res.renewalPlan)}/month)` + (res.renewalEffectiveAt ? `, effective ${res.renewalEffectiveAt}` : " (unchanged)") : res.cancelAtPeriodEnd === false ? "Renewal cancellation: no" : void 0,
|
|
2839
2845
|
res.periodEntitlementPlan ? `Current paid entitlement: ${res.periodEntitlementPlan}` : void 0,
|
|
2840
2846
|
res.currentPeriodStart ? `Current paid period: ${res.currentPeriodStart} -> ${res.currentPeriodEnd ?? "?"}` : void 0,
|
|
2847
|
+
`Usage state: ${res.usageState}`,
|
|
2848
|
+
res.currentPeriodUsage ? `Current usage: storage ${res.currentPeriodUsage.storageBytes} bytes; transfer ${res.currentPeriodUsage.transferBytes} bytes; requests ${res.currentPeriodUsage.requests}` : void 0,
|
|
2849
|
+
res.currentPeriodCountedTransferBytes !== void 0 ? `Transfer counted against current plan: ${res.currentPeriodCountedTransferBytes} bytes` : void 0,
|
|
2850
|
+
res.currentPlanLimits ? `Current plan limits: storage ${res.currentPlanLimits.storageBytes} bytes; transfer ${res.currentPlanLimits.transferBytes} bytes; requests ${res.currentPlanLimits.requests}` : void 0,
|
|
2841
2851
|
res.estimatedUsageTier ? `Estimated usage tier: ${res.estimatedUsageTier}` : void 0,
|
|
2842
2852
|
res.lastReconciledAt ? `Last usage reconciliation: ${res.lastReconciledAt}` : void 0,
|
|
2853
|
+
res.usageLagSeconds !== void 0 ? `Usage lag: ${res.usageLagSeconds} seconds` : void 0,
|
|
2843
2854
|
res.oneTimeTransferCarry ? `One-time transfer carry: ${res.oneTimeTransferCarry.remainingBytes} bytes remaining (granted ${res.oneTimeTransferCarry.grantedBytes}, expires ${res.oneTimeTransferCarry.expiresAt})` : void 0,
|
|
2844
2855
|
res.boundHostnames.length > 0 ? `Bound custom domains: ${res.boundHostnames.join(", ")}` : void 0,
|
|
2845
2856
|
res.risks.pastDue ? "ATTENTION: renewal payment failing \u2014 update the payment method (portal). Serving continues while Stripe retries; if Stripe gives up, the site reverts to free." : void 0
|
|
@@ -3322,7 +3333,6 @@ Summary: ${res.sanitizedSummary}`,
|
|
|
3322
3333
|
|
|
3323
3334
|
// src/tools/billing.ts
|
|
3324
3335
|
import { z as z4 } from "zod";
|
|
3325
|
-
var plan = z4.enum(["water", "personal", "share", "business"]);
|
|
3326
3336
|
function registerBillingTools(server, baseCtx) {
|
|
3327
3337
|
server.registerTool(
|
|
3328
3338
|
"plans",
|
|
@@ -3350,12 +3360,11 @@ function registerBillingTools(server, baseCtx) {
|
|
|
3350
3360
|
}
|
|
3351
3361
|
);
|
|
3352
3362
|
server.registerTool(
|
|
3353
|
-
"
|
|
3363
|
+
"change",
|
|
3354
3364
|
{
|
|
3355
|
-
description: "Create
|
|
3365
|
+
description: "Create one Stripe-hosted subscription-management link. The user chooses the plan or period-end cancellation on Stripe; Sakupa never infers intent from the conversation. Creating the link does not change billing.",
|
|
3356
3366
|
inputSchema: {
|
|
3357
3367
|
projectDir: projectDirInput,
|
|
3358
|
-
targetPlan: plan,
|
|
3359
3368
|
operationId: z4.string().min(1)
|
|
3360
3369
|
},
|
|
3361
3370
|
outputSchema: STRUCTURED_TOOL_OUTPUT_SCHEMA,
|
|
@@ -3367,21 +3376,20 @@ function registerBillingTools(server, baseCtx) {
|
|
|
3367
3376
|
const site = requireSiteFile(ctx);
|
|
3368
3377
|
const result = await ctx.client.changeSubscriptionPlan(site.credential, {
|
|
3369
3378
|
siteId: site.siteId,
|
|
3370
|
-
targetPlan: args.targetPlan,
|
|
3371
3379
|
operationId: args.operationId
|
|
3372
3380
|
});
|
|
3373
3381
|
return structuredToolResult({
|
|
3374
3382
|
schemaVersion: 1,
|
|
3375
3383
|
outcome: "waiting_user",
|
|
3376
|
-
resultCode: "
|
|
3384
|
+
resultCode: "stripe_subscription_management_required",
|
|
3377
3385
|
operationId: args.operationId,
|
|
3378
|
-
summary:
|
|
3386
|
+
summary: "Stripe subscription-management link created; the subscription has NOT changed yet. Stripe is the authoritative place to choose Water, Personal, Share, Business, or period-end cancellation. Query billing after the user finishes.",
|
|
3379
3387
|
data: { result },
|
|
3380
3388
|
userAction: {
|
|
3381
3389
|
type: "open_url",
|
|
3382
3390
|
provider: "stripe",
|
|
3383
3391
|
url: result.portalUrl,
|
|
3384
|
-
expectedOutcome: "After the user
|
|
3392
|
+
expectedOutcome: "After the user finishes on Stripe, webhooks update Sakupa and billing reports the authoritative result"
|
|
3385
3393
|
},
|
|
3386
3394
|
nextActions: [{ tool: "billing", allowed: true }]
|
|
3387
3395
|
});
|
|
@@ -3611,7 +3619,7 @@ Workflow:
|
|
|
3611
3619
|
4. Optionally bind a custom domain to the subscribed site (bind): an included extra
|
|
3612
3620
|
serving surface alongside the permanent URL. Ownership is proven only by DNS control; the
|
|
3613
3621
|
first verified request wins; unverified requests expire after 72 hours. billing,
|
|
3614
|
-
|
|
3622
|
+
change, portal and recover manage the paid
|
|
3615
3623
|
lifecycle; delete tears the whole site down after explicit confirmation. Binding a
|
|
3616
3624
|
NEW domain while one is live is a zero-downtime SWITCH: the old domain keeps serving
|
|
3617
3625
|
until the new domain's www is confirmed live, then it is replaced automatically.
|
package/dist/index.js
CHANGED
|
@@ -124,7 +124,7 @@ var FORBIDDEN_PATH_SEGMENTS = [
|
|
|
124
124
|
var ALLOWED_HIDDEN_PATHS = [".well-known/"];
|
|
125
125
|
|
|
126
126
|
// ../core/dist/domain/version.js
|
|
127
|
-
var SAKUPA_MCP_VERSION = "0.7.
|
|
127
|
+
var SAKUPA_MCP_VERSION = "0.7.28";
|
|
128
128
|
|
|
129
129
|
// ../core/dist/domain/errors.js
|
|
130
130
|
var HTTP_STATUS = {
|
|
@@ -2720,7 +2720,7 @@ NO content was uploaded or changed by this call \u2014 to publish new or edited
|
|
|
2720
2720
|
server.registerTool(
|
|
2721
2721
|
"status",
|
|
2722
2722
|
{
|
|
2723
|
-
description: "Show the current status of this project's Sakupa site: URL, mode (free/paid), expiry,
|
|
2723
|
+
description: "Show the current status of this project's Sakupa site: URL, mode (free/paid), expiry, custom domains, size, last deployment and warnings. For a paid site this tool also automatically returns the complete authoritative billing snapshot; users never need to know or name a separate billing tool to get accurate subscription information.",
|
|
2724
2724
|
outputSchema: STRUCTURED_TOOL_OUTPUT_SCHEMA,
|
|
2725
2725
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
2726
2726
|
inputSchema: { projectDir: projectDirInput }
|
|
@@ -2731,12 +2731,18 @@ NO content was uploaded or changed by this call \u2014 to publish new or edited
|
|
|
2731
2731
|
const site = requireSiteFile(ctx);
|
|
2732
2732
|
const res = await ctx.client.getSiteStatus(site.siteId, site.credential);
|
|
2733
2733
|
noteSiteMode(res.siteId, res.mode);
|
|
2734
|
+
const billing = res.mode === "paid" ? await ctx.client.getBillingStatus(site.siteId, site.credential) : void 0;
|
|
2734
2735
|
const binding = res.pendingDomainBinding ? await describePendingBinding(ctx.client, site.credential, res.pendingDomainBinding) : void 0;
|
|
2735
|
-
return textJson(
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2736
|
+
return textJson(
|
|
2737
|
+
"status_returned",
|
|
2738
|
+
billing ? `Site status with AUTHORITATIVE BILLING SNAPSHOT. When answering any subscription question, use the nested billing object and report the current plan, scheduled renewal or cancellation, effective time, current entitlement, billing period, usage state and one-time carry when present:${binding?.note ?? ""}` : `Site status:${binding?.note ?? ""}`,
|
|
2739
|
+
{
|
|
2740
|
+
...res,
|
|
2741
|
+
projectDir: ctx.projectDir,
|
|
2742
|
+
...billing ? { billing } : {},
|
|
2743
|
+
...binding?.checklist ? { dnsChecklist: binding.checklist } : {}
|
|
2744
|
+
}
|
|
2745
|
+
);
|
|
2740
2746
|
} catch (e) {
|
|
2741
2747
|
return toolError(e);
|
|
2742
2748
|
}
|
|
@@ -2908,7 +2914,7 @@ When the user says the TXT is set, run bind "status". It verifies ownership and
|
|
|
2908
2914
|
server.registerTool(
|
|
2909
2915
|
"billing",
|
|
2910
2916
|
{
|
|
2911
|
-
description: "
|
|
2917
|
+
description: "Return the sole authoritative source for this site's hosting subscription: current plan, next renewal plan or cancellation, effective time, payment state, current paid entitlement, reconciled usage, estimated usage tier, bound custom domains and risks. Owner-only (uses the credential in .sakupa/site.json).",
|
|
2912
2918
|
outputSchema: STRUCTURED_TOOL_OUTPUT_SCHEMA,
|
|
2913
2919
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
2914
2920
|
inputSchema: { projectDir: projectDirInput }
|
|
@@ -2920,15 +2926,20 @@ When the user says the TXT is set, run bind "status". It verifies ownership and
|
|
|
2920
2926
|
const res = await ctx.client.getBillingStatus(site.siteId, site.credential);
|
|
2921
2927
|
noteSiteMode(res.siteId, res.mode);
|
|
2922
2928
|
const lines = [
|
|
2923
|
-
`
|
|
2929
|
+
`AUTHORITATIVE BILLING SNAPSHOT for site ${res.siteId} (mode: ${res.mode})`,
|
|
2924
2930
|
res.permanentUrl ? `Permanent URL: ${res.permanentUrl}` : void 0,
|
|
2925
2931
|
res.plan ? `Current plan: ${res.plan} (JPY ${res.monthlyPriceJpy ?? tierPriceJpy(res.plan)}/month)` : "Current plan: (no subscription yet)",
|
|
2926
2932
|
res.subscriptionStatus ? `Subscription payment state: ${res.subscriptionStatus}` : void 0,
|
|
2927
|
-
res.cancelAtPeriodEnd ? "Renewal: CANCELED \u2014 the site reverts to free at the end of the already-paid month" : res.renewalPlan ? `Next renewal plan: ${res.renewalPlan} (JPY ${res.renewalMonthlyPriceJpy ?? tierPriceJpy(res.renewalPlan)}/month)` + (res.renewalEffectiveAt ? `, effective ${res.renewalEffectiveAt}` : " (unchanged)") : void 0,
|
|
2933
|
+
res.cancelAtPeriodEnd === true ? "Renewal: CANCELED \u2014 the site reverts to free at the end of the already-paid month" : res.renewalPlan ? `Next renewal plan: ${res.renewalPlan} (JPY ${res.renewalMonthlyPriceJpy ?? tierPriceJpy(res.renewalPlan)}/month)` + (res.renewalEffectiveAt ? `, effective ${res.renewalEffectiveAt}` : " (unchanged)") : res.cancelAtPeriodEnd === false ? "Renewal cancellation: no" : void 0,
|
|
2928
2934
|
res.periodEntitlementPlan ? `Current paid entitlement: ${res.periodEntitlementPlan}` : void 0,
|
|
2929
2935
|
res.currentPeriodStart ? `Current paid period: ${res.currentPeriodStart} -> ${res.currentPeriodEnd ?? "?"}` : void 0,
|
|
2936
|
+
`Usage state: ${res.usageState}`,
|
|
2937
|
+
res.currentPeriodUsage ? `Current usage: storage ${res.currentPeriodUsage.storageBytes} bytes; transfer ${res.currentPeriodUsage.transferBytes} bytes; requests ${res.currentPeriodUsage.requests}` : void 0,
|
|
2938
|
+
res.currentPeriodCountedTransferBytes !== void 0 ? `Transfer counted against current plan: ${res.currentPeriodCountedTransferBytes} bytes` : void 0,
|
|
2939
|
+
res.currentPlanLimits ? `Current plan limits: storage ${res.currentPlanLimits.storageBytes} bytes; transfer ${res.currentPlanLimits.transferBytes} bytes; requests ${res.currentPlanLimits.requests}` : void 0,
|
|
2930
2940
|
res.estimatedUsageTier ? `Estimated usage tier: ${res.estimatedUsageTier}` : void 0,
|
|
2931
2941
|
res.lastReconciledAt ? `Last usage reconciliation: ${res.lastReconciledAt}` : void 0,
|
|
2942
|
+
res.usageLagSeconds !== void 0 ? `Usage lag: ${res.usageLagSeconds} seconds` : void 0,
|
|
2932
2943
|
res.oneTimeTransferCarry ? `One-time transfer carry: ${res.oneTimeTransferCarry.remainingBytes} bytes remaining (granted ${res.oneTimeTransferCarry.grantedBytes}, expires ${res.oneTimeTransferCarry.expiresAt})` : void 0,
|
|
2933
2944
|
res.boundHostnames.length > 0 ? `Bound custom domains: ${res.boundHostnames.join(", ")}` : void 0,
|
|
2934
2945
|
res.risks.pastDue ? "ATTENTION: renewal payment failing \u2014 update the payment method (portal). Serving continues while Stripe retries; if Stripe gives up, the site reverts to free." : void 0
|
|
@@ -3515,7 +3526,6 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
3515
3526
|
|
|
3516
3527
|
// src/tools/billing.ts
|
|
3517
3528
|
import { z as z5 } from "zod";
|
|
3518
|
-
var plan = z5.enum(["water", "personal", "share", "business"]);
|
|
3519
3529
|
function registerBillingTools(server, baseCtx) {
|
|
3520
3530
|
server.registerTool(
|
|
3521
3531
|
"plans",
|
|
@@ -3543,12 +3553,11 @@ function registerBillingTools(server, baseCtx) {
|
|
|
3543
3553
|
}
|
|
3544
3554
|
);
|
|
3545
3555
|
server.registerTool(
|
|
3546
|
-
"
|
|
3556
|
+
"change",
|
|
3547
3557
|
{
|
|
3548
|
-
description: "Create
|
|
3558
|
+
description: "Create one Stripe-hosted subscription-management link. The user chooses the plan or period-end cancellation on Stripe; Sakupa never infers intent from the conversation. Creating the link does not change billing.",
|
|
3549
3559
|
inputSchema: {
|
|
3550
3560
|
projectDir: projectDirInput,
|
|
3551
|
-
targetPlan: plan,
|
|
3552
3561
|
operationId: z5.string().min(1)
|
|
3553
3562
|
},
|
|
3554
3563
|
outputSchema: STRUCTURED_TOOL_OUTPUT_SCHEMA,
|
|
@@ -3560,21 +3569,20 @@ function registerBillingTools(server, baseCtx) {
|
|
|
3560
3569
|
const site = requireSiteFile(ctx);
|
|
3561
3570
|
const result = await ctx.client.changeSubscriptionPlan(site.credential, {
|
|
3562
3571
|
siteId: site.siteId,
|
|
3563
|
-
targetPlan: args.targetPlan,
|
|
3564
3572
|
operationId: args.operationId
|
|
3565
3573
|
});
|
|
3566
3574
|
return structuredToolResult({
|
|
3567
3575
|
schemaVersion: 1,
|
|
3568
3576
|
outcome: "waiting_user",
|
|
3569
|
-
resultCode: "
|
|
3577
|
+
resultCode: "stripe_subscription_management_required",
|
|
3570
3578
|
operationId: args.operationId,
|
|
3571
|
-
summary:
|
|
3579
|
+
summary: "Stripe subscription-management link created; the subscription has NOT changed yet. Stripe is the authoritative place to choose Water, Personal, Share, Business, or period-end cancellation. Query billing after the user finishes.",
|
|
3572
3580
|
data: { result },
|
|
3573
3581
|
userAction: {
|
|
3574
3582
|
type: "open_url",
|
|
3575
3583
|
provider: "stripe",
|
|
3576
3584
|
url: result.portalUrl,
|
|
3577
|
-
expectedOutcome: "After the user
|
|
3585
|
+
expectedOutcome: "After the user finishes on Stripe, webhooks update Sakupa and billing reports the authoritative result"
|
|
3578
3586
|
},
|
|
3579
3587
|
nextActions: [{ tool: "billing", allowed: true }]
|
|
3580
3588
|
});
|
|
@@ -3606,7 +3614,7 @@ Workflow:
|
|
|
3606
3614
|
4. Optionally bind a custom domain to the subscribed site (bind): an included extra
|
|
3607
3615
|
serving surface alongside the permanent URL. Ownership is proven only by DNS control; the
|
|
3608
3616
|
first verified request wins; unverified requests expire after 72 hours. billing,
|
|
3609
|
-
|
|
3617
|
+
change, portal and recover manage the paid
|
|
3610
3618
|
lifecycle; delete tears the whole site down after explicit confirmation. Binding a
|
|
3611
3619
|
NEW domain while one is live is a zero-downtime SWITCH: the old domain keeps serving
|
|
3612
3620
|
until the new domain's www is confirmed live, then it is replaced automatically.
|