@frontmcp/plugin-webmcp 1.9.5 → 1.9.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/README.md +102 -41
- package/esm/package.json +7 -5
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# @frontmcp/plugin-webmcp
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[WebMCP](https://webmachinelearning.github.io/webmcp/) (`document.modelContext`)
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Offers the tools of a [FrontMCP](https://frontmcp.dev) server that runs **in the page** to the agents in the user's
|
|
4
|
+
browser, through [WebMCP](https://webmachinelearning.github.io/webmcp/) (`document.modelContext`): the browser's own
|
|
5
|
+
assistant, an extension, or the developer tools. Use it on a website that creates a FrontMCP server in the page, often
|
|
6
|
+
under `@frontmcp/react`. The plugin registers the server's tools, keeps them in step as tools come and go, and runs each
|
|
7
|
+
agent's call through the server's own flow.
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/@frontmcp/plugin-webmcp) [](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
|
|
10
|
+
|
|
11
|
+
## Install
|
|
9
12
|
|
|
10
13
|
```bash
|
|
11
|
-
npm install @frontmcp/plugin-webmcp
|
|
14
|
+
npm install @frontmcp/sdk @frontmcp/plugin-webmcp
|
|
12
15
|
```
|
|
13
16
|
|
|
17
|
+
Use the same version for both packages. The plugin's peer dependency `@frontmcp/lazy-zod` comes with the SDK. The
|
|
18
|
+
build-time helper `listWebMcpTools()` runs in Node.js 24 or later.
|
|
19
|
+
|
|
14
20
|
## Usage
|
|
15
21
|
|
|
16
22
|
```typescript
|
|
@@ -24,44 +30,66 @@ const server = await create({
|
|
|
24
30
|
});
|
|
25
31
|
```
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
Register the plugin with `WebMcpPlugin.init()`, with or without options; `plugins: [WebMcpPlugin]` uses the defaults.
|
|
34
|
+
Install it once: it offers every tool the server lists, whichever app it's registered on.
|
|
28
35
|
|
|
29
36
|
Once the server is ready, every tool it lists on the `'webmcp'` surface is registered with
|
|
30
37
|
`document.modelContext.registerTool()`:
|
|
31
38
|
|
|
32
|
-
- **Kept in sync.** Tools added or removed later, including tools added with `server.registerTool()`
|
|
33
|
-
|
|
39
|
+
- **Kept in sync.** Tools added or removed later, including tools added with `server.registerTool()` and React's
|
|
40
|
+
`useDynamicTool()`, are registered or unregistered as they change.
|
|
34
41
|
- **Cleaned up.** Every tool is unregistered when `server.dispose()` runs.
|
|
35
42
|
|
|
36
|
-
An agent's call runs the server's `tools:call-tool` flow, so hooks, authorities, quota and
|
|
37
|
-
|
|
43
|
+
An agent's call runs the server's `tools:call-tool` flow, so hooks, authorities, quota and `availableWhen` apply to it
|
|
44
|
+
as they do to any MCP client.
|
|
38
45
|
|
|
39
46
|
## Options
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
48
|
+
All optional.
|
|
49
|
+
|
|
50
|
+
| Option | Type | Default | Description |
|
|
51
|
+
| -------------- | ---------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
52
|
+
| `prefix` | `string` | `''` | Prepended to every exposed tool name, e.g. `'shop.'`. |
|
|
53
|
+
| `include` | `(tool) => boolean` | every tool | Decides which listed tools are exposed. Runs after `availableWhen` and authorities. |
|
|
54
|
+
| `exposedTo` | `string[]` | | Other origins (e.g. an iframe's parent) the tools are offered to. |
|
|
55
|
+
| `authContext` | `DirectAuthContext \| () => DirectAuthContext` | an anonymous caller, `anon:webmcp` | Who the server sees calling. A function is called again for every listing and every call. |
|
|
56
|
+
| `modelContext` | `ModelContext` | `document.modelContext` | The context to register with: a polyfill, or a test double. |
|
|
57
|
+
| `result` | `'structured' \| 'content' \| 'both'` | `'structured'` | What a call resolves to (see [Results](#how-tools-are-translated)). |
|
|
58
|
+
|
|
59
|
+
Without `authContext`, every call comes from an anonymous caller, so a tool that refuses anonymous callers refuses
|
|
60
|
+
agents too. To let agents act as the person using the page, pass that user, for example
|
|
61
|
+
`authContext: () => ({ user: { sub: userId, roles: ['agent'] } })`.
|
|
49
62
|
|
|
50
63
|
## Choosing which tools agents see
|
|
51
64
|
|
|
52
65
|
Tools are listed through the `'webmcp'` call surface, so `availableWhen` decides per tool:
|
|
53
66
|
|
|
54
67
|
```typescript
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
import { Tool, ToolContext } from '@frontmcp/sdk';
|
|
69
|
+
|
|
70
|
+
@Tool({ name: 'checkout', description: 'Check out the cart', inputSchema: {}, availableWhen: { surface: ['webmcp'] } })
|
|
71
|
+
export class Checkout extends ToolContext {
|
|
72
|
+
async execute() {
|
|
73
|
+
return { ordered: true };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@Tool({ name: 'admin_reset', description: 'Reset the store', inputSchema: {}, availableWhen: { surface: ['mcp'] } })
|
|
78
|
+
export class AdminReset extends ToolContext {
|
|
79
|
+
async execute() {
|
|
80
|
+
return { reset: true };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
57
83
|
```
|
|
58
84
|
|
|
85
|
+
`checkout` is offered only to in-browser agents, and `admin_reset` never through WebMCP.
|
|
86
|
+
|
|
59
87
|
## How tools are translated
|
|
60
88
|
|
|
61
|
-
- **Names.** Names become WebMCP-valid. Characters outside `[A-Za-z0-9_.-]` become `_` (so
|
|
62
|
-
`
|
|
63
|
-
- **Annotations.** MCP's `readOnlyHint` maps to `readOnlyHint`. An explicit `destructiveHint: true`
|
|
64
|
-
|
|
89
|
+
- **Names.** Names become WebMCP-valid. Characters outside `[A-Za-z0-9_.-]` become `_` (so `app:tool` becomes
|
|
90
|
+
`app_tool`), names are cut to 128 characters, and collisions get `_2`, `_3`, …
|
|
91
|
+
- **Annotations.** MCP's `readOnlyHint` maps to `readOnlyHint`. An explicit `destructiveHint: true` maps to
|
|
92
|
+
`consequentialHint`, and an explicit `openWorldHint: true` to `untrustedContentHint`.
|
|
65
93
|
- **Results.** An agent reads the whole result as text, so by default it gets each result once. With
|
|
66
94
|
`result: 'structured'` (the default) a call resolves to the tool's `structuredContent` alone when its content only
|
|
67
95
|
repeats it: one text block with the same JSON, or the primitive a `{ content }` wrapper holds, as the server writes
|
|
@@ -73,12 +101,15 @@ Tools are listed through the `'webmcp'` call surface, so `availableWhen` decides
|
|
|
73
101
|
|
|
74
102
|
## Registering tools before the server loads
|
|
75
103
|
|
|
76
|
-
A server in the page is a large bundle, and starting it is one long task. To keep it off page load, compute the
|
|
77
|
-
|
|
104
|
+
A server in the page is a large bundle, and starting it is one long task. To keep it off page load, compute the tool
|
|
105
|
+
list at build time and register it in the page; the server loads on an agent's first call.
|
|
78
106
|
|
|
79
107
|
`server.ts`, one factory for the build script and the page:
|
|
80
108
|
|
|
81
109
|
```typescript
|
|
110
|
+
import { WebMcpPlugin, type ModelContext } from '@frontmcp/plugin-webmcp';
|
|
111
|
+
import { create } from '@frontmcp/sdk';
|
|
112
|
+
|
|
82
113
|
export function createShopServer({ modelContext }: { modelContext?: ModelContext } = {}) {
|
|
83
114
|
return create({
|
|
84
115
|
info: { name: 'shop', version: '1.0.0' },
|
|
@@ -88,11 +119,15 @@ export function createShopServer({ modelContext }: { modelContext?: ModelContext
|
|
|
88
119
|
}
|
|
89
120
|
```
|
|
90
121
|
|
|
91
|
-
The build script (Node):
|
|
122
|
+
The build script (Node.js):
|
|
92
123
|
|
|
93
124
|
```typescript
|
|
125
|
+
import { writeFile } from 'node:fs/promises';
|
|
126
|
+
|
|
94
127
|
import { listWebMcpTools } from '@frontmcp/plugin-webmcp';
|
|
95
128
|
|
|
129
|
+
import { createShopServer } from './server';
|
|
130
|
+
|
|
96
131
|
const tools = await listWebMcpTools((modelContext) => createShopServer({ modelContext }));
|
|
97
132
|
await writeFile('src/webmcp-tools.json', JSON.stringify(tools));
|
|
98
133
|
```
|
|
@@ -109,24 +144,50 @@ void registerWebMcpTools(resolveDocumentModelContext(), tools, (modelContext) =>
|
|
|
109
144
|
);
|
|
110
145
|
```
|
|
111
146
|
|
|
112
|
-
- `listWebMcpTools(factory)` builds the server with a `modelContext` that records what the plugin registers,
|
|
113
|
-
|
|
114
|
-
|
|
147
|
+
- `listWebMcpTools(factory)` builds the server with a `modelContext` that records what the plugin registers, returns
|
|
148
|
+
those descriptors (name, title, description, input schema, hints) and disposes the server. The factory must pass the
|
|
149
|
+
`modelContext` it is given to `WebMcpPlugin.init()`.
|
|
115
150
|
- `registerWebMcpTools(modelContext, tools, loadServer, { exposedTo? })` registers the list at once. The first call
|
|
116
151
|
loads the server with `loadServer` (once, however many calls arrive together) and runs through the plugin; a failed
|
|
117
|
-
load rejects that call (a server it built is disposed, and the listed tools stay), and the next call tries again.
|
|
118
|
-
the server's tools change, and `server.dispose()`
|
|
119
|
-
unregistered. Without a `modelContext` (no WebMCP) it does
|
|
120
|
-
|
|
152
|
+
load rejects that call (a server it built is disposed, and the listed tools stay), and the next call tries again.
|
|
153
|
+
From then on the plugin registers and unregisters tools as the server's tools change, and `server.dispose()`
|
|
154
|
+
unregisters them. A listed tool the loaded server lacks is unregistered. Without a `modelContext` (no WebMCP) it does
|
|
155
|
+
nothing.
|
|
156
|
+
- `@frontmcp/plugin-webmcp/register` does not import `@frontmcp/sdk`; it is a few kilobytes. It exports
|
|
157
|
+
`registerWebMcpTools`, `resolveDocumentModelContext` and `isWebMcpSupported`.
|
|
121
158
|
|
|
122
159
|
## Browser support
|
|
123
160
|
|
|
124
|
-
WebMCP is
|
|
125
|
-
`chrome://flags/#enable-webmcp-testing`.
|
|
161
|
+
WebMCP is a draft. Chrome and Edge have it behind a flag or an origin trial; for local development, turn on
|
|
162
|
+
`chrome://flags/#enable-webmcp-testing`. The plugin follows the draft of 2026-09-30. See
|
|
163
|
+
[Browsers](https://frontmcp.dev/reference/plugins/webmcp#browsers) for where `document.modelContext` is available.
|
|
126
164
|
|
|
127
|
-
Where `document.modelContext` is missing, the plugin does nothing
|
|
128
|
-
up front. To support other browsers, load a polyfill that installs
|
|
129
|
-
creating the server, such as
|
|
130
|
-
|
|
165
|
+
Where `document.modelContext` is missing, the plugin does nothing and the server works as before;
|
|
166
|
+
`isWebMcpSupported()` tells you up front. To support other browsers, load a polyfill that installs
|
|
167
|
+
`document.modelContext` before creating the server, such as
|
|
168
|
+
[`@mcp-b/global`](https://www.npmjs.com/package/@mcp-b/global), or pass one as `modelContext`.
|
|
131
169
|
|
|
132
170
|
WebMCP exposes tools only: resources and prompts stay MCP-only.
|
|
171
|
+
|
|
172
|
+
## Docs
|
|
173
|
+
|
|
174
|
+
- [WebMCP plugin reference](https://frontmcp.dev/reference/plugins/webmcp): options, translation, who the server sees
|
|
175
|
+
calling, and troubleshooting.
|
|
176
|
+
- [Running in the browser](https://frontmcp.dev/reference/deployment/browser): what a FrontMCP server can do in a web
|
|
177
|
+
page.
|
|
178
|
+
|
|
179
|
+
## Related packages
|
|
180
|
+
|
|
181
|
+
- [`@frontmcp/sdk`](https://www.npmjs.com/package/@frontmcp/sdk): the FrontMCP framework, including `create()` for a
|
|
182
|
+
server in the page.
|
|
183
|
+
- [`@frontmcp/react`](https://www.npmjs.com/package/@frontmcp/react): React hooks and components for a server in the
|
|
184
|
+
page; tools a component adds with `useDynamicTool()` are offered to agents while it's mounted.
|
|
185
|
+
|
|
186
|
+
## Contributing
|
|
187
|
+
|
|
188
|
+
Source: [`plugins/plugin-webmcp`](https://github.com/agentfront/frontmcp/tree/main/plugins/plugin-webmcp). Issues and
|
|
189
|
+
pull requests are welcome; see [CONTRIBUTING.md](https://github.com/agentfront/frontmcp/blob/main/CONTRIBUTING.md).
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
Apache-2.0. See [LICENSE](https://github.com/agentfront/frontmcp/blob/main/LICENSE).
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-webmcp",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.7",
|
|
4
4
|
"description": "WebMCP plugin for FrontMCP - expose an in-browser FrontMCP server's tools to browser agents through document.modelContext",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
"node": ">=24.0.0"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
|
+
"frontmcp",
|
|
11
12
|
"mcp",
|
|
13
|
+
"model-context-protocol",
|
|
12
14
|
"webmcp",
|
|
13
15
|
"modelcontext",
|
|
14
16
|
"browser",
|
|
15
17
|
"agents",
|
|
16
18
|
"plugin",
|
|
17
|
-
"frontmcp",
|
|
18
19
|
"agentfront"
|
|
19
20
|
],
|
|
20
21
|
"repository": {
|
|
@@ -59,13 +60,14 @@
|
|
|
59
60
|
}
|
|
60
61
|
},
|
|
61
62
|
"dependencies": {
|
|
62
|
-
"@frontmcp/
|
|
63
|
-
"@frontmcp/utils": "1.9.5"
|
|
63
|
+
"@frontmcp/utils": "1.9.7"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
66
|
+
"@frontmcp/lazy-zod": "1.9.7",
|
|
67
|
+
"@frontmcp/sdk": "1.9.7"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
70
|
+
"@frontmcp/sdk": "1.9.7",
|
|
69
71
|
"reflect-metadata": "^0.2.2"
|
|
70
72
|
}
|
|
71
73
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-webmcp",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.7",
|
|
4
4
|
"description": "WebMCP plugin for FrontMCP - expose an in-browser FrontMCP server's tools to browser agents through document.modelContext",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
"node": ">=24.0.0"
|
|
9
9
|
},
|
|
10
10
|
"keywords": [
|
|
11
|
+
"frontmcp",
|
|
11
12
|
"mcp",
|
|
13
|
+
"model-context-protocol",
|
|
12
14
|
"webmcp",
|
|
13
15
|
"modelcontext",
|
|
14
16
|
"browser",
|
|
15
17
|
"agents",
|
|
16
18
|
"plugin",
|
|
17
|
-
"frontmcp",
|
|
18
19
|
"agentfront"
|
|
19
20
|
],
|
|
20
21
|
"repository": {
|
|
@@ -59,13 +60,14 @@
|
|
|
59
60
|
}
|
|
60
61
|
},
|
|
61
62
|
"dependencies": {
|
|
62
|
-
"@frontmcp/
|
|
63
|
-
"@frontmcp/utils": "1.9.5"
|
|
63
|
+
"@frontmcp/utils": "1.9.7"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
66
|
+
"@frontmcp/lazy-zod": "1.9.7",
|
|
67
|
+
"@frontmcp/sdk": "1.9.7"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
70
|
+
"@frontmcp/sdk": "1.9.7",
|
|
69
71
|
"reflect-metadata": "^0.2.2"
|
|
70
72
|
}
|
|
71
73
|
}
|