@absolutejs/mcp 0.14.0 → 0.15.1

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/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ This file is generated by `absolute-changelog` from the entries in
6
6
  `changelog/`. Edit an entry, not this file — and add new ones under
7
7
  `changelog/unreleased/`.
8
8
 
9
+ ## 0.15.1 — 2026-09-11
10
+
11
+ ### Fixed
12
+
13
+ - **Build and test before publishing so checkout exports are present in the distributed artifact**
14
+
15
+ ## 0.15.0 — 2026-09-11
16
+
17
+ ### Added
18
+
19
+ - **Add commerce-classified account-bound checkout handoff and purchase status tools**
20
+
9
21
  ## 0.14.0 — 2026-09-11
10
22
 
11
23
  ### Added
package/README.md CHANGED
@@ -427,3 +427,7 @@ on the Change Date.
427
427
  ### Budgeted prepaid work
428
428
 
429
429
  `budgetedMcpTool({ tool, execute })` adds a stable work ID, an explicit maximum-credit budget, and a `paid_access` commerce requirement. The executor must bind the account and use durable claims and settlement (for example `@absolutejs/billing/credit-work`). Only wrap tools whose effects and metering finish inside the execution scope. Deferred jobs need a durable budget handoff. Task-required, authorization-mapped, and already commerce-tagged tools are rejected rather than silently changing their enforcement contracts.
430
+
431
+ ## Secure credit checkout
432
+
433
+ `createCheckoutHandoffTool` and `createPurchaseStatusTool` provide account-bound credit checkout and recovery contracts. The issuer must bind server pricing and identity; route these tools through the commerce guard. Checkout is classified as `external_checkout`, so restricted and unverified channels cannot discover or execute it. Status works at zero credits. Never pass card data in tool input. See [host rules](docs/commerce-host-rules.md).
package/changelog.json CHANGED
@@ -1,32 +1,52 @@
1
1
  {
2
- "contract": 1,
3
- "name": "@absolutejs/mcp",
4
- "releases": [
5
- {
6
- "changes": [
7
- {
8
- "kind": "added",
9
- "summary": "Add explicit credit-budget envelopes for durable prepaid MCP work"
10
- }
11
- ],
12
- "date": "2026-09-11",
13
- "version": "0.14.0"
14
- },
15
- {
16
- "changes": [
17
- {
18
- "kind": "added",
19
- "summary": "Add reviewed host commerce eligibility, execution guards, and reusable credit status tools",
20
- "symbols": [
21
- "McpServerConfig",
22
- "McpTool",
23
- "evaluateCommerce",
24
- "createCreditBalanceTool"
25
- ]
26
- }
27
- ],
28
- "date": "2026-09-11",
29
- "version": "0.13.0"
30
- }
31
- ]
2
+ "contract": 1,
3
+ "name": "@absolutejs/mcp",
4
+ "releases": [
5
+ {
6
+ "version": "0.15.1",
7
+ "date": "2026-09-11",
8
+ "changes": [
9
+ {
10
+ "kind": "fixed",
11
+ "summary": "Build and test before publishing so checkout exports are present in the distributed artifact"
12
+ }
13
+ ]
14
+ },
15
+ {
16
+ "version": "0.15.0",
17
+ "date": "2026-09-11",
18
+ "changes": [
19
+ {
20
+ "kind": "added",
21
+ "summary": "Add commerce-classified account-bound checkout handoff and purchase status tools"
22
+ }
23
+ ]
24
+ },
25
+ {
26
+ "changes": [
27
+ {
28
+ "kind": "added",
29
+ "summary": "Add explicit credit-budget envelopes for durable prepaid MCP work"
30
+ }
31
+ ],
32
+ "date": "2026-09-11",
33
+ "version": "0.14.0"
34
+ },
35
+ {
36
+ "changes": [
37
+ {
38
+ "kind": "added",
39
+ "summary": "Add reviewed host commerce eligibility, execution guards, and reusable credit status tools",
40
+ "symbols": [
41
+ "McpServerConfig",
42
+ "McpTool",
43
+ "evaluateCommerce",
44
+ "createCreditBalanceTool"
45
+ ]
46
+ }
47
+ ],
48
+ "date": "2026-09-11",
49
+ "version": "0.13.0"
50
+ }
51
+ ]
32
52
  }
