@jini-ai/agentic 0.1.0 → 0.1.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/dist/a2ui/agent-to-renderer.d.ts +579 -0
- package/dist/a2ui/agent-to-renderer.d.ts.map +1 -0
- package/dist/a2ui/agent-to-renderer.js +169 -0
- package/dist/a2ui/agent-to-renderer.js.map +1 -0
- package/dist/a2ui/catalog.d.ts +73 -0
- package/dist/a2ui/catalog.d.ts.map +1 -0
- package/dist/a2ui/catalog.js +304 -0
- package/dist/a2ui/catalog.js.map +1 -0
- package/dist/a2ui/common-types.d.ts +401 -0
- package/dist/a2ui/common-types.d.ts.map +1 -0
- package/dist/a2ui/common-types.js +130 -0
- package/dist/a2ui/common-types.js.map +1 -0
- package/dist/a2ui/index.d.ts +16 -0
- package/dist/a2ui/index.d.ts.map +1 -0
- package/dist/a2ui/index.js +16 -0
- package/dist/a2ui/index.js.map +1 -0
- package/dist/a2ui/interpreter.d.ts +48 -0
- package/dist/a2ui/interpreter.d.ts.map +1 -0
- package/dist/a2ui/interpreter.js +287 -0
- package/dist/a2ui/interpreter.js.map +1 -0
- package/dist/a2ui/json-pointer.d.ts +48 -0
- package/dist/a2ui/json-pointer.d.ts.map +1 -0
- package/dist/a2ui/json-pointer.js +149 -0
- package/dist/a2ui/json-pointer.js.map +1 -0
- package/dist/a2ui/renderer-to-agent.d.ts +318 -0
- package/dist/a2ui/renderer-to-agent.d.ts.map +1 -0
- package/dist/a2ui/renderer-to-agent.js +98 -0
- package/dist/a2ui/renderer-to-agent.js.map +1 -0
- package/dist/a2ui/resolve.d.ts +28 -0
- package/dist/a2ui/resolve.d.ts.map +1 -0
- package/dist/a2ui/resolve.js +118 -0
- package/dist/a2ui/resolve.js.map +1 -0
- package/dist/a2ui/tree.d.ts +41 -0
- package/dist/a2ui/tree.d.ts.map +1 -0
- package/dist/a2ui/tree.js +35 -0
- package/dist/a2ui/tree.js.map +1 -0
- package/dist/dom/model-context.d.ts +15 -0
- package/dist/dom/model-context.d.ts.map +1 -1
- package/dist/dom/model-context.js +8 -0
- package/dist/dom/model-context.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-ui-apps.d.ts +81 -10
- package/dist/mcp-ui-apps.d.ts.map +1 -1
- package/dist/mcp-ui-apps.js +84 -11
- package/dist/mcp-ui-apps.js.map +1 -1
- package/dist/webmcp.d.ts +126 -5
- package/dist/webmcp.d.ts.map +1 -1
- package/dist/webmcp.js +110 -4
- package/dist/webmcp.js.map +1 -1
- package/package.json +14 -5
package/dist/webmcp.d.ts
CHANGED
|
@@ -14,14 +14,91 @@
|
|
|
14
14
|
* That detection is deliberately NOT here: it touches browser globals, and this package holds
|
|
15
15
|
* none. Framework bindings own host access; this file owns only the shape translation, so when
|
|
16
16
|
* the registration shape changes again there is exactly one place to change it.
|
|
17
|
+
*
|
|
18
|
+
* Re-verified 2026-07-28 against the primary spec source
|
|
19
|
+
* (https://webmachinelearning.github.io/webmcp/, `index.bs`). Four real gaps closed this pass,
|
|
20
|
+
* all additive — none change the confirmation gate below, which is Jini's own addition and has
|
|
21
|
+
* no spec counterpart:
|
|
22
|
+
*
|
|
23
|
+
* 1. **`signal`/`exposedTo`** — `ModelContextRegisterToolOptions`, the *second* positional
|
|
24
|
+
* argument to `registerTool(tool, options)`. `signal` is the spec's ONLY unregistration
|
|
25
|
+
* mechanism (there is no `unregisterTool()`); aborting it removes the tool and fires
|
|
26
|
+
* `toolchange`. `exposedTo` scopes which cross-origin documents in the same tree may see the
|
|
27
|
+
* tool. Neither belongs on the `ModelContextTool` dict itself, so they are not fields of
|
|
28
|
+
* {@link WebMcpToolRegistration} — they ride along on its optional `registerOptions`, computed
|
|
29
|
+
* from {@link ToWebMcpToolOptions}, so a caller has exactly one object to destructure:
|
|
30
|
+
* `modelContext.registerTool(reg, reg.registerOptions)`.
|
|
31
|
+
* 2. **`title`/`annotations`** — real `ModelContextTool` dict fields (`USVString title`,
|
|
32
|
+
* `ToolAnnotations annotations`), now on {@link WebMcpToolRegistration}. `annotations.readOnlyHint`
|
|
33
|
+
* defaults from {@link CapabilityDef.risk} (`'read'` → `true`) since Jini's manifests already
|
|
34
|
+
* carry that judgment; a caller may override or add `untrustedContentHint` via `options.annotations`.
|
|
35
|
+
* 3. **Tool name validation** — the spec's `registerTool` algorithm rejects (with an
|
|
36
|
+
* `InvalidStateError` `DOMException`) a name that is empty, over 128 code points, or contains
|
|
37
|
+
* anything outside ASCII alphanumeric plus `_`, `-`, `.`. `capability.id` becomes `name`
|
|
38
|
+
* verbatim, so a malformed manifest entry previously surfaced as a cryptic browser-side
|
|
39
|
+
* rejection days later; {@link toWebMcpTool} now checks it at projection time and names the
|
|
40
|
+
* offending capability.
|
|
41
|
+
* 4. **Schema-on-error** — WebMCP defines no input validation of its own (the spec's
|
|
42
|
+
* `ToolExecuteCallback` is just `Promise<any> (object input)`), and this module's own doc used
|
|
43
|
+
* to say so ("the caller is responsible for validating it... WebMCP does not"). That left a
|
|
44
|
+
* wrong-schema call to fail deep inside whatever `execute` does, with no way for the caller to
|
|
45
|
+
* self-correct in the same turn. `execute` now runs the manifest's own
|
|
46
|
+
* {@link findCapabilityInputError} first and, on failure, throws the same
|
|
47
|
+
* `"<id>: <reason>. Expected input: <schema>"` shape `page-executor.ts` already uses for
|
|
48
|
+
* `page.*` — one discipline, not two.
|
|
17
49
|
*/
|
|
18
|
-
import type
|
|
50
|
+
import { type CapabilityDef, type CapabilityInputSchema } from './capability.js';
|
|
19
51
|
/** The registration object `registerTool` accepts. WebMCP names the schema field `inputSchema`. */
|
|
20
52
|
export interface WebMcpToolRegistration {
|
|
21
53
|
readonly name: string;
|
|
54
|
+
/**
|
|
55
|
+
* `ModelContextTool.title` — an optional human-readable label, distinct from `name` (the
|
|
56
|
+
* machine identifier) and `description` (what an agent reads to decide whether to call it). The
|
|
57
|
+
* spec recommends localizing it to the user's language; this projection makes no attempt at
|
|
58
|
+
* that; a caller wanting a localized title supplies it via `options.title`.
|
|
59
|
+
*/
|
|
60
|
+
readonly title?: string;
|
|
22
61
|
readonly description: string;
|
|
23
62
|
readonly inputSchema: CapabilityInputSchema;
|
|
24
63
|
readonly execute: (args: Record<string, unknown>) => Promise<unknown>;
|
|
64
|
+
/** `ModelContextTool.annotations` — behavior hints. See {@link WebMcpToolAnnotations}. */
|
|
65
|
+
readonly annotations?: WebMcpToolAnnotations;
|
|
66
|
+
/**
|
|
67
|
+
* The SECOND positional argument `registerTool(tool, options)` expects — the spec's
|
|
68
|
+
* `ModelContextRegisterToolOptions`, not part of the `ModelContextTool` dict this object
|
|
69
|
+
* otherwise models. Present only when `options.signal` or `options.exposedTo` was supplied.
|
|
70
|
+
* Bundled here rather than returned as a second value so `toWebMcpTool`'s output stays a single
|
|
71
|
+
* object a caller can pass straight through: `modelContext.registerTool(reg, reg.registerOptions)`.
|
|
72
|
+
*/
|
|
73
|
+
readonly registerOptions?: WebMcpRegisterToolOptions;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* `ToolAnnotations` — optional behavior hints a host UI or agent may use to decide how to treat a
|
|
77
|
+
* tool without calling it. Both default to `false` in the spec; this projection only ever sets
|
|
78
|
+
* `readOnlyHint` by default (from {@link CapabilityDef.risk}) and leaves `untrustedContentHint`
|
|
79
|
+
* unset unless a caller supplies one, since nothing in {@link CapabilityDef} implies it.
|
|
80
|
+
*/
|
|
81
|
+
export interface WebMcpToolAnnotations {
|
|
82
|
+
/** True when the tool never mutates state. Defaults from `capability.risk === 'read'`. */
|
|
83
|
+
readonly readOnlyHint?: boolean;
|
|
84
|
+
/** True when the tool's return value may contain content from outside the page's trust boundary. */
|
|
85
|
+
readonly untrustedContentHint?: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* `ModelContextRegisterToolOptions` — the second positional argument to the real
|
|
89
|
+
* `registerTool(tool, options)`, per the spec IDL:
|
|
90
|
+
* `dictionary ModelContextRegisterToolOptions { AbortSignal signal; sequence<USVString> exposedTo; }`.
|
|
91
|
+
*/
|
|
92
|
+
export interface WebMcpRegisterToolOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Aborting this unregisters the tool and rejects the in-flight `registerTool()` promise with the
|
|
95
|
+
* signal's abort reason — the spec's ONLY unregistration mechanism. There is no `unregisterTool()`
|
|
96
|
+
* in the current draft; a host that wants to drop a tool later must have registered it with a
|
|
97
|
+
* signal in the first place.
|
|
98
|
+
*/
|
|
99
|
+
readonly signal?: AbortSignal;
|
|
100
|
+
/** Origins (besides same-origin, always allowed) that may see and call this tool from other documents in the same tree. */
|
|
101
|
+
readonly exposedTo?: readonly string[];
|
|
25
102
|
}
|
|
26
103
|
/** What a confirmation handler is asked to approve. */
|
|
27
104
|
export interface WebMcpUserInteraction {
|
|
@@ -36,10 +113,34 @@ export interface WebMcpUserInteraction {
|
|
|
36
113
|
* (https://webmachinelearning.github.io/webmcp/) does not define one, so there is nothing to
|
|
37
114
|
* feature-detect and nothing standard to call. A host that wants a confirmed WebMCP tool supplies
|
|
38
115
|
* this itself.
|
|
116
|
+
*
|
|
117
|
+
* Independently re-confirmed 2026-07-28: the reference polyfill `@mcp-b/webmcp-polyfill` (the
|
|
118
|
+
* `MCP-B`/`WebMCP-org` community project, not the W3C CG spec) DOES pass a second
|
|
119
|
+
* `client: { requestUserInteraction(callback) }` argument to `execute`, as one of its own
|
|
120
|
+
* non-standard "MCPB extensions". That is further evidence the idea is real and wanted, and
|
|
121
|
+
* further confirmation it is NOT part of the standardized `ToolExecuteCallback` — whose IDL is
|
|
122
|
+
* `Promise<any> (object input)`, one argument. This module's `execute` wrapper below takes one
|
|
123
|
+
* argument for exactly that reason; a second, ignored argument from a polyfill is harmless.
|
|
39
124
|
*/
|
|
40
125
|
export type RequestUserInteraction = (interaction: WebMcpUserInteraction) => Promise<boolean>;
|
|
41
126
|
export interface ToWebMcpToolOptions {
|
|
42
127
|
readonly requestUserInteraction?: RequestUserInteraction;
|
|
128
|
+
/**
|
|
129
|
+
* `ModelContextTool.title`. Meaningful per-capability, so pass this through {@link toWebMcpTool}
|
|
130
|
+
* (one capability) rather than {@link toWebMcpTools} (a whole manifest) — the latter shares one
|
|
131
|
+
* `options` object across every capability in the batch, and a shared title would repeat
|
|
132
|
+
* verbatim across dissimilar tools.
|
|
133
|
+
*/
|
|
134
|
+
readonly title?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Overrides or extends the default `annotations` (`{ readOnlyHint: capability.risk === 'read' }`).
|
|
137
|
+
* Fields set here win over the default.
|
|
138
|
+
*/
|
|
139
|
+
readonly annotations?: WebMcpToolAnnotations;
|
|
140
|
+
/** See {@link WebMcpRegisterToolOptions.signal}. Safe to share across a whole {@link toWebMcpTools} batch — one `AbortController` per registration session, aborted once on teardown. */
|
|
141
|
+
readonly signal?: AbortSignal;
|
|
142
|
+
/** See {@link WebMcpRegisterToolOptions.exposedTo}. Safe to share across a whole {@link toWebMcpTools} batch when every capability in it gets the same scoping. */
|
|
143
|
+
readonly exposedTo?: readonly string[];
|
|
43
144
|
}
|
|
44
145
|
/** Thrown in place of executing, when a call needed confirmation and did not get it. */
|
|
45
146
|
export declare class WebMcpConfirmationRequiredError extends Error {
|
|
@@ -47,6 +148,17 @@ export declare class WebMcpConfirmationRequiredError extends Error {
|
|
|
47
148
|
readonly reason: 'declined' | 'no-handler';
|
|
48
149
|
constructor(capabilityId: string, reason: 'declined' | 'no-handler');
|
|
49
150
|
}
|
|
151
|
+
/** Whether `name` satisfies the spec's tool-name rule. Exported so a caller can pre-check a manifest without registering anything. */
|
|
152
|
+
export declare function isValidWebMcpToolName(name: string): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Thrown synchronously by {@link toWebMcpTool} for a capability whose `id` cannot legally become a
|
|
155
|
+
* WebMCP tool name. Distinct from {@link WebMcpConfirmationRequiredError}: this is a manifest
|
|
156
|
+
* defect caught before any registration is attempted, not a runtime refusal of a call.
|
|
157
|
+
*/
|
|
158
|
+
export declare class InvalidWebMcpToolNameError extends Error {
|
|
159
|
+
readonly capabilityId: string;
|
|
160
|
+
constructor(capabilityId: string);
|
|
161
|
+
}
|
|
50
162
|
/**
|
|
51
163
|
* Projects one capability into a WebMCP registration.
|
|
52
164
|
*
|
|
@@ -61,11 +173,13 @@ export declare class WebMcpConfirmationRequiredError extends Error {
|
|
|
61
173
|
* capability reaching the page with nothing in front of it — not the authorization gap.
|
|
62
174
|
*
|
|
63
175
|
* @param capability - The capability to expose.
|
|
64
|
-
* @param execute - Runs the capability. Receives the raw argument object
|
|
65
|
-
*
|
|
66
|
-
* @param options - Optional confirmation handler
|
|
67
|
-
* declaring `requiresConfirmation`.
|
|
176
|
+
* @param execute - Runs the capability. Receives the raw argument object, already checked against
|
|
177
|
+
* `capability.inputSchema` — a caller-supplied value that fails validation never reaches this.
|
|
178
|
+
* @param options - Optional confirmation handler, title/annotations, and registration options
|
|
179
|
+
* (`signal`/`exposedTo`); required in practice for any capability declaring `requiresConfirmation`.
|
|
68
180
|
* @returns The registration object to hand to `registerTool`.
|
|
181
|
+
* @throws {@link InvalidWebMcpToolNameError} synchronously, if `capability.id` cannot be a WebMCP
|
|
182
|
+
* tool name.
|
|
69
183
|
* @throws {@link WebMcpConfirmationRequiredError} from `execute`, when confirmation is required
|
|
70
184
|
* and is either declined or unobtainable.
|
|
71
185
|
*/
|
|
@@ -73,9 +187,16 @@ export declare function toWebMcpTool(capability: CapabilityDef, execute: (id: st
|
|
|
73
187
|
/**
|
|
74
188
|
* Projects a whole manifest.
|
|
75
189
|
*
|
|
190
|
+
* `options` is shared across every capability — safe for `requestUserInteraction`, `signal`, and
|
|
191
|
+
* `exposedTo`, which are naturally uniform for one registration session; do not pass `title`
|
|
192
|
+
* through this one, since it would repeat verbatim across every tool in the manifest (see
|
|
193
|
+
* {@link ToWebMcpToolOptions.title}).
|
|
194
|
+
*
|
|
76
195
|
* @param capabilities - Capabilities to expose, already filtered by whatever policy applies.
|
|
77
196
|
* @param execute - Shared dispatcher, keyed by capability id.
|
|
78
197
|
* @returns One registration per capability, in manifest order.
|
|
198
|
+
* @throws {@link InvalidWebMcpToolNameError} synchronously, for the first capability whose `id`
|
|
199
|
+
* cannot be a WebMCP tool name.
|
|
79
200
|
*/
|
|
80
201
|
export declare function toWebMcpTools(capabilities: readonly CapabilityDef[], execute: (id: string, args: Record<string, unknown>) => Promise<unknown>, options?: ToWebMcpToolOptions): readonly WebMcpToolRegistration[];
|
|
81
202
|
//# sourceMappingURL=webmcp.d.ts.map
|
package/dist/webmcp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webmcp.d.ts","sourceRoot":"","sources":["../src/webmcp.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"webmcp.d.ts","sourceRoot":"","sources":["../src/webmcp.ts"],"names":[],"mappings":"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"}
|
package/dist/webmcp.js
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module webmcp
|
|
3
|
+
*
|
|
4
|
+
* Projection: {@link CapabilityDef} → a WebMCP tool registration.
|
|
5
|
+
*
|
|
6
|
+
* WebMCP (`document.modelContext.registerTool`) is the browser API by which a *page* offers
|
|
7
|
+
* tools to an agent running inside the browser. It is a W3C Community Group draft, not a
|
|
8
|
+
* standards-track spec, and it moves: the API relocated from `navigator.modelContext` to
|
|
9
|
+
* `document.modelContext` on 2026-07-21, Chrome 150 deprecated the `navigator` location while
|
|
10
|
+
* still serving it during the origin trial (Chrome 149–156), Edge ships it behind a flag, and
|
|
11
|
+
* Firefox and Safari have made no commitment. Feature detection must therefore check `document`
|
|
12
|
+
* first and fall back to `navigator`.
|
|
13
|
+
*
|
|
14
|
+
* That detection is deliberately NOT here: it touches browser globals, and this package holds
|
|
15
|
+
* none. Framework bindings own host access; this file owns only the shape translation, so when
|
|
16
|
+
* the registration shape changes again there is exactly one place to change it.
|
|
17
|
+
*
|
|
18
|
+
* Re-verified 2026-07-28 against the primary spec source
|
|
19
|
+
* (https://webmachinelearning.github.io/webmcp/, `index.bs`). Four real gaps closed this pass,
|
|
20
|
+
* all additive — none change the confirmation gate below, which is Jini's own addition and has
|
|
21
|
+
* no spec counterpart:
|
|
22
|
+
*
|
|
23
|
+
* 1. **`signal`/`exposedTo`** — `ModelContextRegisterToolOptions`, the *second* positional
|
|
24
|
+
* argument to `registerTool(tool, options)`. `signal` is the spec's ONLY unregistration
|
|
25
|
+
* mechanism (there is no `unregisterTool()`); aborting it removes the tool and fires
|
|
26
|
+
* `toolchange`. `exposedTo` scopes which cross-origin documents in the same tree may see the
|
|
27
|
+
* tool. Neither belongs on the `ModelContextTool` dict itself, so they are not fields of
|
|
28
|
+
* {@link WebMcpToolRegistration} — they ride along on its optional `registerOptions`, computed
|
|
29
|
+
* from {@link ToWebMcpToolOptions}, so a caller has exactly one object to destructure:
|
|
30
|
+
* `modelContext.registerTool(reg, reg.registerOptions)`.
|
|
31
|
+
* 2. **`title`/`annotations`** — real `ModelContextTool` dict fields (`USVString title`,
|
|
32
|
+
* `ToolAnnotations annotations`), now on {@link WebMcpToolRegistration}. `annotations.readOnlyHint`
|
|
33
|
+
* defaults from {@link CapabilityDef.risk} (`'read'` → `true`) since Jini's manifests already
|
|
34
|
+
* carry that judgment; a caller may override or add `untrustedContentHint` via `options.annotations`.
|
|
35
|
+
* 3. **Tool name validation** — the spec's `registerTool` algorithm rejects (with an
|
|
36
|
+
* `InvalidStateError` `DOMException`) a name that is empty, over 128 code points, or contains
|
|
37
|
+
* anything outside ASCII alphanumeric plus `_`, `-`, `.`. `capability.id` becomes `name`
|
|
38
|
+
* verbatim, so a malformed manifest entry previously surfaced as a cryptic browser-side
|
|
39
|
+
* rejection days later; {@link toWebMcpTool} now checks it at projection time and names the
|
|
40
|
+
* offending capability.
|
|
41
|
+
* 4. **Schema-on-error** — WebMCP defines no input validation of its own (the spec's
|
|
42
|
+
* `ToolExecuteCallback` is just `Promise<any> (object input)`), and this module's own doc used
|
|
43
|
+
* to say so ("the caller is responsible for validating it... WebMCP does not"). That left a
|
|
44
|
+
* wrong-schema call to fail deep inside whatever `execute` does, with no way for the caller to
|
|
45
|
+
* self-correct in the same turn. `execute` now runs the manifest's own
|
|
46
|
+
* {@link findCapabilityInputError} first and, on failure, throws the same
|
|
47
|
+
* `"<id>: <reason>. Expected input: <schema>"` shape `page-executor.ts` already uses for
|
|
48
|
+
* `page.*` — one discipline, not two.
|
|
49
|
+
*/
|
|
50
|
+
import { findCapabilityInputError } from './capability.js';
|
|
1
51
|
/** Thrown in place of executing, when a call needed confirmation and did not get it. */
|
|
2
52
|
export class WebMcpConfirmationRequiredError extends Error {
|
|
3
53
|
capabilityId;
|
|
@@ -11,6 +61,32 @@ export class WebMcpConfirmationRequiredError extends Error {
|
|
|
11
61
|
this.name = 'WebMcpConfirmationRequiredError';
|
|
12
62
|
}
|
|
13
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* The spec's tool-name rule, verbatim: "The tool definition's name's length must be between 1 and
|
|
66
|
+
* 128, inclusive, and only consist of ASCII alphanumeric code points, U+005F LOW LINE (_), U+002D
|
|
67
|
+
* HYPHEN-MINUS (-), and U+002E FULL STOP (.)." A name outside this is rejected by `registerTool`
|
|
68
|
+
* with an `InvalidStateError` `DOMException` — this projection checks it earlier, at manifest time.
|
|
69
|
+
*/
|
|
70
|
+
const WEBMCP_TOOL_NAME_PATTERN = /^[A-Za-z0-9_.-]{1,128}$/;
|
|
71
|
+
/** Whether `name` satisfies the spec's tool-name rule. Exported so a caller can pre-check a manifest without registering anything. */
|
|
72
|
+
export function isValidWebMcpToolName(name) {
|
|
73
|
+
return WEBMCP_TOOL_NAME_PATTERN.test(name);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Thrown synchronously by {@link toWebMcpTool} for a capability whose `id` cannot legally become a
|
|
77
|
+
* WebMCP tool name. Distinct from {@link WebMcpConfirmationRequiredError}: this is a manifest
|
|
78
|
+
* defect caught before any registration is attempted, not a runtime refusal of a call.
|
|
79
|
+
*/
|
|
80
|
+
export class InvalidWebMcpToolNameError extends Error {
|
|
81
|
+
capabilityId;
|
|
82
|
+
constructor(capabilityId) {
|
|
83
|
+
super(`WebMCP: capability id "${capabilityId}" is not a valid tool name — the spec requires 1-128 `
|
|
84
|
+
+ 'ASCII alphanumeric characters plus "_", "-", "." '
|
|
85
|
+
+ '(https://webmachinelearning.github.io/webmcp/#dom-modelcontext-registertool)');
|
|
86
|
+
this.capabilityId = capabilityId;
|
|
87
|
+
this.name = 'InvalidWebMcpToolNameError';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
14
90
|
/**
|
|
15
91
|
* Projects one capability into a WebMCP registration.
|
|
16
92
|
*
|
|
@@ -25,21 +101,42 @@ export class WebMcpConfirmationRequiredError extends Error {
|
|
|
25
101
|
* capability reaching the page with nothing in front of it — not the authorization gap.
|
|
26
102
|
*
|
|
27
103
|
* @param capability - The capability to expose.
|
|
28
|
-
* @param execute - Runs the capability. Receives the raw argument object
|
|
29
|
-
*
|
|
30
|
-
* @param options - Optional confirmation handler
|
|
31
|
-
* declaring `requiresConfirmation`.
|
|
104
|
+
* @param execute - Runs the capability. Receives the raw argument object, already checked against
|
|
105
|
+
* `capability.inputSchema` — a caller-supplied value that fails validation never reaches this.
|
|
106
|
+
* @param options - Optional confirmation handler, title/annotations, and registration options
|
|
107
|
+
* (`signal`/`exposedTo`); required in practice for any capability declaring `requiresConfirmation`.
|
|
32
108
|
* @returns The registration object to hand to `registerTool`.
|
|
109
|
+
* @throws {@link InvalidWebMcpToolNameError} synchronously, if `capability.id` cannot be a WebMCP
|
|
110
|
+
* tool name.
|
|
33
111
|
* @throws {@link WebMcpConfirmationRequiredError} from `execute`, when confirmation is required
|
|
34
112
|
* and is either declined or unobtainable.
|
|
35
113
|
*/
|
|
36
114
|
export function toWebMcpTool(capability, execute, options = {}) {
|
|
115
|
+
if (!isValidWebMcpToolName(capability.id)) {
|
|
116
|
+
throw new InvalidWebMcpToolNameError(capability.id);
|
|
117
|
+
}
|
|
118
|
+
const { title, annotations, signal, exposedTo } = options;
|
|
119
|
+
const resolvedAnnotations = {
|
|
120
|
+
readOnlyHint: capability.risk === 'read',
|
|
121
|
+
...annotations,
|
|
122
|
+
};
|
|
123
|
+
const registerOptions = signal !== undefined || exposedTo !== undefined
|
|
124
|
+
? { ...(signal !== undefined ? { signal } : {}), ...(exposedTo !== undefined ? { exposedTo } : {}) }
|
|
125
|
+
: undefined;
|
|
37
126
|
return {
|
|
38
127
|
name: capability.id,
|
|
128
|
+
...(title !== undefined ? { title } : {}),
|
|
39
129
|
description: capability.description,
|
|
40
130
|
inputSchema: capability.inputSchema,
|
|
41
131
|
execute: async (args) => {
|
|
42
132
|
const input = args ?? {};
|
|
133
|
+
// Schema-on-error, matching page-executor.ts's discipline for page.* — WebMCP defines no
|
|
134
|
+
// input validation of its own, so a wrong-schema call would otherwise reach `execute` (or a
|
|
135
|
+
// confirmation prompt for one) with bad arguments instead of a same-turn correctable error.
|
|
136
|
+
const inputError = findCapabilityInputError(capability, input);
|
|
137
|
+
if (inputError !== null) {
|
|
138
|
+
throw new Error(`${capability.id}: ${inputError}. Expected input: ${JSON.stringify(capability.inputSchema)}`);
|
|
139
|
+
}
|
|
43
140
|
if (capability.requiresConfirmation === true) {
|
|
44
141
|
const { requestUserInteraction } = options;
|
|
45
142
|
if (!requestUserInteraction) {
|
|
@@ -52,14 +149,23 @@ export function toWebMcpTool(capability, execute, options = {}) {
|
|
|
52
149
|
}
|
|
53
150
|
return execute(capability.id, input);
|
|
54
151
|
},
|
|
152
|
+
annotations: resolvedAnnotations,
|
|
153
|
+
...(registerOptions !== undefined ? { registerOptions } : {}),
|
|
55
154
|
};
|
|
56
155
|
}
|
|
57
156
|
/**
|
|
58
157
|
* Projects a whole manifest.
|
|
59
158
|
*
|
|
159
|
+
* `options` is shared across every capability — safe for `requestUserInteraction`, `signal`, and
|
|
160
|
+
* `exposedTo`, which are naturally uniform for one registration session; do not pass `title`
|
|
161
|
+
* through this one, since it would repeat verbatim across every tool in the manifest (see
|
|
162
|
+
* {@link ToWebMcpToolOptions.title}).
|
|
163
|
+
*
|
|
60
164
|
* @param capabilities - Capabilities to expose, already filtered by whatever policy applies.
|
|
61
165
|
* @param execute - Shared dispatcher, keyed by capability id.
|
|
62
166
|
* @returns One registration per capability, in manifest order.
|
|
167
|
+
* @throws {@link InvalidWebMcpToolNameError} synchronously, for the first capability whose `id`
|
|
168
|
+
* cannot be a WebMCP tool name.
|
|
63
169
|
*/
|
|
64
170
|
export function toWebMcpTools(capabilities, execute, options = {}) {
|
|
65
171
|
return capabilities.map((capability) => toWebMcpTool(capability, execute, options));
|
package/dist/webmcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webmcp.js","sourceRoot":"","sources":["../src/webmcp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webmcp.js","sourceRoot":"","sources":["../src/webmcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,OAAO,EAAE,wBAAwB,EAAkD,MAAM,iBAAiB,CAAC;AAsG3G,wFAAwF;AACxF,MAAM,OAAO,+BAAgC,SAAQ,KAAK;IACnC;IAA+B;IAApD,YAAqB,YAAoB,EAAW,MAAiC;QACnF,KAAK,CACH,MAAM,KAAK,UAAU;YACnB,CAAC,CAAC,YAAY,YAAY,4BAA4B;YACtD,CAAC,CAAC,YAAY,YAAY,6EAA6E,CAC1G,CAAC;QALiB,iBAAY,GAAZ,YAAY,CAAQ;QAAW,WAAM,GAAN,MAAM,CAA2B;QAMnF,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,yBAAyB,CAAC;AAE3D,sIAAsI;AACtI,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,OAAO,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC9B;IAArB,YAAqB,YAAoB;QACvC,KAAK,CACH,0BAA0B,YAAY,uDAAuD;cAC3F,mDAAmD;cACnD,8EAA8E,CACjF,CAAC;QALiB,iBAAY,GAAZ,YAAY,CAAQ;QAMvC,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,YAAY,CAC1B,UAAyB,EACzB,OAAwE,EACxE,UAA+B,EAAE;IAEjC,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,0BAA0B,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC1D,MAAM,mBAAmB,GAA0B;QACjD,YAAY,EAAE,UAAU,CAAC,IAAI,KAAK,MAAM;QACxC,GAAG,WAAW;KACf,CAAC;IACF,MAAM,eAAe,GACnB,MAAM,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS;QAC7C,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QACpG,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,EAAE;QACnB,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACtB,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;YAEzB,yFAAyF;YACzF,4FAA4F;YAC5F,4FAA4F;YAC5F,MAAM,UAAU,GAAG,wBAAwB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC/D,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,CAAC,EAAE,KAAK,UAAU,qBAAqB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAChH,CAAC;YAED,IAAI,UAAU,CAAC,oBAAoB,KAAK,IAAI,EAAE,CAAC;gBAC7C,MAAM,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC;gBAC3C,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBAC5B,MAAM,IAAI,+BAA+B,CAAC,UAAU,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;gBACzE,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC3E,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;oBACtB,MAAM,IAAI,+BAA+B,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;QACD,WAAW,EAAE,mBAAmB;QAChC,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAC3B,YAAsC,EACtC,OAAwE,EACxE,UAA+B,EAAE;IAEjC,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AACtF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/agentic",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,18 +14,26 @@
|
|
|
14
14
|
"admission": "admitted",
|
|
15
15
|
"entries": {
|
|
16
16
|
".": "universal",
|
|
17
|
-
"./dom": "browser"
|
|
17
|
+
"./dom": "browser",
|
|
18
|
+
"./a2ui": "universal"
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
"type": "module",
|
|
21
22
|
"exports": {
|
|
22
23
|
".": {
|
|
23
24
|
"types": "./dist/index.d.ts",
|
|
24
|
-
"import": "./dist/index.js"
|
|
25
|
+
"import": "./dist/index.js",
|
|
26
|
+
"default": "./dist/index.js"
|
|
25
27
|
},
|
|
26
28
|
"./dom": {
|
|
27
29
|
"types": "./dist/dom/index.d.ts",
|
|
28
|
-
"import": "./dist/dom/index.js"
|
|
30
|
+
"import": "./dist/dom/index.js",
|
|
31
|
+
"default": "./dist/dom/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./a2ui": {
|
|
34
|
+
"types": "./dist/a2ui/index.d.ts",
|
|
35
|
+
"import": "./dist/a2ui/index.js",
|
|
36
|
+
"default": "./dist/a2ui/index.js"
|
|
29
37
|
}
|
|
30
38
|
},
|
|
31
39
|
"files": [
|
|
@@ -41,7 +49,8 @@
|
|
|
41
49
|
"registry": "https://registry.npmjs.org"
|
|
42
50
|
},
|
|
43
51
|
"dependencies": {
|
|
44
|
-
"
|
|
52
|
+
"zod": "^3.25.76",
|
|
53
|
+
"@jini-ai/protocol": "0.1.1"
|
|
45
54
|
},
|
|
46
55
|
"devDependencies": {
|
|
47
56
|
"@vitest/coverage-v8": "^2.1.9",
|