@agent-surface/webmcp 0.24.0 → 0.26.0

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Experimental.** The WebMCP (`navigator.modelContext`) surface area, permission model, and lifecycle are unstable; this adapter tracks them and absorbs the drift so nothing WebMCP-shaped leaks into `@agent-surface/core`. The application model stays in agent-surface — WebMCP is strictly transport/discovery.
4
4
 
5
- WebMCP transport adapter for [agent-surface](https://github.com/Wiseair-srl/agent-surface): one wire-named tool per **available** capability, re-provided on every `surface-changed`. Unavailable capabilities are not registered (WebMCP has no disabled state today — the availability reason is lost on this transport; accepted limitation). The user agent is treated as the least-trusted consumer: scope the adapter and keep two-phase confirmations.
5
+ WebMCP transport adapter for [agent-surface](https://github.com/Wiseair-srl/agent-surface): one wire-named tool per **available** capability, reconciled on every `surface-changed` (incremental `registerTool`/`unregisterTool` when the browser has them, a full `provideContext` otherwise). Unavailable capabilities are not registered (WebMCP has no disabled state today, so the availability reason is lost on this transport; accepted limitation). Observations and read-only effects carry `annotations.readOnlyHint`. The user agent is treated as the least-trusted consumer: scope the adapter and keep confirmations governed by the registry.
6
6
 
7
7
  Docs: https://agent-surface.dev
8
8
 
@@ -23,7 +23,33 @@ const adapter = createWebMcpAdapter({
23
23
  adapter.start({ registry, consumer: { id: "browser-agent", kind: "webmcp" } });
24
24
  ```
25
25
 
26
- If `navigator.modelContext` is absent, `start()` resolves and does nothing (feature-detect, never polyfill). Capability errors ride in tool content with `code`/`retry`/`details` preserved — never protocol-level errors.
26
+ If `navigator.modelContext` is absent, `start()` resolves and does nothing (feature-detect, never polyfill). Capability errors ride in tool content with `code`/`retry`/`details` preserved, never as protocol-level errors. `stop()` withdraws every tool the adapter exposed and can run repeatedly.
27
+
28
+ Confirmations complete within one tool call. By default the call waits for your host's confirmation UI to resolve the pending record, then retries with the evidence; denial or expiry returns `CONFIRMATION_INVALID`, and `stop()` aborts the wait. To prompt through WebMCP's `client.requestUserInteraction` instead, pass host UI; the registry still decides:
29
+
30
+ ```ts
31
+ createWebMcpAdapter({
32
+ confirm: (request) => showConfirmDialog(request.summary),
33
+ });
34
+ ```
35
+
36
+ WebMCP does not revoke the agent's DOM access, and the confirmation UI lives in the same page, so the server stays the real gate.
37
+
38
+ Only the imperative API is used. The declarative API (DOM forms as tools) is a non-goal: capabilities must be compiler-authorized, not derived from rendered DOM.
39
+
40
+ ## Targeted WebMCP revision
41
+
42
+ The W3C Web Machine Learning CG draft ([webmachinelearning/webmcp](https://github.com/webmachinelearning/webmcp)) as exposed by the Chrome early preview (Chrome 146+, `chrome://flags/#enable-webmcp-testing`). Assumed surface:
43
+
44
+ | Member | Use |
45
+ |---|---|
46
+ | `modelContext.provideContext({ tools })` | required; fallback full-set replacement |
47
+ | `modelContext.clearContext()` | optional; `stop()` on the fallback path |
48
+ | `modelContext.registerTool(tool)` / `unregisterTool(name)` | optional, feature-detected together |
49
+ | tool `{ name, description, inputSchema, annotations?: { readOnlyHint? }, execute(input, client) }` | tool shape |
50
+ | `client.requestUserInteraction(callback)` | optional; in-page confirmation |
51
+
52
+ Keep this table in sync with [docs/09](https://github.com/Wiseair-srl/agent-surface/blob/main/docs/09-adapters.md#targeted-webmcp-revision).
27
53
 
28
54
  Full specification: [docs/09](https://github.com/Wiseair-srl/agent-surface/blob/main/docs/09-adapters.md).
29
55
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AgentSurfaceRegistry, AgentConsumer, SnapshotContext, AgentCapabilityDescriptorUnion, JsonSchema, JsonValue } from '@agent-surface/core';
1
+ import { AgentSurfaceRegistry, AgentConsumer, SnapshotContext, AgentCapabilityDescriptorUnion, PendingConfirmation, JsonSchema, JsonValue } from '@agent-surface/core';
2
2
 
3
3
  interface AdapterHost {
4
4
  registry: AgentSurfaceRegistry;
@@ -11,11 +11,21 @@ interface AgentSurfaceAdapter {
11
11
  start(host: AdapterHost): void | Promise<void>;
12
12
  stop(): void | Promise<void>;
13
13
  }
14
+ interface WebMcpToolAnnotations {
15
+ /** The tool does not change state; a browser agent may skip its approval prompt. */
16
+ readOnlyHint?: boolean;
17
+ }
18
+ /** The per-call client WebMCP passes to `execute`. */
19
+ interface WebMcpClient {
20
+ /** Pauses the tool call to run in-page UI; resolves with the callback's value. */
21
+ requestUserInteraction?<T>(callback: () => Promise<T>): Promise<T>;
22
+ }
14
23
  interface WebMcpToolInit {
15
24
  name: string;
16
25
  description: string;
17
26
  inputSchema: JsonSchema;
18
- execute(input: JsonValue): Promise<WebMcpToolResult>;
27
+ annotations?: WebMcpToolAnnotations;
28
+ execute(input: JsonValue, client?: WebMcpClient): Promise<WebMcpToolResult>;
19
29
  }
20
30
  interface WebMcpToolResult {
21
31
  content: Array<{
@@ -25,9 +35,14 @@ interface WebMcpToolResult {
25
35
  isError?: boolean;
26
36
  }
27
37
  interface WebMcpModelContext {
38
+ /** Replaces the whole tool set. Fallback when the incremental API is absent. */
28
39
  provideContext(context: {
29
40
  tools: WebMcpToolInit[];
30
41
  }): void;
42
+ /** Removes every tool provided through provideContext. */
43
+ clearContext?(): void;
44
+ registerTool?(tool: WebMcpToolInit): unknown;
45
+ unregisterTool?(name: string): void;
31
46
  }
32
47
  interface CreateWebMcpAdapterOptions {
33
48
  snapshotContext?: Omit<SnapshotContext, "consumer">;
@@ -38,16 +53,33 @@ interface CreateWebMcpAdapterOptions {
38
53
  exposeCapability?: (descriptor: AgentCapabilityDescriptorUnion) => {
39
54
  description?: string;
40
55
  } | null | undefined;
56
+ /**
57
+ * Opt-in in-page confirmation. When a call returns CONFIRMATION_REQUIRED and
58
+ * the WebMCP client supports `requestUserInteraction`, this host UI runs
59
+ * inside it; the answer resolves the registry's pending confirmation and the
60
+ * call is retried once, so the agent sees one final result. The registry
61
+ * stays the confirmation authority. Absent (or no client support, or the UI
62
+ * throws) ⇒ the call waits for the host's own confirmation UI instead.
63
+ */
64
+ confirm?: (request: PendingConfirmation, client: WebMcpClient) => Promise<boolean> | boolean;
41
65
  /** Test seam: defaults to (navigator as any).modelContext. */
42
66
  modelContext?: WebMcpModelContext;
43
67
  }
44
68
  /**
45
69
  * Maps the registry onto `navigator.modelContext`, treating WebMCP strictly
46
70
  * as transport/discovery: one wire-named tool per AVAILABLE capability,
47
- * re-provided on every surface-changed; unavailable capabilities are not
48
- * registered (WebMCP has no disabled state today — accepted limitation);
49
- * confirmations stay two-phase; absent modelContext ⇒ start() does nothing.
71
+ * reconciled on every surface-changed (incremental registerTool/unregisterTool
72
+ * when the browser supports it, full provideContext otherwise); unavailable
73
+ * capabilities are not registered (WebMCP has no disabled state today —
74
+ * accepted limitation); absent modelContext ⇒ start() does nothing; stop()
75
+ * withdraws every tool and aborts confirmation waits.
76
+ *
77
+ * Confirmations complete within one call: through `confirm` when it applies,
78
+ * otherwise by waiting (bounded by the confirmation TTL) for the host to
79
+ * resolve the pending record. Plain two-phase cannot work on this transport:
80
+ * the tool schema has no slot for a confirmationId, so a retry never carries
81
+ * evidence and each one opens a new confirmation.
50
82
  */
51
83
  declare function createWebMcpAdapter(options?: CreateWebMcpAdapterOptions): AgentSurfaceAdapter;
52
84
 
53
- export { type AdapterHost, type AgentSurfaceAdapter, type CreateWebMcpAdapterOptions, type WebMcpModelContext, type WebMcpToolInit, type WebMcpToolResult, createWebMcpAdapter };
85
+ export { type AdapterHost, type AgentSurfaceAdapter, type CreateWebMcpAdapterOptions, type WebMcpClient, type WebMcpModelContext, type WebMcpToolAnnotations, type WebMcpToolInit, type WebMcpToolResult, createWebMcpAdapter };
package/dist/index.js CHANGED
@@ -5,100 +5,214 @@ function randomInvocationId() {
5
5
  }
6
6
 
7
7
  // src/index.ts
8
+ var READ_ONLY_EFFECTS = /* @__PURE__ */ new Set(["read", "server-query"]);
8
9
  function createWebMcpAdapter(options) {
9
- let unsubscribe;
10
+ let session;
10
11
  return {
11
12
  name: "webmcp",
12
13
  start(host) {
14
+ if (session) return;
13
15
  const modelContext = options?.modelContext ?? globalThis.navigator?.modelContext;
14
16
  if (!modelContext) return;
15
- const provide = () => {
17
+ const incremental = typeof modelContext.registerTool === "function" && typeof modelContext.unregisterTool === "function";
18
+ const state = {
19
+ modelContext,
20
+ incremental,
21
+ exposed: /* @__PURE__ */ new Map(),
22
+ unsubscribe: () => {
23
+ },
24
+ active: true,
25
+ waits: /* @__PURE__ */ new Set()
26
+ };
27
+ const waitForConfirmation = async (confirmationId) => {
28
+ const controller = new AbortController();
29
+ state.waits.add(controller);
30
+ try {
31
+ await host.registry.confirmations.waitFor(confirmationId, { signal: controller.signal });
32
+ } finally {
33
+ state.waits.delete(controller);
34
+ }
35
+ };
36
+ const invoke = (target, invocationId, input, confirmationId) => host.registry.invoke(
37
+ {
38
+ invocationId,
39
+ capabilityId: target.capabilityId,
40
+ registrationId: target.registrationId,
41
+ surfaceVersion: target.surfaceVersion,
42
+ // Forwarded as given (like the core toolset): dropping `{}` made
43
+ // zero-argument actions fail INVALID_INPUT. Observations ignore input.
44
+ ...input !== void 0 ? { input } : {},
45
+ ...confirmationId !== void 0 ? { confirmationId } : {}
46
+ },
47
+ { consumer: host.consumer }
48
+ );
49
+ const toTool = (desired, target) => ({
50
+ name: desired.name,
51
+ description: desired.description,
52
+ inputSchema: desired.inputSchema,
53
+ ...desired.readOnly ? { annotations: { readOnlyHint: true } } : {},
54
+ execute: async (input, client) => {
55
+ const invocationId = randomInvocationId();
56
+ let result = await invoke(target, invocationId, input);
57
+ const confirmationId = result.status === "error" && result.error.code === "CONFIRMATION_REQUIRED" ? result.error.details?.confirmationId : void 0;
58
+ let resolvedInPage = false;
59
+ if (options?.confirm && typeof confirmationId === "string" && typeof client?.requestUserInteraction === "function" && state.active) {
60
+ const pending = host.registry.confirmations.pending().find((record) => record.confirmationId === confirmationId);
61
+ if (pending) {
62
+ const confirm = options.confirm;
63
+ let approved;
64
+ try {
65
+ approved = await client.requestUserInteraction(async () => confirm(pending, client)) === true;
66
+ } catch {
67
+ approved = void 0;
68
+ }
69
+ if (approved !== void 0 && state.active) {
70
+ host.registry.confirmations.resolve(
71
+ confirmationId,
72
+ approved ? { approved: true } : { approved: false, reason: "Declined in page" }
73
+ );
74
+ result = await invoke(target, invocationId, input, confirmationId);
75
+ resolvedInPage = true;
76
+ }
77
+ }
78
+ }
79
+ if (!resolvedInPage && typeof confirmationId === "string" && state.active) {
80
+ await waitForConfirmation(confirmationId);
81
+ if (state.active) result = await invoke(target, invocationId, input, confirmationId);
82
+ }
83
+ if (result.status === "ok") {
84
+ return {
85
+ content: [{ type: "text", text: JSON.stringify(result.output ?? null) }]
86
+ };
87
+ }
88
+ return {
89
+ content: [{ type: "text", text: JSON.stringify(result.error) }],
90
+ isError: true
91
+ };
92
+ }
93
+ });
94
+ const desiredTools = () => {
16
95
  const snapshot = host.registry.snapshot({
17
96
  consumer: host.consumer,
18
97
  ...options?.snapshotContext ?? host.snapshotContext ?? {},
19
98
  includeUnavailable: false
20
99
  });
21
100
  const tools = [];
22
- const toTool = (descriptor, capabilityId, registrationId, inputSchema, description) => ({
23
- name: encodeWireName(capabilityId),
24
- description,
25
- inputSchema,
26
- execute: async (input) => {
27
- const result = await host.registry.invoke(
28
- {
29
- invocationId: randomInvocationId(),
30
- capabilityId,
31
- registrationId,
32
- surfaceVersion: snapshot.surfaceVersion,
33
- ...input !== void 0 && Object.keys(input).length > 0 ? { input } : {}
34
- },
35
- { consumer: host.consumer }
36
- );
37
- if (result.status === "ok") {
38
- return {
39
- content: [{ type: "text", text: JSON.stringify(result.output ?? null) }]
40
- };
41
- }
42
- return {
43
- content: [{ type: "text", text: JSON.stringify(result.error) }],
44
- isError: true
45
- };
46
- }
47
- });
101
+ const add = (descriptor, capabilityId, registrationId, inputSchema, defaultDescription, readOnly) => {
102
+ if (!descriptor.available) return;
103
+ const curated = options?.exposeCapability?.(descriptor);
104
+ if (options?.exposeCapability && curated === null) return;
105
+ tools.push({
106
+ name: encodeWireName(capabilityId),
107
+ capabilityId,
108
+ registrationId,
109
+ inputSchema,
110
+ description: curated?.description ?? defaultDescription,
111
+ // Derived from the declared kind/effect only; curation cannot widen it.
112
+ readOnly
113
+ });
114
+ };
48
115
  for (const component of snapshot.components) {
49
116
  for (const obs of component.observations) {
50
- if (!obs.available) continue;
51
- const curated = options?.exposeCapability?.(obs);
52
- if (options?.exposeCapability && curated === null) continue;
53
- tools.push(
54
- toTool(
55
- obs,
56
- obs.capabilityId,
57
- component.registrationId,
58
- { type: "object", properties: {}, additionalProperties: false },
59
- curated?.description ?? `[view \xB7 read] ${obs.description}`
60
- )
117
+ add(
118
+ obs,
119
+ obs.capabilityId,
120
+ component.registrationId,
121
+ { type: "object", properties: {}, additionalProperties: false },
122
+ `[view \xB7 read] ${obs.description}`,
123
+ true
61
124
  );
62
125
  }
63
126
  for (const act of component.actions) {
64
- if (!act.available) continue;
65
- const curated = options?.exposeCapability?.(act);
66
- if (options?.exposeCapability && curated === null) continue;
67
- tools.push(
68
- toTool(
69
- act,
70
- act.capabilityId,
71
- component.registrationId,
72
- act.inputSchema,
73
- curated?.description ?? `[view \xB7 ${act.effect}] ${act.description}`
74
- )
127
+ add(
128
+ act,
129
+ act.capabilityId,
130
+ component.registrationId,
131
+ act.inputSchema,
132
+ `[view \xB7 ${act.effect}] ${act.description}`,
133
+ READ_ONLY_EFFECTS.has(act.effect)
75
134
  );
76
135
  }
77
136
  }
78
137
  for (const proc of snapshot.procedures) {
79
- if (!proc.available) continue;
80
- const curated = options?.exposeCapability?.(proc);
81
- if (options?.exposeCapability && curated === null) continue;
82
- tools.push(
83
- toTool(
84
- proc,
85
- proc.procedureId,
86
- proc.registrationId,
87
- proc.inputSchema,
88
- curated?.description ?? `[domain \xB7 ${proc.effect}${proc.confirmation === "required" ? " \xB7 requires confirmation" : ""}] ${proc.description}`
89
- )
138
+ add(
139
+ proc,
140
+ proc.procedureId,
141
+ proc.registrationId,
142
+ proc.inputSchema,
143
+ `[domain \xB7 ${proc.effect}${proc.confirmation === "required" ? " \xB7 requires confirmation" : ""}] ${proc.description}`,
144
+ READ_ONLY_EFFECTS.has(proc.effect)
90
145
  );
91
146
  }
92
- modelContext.provideContext({ tools });
147
+ return { surfaceVersion: snapshot.surfaceVersion, tools };
148
+ };
149
+ const reconcile = () => {
150
+ if (!state.active) return;
151
+ const { surfaceVersion, tools } = desiredTools();
152
+ const next = /* @__PURE__ */ new Map();
153
+ const toRegister = [];
154
+ for (const desired of tools) {
155
+ const signature = JSON.stringify([
156
+ desired.description,
157
+ desired.inputSchema,
158
+ desired.registrationId,
159
+ desired.capabilityId,
160
+ desired.readOnly
161
+ ]);
162
+ const current = state.exposed.get(desired.name);
163
+ if (current && current.signature === signature) {
164
+ current.target.surfaceVersion = surfaceVersion;
165
+ next.set(desired.name, current);
166
+ continue;
167
+ }
168
+ const target = {
169
+ capabilityId: desired.capabilityId,
170
+ registrationId: desired.registrationId,
171
+ surfaceVersion
172
+ };
173
+ const tool = toTool(desired, target);
174
+ next.set(desired.name, { tool, target, signature });
175
+ toRegister.push(tool);
176
+ }
177
+ if (state.incremental) {
178
+ for (const [name, current] of state.exposed) {
179
+ const replacement = next.get(name);
180
+ if (replacement !== current) modelContext.unregisterTool(name);
181
+ }
182
+ for (const tool of toRegister) modelContext.registerTool(tool);
183
+ } else {
184
+ modelContext.provideContext({ tools: [...next.values()].map((entry) => entry.tool) });
185
+ }
186
+ state.exposed = next;
93
187
  };
94
- provide();
95
- unsubscribe = host.registry.subscribe((event) => {
96
- if (event.type === "surface-changed") provide();
188
+ session = state;
189
+ reconcile();
190
+ state.unsubscribe = host.registry.subscribe((event) => {
191
+ if (event.type === "surface-changed") reconcile();
97
192
  });
98
193
  },
99
194
  stop() {
100
- unsubscribe?.();
101
- unsubscribe = void 0;
195
+ const state = session;
196
+ session = void 0;
197
+ if (!state) return;
198
+ state.active = false;
199
+ state.unsubscribe();
200
+ for (const controller of state.waits) controller.abort();
201
+ state.waits.clear();
202
+ const { modelContext } = state;
203
+ if (state.incremental) {
204
+ for (const name of state.exposed.keys()) {
205
+ try {
206
+ modelContext.unregisterTool(name);
207
+ } catch {
208
+ }
209
+ }
210
+ } else if (typeof modelContext.clearContext === "function") {
211
+ modelContext.clearContext();
212
+ } else {
213
+ modelContext.provideContext({ tools: [] });
214
+ }
215
+ state.exposed.clear();
102
216
  }
103
217
  };
104
218
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core-facade.ts","../src/index.ts"],"sourcesContent":["export { encodeWireName, encodeWireNameForInstance } from \"@agent-surface/core\";\nexport type {\n AgentCapabilityDescriptorUnion,\n AgentConsumer,\n AgentSurfaceRegistry,\n JsonSchema,\n JsonValue,\n SnapshotContext,\n} from \"@agent-surface/core\";\n\nexport function randomInvocationId(): string {\n return `inv_${Math.random().toString(36).slice(2, 14)}`;\n}\n","import {\n encodeWireName,\n randomInvocationId,\n type AgentCapabilityDescriptorUnion,\n type AgentConsumer,\n type AgentSurfaceRegistry,\n type JsonSchema,\n type JsonValue,\n type SnapshotContext,\n} from \"./core-facade.js\";\n\n/* ───────────────────────── adapter contract (docs/09) ───────────────────────── */\n\nexport interface AdapterHost {\n registry: AgentSurfaceRegistry;\n consumer: AgentConsumer; // identity this adapter acts as\n /** Adapter-scoped snapshot defaults (scope, budget). */\n snapshotContext?: Omit<SnapshotContext, \"consumer\">;\n}\n\nexport interface AgentSurfaceAdapter {\n readonly name: string;\n start(host: AdapterHost): void | Promise<void>;\n stop(): void | Promise<void>;\n}\n\n/* ───────────── assumed navigator.modelContext shape (Experimental) ─────────────\n * The WebMCP surface area is unstable (OQ-2); this module encodes the current\n * assumption and absorbs drift so nothing WebMCP-shaped leaks into core.\n */\n\nexport interface WebMcpToolInit {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n execute(input: JsonValue): Promise<WebMcpToolResult>;\n}\n\nexport interface WebMcpToolResult {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n}\n\nexport interface WebMcpModelContext {\n provideContext(context: { tools: WebMcpToolInit[] }): void;\n}\n\nexport interface CreateWebMcpAdapterOptions {\n snapshotContext?: Omit<SnapshotContext, \"consumer\">;\n /**\n * Curate presentation before exposing. Execution always remains registry-routed.\n * Return null to skip; undefined to keep defaults.\n */\n exposeCapability?: (\n descriptor: AgentCapabilityDescriptorUnion,\n ) => { description?: string } | null | undefined;\n /** Test seam: defaults to (navigator as any).modelContext. */\n modelContext?: WebMcpModelContext;\n}\n\n/**\n * Maps the registry onto `navigator.modelContext`, treating WebMCP strictly\n * as transport/discovery: one wire-named tool per AVAILABLE capability,\n * re-provided on every surface-changed; unavailable capabilities are not\n * registered (WebMCP has no disabled state today — accepted limitation);\n * confirmations stay two-phase; absent modelContext ⇒ start() does nothing.\n */\nexport function createWebMcpAdapter(options?: CreateWebMcpAdapterOptions): AgentSurfaceAdapter {\n let unsubscribe: (() => void) | undefined;\n\n return {\n name: \"webmcp\",\n\n start(host: AdapterHost): void {\n const modelContext =\n options?.modelContext ??\n (globalThis as { navigator?: { modelContext?: WebMcpModelContext } }).navigator\n ?.modelContext;\n if (!modelContext) return; // feature-detect, never polyfill\n\n const provide = (): void => {\n const snapshot = host.registry.snapshot({\n consumer: host.consumer,\n ...(options?.snapshotContext ?? host.snapshotContext ?? {}),\n includeUnavailable: false,\n });\n\n const tools: WebMcpToolInit[] = [];\n\n const toTool = (\n descriptor: AgentCapabilityDescriptorUnion,\n capabilityId: string,\n registrationId: string,\n inputSchema: JsonSchema,\n description: string,\n ): WebMcpToolInit => ({\n name: encodeWireName(capabilityId),\n description,\n inputSchema,\n execute: async (input: JsonValue): Promise<WebMcpToolResult> => {\n const result = await host.registry.invoke(\n {\n invocationId: randomInvocationId(),\n capabilityId,\n registrationId,\n surfaceVersion: snapshot.surfaceVersion,\n ...(input !== undefined && Object.keys(input as object).length > 0\n ? { input }\n : {}),\n },\n { consumer: host.consumer },\n );\n // Capability errors ride in tool CONTENT, never protocol errors\n // (docs/07 adapter mapping): code/retry/details preserved.\n if (result.status === \"ok\") {\n return {\n content: [{ type: \"text\", text: JSON.stringify(result.output ?? null) }],\n };\n }\n return {\n content: [{ type: \"text\", text: JSON.stringify(result.error) }],\n isError: true,\n };\n },\n });\n\n for (const component of snapshot.components) {\n for (const obs of component.observations) {\n if (!obs.available) continue;\n const curated = options?.exposeCapability?.(obs);\n if (options?.exposeCapability && curated === null) continue;\n tools.push(\n toTool(\n obs,\n obs.capabilityId,\n component.registrationId,\n { type: \"object\", properties: {}, additionalProperties: false },\n curated?.description ?? `[view · read] ${obs.description}`,\n ),\n );\n }\n for (const act of component.actions) {\n if (!act.available) continue;\n const curated = options?.exposeCapability?.(act);\n if (options?.exposeCapability && curated === null) continue;\n tools.push(\n toTool(\n act,\n act.capabilityId,\n component.registrationId,\n act.inputSchema,\n curated?.description ?? `[view · ${act.effect}] ${act.description}`,\n ),\n );\n }\n }\n for (const proc of snapshot.procedures) {\n if (!proc.available) continue;\n const curated = options?.exposeCapability?.(proc);\n if (options?.exposeCapability && curated === null) continue;\n tools.push(\n toTool(\n proc,\n proc.procedureId,\n proc.registrationId,\n proc.inputSchema,\n curated?.description ??\n `[domain · ${proc.effect}${proc.confirmation === \"required\" ? \" · requires confirmation\" : \"\"}] ${proc.description}`,\n ),\n );\n }\n\n modelContext.provideContext({ tools });\n };\n\n provide();\n unsubscribe = host.registry.subscribe((event) => {\n if (event.type === \"surface-changed\") provide();\n });\n },\n\n stop(): void {\n unsubscribe?.();\n unsubscribe = undefined;\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/core-facade.ts","../src/index.ts"],"sourcesContent":["export { encodeWireName, encodeWireNameForInstance } from \"@agent-surface/core\";\nexport type {\n AgentCapabilityDescriptorUnion,\n AgentConsumer,\n AgentSurfaceRegistry,\n JsonSchema,\n JsonValue,\n PendingConfirmation,\n SnapshotContext,\n} from \"@agent-surface/core\";\n\nexport function randomInvocationId(): string {\n return `inv_${Math.random().toString(36).slice(2, 14)}`;\n}\n","import {\n encodeWireName,\n randomInvocationId,\n type AgentCapabilityDescriptorUnion,\n type AgentConsumer,\n type AgentSurfaceRegistry,\n type JsonSchema,\n type JsonValue,\n type PendingConfirmation,\n type SnapshotContext,\n} from \"./core-facade.js\";\n\n/* ───────────────────────── adapter contract (docs/09) ───────────────────────── */\n\nexport interface AdapterHost {\n registry: AgentSurfaceRegistry;\n consumer: AgentConsumer; // identity this adapter acts as\n /** Adapter-scoped snapshot defaults (scope, budget). */\n snapshotContext?: Omit<SnapshotContext, \"consumer\">;\n}\n\nexport interface AgentSurfaceAdapter {\n readonly name: string;\n start(host: AdapterHost): void | Promise<void>;\n stop(): void | Promise<void>;\n}\n\n/* ───────────── assumed navigator.modelContext shape (Experimental) ─────────────\n * The WebMCP surface area is unstable (OQ-2); this module encodes the current\n * assumption and absorbs drift so nothing WebMCP-shaped leaks into core.\n * Targeted revision: see \"Targeted WebMCP revision\" in docs/09.\n */\n\nexport interface WebMcpToolAnnotations {\n /** The tool does not change state; a browser agent may skip its approval prompt. */\n readOnlyHint?: boolean;\n}\n\n/** The per-call client WebMCP passes to `execute`. */\nexport interface WebMcpClient {\n /** Pauses the tool call to run in-page UI; resolves with the callback's value. */\n requestUserInteraction?<T>(callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface WebMcpToolInit {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n annotations?: WebMcpToolAnnotations;\n execute(input: JsonValue, client?: WebMcpClient): Promise<WebMcpToolResult>;\n}\n\nexport interface WebMcpToolResult {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n}\n\nexport interface WebMcpModelContext {\n /** Replaces the whole tool set. Fallback when the incremental API is absent. */\n provideContext(context: { tools: WebMcpToolInit[] }): void;\n /** Removes every tool provided through provideContext. */\n clearContext?(): void;\n registerTool?(tool: WebMcpToolInit): unknown;\n unregisterTool?(name: string): void;\n}\n\nexport interface CreateWebMcpAdapterOptions {\n snapshotContext?: Omit<SnapshotContext, \"consumer\">;\n /**\n * Curate presentation before exposing. Execution always remains registry-routed.\n * Return null to skip; undefined to keep defaults.\n */\n exposeCapability?: (\n descriptor: AgentCapabilityDescriptorUnion,\n ) => { description?: string } | null | undefined;\n /**\n * Opt-in in-page confirmation. When a call returns CONFIRMATION_REQUIRED and\n * the WebMCP client supports `requestUserInteraction`, this host UI runs\n * inside it; the answer resolves the registry's pending confirmation and the\n * call is retried once, so the agent sees one final result. The registry\n * stays the confirmation authority. Absent (or no client support, or the UI\n * throws) ⇒ the call waits for the host's own confirmation UI instead.\n */\n confirm?: (request: PendingConfirmation, client: WebMcpClient) => Promise<boolean> | boolean;\n /** Test seam: defaults to (navigator as any).modelContext. */\n modelContext?: WebMcpModelContext;\n}\n\ninterface ToolTarget {\n capabilityId: string;\n registrationId: string;\n /** Updated in place when the tool survives a surface change unchanged. */\n surfaceVersion: string;\n}\n\ninterface ExposedTool {\n tool: WebMcpToolInit;\n target: ToolTarget;\n /** Everything the browser agent sees, plus the registration it routes to. */\n signature: string;\n}\n\ninterface DesiredTool {\n name: string;\n capabilityId: string;\n registrationId: string;\n inputSchema: JsonSchema;\n description: string;\n readOnly: boolean;\n}\n\nconst READ_ONLY_EFFECTS: ReadonlySet<string> = new Set([\"read\", \"server-query\"]);\n\n/**\n * Maps the registry onto `navigator.modelContext`, treating WebMCP strictly\n * as transport/discovery: one wire-named tool per AVAILABLE capability,\n * reconciled on every surface-changed (incremental registerTool/unregisterTool\n * when the browser supports it, full provideContext otherwise); unavailable\n * capabilities are not registered (WebMCP has no disabled state today —\n * accepted limitation); absent modelContext ⇒ start() does nothing; stop()\n * withdraws every tool and aborts confirmation waits.\n *\n * Confirmations complete within one call: through `confirm` when it applies,\n * otherwise by waiting (bounded by the confirmation TTL) for the host to\n * resolve the pending record. Plain two-phase cannot work on this transport:\n * the tool schema has no slot for a confirmationId, so a retry never carries\n * evidence and each one opens a new confirmation.\n */\nexport function createWebMcpAdapter(options?: CreateWebMcpAdapterOptions): AgentSurfaceAdapter {\n let session:\n | {\n modelContext: WebMcpModelContext;\n incremental: boolean;\n exposed: Map<string, ExposedTool>;\n unsubscribe: () => void;\n active: boolean;\n waits: Set<AbortController>;\n }\n | undefined;\n\n return {\n name: \"webmcp\",\n\n start(host: AdapterHost): void {\n if (session) return;\n const modelContext =\n options?.modelContext ??\n (globalThis as { navigator?: { modelContext?: WebMcpModelContext } }).navigator\n ?.modelContext;\n if (!modelContext) return; // feature-detect, never polyfill\n\n const incremental =\n typeof modelContext.registerTool === \"function\" &&\n typeof modelContext.unregisterTool === \"function\";\n const state = {\n modelContext,\n incremental,\n exposed: new Map<string, ExposedTool>(),\n unsubscribe: () => {},\n active: true,\n waits: new Set<AbortController>(),\n };\n\n /** Wait for the host to resolve a pending confirmation; aborted by stop(). */\n const waitForConfirmation = async (confirmationId: string): Promise<void> => {\n const controller = new AbortController();\n state.waits.add(controller);\n try {\n await host.registry.confirmations.waitFor(confirmationId, { signal: controller.signal });\n } finally {\n state.waits.delete(controller);\n }\n };\n\n const invoke = (target: ToolTarget, invocationId: string, input: JsonValue, confirmationId?: string) =>\n host.registry.invoke(\n {\n invocationId,\n capabilityId: target.capabilityId,\n registrationId: target.registrationId,\n surfaceVersion: target.surfaceVersion,\n // Forwarded as given (like the core toolset): dropping `{}` made\n // zero-argument actions fail INVALID_INPUT. Observations ignore input.\n ...(input !== undefined ? { input } : {}),\n ...(confirmationId !== undefined ? { confirmationId } : {}),\n },\n { consumer: host.consumer },\n );\n\n const toTool = (desired: DesiredTool, target: ToolTarget): WebMcpToolInit => ({\n name: desired.name,\n description: desired.description,\n inputSchema: desired.inputSchema,\n ...(desired.readOnly ? { annotations: { readOnlyHint: true } } : {}),\n execute: async (input: JsonValue, client?: WebMcpClient): Promise<WebMcpToolResult> => {\n const invocationId = randomInvocationId();\n let result = await invoke(target, invocationId, input);\n\n const confirmationId =\n result.status === \"error\" && result.error.code === \"CONFIRMATION_REQUIRED\"\n ? result.error.details?.confirmationId\n : undefined;\n let resolvedInPage = false;\n if (\n options?.confirm &&\n typeof confirmationId === \"string\" &&\n typeof client?.requestUserInteraction === \"function\" &&\n state.active\n ) {\n const pending = host.registry.confirmations\n .pending()\n .find((record) => record.confirmationId === confirmationId);\n if (pending) {\n const confirm = options.confirm;\n let approved: boolean | undefined;\n try {\n approved =\n (await client.requestUserInteraction(async () => confirm(pending, client))) ===\n true;\n } catch {\n approved = undefined; // UI failed: leave it pending, fall back to waiting\n }\n // A stop() mid-prompt returns the pending result as-is (docs/09 §9).\n if (approved !== undefined && state.active) {\n host.registry.confirmations.resolve(\n confirmationId,\n approved ? { approved: true } : { approved: false, reason: \"Declined in page\" },\n );\n // Same invocationId + confirmationId (docs/03 D14): the registry\n // decides the outcome, the adapter only relayed the answer.\n result = await invoke(target, invocationId, input, confirmationId);\n resolvedInPage = true;\n }\n }\n }\n\n // Fallback: wait for the host's own confirmation UI, then retry once.\n // Denial and expiry come back as CONFIRMATION_INVALID, never retried.\n // A stop() before or during the wait returns the pending result as-is.\n if (!resolvedInPage && typeof confirmationId === \"string\" && state.active) {\n await waitForConfirmation(confirmationId);\n if (state.active) result = await invoke(target, invocationId, input, confirmationId);\n }\n\n // Capability errors ride in tool CONTENT, never protocol errors\n // (docs/07 adapter mapping): code/retry/details preserved.\n if (result.status === \"ok\") {\n return {\n content: [{ type: \"text\", text: JSON.stringify(result.output ?? null) }],\n };\n }\n return {\n content: [{ type: \"text\", text: JSON.stringify(result.error) }],\n isError: true,\n };\n },\n });\n\n const desiredTools = (): { surfaceVersion: string; tools: DesiredTool[] } => {\n const snapshot = host.registry.snapshot({\n consumer: host.consumer,\n ...(options?.snapshotContext ?? host.snapshotContext ?? {}),\n includeUnavailable: false,\n });\n const tools: DesiredTool[] = [];\n const add = (\n descriptor: AgentCapabilityDescriptorUnion,\n capabilityId: string,\n registrationId: string,\n inputSchema: JsonSchema,\n defaultDescription: string,\n readOnly: boolean,\n ): void => {\n if (!descriptor.available) return;\n const curated = options?.exposeCapability?.(descriptor);\n if (options?.exposeCapability && curated === null) return;\n tools.push({\n name: encodeWireName(capabilityId),\n capabilityId,\n registrationId,\n inputSchema,\n description: curated?.description ?? defaultDescription,\n // Derived from the declared kind/effect only; curation cannot widen it.\n readOnly,\n });\n };\n\n for (const component of snapshot.components) {\n for (const obs of component.observations) {\n add(\n obs,\n obs.capabilityId,\n component.registrationId,\n { type: \"object\", properties: {}, additionalProperties: false },\n `[view · read] ${obs.description}`,\n true,\n );\n }\n for (const act of component.actions) {\n add(\n act,\n act.capabilityId,\n component.registrationId,\n act.inputSchema,\n `[view · ${act.effect}] ${act.description}`,\n READ_ONLY_EFFECTS.has(act.effect),\n );\n }\n }\n for (const proc of snapshot.procedures) {\n add(\n proc,\n proc.procedureId,\n proc.registrationId,\n proc.inputSchema,\n `[domain · ${proc.effect}${proc.confirmation === \"required\" ? \" · requires confirmation\" : \"\"}] ${proc.description}`,\n READ_ONLY_EFFECTS.has(proc.effect),\n );\n }\n return { surfaceVersion: snapshot.surfaceVersion, tools };\n };\n\n const reconcile = (): void => {\n if (!state.active) return;\n const { surfaceVersion, tools } = desiredTools();\n const next = new Map<string, ExposedTool>();\n const toRegister: WebMcpToolInit[] = [];\n\n for (const desired of tools) {\n const signature = JSON.stringify([\n desired.description,\n desired.inputSchema,\n desired.registrationId,\n desired.capabilityId,\n desired.readOnly,\n ]);\n const current = state.exposed.get(desired.name);\n if (current && current.signature === signature) {\n // Unchanged tool: keep the registration, refresh the version it\n // echoes so execute carries the latest projected surfaceVersion.\n current.target.surfaceVersion = surfaceVersion;\n next.set(desired.name, current);\n continue;\n }\n const target: ToolTarget = {\n capabilityId: desired.capabilityId,\n registrationId: desired.registrationId,\n surfaceVersion,\n };\n const tool = toTool(desired, target);\n next.set(desired.name, { tool, target, signature });\n toRegister.push(tool);\n }\n\n if (state.incremental) {\n for (const [name, current] of state.exposed) {\n const replacement = next.get(name);\n if (replacement !== current) modelContext.unregisterTool!(name);\n }\n for (const tool of toRegister) modelContext.registerTool!(tool);\n } else {\n modelContext.provideContext({ tools: [...next.values()].map((entry) => entry.tool) });\n }\n state.exposed = next;\n };\n\n session = state;\n reconcile();\n state.unsubscribe = host.registry.subscribe((event) => {\n if (event.type === \"surface-changed\") reconcile();\n });\n },\n\n stop(): void {\n const state = session;\n session = undefined;\n if (!state) return; // idempotent\n state.active = false;\n state.unsubscribe();\n for (const controller of state.waits) controller.abort();\n state.waits.clear();\n const { modelContext } = state;\n if (state.incremental) {\n // Withdraw only our tools; other page code may own the rest.\n for (const name of state.exposed.keys()) {\n try {\n modelContext.unregisterTool!(name);\n } catch {\n // Already gone on the browser side; nothing left to release.\n }\n }\n } else if (typeof modelContext.clearContext === \"function\") {\n modelContext.clearContext();\n } else {\n modelContext.provideContext({ tools: [] });\n }\n state.exposed.clear();\n },\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-surface/webmcp",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "description": "[Experimental] WebMCP (navigator.modelContext) transport adapter for agent-surface",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -18,11 +18,11 @@
18
18
  "LICENSE"
19
19
  ],
20
20
  "dependencies": {
21
- "@agent-surface/core": "^0.24.0"
21
+ "@agent-surface/core": "^0.26.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "zod": "^4.1.5",
25
- "@agent-surface/testing": "0.24.0"
25
+ "@agent-surface/testing": "0.26.0"
26
26
  },
27
27
  "author": "Paolo Barbato",
28
28
  "engines": {