package/dist/commerce.js CHANGED
@@ -59,6 +59,92 @@ var createCreditBalanceTool = (options) => ({
59
59
  };
60
60
  }
61
61
  });
62
+ // src/checkoutTools.ts
63
+ var record = (input) => typeof input === "object" && input !== null && !Array.isArray(input);
64
+ var createCheckoutHandoffTool = (options) => ({
65
+ annotations: {
66
+ readOnlyHint: false,
67
+ destructiveHint: false,
68
+ openWorldHint: true,
69
+ title: "Open credit checkout"
70
+ },
71
+ commerce: { action: "external_checkout", categories: ["usage_credits"] },
72
+ description: "Prepare a short-lived credit-purchase link on the service website. The user reviews and explicitly pays there. Never send card data in chat. Does not charge a card or create a subscription.",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: { productId: { type: "string", minLength: 1, maxLength: 128 } },
76
+ required: ["productId"],
77
+ additionalProperties: false
78
+ },
79
+ handler: async (input) => {
80
+ if (!record(input) || Object.keys(input).length !== 1 || typeof input.productId !== "string" || !input.productId || input.productId.length > 128)
81
+ throw new Error("A productId is required");
82
+ const result = await options.issue(input.productId);
83
+ const url = new URL(result.url);
84
+ if (url.protocol !== "https:" || url.origin !== new URL(options.origin).origin || url.username || url.password || !Number.isFinite(Date.parse(result.expiresAt)))
85
+ throw new Error("Invalid checkout handoff");
86
+ return {
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: `Review and pay on ${url.hostname}: ${url.href}. Expires ${result.expiresAt}. No payment has been made.`
91
+ }
92
+ ],
93
+ structuredContent: {
94
+ purchaseId: result.purchaseId,
95
+ url: url.href,
96
+ expiresAt: result.expiresAt
97
+ }
98
+ };
99
+ }
100
+ });
101
+ var createPurchaseStatusTool = (options) => ({
102
+ annotations: {
103
+ readOnlyHint: true,
104
+ destructiveHint: false,
105
+ openWorldHint: false
106
+ },
107
+ commerce: { action: "entitlement_status", categories: ["usage_credits"] },
108
+ description: "Read this account's credit-purchase status. Available at zero balance. Does not initiate or retry payment.",
109
+ inputSchema: {
110
+ type: "object",
111
+ properties: {
112
+ purchaseId: { type: "string", minLength: 1, maxLength: 128 }
113
+ },
114
+ required: ["purchaseId"],
115
+ additionalProperties: false
116
+ },
117
+ handler: async (input) => {
118
+ if (!record(input) || Object.keys(input).length !== 1 || typeof input.purchaseId !== "string" || !input.purchaseId || input.purchaseId.length > 128)
119
+ throw new Error("A purchaseId is required");
120
+ const value = await options.read(input.purchaseId);
121
+ if (!value)
122
+ return "No purchase with that ID exists for this account.";
123
+ if (value.purchaseId !== input.purchaseId || ![
124
+ "not_started",
125
+ "pending",
126
+ "approved",
127
+ "declined",
128
+ "refunded",
129
+ "reconciliation"
130
+ ].includes(value.status) || !Number.isSafeInteger(value.creditsGranted) || value.creditsGranted < 0)
131
+ throw new Error("Purchase status is unavailable");
132
+ const summary = {
133
+ purchaseId: value.purchaseId,
134
+ status: value.status,
135
+ creditsGranted: value.creditsGranted
136
+ };
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text: `Purchase ${summary.status}; ${summary.creditsGranted} credits granted.`
142
+ }
143
+ ],
144
+ structuredContent: summary
145
+ };
146
+ }
147
+ });
62
148
 
63
149
  // src/commerce.ts
64
150
  var COMMERCE_POLICY_VERSION = "2026-09-10.1";
