@absolutejs/mcp 0.15.1 → 0.17.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/CHANGELOG.md +17 -0
- package/README.md +6 -0
- package/changelog.json +37 -0
- package/dist/apps.js +90 -0
- package/dist/browser/billing.d.ts +1 -0
- package/dist/commerce.js +223 -0
- package/dist/index.js +436 -88
- package/dist/scripts/build-apps.d.ts +1 -0
- package/dist/src/apps.d.ts +33 -0
- package/dist/src/billingApp.generated.d.ts +2 -0
- package/dist/src/billingApps.d.ts +8 -0
- package/dist/src/billingTools.d.ts +30 -0
- package/dist/src/client.d.ts +3 -0
- package/dist/src/commerce.d.ts +1 -0
- package/dist/src/index.d.ts +4 -1
- package/dist/src/postgres.d.ts +5 -0
- package/dist/src/sessions.d.ts +2 -1
- package/dist/src/types.d.ts +11 -0
- package/docs/mcp-apps.md +56 -0
- package/docs/third-party/mcp-apps-LICENSE +216 -0
- package/docs/third-party/mcp-client-LICENSE +216 -0
- package/docs/third-party/mcp-core-LICENSE +216 -0
- package/docs/third-party/standard-schema-LICENSE +21 -0
- package/docs/third-party/zod-LICENSE +21 -0
- package/package.json +18 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/commerce.js
CHANGED
|
@@ -145,6 +145,227 @@ var createPurchaseStatusTool = (options) => ({
|
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
|
+
// node_modules/@absolutejs/billing/dist/reports.js
|
|
149
|
+
var DAY_MS = 86400000;
|
|
150
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
151
|
+
var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
152
|
+
var only = (input, keys) => {
|
|
153
|
+
if (!record2(input) || Object.keys(input).some((key) => !keys.includes(key)))
|
|
154
|
+
throw new Error("Invalid report input");
|
|
155
|
+
return input;
|
|
156
|
+
};
|
|
157
|
+
var integer = (value) => {
|
|
158
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
159
|
+
throw new Error("Invalid report amount");
|
|
160
|
+
return value;
|
|
161
|
+
};
|
|
162
|
+
var iso = (value) => {
|
|
163
|
+
if (!Number.isFinite(Date.parse(value)) || new Date(value).toISOString() !== value)
|
|
164
|
+
throw new Error("Invalid report timestamp");
|
|
165
|
+
return value;
|
|
166
|
+
};
|
|
167
|
+
var day = (value) => {
|
|
168
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value) || new Date(value + "T00:00:00.000Z").toISOString().slice(0, 10) !== value)
|
|
169
|
+
throw new Error("Expected a UTC calendar date");
|
|
170
|
+
return value;
|
|
171
|
+
};
|
|
172
|
+
var parseUsageRange = (input, now = new Date) => {
|
|
173
|
+
const args = only(input, ["from", "to"]);
|
|
174
|
+
const tomorrow = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()) + DAY_MS);
|
|
175
|
+
const to = day(args.to ?? tomorrow.toISOString().slice(0, 10));
|
|
176
|
+
const from = day(args.from ?? new Date(Date.parse(to) - 30 * DAY_MS).toISOString().slice(0, 10));
|
|
177
|
+
const duration = Date.parse(to) - Date.parse(from);
|
|
178
|
+
if (duration <= 0 || duration > 90 * DAY_MS || Date.parse(to) > tomorrow.getTime())
|
|
179
|
+
throw new Error("Choose a range of 1\u201390 UTC days, ending no later than tomorrow");
|
|
180
|
+
return { from, to };
|
|
181
|
+
};
|
|
182
|
+
var parseReceiptPage = (input) => {
|
|
183
|
+
const args = only(input, ["limit", "cursor"]);
|
|
184
|
+
const limit = args.limit ?? 20;
|
|
185
|
+
if (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1 || limit > 50)
|
|
186
|
+
throw new Error("Receipt limit must be 1\u201350");
|
|
187
|
+
if (args.cursor === undefined || args.cursor === null)
|
|
188
|
+
return { limit, cursor: null };
|
|
189
|
+
if (typeof args.cursor !== "string" || args.cursor.length > 256 || !/^[A-Za-z0-9_-]+$/.test(args.cursor))
|
|
190
|
+
throw new Error("Invalid receipt cursor");
|
|
191
|
+
const decoded = JSON.parse(Buffer.from(args.cursor, "base64url").toString("utf8"));
|
|
192
|
+
if (!record2(decoded) || typeof decoded.at !== "string" || typeof decoded.id !== "string" || !UUID.test(decoded.id))
|
|
193
|
+
throw new Error("Invalid receipt cursor");
|
|
194
|
+
return { limit, cursor: { at: iso(decoded.at), id: decoded.id } };
|
|
195
|
+
};
|
|
196
|
+
var projectBillingStatus = (value) => ({
|
|
197
|
+
portalAccess: value.portalAccess === true,
|
|
198
|
+
subscription: value.subscription ? {
|
|
199
|
+
status: String(value.subscription.status).slice(0, 64),
|
|
200
|
+
renewsAt: value.subscription.renewsAt === null ? null : iso(value.subscription.renewsAt),
|
|
201
|
+
cancelAtPeriodEnd: value.subscription.cancelAtPeriodEnd === true
|
|
202
|
+
} : null,
|
|
203
|
+
credits: {
|
|
204
|
+
remaining: integer(value.credits.remaining),
|
|
205
|
+
reserved: integer(value.credits.reserved),
|
|
206
|
+
purchased: integer(value.credits.purchased),
|
|
207
|
+
promotional: integer(value.credits.promotional),
|
|
208
|
+
debt: integer(value.credits.debt)
|
|
209
|
+
},
|
|
210
|
+
automaticRefill: false
|
|
211
|
+
});
|
|
212
|
+
var projectReceiptPage = (value, limit) => {
|
|
213
|
+
if (value.receipts.length > limit)
|
|
214
|
+
throw new Error("Receipt page exceeds its limit");
|
|
215
|
+
if (value.nextCursor !== null)
|
|
216
|
+
parseReceiptPage({ cursor: value.nextCursor });
|
|
217
|
+
return {
|
|
218
|
+
receipts: value.receipts.map((row) => {
|
|
219
|
+
if (!UUID.test(row.id) || !/^[A-Z]{3}$/.test(row.currency) || !["credit_purchase", "initial", "plan_change", "renewal"].includes(row.source) || !["paid", "partially_refunded", "refunded"].includes(row.status) || row.refundedAmountCents > row.amountCents)
|
|
220
|
+
throw new Error("Invalid receipt");
|
|
221
|
+
return {
|
|
222
|
+
id: row.id,
|
|
223
|
+
issuedAt: iso(row.issuedAt),
|
|
224
|
+
currency: row.currency,
|
|
225
|
+
amountCents: integer(row.amountCents),
|
|
226
|
+
refundedAmountCents: integer(row.refundedAmountCents),
|
|
227
|
+
source: row.source,
|
|
228
|
+
status: row.status
|
|
229
|
+
};
|
|
230
|
+
}),
|
|
231
|
+
nextCursor: value.nextCursor
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
var projectUsageReport = (value, range) => {
|
|
235
|
+
if (value.from !== range.from || value.to !== range.to || value.byDay.length > 90 || value.byFeature.length > 21)
|
|
236
|
+
throw new Error("Invalid usage report bounds");
|
|
237
|
+
const byDay = value.byDay.map((row) => ({
|
|
238
|
+
day: day(row.day),
|
|
239
|
+
credits: integer(row.credits),
|
|
240
|
+
events: integer(row.events)
|
|
241
|
+
}));
|
|
242
|
+
const byFeature = value.byFeature.map((row) => ({
|
|
243
|
+
feature: row.feature.slice(0, 128),
|
|
244
|
+
credits: integer(row.credits),
|
|
245
|
+
events: integer(row.events)
|
|
246
|
+
}));
|
|
247
|
+
const credits = integer(value.creditsConsumed), events = integer(value.events);
|
|
248
|
+
for (const rows of [byDay, byFeature])
|
|
249
|
+
if (rows.reduce((sum, row) => sum + row.credits, 0) !== credits || rows.reduce((sum, row) => sum + row.events, 0) !== events)
|
|
250
|
+
throw new Error("Usage breakdown does not reconcile");
|
|
251
|
+
if (new Set(byDay.map((row) => row.day)).size !== byDay.length || byDay.some((row) => row.day < range.from || row.day >= range.to))
|
|
252
|
+
throw new Error("Invalid usage days");
|
|
253
|
+
return {
|
|
254
|
+
from: range.from,
|
|
255
|
+
to: range.to,
|
|
256
|
+
creditsConsumed: credits,
|
|
257
|
+
events,
|
|
258
|
+
byDay,
|
|
259
|
+
byFeature
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// src/billingTools.ts
|
|
264
|
+
var result = (text, data) => ({
|
|
265
|
+
content: [{ type: "text", text }],
|
|
266
|
+
structuredContent: { ...data }
|
|
267
|
+
});
|
|
268
|
+
var empty = (input) => {
|
|
269
|
+
if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).length)
|
|
270
|
+
throw new Error("This tool takes no arguments");
|
|
271
|
+
};
|
|
272
|
+
var createBillingReportTools = (readers) => ({
|
|
273
|
+
get_billing_status: {
|
|
274
|
+
annotations: {
|
|
275
|
+
readOnlyHint: true,
|
|
276
|
+
destructiveHint: false,
|
|
277
|
+
openWorldHint: false
|
|
278
|
+
},
|
|
279
|
+
commerce: {
|
|
280
|
+
action: "entitlement_status",
|
|
281
|
+
categories: ["usage_credits", "subscription"]
|
|
282
|
+
},
|
|
283
|
+
description: "Read subscription and service-credit status for this account, including reserved credits and debt. Does not charge, renew or cancel anything. Available at zero balance.",
|
|
284
|
+
inputSchema: {
|
|
285
|
+
type: "object",
|
|
286
|
+
properties: {},
|
|
287
|
+
additionalProperties: false
|
|
288
|
+
},
|
|
289
|
+
handler: async (input) => {
|
|
290
|
+
empty(input);
|
|
291
|
+
const status = projectBillingStatus(await readers.status());
|
|
292
|
+
return result(`${status.credits.remaining} service credits available, ${status.credits.reserved} reserved. Portal access: ${status.portalAccess ? "enabled" : "not enabled"}. Automatic refill is off.`, status);
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
list_receipts: {
|
|
296
|
+
annotations: {
|
|
297
|
+
readOnlyHint: true,
|
|
298
|
+
destructiveHint: false,
|
|
299
|
+
openWorldHint: false
|
|
300
|
+
},
|
|
301
|
+
commerce: {
|
|
302
|
+
action: "entitlement_status",
|
|
303
|
+
categories: ["usage_credits", "subscription"]
|
|
304
|
+
},
|
|
305
|
+
description: "List this account's payment receipts, newest first, with original amounts and refunds recorded to date. Amounts are currency minor units, not consumed credits. Follow nextCursor for more. No payment credentials or provider references are exposed.",
|
|
306
|
+
inputSchema: {
|
|
307
|
+
type: "object",
|
|
308
|
+
properties: {
|
|
309
|
+
limit: { type: "integer", minimum: 1, maximum: 50, default: 20 },
|
|
310
|
+
cursor: { type: ["string", "null"], maxLength: 256 }
|
|
311
|
+
},
|
|
312
|
+
additionalProperties: false
|
|
313
|
+
},
|
|
314
|
+
handler: async (input) => {
|
|
315
|
+
const request = parseReceiptPage(input);
|
|
316
|
+
const page = projectReceiptPage(await readers.receipts(request), request.limit);
|
|
317
|
+
return result(`${page.receipts.length} receipts.${page.nextCursor ? " More receipts are available using nextCursor." : ""}`, page);
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
get_usage_report: {
|
|
321
|
+
annotations: {
|
|
322
|
+
readOnlyHint: true,
|
|
323
|
+
destructiveHint: false,
|
|
324
|
+
openWorldHint: false
|
|
325
|
+
},
|
|
326
|
+
commerce: { action: "entitlement_status", categories: ["usage_credits"] },
|
|
327
|
+
description: "Read recorded service-credit consumption by UTC day and feature. from is inclusive and to is exclusive; at most 90 days, default last 30 days including today. Credits consumed are not dollars paid or the assistant's own tokens. Does not estimate ROI or expose internal provider costs.",
|
|
328
|
+
inputSchema: {
|
|
329
|
+
type: "object",
|
|
330
|
+
properties: {
|
|
331
|
+
from: { type: "string", format: "date" },
|
|
332
|
+
to: { type: "string", format: "date" }
|
|
333
|
+
},
|
|
334
|
+
additionalProperties: false
|
|
335
|
+
},
|
|
336
|
+
handler: async (input) => {
|
|
337
|
+
const range = parseUsageRange(input, readers.now?.());
|
|
338
|
+
const usage = projectUsageReport(await readers.usage(range), range);
|
|
339
|
+
return result(`${usage.creditsConsumed} service credits across ${usage.events} recorded events, ${range.from} inclusive to ${range.to} exclusive (UTC).`, usage);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
var createBillingManagementTool = (destination) => {
|
|
344
|
+
const url = new URL(destination);
|
|
345
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
|
|
346
|
+
throw new Error("Billing management requires a fixed HTTPS page URL");
|
|
347
|
+
return {
|
|
348
|
+
annotations: {
|
|
349
|
+
readOnlyHint: true,
|
|
350
|
+
destructiveHint: false,
|
|
351
|
+
openWorldHint: true
|
|
352
|
+
},
|
|
353
|
+
commerce: {
|
|
354
|
+
action: "external_checkout",
|
|
355
|
+
categories: ["usage_credits", "subscription"]
|
|
356
|
+
},
|
|
357
|
+
description: "Open the service's authenticated billing page to buy credits, review receipts, or manage an existing subscription. Uses a matching browser login; may require sign-in. This link does not grant a login session or authorize any payment.",
|
|
358
|
+
inputSchema: {
|
|
359
|
+
type: "object",
|
|
360
|
+
properties: {},
|
|
361
|
+
additionalProperties: false
|
|
362
|
+
},
|
|
363
|
+
handler: async (input) => {
|
|
364
|
+
empty(input);
|
|
365
|
+
return result(`Manage billing on ${url.hostname}: ${url.href}. Sign in if needed; changes require your confirmation.`, { url: url.href, requiresBrowserAuthentication: true });
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
};
|
|
148
369
|
|
|
149
370
|
// src/commerce.ts
|
|
150
371
|
var COMMERCE_POLICY_VERSION = "2026-09-10.1";
|
|
@@ -254,6 +475,8 @@ var evaluateCommerce = (req, context, now = new Date) => {
|
|
|
254
475
|
export {
|
|
255
476
|
COMMERCE_POLICY_SOURCES,
|
|
256
477
|
COMMERCE_POLICY_VERSION,
|
|
478
|
+
createBillingManagementTool,
|
|
479
|
+
createBillingReportTools,
|
|
257
480
|
createCheckoutHandoffTool,
|
|
258
481
|
createCreditBalanceTool,
|
|
259
482
|
createPurchaseStatusTool,
|