@absolutejs/mcp 0.22.0 → 0.24.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 +12 -0
- package/README.md +44 -0
- package/changelog.json +23 -0
- package/dist/index.js +81 -0
- package/dist/src/backgroundWork.d.ts +21 -0
- package/dist/src/creditWorkResult.d.ts +13 -0
- package/dist/src/index.d.ts +3 -1
- package/package.json +1 -1
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.24.0 — 2026-09-13
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Add durable background work launch and read-only recovery tools with matching text and structured progress.**
|
|
14
|
+
|
|
15
|
+
## 0.23.0 — 2026-09-13
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Preserve saved credit work results in identical text and structured host responses** (`createCreditWorkResult`)
|
|
20
|
+
|
|
9
21
|
## 0.22.0 — 2026-09-13
|
|
10
22
|
|
|
11
23
|
### Added
|
package/README.md
CHANGED
|
@@ -437,3 +437,47 @@ on the Change Date.
|
|
|
437
437
|
## Interactive MCP Apps
|
|
438
438
|
|
|
439
439
|
`createBillingApps()` adds reusable read-only credit, usage and receipt views with the official browser SDK. Apps capability negotiation, guarded resources and text fallbacks live in the package. See [MCP Apps](docs/mcp-apps.md) for integration, session migration, CSP restrictions and host validation boundaries.
|
|
440
|
+
|
|
441
|
+
### Saved credit-work results
|
|
442
|
+
|
|
443
|
+
Use `createCreditWorkResult(requestId, work)` for initial completion, duplicate
|
|
444
|
+
requests and read-only recovery. Pass the account-bound saved `budget`, `charged`,
|
|
445
|
+
`status` and `result`; extra database fields are not projected. Both MCP `content`
|
|
446
|
+
and `structuredContent` carry the same JSON envelope:
|
|
447
|
+
|
|
448
|
+
```json
|
|
449
|
+
{
|
|
450
|
+
"requestId": "proposal-1",
|
|
451
|
+
"status": "completed",
|
|
452
|
+
"maxCredits": 1,
|
|
453
|
+
"creditsCharged": 0,
|
|
454
|
+
"result": { "actionId": "action-1", "status": "proposed" }
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Read the tool outcome under `result`; the outer `status` describes credit work,
|
|
459
|
+
not action approval or delivery. Saved JSON is decoded once; plain text remains
|
|
460
|
+
a string, and serialized MCP results remain nested without discarding content.
|
|
461
|
+
The formatter never retries work. A missing saved result carries a same-ID polling
|
|
462
|
+
instruction. Bind account identity and authorization before retrieving the saved
|
|
463
|
+
work; this helper does not authorize access or filter the tool's saved payload.
|
|
464
|
+
|
|
465
|
+
## Budgeted background work
|
|
466
|
+
|
|
467
|
+
`createBackgroundWorkTools({ description, inputSchema, start, read })` exposes
|
|
468
|
+
`start_background_work` with a stable requestId and maximum service credits, plus
|
|
469
|
+
read-only `get_background_work` recovery. Omit `start` to support recovery at zero
|
|
470
|
+
credits or while rollout is disabled. Account ownership must come from the
|
|
471
|
+
authenticated caller, never tool arguments.
|
|
472
|
+
|
|
473
|
+
The start adapter must atomically reserve credits, bind immutable work and enqueue
|
|
474
|
+
a durable job; duplicate IDs must return existing work and reject changed input or
|
|
475
|
+
budget. The read adapter returns public results and accounting only, without
|
|
476
|
+
starting, settling or retrying work. `createBackgroundWorkResult` projects the
|
|
477
|
+
same progress, results and spend in text and structured content for broad host
|
|
478
|
+
support. In uncertain states, retain the reservation and do not create a new ID
|
|
479
|
+
to repeat work.
|
|
480
|
+
|
|
481
|
+
Start is classified as `paid_access`; recovery is `entitlement_status`. Existing
|
|
482
|
+
commerce host reviews and account/client restrictions still apply. These tools
|
|
483
|
+
do not enable embedded checkout or override any host's commerce rules.
|
package/changelog.json
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
"contract": 1,
|
|
3
3
|
"name": "@absolutejs/mcp",
|
|
4
4
|
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "added",
|
|
9
|
+
"summary": "Add durable background work launch and read-only recovery tools with matching text and structured progress."
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"date": "2026-09-13",
|
|
13
|
+
"version": "0.24.0"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"changes": [
|
|
17
|
+
{
|
|
18
|
+
"kind": "added",
|
|
19
|
+
"summary": "Preserve saved credit work results in identical text and structured host responses",
|
|
20
|
+
"symbols": [
|
|
21
|
+
"createCreditWorkResult"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"date": "2026-09-13",
|
|
26
|
+
"version": "0.23.0"
|
|
27
|
+
},
|
|
5
28
|
{
|
|
6
29
|
"changes": [
|
|
7
30
|
{
|
package/dist/index.js
CHANGED
|
@@ -2853,6 +2853,84 @@ Provide a stable requestId and the maximum service credits this work may charge.
|
|
|
2853
2853
|
}
|
|
2854
2854
|
};
|
|
2855
2855
|
};
|
|
2856
|
+
// src/creditWorkResult.ts
|
|
2857
|
+
var savedResult = (value) => {
|
|
2858
|
+
if (value === null)
|
|
2859
|
+
return null;
|
|
2860
|
+
try {
|
|
2861
|
+
return JSON.parse(value);
|
|
2862
|
+
} catch {
|
|
2863
|
+
return value;
|
|
2864
|
+
}
|
|
2865
|
+
};
|
|
2866
|
+
var createCreditWorkResult = (requestId, work) => {
|
|
2867
|
+
if (typeof requestId !== "string" || !requestId || requestId.length > 128 || !Number.isSafeInteger(work.budget) || work.budget < 0 || !Number.isSafeInteger(work.charged) || work.charged < 0 || work.charged > work.budget || !["running", "completed", "failed"].includes(work.status) || work.result !== null && typeof work.result !== "string")
|
|
2868
|
+
throw new Error("Invalid saved credit work");
|
|
2869
|
+
const summary = {
|
|
2870
|
+
requestId,
|
|
2871
|
+
status: work.status,
|
|
2872
|
+
maxCredits: work.budget,
|
|
2873
|
+
creditsCharged: work.charged,
|
|
2874
|
+
result: savedResult(work.result),
|
|
2875
|
+
...work.result === null ? {
|
|
2876
|
+
message: "No saved result is available. Poll get_credit_work with the same requestId; do not restart it with a new ID."
|
|
2877
|
+
} : {}
|
|
2878
|
+
};
|
|
2879
|
+
return {
|
|
2880
|
+
content: [{ type: "text", text: JSON.stringify(summary) }],
|
|
2881
|
+
structuredContent: summary,
|
|
2882
|
+
isError: work.status === "failed"
|
|
2883
|
+
};
|
|
2884
|
+
};
|
|
2885
|
+
// src/backgroundWork.ts
|
|
2886
|
+
var createBackgroundWorkResult = (requestId, work) => {
|
|
2887
|
+
if (!requestId || requestId.length > 128 || !Number.isSafeInteger(work.budget) || work.budget < 1 || !Number.isSafeInteger(work.charged) || work.charged < 0 || work.charged > work.budget || !Number.isSafeInteger(work.totalSteps) || work.totalSteps < 1 || !Array.isArray(work.results) || work.results.length > work.totalSteps || typeof work.settled !== "boolean" || !["queued", "running", "completed", "stopped", "failed", "unknown"].includes(work.status))
|
|
2888
|
+
throw new Error("Invalid background work snapshot");
|
|
2889
|
+
const summary = {
|
|
2890
|
+
requestId,
|
|
2891
|
+
status: work.status,
|
|
2892
|
+
maxCredits: work.budget,
|
|
2893
|
+
creditsCharged: work.charged,
|
|
2894
|
+
settled: work.settled,
|
|
2895
|
+
totalSteps: work.totalSteps,
|
|
2896
|
+
completedSteps: work.results.length,
|
|
2897
|
+
results: work.results,
|
|
2898
|
+
message: work.status === "unknown" ? "A step has an uncertain outcome. Saved results remain available; credits stay held pending reconciliation. Do not start another job to retry it." : "Read get_background_work with this requestId to recover saved progress and spend. Reading never starts or repeats work."
|
|
2899
|
+
};
|
|
2900
|
+
return { content: [{ type: "text", text: JSON.stringify(summary) }], structuredContent: summary, isError: work.status === "failed" || work.status === "unknown" };
|
|
2901
|
+
};
|
|
2902
|
+
var createBackgroundWorkTools = (options) => {
|
|
2903
|
+
const tools = {
|
|
2904
|
+
get_background_work: {
|
|
2905
|
+
description: "Recover this account's saved background work, partial results and credit spend. Read-only; available without credits. Never restarts a provider call.",
|
|
2906
|
+
annotations: { readOnlyHint: true },
|
|
2907
|
+
commerce: { action: "entitlement_status", categories: ["usage_credits"] },
|
|
2908
|
+
inputSchema: { type: "object", additionalProperties: false, required: ["requestId"], properties: { requestId: { type: "string", minLength: 1, maxLength: 128 } } },
|
|
2909
|
+
handler: async (args) => {
|
|
2910
|
+
const requestId = args && typeof args === "object" && !Array.isArray(args) ? Reflect.get(args, "requestId") : undefined;
|
|
2911
|
+
if (typeof requestId !== "string" || !requestId || requestId.length > 128)
|
|
2912
|
+
throw new Error("A request ID is required");
|
|
2913
|
+
const work = await options.read(requestId);
|
|
2914
|
+
if (!work)
|
|
2915
|
+
return { content: [{ type: "text", text: "No background work found for this account and request ID." }], isError: true };
|
|
2916
|
+
return createBackgroundWorkResult(requestId, work);
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
};
|
|
2920
|
+
const start = options.start;
|
|
2921
|
+
if (start)
|
|
2922
|
+
tools.start_background_work = budgetedMcpTool({
|
|
2923
|
+
tool: {
|
|
2924
|
+
description: `${options.description} Launch bounded background work only after the user agrees to the plan and maximum credits. Return the requestId promptly; poll get_background_work for progress.`,
|
|
2925
|
+
inputSchema: options.inputSchema,
|
|
2926
|
+
handler: async () => {
|
|
2927
|
+
throw new Error("Background work must use durable dispatch");
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
execute: async (request) => createBackgroundWorkResult(request.requestId, await start(request))
|
|
2931
|
+
});
|
|
2932
|
+
return tools;
|
|
2933
|
+
};
|
|
2856
2934
|
export {
|
|
2857
2935
|
COMMERCE_POLICY_SOURCES,
|
|
2858
2936
|
COMMERCE_POLICY_VERSION,
|
|
@@ -2863,11 +2941,14 @@ export {
|
|
|
2863
2941
|
budgetedMcpTool,
|
|
2864
2942
|
clientSupportsMcpApps,
|
|
2865
2943
|
createActionWorkflowTools,
|
|
2944
|
+
createBackgroundWorkResult,
|
|
2945
|
+
createBackgroundWorkTools,
|
|
2866
2946
|
createBillingApps,
|
|
2867
2947
|
createBillingManagementTool,
|
|
2868
2948
|
createBillingReportTools,
|
|
2869
2949
|
createCheckoutHandoffTool,
|
|
2870
2950
|
createCreditBalanceTool,
|
|
2951
|
+
createCreditWorkResult,
|
|
2871
2952
|
createMcpAuthorizationRequest,
|
|
2872
2953
|
createMcpClient,
|
|
2873
2954
|
createMcpHandler,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type McpCreditWorkRequest } from "./budgetedTool";
|
|
2
|
+
import type { McpTool, McpToolRegistry, McpToolResult } from "./types";
|
|
3
|
+
/** Public output only. Adapters must scope reads to the authenticated account. */
|
|
4
|
+
export type McpBackgroundWorkSnapshot = {
|
|
5
|
+
status: "queued" | "running" | "completed" | "stopped" | "failed" | "unknown";
|
|
6
|
+
budget: number;
|
|
7
|
+
charged: number;
|
|
8
|
+
settled: boolean;
|
|
9
|
+
totalSteps: number;
|
|
10
|
+
results: unknown[];
|
|
11
|
+
};
|
|
12
|
+
export declare const createBackgroundWorkResult: (requestId: string, work: McpBackgroundWorkSnapshot) => McpToolResult;
|
|
13
|
+
/** Durable dispatch is the adapter's responsibility: atomically reserve, bind
|
|
14
|
+
* and enqueue before returning. Start must deduplicate exact IDs/input/budget.
|
|
15
|
+
* Omit start to expose account recovery without allowing new paid work. */
|
|
16
|
+
export declare const createBackgroundWorkTools: (options: {
|
|
17
|
+
description: string;
|
|
18
|
+
inputSchema: McpTool["inputSchema"];
|
|
19
|
+
start?: (request: McpCreditWorkRequest) => Promise<McpBackgroundWorkSnapshot>;
|
|
20
|
+
read: (requestId: string) => Promise<McpBackgroundWorkSnapshot | null>;
|
|
21
|
+
}) => McpToolRegistry;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { McpToolResult } from "./types";
|
|
2
|
+
/** Public projection of account-bound, persisted work. Never pass an unfiltered
|
|
3
|
+
* database row or provider response as the saved result. */
|
|
4
|
+
export type McpCreditWorkSnapshot = {
|
|
5
|
+
budget: number;
|
|
6
|
+
charged: number;
|
|
7
|
+
status: "running" | "completed" | "failed";
|
|
8
|
+
result: string | null;
|
|
9
|
+
};
|
|
10
|
+
/** Keep text-only and structured-only hosts on the same result contract. This
|
|
11
|
+
* pure formatter never starts, retries, approves, or settles work. Use it for
|
|
12
|
+
* initial completion, duplicate requests, and read-only recovery alike. */
|
|
13
|
+
export declare const createCreditWorkResult: (requestId: string, work: McpCreditWorkSnapshot) => McpToolResult;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -52,4 +52,6 @@ export { createBillingApps } from "./billingApps";
|
|
|
52
52
|
export { createWorkflowApps } from "./workflowApps";
|
|
53
53
|
export { createWorkflowTools, projectSetupStatus, projectWorkPreview, type McpSetupStatus, type McpWorkPreview, type McpWorkPreviewRequest, } from "./workflowTools";
|
|
54
54
|
export { createSetupSelectionTools, projectSetupSelection, type SetupSelection, type SetupConfirmation, type SetupOption, } from "./setupSelection";
|
|
55
|
-
export { createActionWorkflowTools, projectActionReview, projectActionJob, type ActionReview, type ActionConfirmation, type ActionJob } from "./actionWorkflow";
|
|
55
|
+
export { createActionWorkflowTools, projectActionReview, projectActionJob, type ActionReview, type ActionConfirmation, type ActionJob, } from "./actionWorkflow";
|
|
56
|
+
export { createCreditWorkResult, type McpCreditWorkSnapshot, } from "./creditWorkResult";
|
|
57
|
+
export { createBackgroundWorkTools, createBackgroundWorkResult, type McpBackgroundWorkSnapshot } from "./backgroundWork";
|
package/package.json
CHANGED