@@ -168,6 +254,8 @@ var evaluateCommerce = (req, context, now = new Date) => {
168
254
  export {
169
255
  COMMERCE_POLICY_SOURCES,
170
256
  COMMERCE_POLICY_VERSION,
257
+ createCheckoutHandoffTool,
171
258
  createCreditBalanceTool,
259
+ createPurchaseStatusTool,
172
260
  evaluateCommerce
173
261
  };
package/dist/index.js CHANGED
@@ -59,6 +59,92 @@ var createCreditBalanceTool = (options) => ({
59
59
  };
60
60
  }
61
61
  });
62
+ // src/checkoutTools.ts
63
+ var record = (input) => typeof input === "object" && input !== null && !Array.isArray(input);
64
+ var createCheckoutHandoffTool = (options) => ({
65
+ annotations: {
66
+ readOnlyHint: false,
67
+ destructiveHint: false,
68
+ openWorldHint: true,
69
+ title: "Open credit checkout"
70
+ },
71
+ commerce: { action: "external_checkout", categories: ["usage_credits"] },
72
+ description: "Prepare a short-lived credit-purchase link on the service website. The user reviews and explicitly pays there. Never send card data in chat. Does not charge a card or create a subscription.",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: { productId: { type: "string", minLength: 1, maxLength: 128 } },
76
+ required: ["productId"],
77
+ additionalProperties: false
78
+ },
79
+ handler: async (input) => {
80
+ if (!record(input) || Object.keys(input).length !== 1 || typeof input.productId !== "string" || !input.productId || input.productId.length > 128)
81
+ throw new Error("A productId is required");
82
+ const result = await options.issue(input.productId);
83
+ const url = new URL(result.url);
84
+ if (url.protocol !== "https:" || url.origin !== new URL(options.origin).origin || url.username || url.password || !Number.isFinite(Date.parse(result.expiresAt)))
85
+ throw new Error("Invalid checkout handoff");
86
+ return {
87
+ content: [
88
+ {
89
+ type: "text",
90
+ text: `Review and pay on ${url.hostname}: ${url.href}. Expires ${result.expiresAt}. No payment has been made.`
91
+ }
92
+ ],
93
+ structuredContent: {
94
+ purchaseId: result.purchaseId,
95
+ url: url.href,
96
+ expiresAt: result.expiresAt
97
+ }
98
+ };
99
+ }
100
+ });
101
+ var createPurchaseStatusTool = (options) => ({
102
+ annotations: {
103
+ readOnlyHint: true,
104
+ destructiveHint: false,
105
+ openWorldHint: false
106
+ },
107
+ commerce: { action: "entitlement_status", categories: ["usage_credits"] },
108
+ description: "Read this account's credit-purchase status. Available at zero balance. Does not initiate or retry payment.",
109
+ inputSchema: {
110
+ type: "object",
111
+ properties: {
112
+ purchaseId: { type: "string", minLength: 1, maxLength: 128 }
113
+ },
114
+ required: ["purchaseId"],
115
+ additionalProperties: false
116
+ },
117
+ handler: async (input) => {
118
+ if (!record(input) || Object.keys(input).length !== 1 || typeof input.purchaseId !== "string" || !input.purchaseId || input.purchaseId.length > 128)
119
+ throw new Error("A purchaseId is required");
120
+ const value = await options.read(input.purchaseId);
121
+ if (!value)
122
+ return "No purchase with that ID exists for this account.";
123
+ if (value.purchaseId !== input.purchaseId || ![
124
+ "not_started",
125
+ "pending",
126
+ "approved",
127
+ "declined",
128
+ "refunded",
129
+ "reconciliation"
130
+ ].includes(value.status) || !Number.isSafeInteger(value.creditsGranted) || value.creditsGranted < 0)
131
+ throw new Error("Purchase status is unavailable");
132
+ const summary = {
133
+ purchaseId: value.purchaseId,
134
+ status: value.status,
135
+ creditsGranted: value.creditsGranted
136
+ };
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text: `Purchase ${summary.status}; ${summary.creditsGranted} credits granted.`
142
+ }
143
+ ],
144
+ structuredContent: summary
145
+ };
146
+ }
147
+ });
62
148
 
