@webmcpui/webmcp 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +56 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +54 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gary Pfaff (Pfaff Digital)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @webmcpui/webmcp
|
|
2
|
+
|
|
3
|
+
The imperative [WebMCP](https://webmcpui.com/docs/webmcp) exposure layer, on its
|
|
4
|
+
own — zero dependencies, Lit-free, ~2 kB. Register tools with a page's
|
|
5
|
+
`document.modelContext` host without taking a dependency on the
|
|
6
|
+
[`@webmcpui/core`](https://www.npmjs.com/package/@webmcpui/core) component
|
|
7
|
+
library (which builds on this package).
|
|
8
|
+
|
|
9
|
+
Everything is additive and feature-detected: WebMCP ships only behind a Chrome
|
|
10
|
+
origin trial today, so on pages with no agent host every call is a safe no-op.
|
|
11
|
+
The package prefers the canonical `document.modelContext` and falls back to the
|
|
12
|
+
deprecated `navigator.modelContext`.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @webmcpui/webmcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Use
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { exposeTool, isWebMCPAvailable } from '@webmcpui/webmcp';
|
|
24
|
+
|
|
25
|
+
const dispose = exposeTool({
|
|
26
|
+
name: 'book_appointment',
|
|
27
|
+
description: 'Book the currently selected appointment slot.',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: { slot: { type: 'string' } },
|
|
31
|
+
required: ['slot'],
|
|
32
|
+
},
|
|
33
|
+
async execute(args) {
|
|
34
|
+
const slot = String(args.slot);
|
|
35
|
+
const ok = await book(slot);
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: ok ? `Booked ${slot}.` : 'Slot taken.' }],
|
|
38
|
+
isError: !ok,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Later — unregister the tool:
|
|
44
|
+
dispose();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API
|
|
48
|
+
|
|
49
|
+
- **`exposeTool(definition): ToolDisposer`** — registers a tool with the page's
|
|
50
|
+
WebMCP host (no-op returning a no-op disposer when none is present). Warns in
|
|
51
|
+
dev on duplicate tool names.
|
|
52
|
+
- **`isWebMCPAvailable(): boolean`** — whether a WebMCP host exists on this page.
|
|
53
|
+
- **Types** — `WebMCPToolDefinition`, `WebMCPToolResult`,
|
|
54
|
+
`WebMCPToolResultContent`, `JSONSchema`, `ToolDisposer`.
|
|
55
|
+
|
|
56
|
+
Part of [webmcpui](https://webmcpui.com). MIT licensed.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The imperative WebMCP exposure layer.
|
|
3
|
+
*
|
|
4
|
+
* WebMCP is an imperative API: `document.modelContext.registerTool(...)`. The
|
|
5
|
+
* surface is still churning — `document.modelContext` is canonical as of the
|
|
6
|
+
* Chrome 149+ origin trial, and `navigator.modelContext` is the original
|
|
7
|
+
* location, deprecated in Chrome 150 — so we feature-detect both and prefer
|
|
8
|
+
* `document`. As of mid-2026 it ships only behind the origin trial and is
|
|
9
|
+
* undefined for almost everyone, with no mainstream agent consuming it yet. So
|
|
10
|
+
* everything here is additive and feature-detected: a component must be a
|
|
11
|
+
* perfectly good form control with zero agent present.
|
|
12
|
+
*
|
|
13
|
+
* The API is `[SecureContext]`, so it only exists on HTTPS pages (localhost
|
|
14
|
+
* counts as secure); on plain-HTTP origins detection is a no-op by design.
|
|
15
|
+
*/
|
|
16
|
+
/** A JSON-Schema-ish description of a tool's parameters. */
|
|
17
|
+
type JSONSchema = Record<string, unknown>;
|
|
18
|
+
/** A single piece of a tool result. Today only `text` content is supported. */
|
|
19
|
+
interface WebMCPToolResultContent {
|
|
20
|
+
type: 'text';
|
|
21
|
+
text: string;
|
|
22
|
+
}
|
|
23
|
+
/** The value a tool's `execute` returns to the agent. */
|
|
24
|
+
interface WebMCPToolResult {
|
|
25
|
+
content: WebMCPToolResultContent[];
|
|
26
|
+
isError?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Describes a WebMCP tool to register via {@link exposeTool}. */
|
|
29
|
+
interface WebMCPToolDefinition {
|
|
30
|
+
/** Stable, unique tool name (snake_case by convention). */
|
|
31
|
+
name: string;
|
|
32
|
+
/** Natural-language description the agent reads to decide when to call it. */
|
|
33
|
+
description: string;
|
|
34
|
+
/** JSON Schema for the tool's arguments. */
|
|
35
|
+
inputSchema?: JSONSchema;
|
|
36
|
+
/** Invoked when the agent calls the tool. */
|
|
37
|
+
execute: (args: Record<string, unknown>) => WebMCPToolResult | Promise<WebMCPToolResult>;
|
|
38
|
+
}
|
|
39
|
+
/** Disposer returned by {@link exposeTool}; safe to call when nothing was registered. */
|
|
40
|
+
type ToolDisposer = () => void;
|
|
41
|
+
/** True when a WebMCP host is present in this environment. */
|
|
42
|
+
declare function isWebMCPAvailable(): boolean;
|
|
43
|
+
declare const isDevEnv: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Register a tool with the page's WebMCP host. Returns a disposer that
|
|
46
|
+
* unregisters it. If no host is present (the common case today), this is a
|
|
47
|
+
* no-op and the returned disposer does nothing — callers never need to branch.
|
|
48
|
+
*/
|
|
49
|
+
declare function exposeTool(definition: WebMCPToolDefinition): ToolDisposer;
|
|
50
|
+
|
|
51
|
+
export { type JSONSchema, type ToolDisposer, type WebMCPToolDefinition, type WebMCPToolResult, type WebMCPToolResultContent, exposeTool, isDevEnv, isWebMCPAvailable };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function getModelContext() {
|
|
3
|
+
const fromDocument = typeof document !== "undefined" ? document.modelContext : void 0;
|
|
4
|
+
const fromNavigator = typeof navigator !== "undefined" ? navigator.modelContext : void 0;
|
|
5
|
+
const mc = fromDocument ?? fromNavigator;
|
|
6
|
+
return mc && typeof mc.registerTool === "function" ? mc : void 0;
|
|
7
|
+
}
|
|
8
|
+
function isWebMCPAvailable() {
|
|
9
|
+
return getModelContext() !== void 0;
|
|
10
|
+
}
|
|
11
|
+
var isDevEnv = globalThis.process?.env?.NODE_ENV !== "production";
|
|
12
|
+
var registeredToolNames = /* @__PURE__ */ new Set();
|
|
13
|
+
function exposeTool(definition) {
|
|
14
|
+
const mc = getModelContext();
|
|
15
|
+
if (!mc?.registerTool) return () => {
|
|
16
|
+
};
|
|
17
|
+
const descriptor = {
|
|
18
|
+
name: definition.name,
|
|
19
|
+
description: definition.description,
|
|
20
|
+
inputSchema: definition.inputSchema ?? { type: "object", properties: {} },
|
|
21
|
+
execute: definition.execute
|
|
22
|
+
};
|
|
23
|
+
if (isDevEnv && registeredToolNames.has(descriptor.name)) {
|
|
24
|
+
console.warn(
|
|
25
|
+
`[webmcpui] A WebMCP tool named "${descriptor.name}" is already registered on this page. Tool names are page-global, so the host rejects the duplicate and this control won't be agent-callable. Give one control a unique \`name\`, or override it with \`tool-name\`.`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
registeredToolNames.add(descriptor.name);
|
|
29
|
+
const controller = typeof AbortController === "function" ? new AbortController() : void 0;
|
|
30
|
+
const handle = mc.registerTool(
|
|
31
|
+
descriptor,
|
|
32
|
+
controller ? { signal: controller.signal } : void 0
|
|
33
|
+
);
|
|
34
|
+
let disposed = false;
|
|
35
|
+
return () => {
|
|
36
|
+
if (disposed) return;
|
|
37
|
+
disposed = true;
|
|
38
|
+
registeredToolNames.delete(descriptor.name);
|
|
39
|
+
try {
|
|
40
|
+
controller?.abort();
|
|
41
|
+
if (handle && typeof handle.unregister === "function") {
|
|
42
|
+
handle.unregister();
|
|
43
|
+
} else if (typeof mc.unregisterTool === "function") {
|
|
44
|
+
mc.unregisterTool(definition.name);
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
exposeTool,
|
|
52
|
+
isDevEnv,
|
|
53
|
+
isWebMCPAvailable
|
|
54
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webmcpui/webmcp",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "Imperative WebMCP exposure layer — register browser-side tools with the model context host.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gary Pfaff (Pfaff Digital)",
|
|
7
|
+
"homepage": "https://webmcpui.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/webmcpui/webmcpui.git",
|
|
11
|
+
"directory": "packages/webmcp"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/webmcpui/webmcpui/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"webmcp",
|
|
18
|
+
"modelcontext",
|
|
19
|
+
"ai-agents"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"clean": "rm -rf dist"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"tsup": "^8.3.5",
|
|
41
|
+
"typescript": "^5.7.2"
|
|
42
|
+
}
|
|
43
|
+
}
|