@absolutejs/mcp 0.17.4 → 0.17.5
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/vscode/README.md +31 -0
- package/canary/vscode/check-mount.ts +75 -0
- package/canary/vscode/webview-mount-race.patch +22 -0
- package/changelog.json +10 -0
- package/docs/host-canaries.md +4 -0
- package/package.json +2 -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.5 — 2026-09-11
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Distribute a verified VS Code webview startup-race source patch and actual-method regression checker, with explicit upstream delivery requirements**
|
|
14
|
+
|
|
9
15
|
## 0.17.4 — 2026-09-11
|
|
10
16
|
|
|
11
17
|
### Added
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# VS Code webview mount race
|
|
2
|
+
|
|
3
|
+
A host lifecycle race can leave an MCP App blank before its inner document loads. `mountTo` computes the parent-origin hash asynchronously. A subsequent mount can finish first; without a current-startup check, the older completion can overwrite the origin and reset the iframe after the newer connection is ready.
|
|
4
|
+
|
|
5
|
+
`webview-mount-race.patch` fixes the host's source implementation by applying a completion only when its captured promise is still the current mount promise. It does not change MCP or billing code, disable sandboxing, retry tools, or add an arbitrary delay.
|
|
6
|
+
|
|
7
|
+
The baseline is VS Code 1.135.0, commit `08d4889f9ec4a1685d257b9b95de036c8e1ce1e5`. The same mount method was present on upstream main when checked September 11, 2026. [Upstream source](https://github.com/microsoft/vscode/blob/08d4889f9ec4a1685d257b9b95de036c8e1ce1e5/src/vs/workbench/contrib/webview/browser/webviewElement.ts).
|
|
8
|
+
|
|
9
|
+
## Reproduce and check the source fix
|
|
10
|
+
|
|
11
|
+
Use a trusted VS Code checkout and the package's Bun checker. The checker extracts and executes the actual `mountTo` method; it does not substitute a second implementation. Other DOM/service hooks are stubbed, and hash completion order is controlled.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
bun /path/to/node_modules/@absolutejs/mcp/canary/vscode/check-mount.ts src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
|
15
|
+
# Original: exits 1 for both obsolete-startup checks.
|
|
16
|
+
git apply /path/to/node_modules/@absolutejs/mcp/canary/vscode/webview-mount-race.patch
|
|
17
|
+
bun /path/to/node_modules/@absolutejs/mcp/canary/vscode/check-mount.ts src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
|
18
|
+
# Patched: all four checks pass; exits 0.
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The checker executes code from the supplied source file. Use only a trusted checkout. It needs Bun and is a targeted lifecycle regression, not the complete VS Code test suite.
|
|
22
|
+
|
|
23
|
+
## Native-host verification
|
|
24
|
+
|
|
25
|
+
In the isolated, signed-in native Windows VS Code 1.135.0 test window, completing an earlier origin hash 350ms after a newer startup reproduced a blank report on the unmodified host. With the equivalent current-promise guard applied only in the test process, three repeated rounds across balance, usage and receipts rendered all views without reloading. Both source-level completion orders now pass, and disposed views remain excluded. No paid tools or customer data were used.
|
|
26
|
+
|
|
27
|
+
Some unmodified first-load runs passed too: this is a timing-sensitive failure, and ordinary successful retries do not prove it fixed. The controlled race provides the regression. Additional host defects remain possible; this patch addresses the demonstrated obsolete-startup race.
|
|
28
|
+
|
|
29
|
+
## Delivery status
|
|
30
|
+
|
|
31
|
+
This package distributes a reviewable upstream source patch and regression checker. It does **not** patch users' VS Code installations. The in-memory test change does not survive an editor restart. An upstream release or an explicitly maintained patched host build is required before claiming that ordinary VS Code users receive this fix. Keep the first-load rollout gate open until that distribution is verified. No upstream submission is implied by this artifact.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Run against a trusted VS Code webviewElement.ts checkout; executes its real mountTo method. */
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
const file = process.argv[2];
|
|
4
|
+
if (!file) throw Error("Usage: bun check-mount.ts /path/to/webviewElement.ts");
|
|
5
|
+
const source = await readFile(file, "utf8");
|
|
6
|
+
const start = source.indexOf("\tpublic mountTo(");
|
|
7
|
+
const end = source.indexOf("\n\tprivate _registerMessageHandler(", start);
|
|
8
|
+
if (start < 0 || end < 0) throw Error("Unsupported source layout");
|
|
9
|
+
const method = source.slice(start, end);
|
|
10
|
+
const javascript = new Bun.Transpiler({ loader: "ts" }).transformSync(
|
|
11
|
+
`class MountProbe { ${method} }`,
|
|
12
|
+
);
|
|
13
|
+
type Probe = {
|
|
14
|
+
mountTo: (element: unknown, window: unknown) => void;
|
|
15
|
+
_encodedWebviewOrigin?: string;
|
|
16
|
+
_disposed: boolean;
|
|
17
|
+
};
|
|
18
|
+
const results: { name: string; passed: boolean }[] = [];
|
|
19
|
+
for (const order of [
|
|
20
|
+
[1, 0],
|
|
21
|
+
[0, 1],
|
|
22
|
+
]) {
|
|
23
|
+
const pending: ((origin: string) => void)[] = [];
|
|
24
|
+
const mounted: string[] = [];
|
|
25
|
+
const create = new Function(
|
|
26
|
+
"parentOriginHash",
|
|
27
|
+
"EventType",
|
|
28
|
+
"addDisposableListener",
|
|
29
|
+
`${javascript};return MountProbe;`,
|
|
30
|
+
);
|
|
31
|
+
const Constructor = create(
|
|
32
|
+
() => new Promise<string>((resolve) => pending.push(resolve)),
|
|
33
|
+
{},
|
|
34
|
+
() => ({}),
|
|
35
|
+
) as new () => Probe;
|
|
36
|
+
const probe = new Constructor();
|
|
37
|
+
Object.assign(probe, {
|
|
38
|
+
element: {},
|
|
39
|
+
origin: "test",
|
|
40
|
+
_disposed: false,
|
|
41
|
+
_registerMessageHandler: () => {},
|
|
42
|
+
_register: () => {},
|
|
43
|
+
perfMark: () => {},
|
|
44
|
+
_initElement: (origin: string) => mounted.push(origin),
|
|
45
|
+
});
|
|
46
|
+
const container = { appendChild: () => {} };
|
|
47
|
+
probe.mountTo(container, { origin: "first-window", vscodeWindowId: 1 });
|
|
48
|
+
probe.mountTo(container, { origin: "second-window", vscodeWindowId: 2 });
|
|
49
|
+
for (const index of order) {
|
|
50
|
+
pending[index]!(index === 0 ? "old-origin" : "new-origin");
|
|
51
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
52
|
+
}
|
|
53
|
+
results.push({
|
|
54
|
+
name:
|
|
55
|
+
order[0] === 1
|
|
56
|
+
? "late-old-startup-ignored"
|
|
57
|
+
: "early-obsolete-startup-ignored",
|
|
58
|
+
passed:
|
|
59
|
+
mounted.length === 1 &&
|
|
60
|
+
mounted[0] === "new-origin" &&
|
|
61
|
+
probe._encodedWebviewOrigin === "new-origin",
|
|
62
|
+
});
|
|
63
|
+
mounted.length = 0;
|
|
64
|
+
probe.mountTo(container, { origin: "disposed-window", vscodeWindowId: 3 });
|
|
65
|
+
probe._disposed = true;
|
|
66
|
+
pending[2]!("disposed-origin");
|
|
67
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
68
|
+
results.push({
|
|
69
|
+
name: "disposed-view-not-mounted",
|
|
70
|
+
passed: mounted.length === 0,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const passed = results.every((result) => result.passed);
|
|
74
|
+
console.log(JSON.stringify({ passed, results }, null, 2));
|
|
75
|
+
if (!passed) process.exitCode = 1;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
--- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
|
2
|
+
+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
|
|
3
|
+
@@ -477,9 +477,16 @@
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
this._windowId = targetWindow.vscodeWindowId;
|
|
7
|
+
- this._encodedWebviewOriginPromise = parentOriginHash(targetWindow.origin, this.origin).then(id => this._encodedWebviewOrigin = id);
|
|
8
|
+
- this._encodedWebviewOriginPromise.then(encodedWebviewOrigin => {
|
|
9
|
+
- if (!this._disposed) {
|
|
10
|
+
+ const encodedWebviewOriginPromise = parentOriginHash(targetWindow.origin, this.origin).then(id => {
|
|
11
|
+
+ if (this._encodedWebviewOriginPromise === encodedWebviewOriginPromise) {
|
|
12
|
+
+ this._encodedWebviewOrigin = id;
|
|
13
|
+
+ }
|
|
14
|
+
+ return id;
|
|
15
|
+
+ });
|
|
16
|
+
+ this._encodedWebviewOriginPromise = encodedWebviewOriginPromise;
|
|
17
|
+
+ encodedWebviewOriginPromise.then(encodedWebviewOrigin => {
|
|
18
|
+
+ // A remount may supersede this startup before its origin hash resolves.
|
|
19
|
+
+ if (!this._disposed && this._encodedWebviewOriginPromise === encodedWebviewOriginPromise) {
|
|
20
|
+
this._initElement(encodedWebviewOrigin, this.extension, this._options, targetWindow);
|
|
21
|
+
}
|
|
22
|
+
});
|
package/changelog.json
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
"contract": 1,
|
|
3
3
|
"name": "@absolutejs/mcp",
|
|
4
4
|
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"version": "0.17.5",
|
|
7
|
+
"date": "2026-09-11",
|
|
8
|
+
"changes": [
|
|
9
|
+
{
|
|
10
|
+
"kind": "added",
|
|
11
|
+
"summary": "Distribute a verified VS Code webview startup-race source patch and actual-method regression checker, with explicit upstream delivery requirements"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
5
15
|
{
|
|
6
16
|
"version": "0.17.4",
|
|
7
17
|
"date": "2026-09-11",
|
package/docs/host-canaries.md
CHANGED
|
@@ -93,3 +93,7 @@ const report = await runAuthenticatedCanary({
|
|
|
93
93
|
Choose two accounts with known distinct data. The canary refuses identical results as inconclusive and verifies repeated reads remain stable. It checks both directions of session-ID substitution: rejecting the foreign session or returning the currently authenticated account's result is acceptable. It also checks missing/invalid credentials, unauthorized DELETE, authorized deletion, terminated-session 404, and fresh initialization/read. It creates and cleans up only its own MCP sessions, never purchases or modifies account data. Read-only annotations are a prerequisite, not a substitute for the operator selecting a known non-billable read tool. The current harness requires JSON RPC responses; SSE-only servers are not certified by it.
|
|
94
94
|
|
|
95
95
|
This verifies the selected read path, not every tenant resource, token revocation, automatic host reconnect, or billing permissions. Session termination is explicit DELETE; timed TTL expiry needs a separate store test. Use dedicated test clients and remove their grants after verification. Do not publish tokens, transcripts, fingerprints, or raw account data.
|
|
96
|
+
|
|
97
|
+
## VS Code first-load race identified
|
|
98
|
+
|
|
99
|
+
MCP 0.17.5 includes `canary/vscode/README.md`, a VS Code source patch and an executable actual-method regression. A controlled out-of-order origin-hash completion reproduces a blank view in native VS Code 1.135.0. The candidate current-promise guard passed three rounds across all three report views and both source-level completion orders. This is a host fix, not an MCP renderer change. The package distributes the patch for review; it does not modify installed editors or certify an upstream release. First-load activation remains blocked until a supported host containing the fix is verified.
|
package/package.json
CHANGED
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"prepublishOnly": "bun run check:package",
|
|
85
85
|
"build:apps": "bun scripts/build-apps.ts",
|
|
86
86
|
"canary": "bun canary/server.ts",
|
|
87
|
-
"check:canary": "tsc --noEmit --strict --skipLibCheck --moduleResolution bundler --module esnext --target esnext --types bun canary/server.ts canary/authenticated.ts"
|
|
87
|
+
"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
88
|
},
|
|
89
89
|
"types": "./dist/src/index.d.ts",
|
|
90
|
-
"version": "0.17.
|
|
90
|
+
"version": "0.17.5"
|
|
91
91
|
}
|