63
149
  // src/commerce.ts
64
150
  var COMMERCE_POLICY_VERSION = "2026-09-10.1";
@@ -2008,6 +2094,7 @@ export {
2008
2094
  MCP_LATEST_PROTOCOL_VERSION,
2009
2095
  McpClientError,
2010
2096
  budgetedMcpTool,
2097
+ createCheckoutHandoffTool,
2011
2098
  createCreditBalanceTool,
2012
2099
  createMcpAuthorizationRequest,
2013
2100
  createMcpClient,
@@ -2017,6 +2104,7 @@ export {
2017
2104
  createMemoryMcpTaskStore,
2018
2105
  createPostgresMcpSessionStore,
2019
2106
  createPostgresMcpTaskStore,
2107
+ createPurchaseStatusTool,
2020
2108
  createSessionRegistry,
2021
2109
  discoverMcpAuthorization,
2022
2110
  dispatchMcp,
package/dist/manifest.js CHANGED
@@ -2861,7 +2861,9 @@ var manifest = defineManifest()({
2861
2861
  tagline: "Let AI assistants connect to your site and use its tools."
2862
2862
  },
2863
2863
  requires: {
2864
- peers: [{ name: "elysia", range: "^2.0.0-beta.6", reason: "plugin host" }]
2864
+ peers: [
2865
+ { name: "elysia", range: "^2.0.0-beta.6", reason: "plugin host" }
2866
+ ]
2865
2867
  },
2866
2868
  settings: Type.Object({
2867
2869
  instructions: Type.Optional(Type.String({
@@ -0,0 +1,19 @@
1
+ import type { McpTool } from "./types";
2
+ export type McpPurchaseStatus = {
3
+ purchaseId: string;
4
+ status: "not_started" | "pending" | "approved" | "declined" | "refunded" | "reconciliation";
5
+ creditsGranted: number;
6
+ };
7
+ /** The issuer is bound to the authenticated account and canonical server pricing.
8
+ * Register only through the commerce guard. This tool never takes payment data. */
9
+ export declare const createCheckoutHandoffTool: (options: {
10
+ origin: string;
11
+ issue: (productId: string) => Promise<{
12
+ purchaseId: string;
13
+ url: string;
14
+ expiresAt: string;
15
+ }>;
16
+ }) => McpTool;
17
+ export declare const createPurchaseStatusTool: (options: {
18
+ read: (purchaseId: string) => Promise<McpPurchaseStatus | null>;
19
+ }) => McpTool;
@@ -48,3 +48,4 @@ export type CommerceDecision = {
48
48
  * Unverified paths need explicit, fresh server-side review evidence. */
49
49
  export declare const evaluateCommerce: (req: CommerceRequirement, context: CommerceContext, now?: Date) => CommerceDecision;
50
50
  export { createCreditBalanceTool, type McpCreditBalance } from "./creditStatus";
51
+ export { createCheckoutHandoffTool, createPurchaseStatusTool, type McpPurchaseStatus, } from "./checkoutTools";
@@ -45,3 +45,4 @@ export type { McpAgencyOptions, McpAudioContent, McpElicitAnswer, McpElicitation
45
45
  export * from "./commerce";
46
46
  export { createCreditBalanceTool, type McpCreditBalance } from "./creditStatus";
47
47
  export { budgetedMcpTool, type McpCreditWorkRequest } from "./budgetedTool";
48
+ export { createCheckoutHandoffTool, createPurchaseStatusTool, type McpPurchaseStatus, } from "./checkoutTools";
package/package.json CHANGED
@@ -68,9 +68,9 @@
68
68
  "release": "bun run format && bun run test && bun run build && bun publish",
69
69
  "test": "bun test",
70
70
  "typecheck": "tsc --noEmit --project tsconfig.json",
71
- "check:package": "absolute-changelog check",
71
+ "check:package": "bun run typecheck && bun run test && bun run build && absolute-changelog check",
72
72
  "prepublishOnly": "bun run check:package"
73
73
  },
74
74
  "types": "./dist/src/index.d.ts",
75
- "version": "0.14.0"
75
+ "version": "0.15.1"
76
76
  }