@absolutejs/mcp 0.17.6 → 0.17.7
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 +6 -0
- package/canary/checkout.ts +198 -0
- package/canary/results/vscode-checkout-2026-09-12.json +28 -0
- package/changelog.json +169 -159
- package/docs/commerce-host-rules.md +13 -0
- package/docs/host-canaries.md +59 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@ 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.17.7 — 2026-09-12
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Ship a synthetic external-checkout host canary with expiring links, explicit approval and purchase-status checks**
|
|
14
|
+
|
|
9
15
|
## 0.17.6 — 2026-09-11
|
|
10
16
|
|
|
11
17
|
### Added
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/** Synthetic external-checkout fixture. No accounts, card inputs or gateway. */
|
|
2
|
+
import {
|
|
3
|
+
createCheckoutHandoffTool,
|
|
4
|
+
createMcpHandler,
|
|
5
|
+
createPurchaseStatusTool,
|
|
6
|
+
} from "@absolutejs/mcp";
|
|
7
|
+
|
|
8
|
+
export function createCheckoutCanary(origin: string, now = () => Date.now()) {
|
|
9
|
+
const publicUrl = new URL(origin);
|
|
10
|
+
if (publicUrl.protocol !== "https:" || publicUrl.origin !== origin)
|
|
11
|
+
throw Error("Provide an exact HTTPS checkout origin");
|
|
12
|
+
const purchases = new Map<
|
|
13
|
+
string,
|
|
14
|
+
{ token: string; expires: number; approved: boolean }
|
|
15
|
+
>();
|
|
16
|
+
const started = now();
|
|
17
|
+
const checkout = createCheckoutHandoffTool({
|
|
18
|
+
origin,
|
|
19
|
+
issue: async (productId) => {
|
|
20
|
+
if (productId !== "synthetic-1000")
|
|
21
|
+
throw Error("Only synthetic-1000 is supported");
|
|
22
|
+
if (purchases.size >= 100)
|
|
23
|
+
throw Error("Restart the canary before creating more fixtures");
|
|
24
|
+
const purchaseId = crypto.randomUUID();
|
|
25
|
+
const token = crypto.randomUUID();
|
|
26
|
+
const expires = now() + 15 * 60_000;
|
|
27
|
+
purchases.set(purchaseId, { token, expires, approved: false });
|
|
28
|
+
return {
|
|
29
|
+
purchaseId,
|
|
30
|
+
url: `${origin}/checkout#${purchaseId}/${token}`,
|
|
31
|
+
expiresAt: new Date(expires).toISOString(),
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const status = createPurchaseStatusTool({
|
|
36
|
+
read: async (purchaseId) => {
|
|
37
|
+
const purchase = purchases.get(purchaseId);
|
|
38
|
+
return purchase
|
|
39
|
+
? {
|
|
40
|
+
purchaseId,
|
|
41
|
+
status: purchase.approved ? "approved" : "not_started",
|
|
42
|
+
creditsGranted: purchase.approved ? 1000 : 0,
|
|
43
|
+
}
|
|
44
|
+
: null;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
const handler = createMcpHandler({
|
|
48
|
+
issuer: "http://127.0.0.1:4428",
|
|
49
|
+
path: "/mcp",
|
|
50
|
+
serverInfo: { name: "absolute-checkout-canary", version: "1" },
|
|
51
|
+
authorize: async () => ({
|
|
52
|
+
ok: true,
|
|
53
|
+
caller: "synthetic-fixture",
|
|
54
|
+
scopes: [],
|
|
55
|
+
}),
|
|
56
|
+
// This review authorizes only this synthetic developer fixture. Never reuse
|
|
57
|
+
// it for a real merchant or infer a commerce binding from clientInfo.
|
|
58
|
+
commerce: () => ({
|
|
59
|
+
profiles: ["direct-mcp"],
|
|
60
|
+
capabilities: { externalLinks: true },
|
|
61
|
+
reviews: [
|
|
62
|
+
{
|
|
63
|
+
id: "operator-synthetic-checkout-canary",
|
|
64
|
+
profile: "direct-mcp",
|
|
65
|
+
actions: ["external_checkout"],
|
|
66
|
+
categories: ["usage_credits"],
|
|
67
|
+
reviewedAt: new Date(started).toISOString(),
|
|
68
|
+
expiresAt: new Date(started + 60 * 60_000).toISOString(),
|
|
69
|
+
sourceUrls: ["https://code.visualstudio.com/license"],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
}),
|
|
73
|
+
tools: () => ({
|
|
74
|
+
prepare_test_checkout: {
|
|
75
|
+
...checkout,
|
|
76
|
+
description: `SYNTHETIC TEST ONLY. Use productId synthetic-1000. ${checkout.description}`,
|
|
77
|
+
},
|
|
78
|
+
get_test_purchase_status: status,
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
const headers = {
|
|
82
|
+
"content-type": "text/html; charset=utf-8",
|
|
83
|
+
"cache-control": "no-store",
|
|
84
|
+
"referrer-policy": "no-referrer",
|
|
85
|
+
"x-content-type-options": "nosniff",
|
|
86
|
+
"content-security-policy":
|
|
87
|
+
"default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'",
|
|
88
|
+
};
|
|
89
|
+
const page = `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>MCP checkout test</title><style>:root{color-scheme:light dark;font:18px system-ui}body{max-width:40rem;margin:10vh auto;padding:2rem}button{padding:1rem;font:inherit}strong{display:block;margin:1rem 0}</style><h1>MCP checkout test</h1><p>Synthetic developer fixture. No real payment, card information, account or subscription.</p><strong>1,000 simulated credits · $0 charged</strong><p id="status" role="status">Checking test link…</p><button id="approve" disabled>Simulate approval</button><script>
|
|
90
|
+
const capability=location.hash.slice(1);history.replaceState(null,'','/checkout');const status=document.getElementById('status'),button=document.getElementById('approve');
|
|
91
|
+
async function update(action){button.disabled=true;try{const r=await fetch('/state',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({capability,action})});if(!r.ok)throw Error('This test link is invalid or expired.');const value=await r.json();status.textContent=value.approved?'Approved — 1,000 simulated credits. Return to your assistant and check purchase status.':'Ready. Opening this page has not approved anything.';button.hidden=value.approved;button.disabled=value.approved;}catch(e){status.textContent=e.message;}}
|
|
92
|
+
button.addEventListener('click',()=>update('approve'));update('read');</script></html>`;
|
|
93
|
+
return {
|
|
94
|
+
mcp: handler,
|
|
95
|
+
checkout: async (request: Request): Promise<Response> => {
|
|
96
|
+
const url = new URL(request.url);
|
|
97
|
+
if (url.pathname === "/checkout" && request.method === "GET")
|
|
98
|
+
return new Response(page, { headers });
|
|
99
|
+
if (url.pathname !== "/state" || request.method !== "POST")
|
|
100
|
+
return new Response("Not found", { status: 404 });
|
|
101
|
+
if (
|
|
102
|
+
request.headers.get("origin") !== origin ||
|
|
103
|
+
!request.headers.get("content-type")?.startsWith("application/json")
|
|
104
|
+
)
|
|
105
|
+
return new Response("Forbidden", { status: 403 });
|
|
106
|
+
const raw = await request.text();
|
|
107
|
+
if (raw.length > 1024) return new Response("Too large", { status: 413 });
|
|
108
|
+
let input;
|
|
109
|
+
try {
|
|
110
|
+
input = JSON.parse(raw);
|
|
111
|
+
} catch {
|
|
112
|
+
return new Response("Invalid JSON", { status: 400 });
|
|
113
|
+
}
|
|
114
|
+
if (
|
|
115
|
+
!input ||
|
|
116
|
+
typeof input.capability !== "string" ||
|
|
117
|
+
!["read", "approve"].includes(input.action)
|
|
118
|
+
)
|
|
119
|
+
return new Response("Invalid request", { status: 400 });
|
|
120
|
+
const [id, token, extra] = input.capability.split("/");
|
|
121
|
+
const purchase = purchases.get(id);
|
|
122
|
+
if (
|
|
123
|
+
extra !== undefined ||
|
|
124
|
+
!purchase ||
|
|
125
|
+
purchase.token !== token ||
|
|
126
|
+
purchase.expires <= now()
|
|
127
|
+
)
|
|
128
|
+
return new Response("Invalid or expired test link", { status: 404 });
|
|
129
|
+
if (input.action === "approve") purchase.approved = true;
|
|
130
|
+
return Response.json(
|
|
131
|
+
{ approved: purchase.approved },
|
|
132
|
+
{ headers: { "cache-control": "no-store" } },
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (import.meta.main) {
|
|
139
|
+
const fixture = createCheckoutCanary(
|
|
140
|
+
process.env.CANARY_CHECKOUT_ORIGIN ?? "",
|
|
141
|
+
);
|
|
142
|
+
Bun.serve({
|
|
143
|
+
hostname: "127.0.0.1",
|
|
144
|
+
port: 4438,
|
|
145
|
+
fetch: async (request) => {
|
|
146
|
+
const response = await fixture.checkout(request);
|
|
147
|
+
const path = new URL(request.url).pathname;
|
|
148
|
+
console.log(
|
|
149
|
+
JSON.stringify({
|
|
150
|
+
surface: "checkout",
|
|
151
|
+
method: request.method,
|
|
152
|
+
route: path === "/checkout" || path === "/state" ? path : "unknown",
|
|
153
|
+
status: response.status,
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
return response;
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
Bun.serve({
|
|
160
|
+
hostname: "127.0.0.1",
|
|
161
|
+
port: 4428,
|
|
162
|
+
fetch: async (request) => {
|
|
163
|
+
let rpc;
|
|
164
|
+
try {
|
|
165
|
+
if (request.method === "POST") rpc = await request.clone().json();
|
|
166
|
+
} catch {
|
|
167
|
+
/* handler validates */
|
|
168
|
+
}
|
|
169
|
+
const response =
|
|
170
|
+
(await fixture.mcp(request)) ??
|
|
171
|
+
new Response("Not found", { status: 404 });
|
|
172
|
+
// Never log checkout capabilities, arguments, transcripts or auth headers.
|
|
173
|
+
console.log(
|
|
174
|
+
JSON.stringify({
|
|
175
|
+
method: rpc?.method ?? request.method,
|
|
176
|
+
status: response.status,
|
|
177
|
+
...(rpc?.method === "initialize"
|
|
178
|
+
? {
|
|
179
|
+
client: rpc.params?.clientInfo?.name,
|
|
180
|
+
version: rpc.params?.clientInfo?.version,
|
|
181
|
+
}
|
|
182
|
+
: {}),
|
|
183
|
+
...(rpc?.method === "tools/call" ? { tool: rpc.params?.name } : {}),
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
186
|
+
return response;
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
console.log(
|
|
190
|
+
JSON.stringify({
|
|
191
|
+
ready: true,
|
|
192
|
+
mcp: "http://127.0.0.1:4428/mcp",
|
|
193
|
+
checkoutPort: 4438,
|
|
194
|
+
synthetic: true,
|
|
195
|
+
payments: false,
|
|
196
|
+
}),
|
|
197
|
+
);
|
|
198
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"host": "Visual Studio Code",
|
|
3
|
+
"version": "1.135.0",
|
|
4
|
+
"surface": "native Windows Copilot chat, directly configured loopback MCP",
|
|
5
|
+
"fixture": "canary/checkout.ts",
|
|
6
|
+
"date": "2026-09-12",
|
|
7
|
+
"synthetic": true,
|
|
8
|
+
"realPayments": false,
|
|
9
|
+
"results": {
|
|
10
|
+
"discoversBothTools": true,
|
|
11
|
+
"linkCreationApprovalVisible": true,
|
|
12
|
+
"toolResultReviewVisible": true,
|
|
13
|
+
"clickableMarkdownAnchor": true,
|
|
14
|
+
"nativeAnchorLaunch": "unverified: mouse and keyboard activation did not produce a measured checkout request",
|
|
15
|
+
"windowsHttpsHandlerOpensReturnedUrl": true,
|
|
16
|
+
"nativeChromeCheckoutPage": true,
|
|
17
|
+
"fragmentRemovedAfterLoad": true,
|
|
18
|
+
"beforeBrowserApproval": { "status": "not_started", "creditsGranted": 0 },
|
|
19
|
+
"afterBrowserApproval": { "status": "approved", "creditsGranted": 1000 },
|
|
20
|
+
"repeatedRead": { "status": "approved", "creditsGranted": 1000 }
|
|
21
|
+
},
|
|
22
|
+
"limits": [
|
|
23
|
+
"Native link launch remains a host-canary gate; no one-click end-to-end claim.",
|
|
24
|
+
"Browser state assertions used a second visible Chrome profile after explicit navigation to the returned URL.",
|
|
25
|
+
"No OAuth, real gateway, rich payment UI, real sales approval or marketplace distribution certified.",
|
|
26
|
+
"No checkout capability, purchase ID, card data or account credentials included."
|
|
27
|
+
]
|
|
28
|
+
}
|
package/changelog.json
CHANGED
|
@@ -1,161 +1,171 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
2
|
+
"contract": 1,
|
|
3
|
+
"name": "@absolutejs/mcp",
|
|
4
|
+
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"kind": "added",
|
|
9
|
+
"summary": "Ship a synthetic external-checkout host canary with expiring links, explicit approval and purchase-status checks"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"date": "2026-09-12",
|
|
13
|
+
"version": "0.17.7"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"changes": [
|
|
17
|
+
{
|
|
18
|
+
"kind": "fixed",
|
|
19
|
+
"summary": "Use text and structured report results on affected VS Code builds while their upstream webview startup race remains unresolved"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"kind": "added",
|
|
23
|
+
"summary": "Allow verified patched hosts through the version fallback with optional Apps configuration",
|
|
24
|
+
"symbols": [
|
|
25
|
+
"clientSupportsMcpApps",
|
|
26
|
+
"McpAppsConfig"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"date": "2026-09-11",
|
|
31
|
+
"version": "0.17.6"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"changes": [
|
|
35
|
+
{
|
|
36
|
+
"kind": "added",
|
|
37
|
+
"summary": "Distribute a verified VS Code webview startup-race source patch and actual-method regression checker, with explicit upstream delivery requirements"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"date": "2026-09-11",
|
|
41
|
+
"version": "0.17.5"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"changes": [
|
|
45
|
+
{
|
|
46
|
+
"kind": "added",
|
|
47
|
+
"summary": "Ship an authenticated two-account staging canary for read isolation, credential rejection and session reconnect with private credentials and aggregate-only results"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"date": "2026-09-11",
|
|
51
|
+
"version": "0.17.4"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"changes": [
|
|
55
|
+
{
|
|
56
|
+
"kind": "fixed",
|
|
57
|
+
"summary": "Authorize session deletion, recover explicit client initialization after expiry, and preserve typed HTTP failures without replaying tools"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"kind": "fixed",
|
|
61
|
+
"summary": "Accept the standard protocol-header compatibility fallback used by VS Code Copilot and record native report rendering evidence"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"date": "2026-09-11",
|
|
65
|
+
"version": "0.17.3"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"changes": [
|
|
69
|
+
{
|
|
70
|
+
"kind": "added",
|
|
71
|
+
"summary": "Record verified Claude web rendering, refresh, pagination and narrow-viewport host canary evidence"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"date": "2026-09-11",
|
|
75
|
+
"version": "0.17.2"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"changes": [
|
|
79
|
+
{
|
|
80
|
+
"kind": "added",
|
|
81
|
+
"summary": "Ship a preflight-validated synthetic host canary and record Claude Code and Codex terminal interoperability evidence"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"date": "2026-09-11",
|
|
85
|
+
"version": "0.17.1"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"changes": [
|
|
89
|
+
{
|
|
90
|
+
"kind": "added",
|
|
91
|
+
"summary": "Negotiate MCP Apps with persisted capabilities, guarded offline UI resources and reusable SDK-backed billing views"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"kind": "added",
|
|
95
|
+
"summary": "Preserve remote UI metadata in the client and expose immutable PostgreSQL migration entries"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"kind": "changed",
|
|
99
|
+
"summary": "Extend McpClientOptions, McpRemoteTool, createSessionRegistry, McpSessionStore, McpServerConfig, McpTool and McpToolResult with optional Apps capability and metadata fields; existing text-only callers remain supported",
|
|
100
|
+
"symbols": [
|
|
101
|
+
"McpClientOptions",
|
|
102
|
+
"McpRemoteTool",
|
|
103
|
+
"createSessionRegistry",
|
|
104
|
+
"McpSessionStore",
|
|
105
|
+
"McpServerConfig",
|
|
106
|
+
"McpTool",
|
|
107
|
+
"McpToolResult"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"date": "2026-09-11",
|
|
112
|
+
"version": "0.17.0"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"changes": [
|
|
116
|
+
{
|
|
117
|
+
"kind": "added",
|
|
118
|
+
"summary": "Add account-bound billing status, paginated receipts, bounded usage and reviewed billing-management links"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"date": "2026-09-11",
|
|
122
|
+
"version": "0.16.0"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"changes": [
|
|
126
|
+
{
|
|
127
|
+
"kind": "fixed",
|
|
128
|
+
"summary": "Build and test before publishing so checkout exports are present in the distributed artifact"
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
"date": "2026-09-11",
|
|
132
|
+
"version": "0.15.1"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"changes": [
|
|
136
|
+
{
|
|
137
|
+
"kind": "added",
|
|
138
|
+
"summary": "Add commerce-classified account-bound checkout handoff and purchase status tools"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"date": "2026-09-11",
|
|
142
|
+
"version": "0.15.0"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"changes": [
|
|
146
|
+
{
|
|
147
|
+
"kind": "added",
|
|
148
|
+
"summary": "Add explicit credit-budget envelopes for durable prepaid MCP work"
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"date": "2026-09-11",
|
|
152
|
+
"version": "0.14.0"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"changes": [
|
|
156
|
+
{
|
|
157
|
+
"kind": "added",
|
|
158
|
+
"summary": "Add reviewed host commerce eligibility, execution guards, and reusable credit status tools",
|
|
159
|
+
"symbols": [
|
|
160
|
+
"McpServerConfig",
|
|
161
|
+
"McpTool",
|
|
162
|
+
"evaluateCommerce",
|
|
163
|
+
"createCreditBalanceTool"
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
],
|
|
167
|
+
"date": "2026-09-11",
|
|
168
|
+
"version": "0.13.0"
|
|
169
|
+
}
|
|
170
|
+
]
|
|
161
171
|
}
|
|
@@ -264,3 +264,16 @@ The first slice exports `evaluateCommerce` through `@absolutejs/mcp/commerce`, a
|
|
|
264
264
|
The bundled rules cover the explicit restrictions established above; the broad host inventory currently maps to reviewed direct/self-hosted or unknown profiles rather than claiming every host has been verified. Missing policy, malformed categories, ambiguous restrictions, expired reviews and unavailable capabilities block the action. Deployment reviews cannot override bundled restrictions.
|
|
265
265
|
|
|
266
266
|
This slice is not a general content filter: prompts, resources, untagged tools and arbitrary returned links require the shared evaluator at their own presentation boundaries. Shared renderers, native capability plumbing, checkout sessions, prepaid accounting changes and live cross-host conformance remain to implement. Existing Agency enforcement remains independent.
|
|
267
|
+
|
|
268
|
+
## September 12 follow-up: native VS Code developer checkout test
|
|
269
|
+
|
|
270
|
+
The directly configured VS Code/Copilot channel now has a package-owned
|
|
271
|
+
[synthetic checkout canary](host-canaries.md#synthetic-external-checkout-canary).
|
|
272
|
+
This is an application development test within VS Code license §1, with no real
|
|
273
|
+
merchant, card input, funds or credits. It does not change the `direct-mcp`
|
|
274
|
+
production default, approve Marketplace distribution, or establish permission
|
|
275
|
+
for live sales under every Copilot agreement. Check the actual account's terms:
|
|
276
|
+
individual Copilot uses GitHub ToS §J; volume licensing has separate current
|
|
277
|
+
Generative AI Services Terms. The old Copilot product-specific terms are archived.
|
|
278
|
+
The linked canary record preserves the exact native host result independently
|
|
279
|
+
of commercial eligibility. Existing Claude and ChatGPT restrictions still apply.
|
package/docs/host-canaries.md
CHANGED
|
@@ -103,3 +103,62 @@ MCP 0.17.5 includes `canary/vscode/README.md`, a VS Code source patch and an exe
|
|
|
103
103
|
The issue is tracked in [microsoft/vscode#335908](https://github.com/microsoft/vscode/issues/335908). Known affected versions now receive text and structured reports on new sessions, keeping tools usable without invoking the faulty webview path. Other hosts retain their negotiated presentation. See [UPSTREAM_ISSUES.md](../UPSTREAM_ISSUES.md) for scope and removal conditions. This workaround does not certify rich rendering on affected editors.
|
|
104
104
|
|
|
105
105
|
Native Windows VS Code 1.135.0 verification: after removing the in-memory editor patch, reconnecting alone left cached UI metadata and produced resource errors. Running **MCP: Reset Cached Tools**, reloading the window and opening a new chat cleared it. The final run returned all three reports as visible text, with three successful tool calls, no resource reads and no App frames. This is a verified text fallback, not rich rendering evidence.
|
|
106
|
+
|
|
107
|
+
## Synthetic external-checkout canary
|
|
108
|
+
|
|
109
|
+
`bun run canary:checkout` (installed: `bun node_modules/@absolutejs/mcp/canary/checkout.ts`)
|
|
110
|
+
uses the package's real checkout handoff and purchase-status tools with in-memory
|
|
111
|
+
synthetic purchases. Set `CANARY_CHECKOUT_ORIGIN` to the exact HTTPS origin of a
|
|
112
|
+
temporary reverse proxy to loopback port 4438. Connect the desktop test host only
|
|
113
|
+
to `http://127.0.0.1:4428/mcp`. Expose only port 4438 through the proxy; it serves
|
|
114
|
+
only the fixture page/state routes, never MCP. Stop both processes after testing.
|
|
115
|
+
No account database, payment provider, card input or real credit ledger is used.
|
|
116
|
+
Do not mount either handler in a customer application.
|
|
117
|
+
|
|
118
|
+
This is an operator-authorized development test, not a live commerce approval.
|
|
119
|
+
The fixture's one-hour, server-owned review applies only to synthetic links;
|
|
120
|
+
never copy it into a production commerce binding. VS Code's [license §1](https://code.visualstudio.com/license)
|
|
121
|
+
permits application development/testing. GitHub's [additional product terms](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot)
|
|
122
|
+
point individual Copilot users to ToS §J and business users to their applicable
|
|
123
|
+
agreement. The older Copilot product terms are archived; current volume purchases
|
|
124
|
+
may instead use the [March 2026 Generative AI Services Terms](https://github.com/customer-terms/github-generative-ai-services-terms).
|
|
125
|
+
Do not treat an old agreement, another product's marketplace rules, or this
|
|
126
|
+
technical test as approval for every Copilot account or live digital sales.
|
|
127
|
+
|
|
128
|
+
1. Request `prepare_test_checkout` with `productId: "synthetic-1000"` and approve
|
|
129
|
+
the host's tool prompt if shown. Ask for a clickable link and a
|
|
130
|
+
`get_test_purchase_status` read using the returned `purchaseId`.
|
|
131
|
+
2. Confirm status is `not_started`, with zero granted credits. Click the link
|
|
132
|
+
using the host's ordinary external-link UI. The HTTPS page must clearly say
|
|
133
|
+
synthetic test, show no card fields, and require **Simulate approval**.
|
|
134
|
+
3. Before clicking that button, read status again: still zero. Click once, then
|
|
135
|
+
return to chat and request status again: approved, 1,000 simulated credits.
|
|
136
|
+
4. Repeat the read: still 1,000. Never let the agent approve the browser step on
|
|
137
|
+
behalf of a paying customer. This operator test contains no real payment.
|
|
138
|
+
|
|
139
|
+
Links expire after 15 minutes. Capabilities travel in a URL fragment, are removed
|
|
140
|
+
from the address bar on load, and are submitted only to the same checkout origin.
|
|
141
|
+
Refreshing after removal intentionally requires reopening the original link.
|
|
142
|
+
The fixture is bounded to 100 purchases per run. Its aggregate log excludes
|
|
143
|
+
capabilities and tool arguments; keep full host transcripts private. Record the
|
|
144
|
+
actual link UI, approval UI, browser navigation, before/after tool results and
|
|
145
|
+
host version. This does not certify real merchant approval, OAuth continuity,
|
|
146
|
+
3DS, or rich embedded payment support.
|
|
147
|
+
|
|
148
|
+
### September 12 VS Code checkout observation
|
|
149
|
+
|
|
150
|
+
Native Windows VS Code 1.135.0/Copilot discovered both tools, displayed link-creation
|
|
151
|
+
and result-review prompts, and rendered the returned HTTPS URL as a Markdown
|
|
152
|
+
anchor. Native Chrome showed the fixture page with its fragment removed. Copilot
|
|
153
|
+
reported `not_started`/0 after the browser opened, then `approved`/1000 after the
|
|
154
|
+
operator's simulated approval, including a second unchanged status read.
|
|
155
|
+
|
|
156
|
+
**Qualified result:** mouse/keyboard activation of the Copilot anchor did not
|
|
157
|
+
produce a measured checkout request in the final navigation probe. Opening the
|
|
158
|
+
returned URL through the Windows HTTPS handler worked in the default Chrome
|
|
159
|
+
profile. Browser state assertions used explicit navigation in a separate visible
|
|
160
|
+
Chrome profile. These are separate observations: native one-click chat-to-browser
|
|
161
|
+
launch is still unverified. No upstream cause has been established. Use the
|
|
162
|
+
returned URL manually during development; do not advertise the seamless host
|
|
163
|
+
handoff as passed. See `canary/results/vscode-checkout-2026-09-12.json` for aggregate
|
|
164
|
+
evidence. No host/source patch or browser-default change was applied.
|
package/package.json
CHANGED
|
@@ -85,8 +85,9 @@
|
|
|
85
85
|
"prepublishOnly": "bun run check:package",
|
|
86
86
|
"build:apps": "bun scripts/build-apps.ts",
|
|
87
87
|
"canary": "bun canary/server.ts",
|
|
88
|
-
"check:canary": "tsc --noEmit --strict --skipLibCheck --moduleResolution bundler --module esnext --target esnext --types bun canary/server.ts canary/authenticated.ts canary/vscode/check-mount.ts"
|
|
88
|
+
"check:canary": "tsc --noEmit --strict --skipLibCheck --moduleResolution bundler --module esnext --target esnext --types bun canary/server.ts canary/authenticated.ts canary/vscode/check-mount.ts canary/checkout.ts",
|
|
89
|
+
"canary:checkout": "bun canary/checkout.ts"
|
|
89
90
|
},
|
|
90
91
|
"types": "./dist/src/index.d.ts",
|
|
91
|
-
"version": "0.17.
|
|
92
|
+
"version": "0.17.7"
|
|
92
93
|
}
|