Skip to content

Commit c1c5312

Browse files
committed
Serve navigator.modelContext as a deprecated alias
Chrome 150 deprecated `navigator.modelContext` in favour of `document.modelContext` (webmachinelearning CG issue 173, PR #184) but still serves it. Playground provides the registry itself, so a plugin that has not migrated — the Abilities-to-WebMCP bridges register through `navigator` with no fallback — worked in Chrome and threw only here. Both registries now expose the deprecated global as a getter returning the same instance, warning once on first access the way a platform deprecation does. `document.modelContext` stays the documented surface, and this goes when Chrome removes it. The test registers its runtime-added tool through the alias, so the proxy path is covered from the deprecated global too. Claude-Session: https://claude.ai/code/session_01SES9wgwFmrkkhwqfmfMuMU
1 parent 147d39f commit c1c5312

4 files changed

Lines changed: 51 additions & 1 deletion

File tree

‎packages/playground/mcp/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ A browser tab shows one site at a time, so the tools always belong to the active
133133

134134
`document.modelContext` is provided by Playground's mu-plugin on `wp_head` and `admin_head`, which covers the front end and wp-admin.
135135

136+
Chrome 150 deprecated `navigator.modelContext` in favour of `document.modelContext` but still serves it, so Playground does the same: the deprecated global returns the very same registry and warns once on first access. A plugin that has not migrated keeps working here exactly as it does in Chrome. Write new code against `document.modelContext` — the alias goes when Chrome removes it.
137+
136138
**The login screen is deliberately not covered.** `wp-login.php` fires neither hook, so that document has no registry and proxies no tools; a site's tools come back when the user leaves it. `login_head` still fires there, so a plugin hooking it must feature-detect rather than assume the registry exists — worth doing anywhere, since most browsers do not implement WebMCP:
137139

138140
```php

‎packages/playground/mcp/src/webmcp-polyfill.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export function installWebMCPPolyfill(): boolean {
9191
configurable: true,
9292
value: modelContext,
9393
});
94+
installDeprecatedNavigatorAlias(modelContext);
9495
} catch (error) {
9596
// A non-configurable `modelContext` cannot be replaced. Callers wire
9697
// up the MCP bridge right after this, so failing loudly here would
@@ -101,6 +102,32 @@ export function installWebMCPPolyfill(): boolean {
101102
return true;
102103
}
103104

105+
/**
106+
* Serves the deprecated `navigator.modelContext` alongside the canonical
107+
* `document.modelContext`.
108+
*
109+
* Chrome 150 deprecated the `navigator` getter but still serves it, so code
110+
* written against it keeps working there and would break only where this
111+
* polyfill stands in. Warn once on first access, as the platform does, and
112+
* drop this when Chrome removes it.
113+
*/
114+
function installDeprecatedNavigatorAlias(modelContext: ModelContext) {
115+
let warned = false;
116+
Object.defineProperty(navigator, 'modelContext', {
117+
configurable: true,
118+
get() {
119+
if (!warned) {
120+
warned = true;
121+
logger.warn(
122+
'navigator.modelContext is deprecated and will be removed. ' +
123+
'Use document.modelContext instead.'
124+
);
125+
}
126+
return modelContext;
127+
},
128+
});
129+
}
130+
104131
/**
105132
* The `client` argument a WebMCP agent passes to `execute()`. Playground's own
106133
* tools ignore it, and a caller reaching a tool through the polyfill has no

‎packages/playground/personal-wp/playwright/e2e/webmcp-proxy.spec.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ add_action('wp_head', function () {
6565
});
6666
6767
// Lets the test add and withdraw a tool while the page stays put.
68+
// Registers through the deprecated \`navigator\` alias on purpose: Chrome
69+
// still serves it, so an unmigrated plugin must reach the same registry.
6870
var extra = null;
6971
window.__addExtraTool = function () {
7072
extra = new AbortController();
71-
document.modelContext.registerTool({
73+
navigator.modelContext.registerTool({
7274
name: 'site_extra',
7375
description: 'Registered after the document loaded.',
7476
inputSchema: { type: 'object', properties: {} },

‎packages/playground/remote/src/lib/playground-mu-plugin/0-playground.php‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,25 @@ function addTool(tool, options) {
498498
value: modelContext
499499
});
500500

501+
// Chrome 150 deprecated `navigator.modelContext` in favour of
502+
// `document.modelContext` but still serves it, so a plugin that
503+
// has not migrated works there and would break only here. Mirror
504+
// the platform, warning once, and drop this when Chrome does.
505+
var warnedAboutNavigator = false;
506+
Object.defineProperty(navigator, 'modelContext', {
507+
configurable: true,
508+
get: function () {
509+
if (!warnedAboutNavigator) {
510+
warnedAboutNavigator = true;
511+
console.warn(
512+
'navigator.modelContext is deprecated and will be ' +
513+
'removed. Use document.modelContext instead.'
514+
);
515+
}
516+
return modelContext;
517+
}
518+
});
519+
501520
// A minimal WebMCP client. The agent lives in the top-level page,
502521
// so this document cannot prompt the user itself.
503522
var toolClient = {

0 commit comments

Comments
 (0)