@absolutejs/mcp 0.17.6 → 0.17.8
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/canary/checkout.ts +198 -0
- package/canary/results/vscode-checkout-2026-09-12.json +40 -0
- package/changelog.json +179 -159
- package/docs/commerce-host-rules.md +23 -0
- package/docs/host-canaries.md +69 -0
- package/docs/reviews/vscode-individual-external-checkout.md +61 -0
- package/package.json +5 -3
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.17.8 — 2026-09-12
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Correct the VS Code checkout canary after verifying native Windows link consent and document the individual Copilot channel review**
|
|
14
|
+
|
|
15
|
+
## 0.17.7 — 2026-09-12
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Ship a synthetic external-checkout host canary with expiring links, explicit approval and purchase-status checks**
|
|
20
|
+
|
|
9
21
|
## 0.17.6 — 2026-09-11
|
|
10
22
|
|
|
11
23
|
### 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,40 @@
|
|
|
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": true,
|
|
15
|
+
"windowsHttpsHandlerOpensReturnedUrl": true,
|
|
16
|
+
"nativeChromeCheckoutPage": true,
|
|
17
|
+
"fragmentRemovedAfterLoad": true,
|
|
18
|
+
"beforeBrowserApproval": {
|
|
19
|
+
"status": "not_started",
|
|
20
|
+
"creditsGranted": 0
|
|
21
|
+
},
|
|
22
|
+
"afterBrowserApproval": {
|
|
23
|
+
"status": "approved",
|
|
24
|
+
"creditsGranted": 1000
|
|
25
|
+
},
|
|
26
|
+
"repeatedRead": {
|
|
27
|
+
"status": "approved",
|
|
28
|
+
"creditsGranted": 1000
|
|
29
|
+
},
|
|
30
|
+
"nativeWindowsExternalSiteConfirmation": true,
|
|
31
|
+
"sameDefaultBrowserApproval": true
|
|
32
|
+
},
|
|
33
|
+
"limits": [
|
|
34
|
+
"Synthetic credits only; no real gateway or OAuth certified.",
|
|
35
|
+
"No editor patch, trusted-domain setting or browser default changed.",
|
|
36
|
+
"Rich payment UI and marketplace distribution are not certified.",
|
|
37
|
+
"No checkout capability, purchase ID, card data or account credentials included."
|
|
38
|
+
],
|
|
39
|
+
"correction": "Earlier unverified result missed a native Windows #32770 external-site confirmation outside the CDP DOM. Full rerun used the native Open prompt and the same default Chrome page."
|
|
40
|
+
}
|
package/changelog.json
CHANGED
|
@@ -1,161 +1,181 @@
|
|
|
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": "fixed",
|
|
9
|
+
"summary": "Correct the VS Code checkout canary after verifying native Windows link consent and document the individual Copilot channel review"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"date": "2026-09-12",
|
|
13
|
+
"version": "0.17.8"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"changes": [
|
|
17
|
+
{
|
|
18
|
+
"kind": "added",
|
|
19
|
+
"summary": "Ship a synthetic external-checkout host canary with expiring links, explicit approval and purchase-status checks"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"date": "2026-09-12",
|
|
23
|
+
"version": "0.17.7"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"changes": [
|
|
27
|
+
{
|
|
28
|
+
"kind": "fixed",
|
|
29
|
+
"summary": "Use text and structured report results on affected VS Code builds while their upstream webview startup race remains unresolved"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"kind": "added",
|
|
33
|
+
"summary": "Allow verified patched hosts through the version fallback with optional Apps configuration",
|
|
34
|
+
"symbols": [
|
|
35
|
+
"clientSupportsMcpApps",
|
|
36
|
+
"McpAppsConfig"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"date": "2026-09-11",
|
|
41
|
+
"version": "0.17.6"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"changes": [
|
|
45
|
+
{
|
|
46
|
+
"kind": "added",
|
|
47
|
+
"summary": "Distribute a verified VS Code webview startup-race source patch and actual-method regression checker, with explicit upstream delivery requirements"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"date": "2026-09-11",
|
|
51
|
+
"version": "0.17.5"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"changes": [
|
|
55
|
+
{
|
|
56
|
+
"kind": "added",
|
|
57
|
+
"summary": "Ship an authenticated two-account staging canary for read isolation, credential rejection and session reconnect with private credentials and aggregate-only results"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"date": "2026-09-11",
|
|
61
|
+
"version": "0.17.4"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"changes": [
|
|
65
|
+
{
|
|
66
|
+
"kind": "fixed",
|
|
67
|
+
"summary": "Authorize session deletion, recover explicit client initialization after expiry, and preserve typed HTTP failures without replaying tools"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"kind": "fixed",
|
|
71
|
+
"summary": "Accept the standard protocol-header compatibility fallback used by VS Code Copilot and record native report rendering evidence"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"date": "2026-09-11",
|
|
75
|
+
"version": "0.17.3"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"changes": [
|
|
79
|
+
{
|
|
80
|
+
"kind": "added",
|
|
81
|
+
"summary": "Record verified Claude web rendering, refresh, pagination and narrow-viewport host canary evidence"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"date": "2026-09-11",
|
|
85
|
+
"version": "0.17.2"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"changes": [
|
|
89
|
+
{
|
|
90
|
+
"kind": "added",
|
|
91
|
+
"summary": "Ship a preflight-validated synthetic host canary and record Claude Code and Codex terminal interoperability evidence"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"date": "2026-09-11",
|
|
95
|
+
"version": "0.17.1"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"changes": [
|
|
99
|
+
{
|
|
100
|
+
"kind": "added",
|
|
101
|
+
"summary": "Negotiate MCP Apps with persisted capabilities, guarded offline UI resources and reusable SDK-backed billing views"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"kind": "added",
|
|
105
|
+
"summary": "Preserve remote UI metadata in the client and expose immutable PostgreSQL migration entries"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"kind": "changed",
|
|
109
|
+
"summary": "Extend McpClientOptions, McpRemoteTool, createSessionRegistry, McpSessionStore, McpServerConfig, McpTool and McpToolResult with optional Apps capability and metadata fields; existing text-only callers remain supported",
|
|
110
|
+
"symbols": [
|
|
111
|
+
"McpClientOptions",
|
|
112
|
+
"McpRemoteTool",
|
|
113
|
+
"createSessionRegistry",
|
|
114
|
+
"McpSessionStore",
|
|
115
|
+
"McpServerConfig",
|
|
116
|
+
"McpTool",
|
|
117
|
+
"McpToolResult"
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"date": "2026-09-11",
|
|
122
|
+
"version": "0.17.0"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"changes": [
|
|
126
|
+
{
|
|
127
|
+
"kind": "added",
|
|
128
|
+
"summary": "Add account-bound billing status, paginated receipts, bounded usage and reviewed billing-management links"
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
"date": "2026-09-11",
|
|
132
|
+
"version": "0.16.0"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"changes": [
|
|
136
|
+
{
|
|
137
|
+
"kind": "fixed",
|
|
138
|
+
"summary": "Build and test before publishing so checkout exports are present in the distributed artifact"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"date": "2026-09-11",
|
|
142
|
+
"version": "0.15.1"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"changes": [
|
|
146
|
+
{
|
|
147
|
+
"kind": "added",
|
|
148
|
+
"summary": "Add commerce-classified account-bound checkout handoff and purchase status tools"
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"date": "2026-09-11",
|
|
152
|
+
"version": "0.15.0"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"changes": [
|
|
156
|
+
{
|
|
157
|
+
"kind": "added",
|
|
158
|
+
"summary": "Add explicit credit-budget envelopes for durable prepaid MCP work"
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"date": "2026-09-11",
|
|
162
|
+
"version": "0.14.0"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"changes": [
|
|
166
|
+
{
|
|
167
|
+
"kind": "added",
|
|
168
|
+
"summary": "Add reviewed host commerce eligibility, execution guards, and reusable credit status tools",
|
|
169
|
+
"symbols": [
|
|
170
|
+
"McpServerConfig",
|
|
171
|
+
"McpTool",
|
|
172
|
+
"evaluateCommerce",
|
|
173
|
+
"createCreditBalanceTool"
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"date": "2026-09-11",
|
|
178
|
+
"version": "0.13.0"
|
|
179
|
+
}
|
|
180
|
+
]
|
|
161
181
|
}
|
|
@@ -264,3 +264,26 @@ 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.
|
|
280
|
+
|
|
281
|
+
## September 12 individual Copilot external-checkout review
|
|
282
|
+
|
|
283
|
+
The operator confirmed an individual subscription. The [scoped review](reviews/vscode-individual-external-checkout.md)
|
|
284
|
+
concludes that user-requested, service-owned HTTPS credit checkout is eligible
|
|
285
|
+
for an explicit deployment binding, with a dated interpretation and exact
|
|
286
|
+
conditions. This does not change the global direct-MCP default. The complete
|
|
287
|
+
native handoff now passes after accounting for Windows' external-site dialog;
|
|
288
|
+
no link defect or need for an upstream link fix was established. Rich-view
|
|
289
|
+
startup remains a separate tracked issue.
|
package/docs/host-canaries.md
CHANGED
|
@@ -103,3 +103,72 @@ 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
|
+
**Corrected after a complete native rerun:** the previous test missed a Windows
|
|
157
|
+
native `#32770` dialog asking whether Code should open the external website. It
|
|
158
|
+
is outside the CDP page DOM: `getByRole("dialog")` returning zero did not mean no
|
|
159
|
+
prompt existed. Several previous clicks had queued confirmations. Dismissing
|
|
160
|
+
stale test prompts and choosing **Open** for the fresh expected origin produced
|
|
161
|
+
checkout GET and state POST responses. Windows accessibility verified the actual
|
|
162
|
+
default Chrome page, then the operator explicitly invoked its **Simulate approval**
|
|
163
|
+
button. Copilot read zero before that click and approved/1000 twice afterward.
|
|
164
|
+
No manual URL navigation was needed in this final run.
|
|
165
|
+
|
|
166
|
+
Use Windows native dialog inspection when a click appears inert; do not repeatedly
|
|
167
|
+
click, change trusted domains, or patch the editor to bypass the prompt. Preserve
|
|
168
|
+
normal per-link consent. This was a test-automation gap, not an established host
|
|
169
|
+
link defect. See `canary/results/vscode-checkout-2026-09-12.json` for the corrected
|
|
170
|
+
aggregate evidence. The separate rich-view startup issue is unchanged.
|
|
171
|
+
|
|
172
|
+
The [individual Copilot external-checkout review](reviews/vscode-individual-external-checkout.md)
|
|
173
|
+
records the exact eligible deployment scope and activation conditions; the
|
|
174
|
+
synthetic fixture is not a real merchant/OAuth acceptance test.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# VS Code individual Copilot: external service-credit checkout
|
|
2
|
+
|
|
3
|
+
Reviewed September 12, 2026; re-review by October 12, 2026. The operator confirmed
|
|
4
|
+
an **individual Copilot subscription**. Channel: native VS Code, manually configured
|
|
5
|
+
remote MCP, service-owned HTTPS checkout. This review covers user-requested
|
|
6
|
+
one-time purchases of non-transferable credits for the connected service.
|
|
7
|
+
|
|
8
|
+
## Decision and evidence
|
|
9
|
+
|
|
10
|
+
**Eligible for a deployment-specific external-checkout binding under the conditions
|
|
11
|
+
below.** This is our documented interpretation of the reviewed terms, not a
|
|
12
|
+
Microsoft/GitHub certification or an express vendor statement about credit sales.
|
|
13
|
+
The inspected terms do not specifically prohibit this scoped flow. Do not describe
|
|
14
|
+
that absence as permission for every commercial use or every Copilot account.
|
|
15
|
+
|
|
16
|
+
- [GitHub additional product terms, Copilot](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot)
|
|
17
|
+
directs individual users to the general terms, including AI-feature terms.
|
|
18
|
+
- [GitHub ToS, effective April 27, 2026](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service#j-ai-features-training-and-your-data)
|
|
19
|
+
covers AI inputs/outputs, user responsibility, and individual data-use controls.
|
|
20
|
+
Section B.5 distinguishes third-party relationships; §H restricts API abuse.
|
|
21
|
+
- [GitHub acceptable-use policies](https://docs.github.com/en/site-policy/acceptable-use-policies/github-acceptable-use-policies)
|
|
22
|
+
forbid service resale without permission, unsolicited promotions/spam, privacy
|
|
23
|
+
violations and deceptive conduct. Our scope is a requested purchase of the
|
|
24
|
+
connected merchant's own service, with no GitHub-service resale or unsolicited
|
|
25
|
+
promotion. Do not source sales-lead data from GitHub contrary to these rules.
|
|
26
|
+
- [VS Code license](https://code.visualstudio.com/license) and
|
|
27
|
+
[MCP documentation](https://code.visualstudio.com/docs/agent-customization/mcp-servers)
|
|
28
|
+
describe the editor and direct MCP/trust mechanisms. The license alone was
|
|
29
|
+
sufficient only for the earlier developer test; it is not a commerce certificate.
|
|
30
|
+
|
|
31
|
+
Native VS Code 1.135.0 passed the synthetic handoff through its normal Windows
|
|
32
|
+
external-site confirmation and the default browser. Opening the page granted
|
|
33
|
+
nothing; explicit simulated approval produced one unchanged 1,000-credit result
|
|
34
|
+
across repeated reads. See the [host canary](../host-canaries.md). This tests
|
|
35
|
+
transport and user interaction; the real merchant/account flow needs its own
|
|
36
|
+
staging validation before activation.
|
|
37
|
+
|
|
38
|
+
## Required deployment scope
|
|
39
|
+
|
|
40
|
+
1. Bind an operator-reviewed OAuth registration to the authenticated account and
|
|
41
|
+
this exact direct channel. Never grant eligibility from `clientInfo`, model
|
|
42
|
+
name, arbitrary client metadata, or a user-supplied profile. Confirm the
|
|
43
|
+
account's agreement; organization-managed accounts need a separate review.
|
|
44
|
+
2. Limit this review to `external_checkout` / `usage_credits`. The shared
|
|
45
|
+
`direct-mcp` default remains unverified until the deployment supplies a fresh
|
|
46
|
+
review. Unknown, ambiguous and published restricted profiles stay closed.
|
|
47
|
+
3. Create an expiring, account-bound link on the merchant's own HTTPS origin.
|
|
48
|
+
Keep card entry and explicit payment confirmation in that browser page.
|
|
49
|
+
Tool approval, native **Open**, page load and a chat claim never charge or
|
|
50
|
+
prove payment. Verify payment and grant credits on the server exactly once.
|
|
51
|
+
4. Offer the link only in response to a purchase/top-up request. Keep normal
|
|
52
|
+
host trust prompts. Do not automatically opt out of review or mark all
|
|
53
|
+
domains trusted. Never collect payment credentials in MCP arguments or chat.
|
|
54
|
+
5. Expire the binding at review expiry; re-review changed terms, account type,
|
|
55
|
+
distribution, categories or host behavior. Follow merchant privacy/terms and
|
|
56
|
+
applicable provider requirements. Treat transcripts as potentially retained.
|
|
57
|
+
|
|
58
|
+
Excluded: Marketplace listings, GitHub-hosted storefronts, organization accounts,
|
|
59
|
+
ChatGPT/Claude hosted channels, embedded card forms, saved-card tool charges,
|
|
60
|
+
automatic refill, subscriptions and blanket approval for other MCP clients.
|
|
61
|
+
The VS Code rich-view startup workaround is a separate issue and still applies.
|
package/package.json
CHANGED
|
@@ -73,7 +73,8 @@
|
|
|
73
73
|
"docs/third-party",
|
|
74
74
|
"canary",
|
|
75
75
|
"docs/host-canaries.md",
|
|
76
|
-
"UPSTREAM_ISSUES.md"
|
|
76
|
+
"UPSTREAM_ISSUES.md",
|
|
77
|
+
"docs/reviews"
|
|
77
78
|
],
|
|
78
79
|
"scripts": {
|
|
79
80
|
"build": "bun run build:apps && rm -rf dist && bun build src/index.ts src/manifest.ts src/commerce.ts src/apps.ts --outdir dist --root ./src --target=bun --external @absolutejs/agency --external '@absolutejs/agency/*' --external elysia && tsc --emitDeclarationOnly --project tsconfig.json && absolute-manifest emit",
|
|
@@ -85,8 +86,9 @@
|
|
|
85
86
|
"prepublishOnly": "bun run check:package",
|
|
86
87
|
"build:apps": "bun scripts/build-apps.ts",
|
|
87
88
|
"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"
|
|
89
|
+
"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",
|
|
90
|
+
"canary:checkout": "bun canary/checkout.ts"
|
|
89
91
|
},
|
|
90
92
|
"types": "./dist/src/index.d.ts",
|
|
91
|
-
"version": "0.17.
|
|
93
|
+
"version": "0.17.8"
|
|
92
94
|
}
|