@mcp-b/webmcp-ts-sdk 2.1.0 → 2.2.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/index.js CHANGED
@@ -105,10 +105,10 @@ function isSchemaOptional(schema) {
105
105
  */
106
106
  function getLiteralValue(schema) {
107
107
  if (isZ4Schema(schema)) {
108
- const def$1 = schema._zod?.def;
109
- if (def$1) {
110
- if (def$1.value !== void 0) return def$1.value;
111
- if (Array.isArray(def$1.values) && def$1.values.length > 0) return def$1.values[0];
108
+ const def = schema._zod?.def;
109
+ if (def) {
110
+ if (def.value !== void 0) return def.value;
111
+ if (Array.isArray(def.values) && def.values.length > 0) return def.values[0];
112
112
  }
113
113
  }
114
114
  const def = schema._def;
@@ -196,7 +196,7 @@ const RequestIdSchema = z.union([z.string(), z.number().int()]);
196
196
  * A request that expects a response.
197
197
  */
198
198
  const JSONRPCRequestSchema = z.object({
199
- jsonrpc: z.literal(JSONRPC_VERSION),
199
+ jsonrpc: z.literal("2.0"),
200
200
  id: RequestIdSchema,
201
201
  ...RequestSchema.shape
202
202
  }).strict();
@@ -205,7 +205,7 @@ const isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).succes
205
205
  * A notification which does not expect a response.
206
206
  */
207
207
  const JSONRPCNotificationSchema = z.object({
208
- jsonrpc: z.literal(JSONRPC_VERSION),
208
+ jsonrpc: z.literal("2.0"),
209
209
  ...NotificationSchema.shape
210
210
  }).strict();
211
211
  const isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success;
@@ -213,7 +213,7 @@ const isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(val
213
213
  * A successful (non-error) response to a request.
214
214
  */
215
215
  const JSONRPCResultResponseSchema = z.object({
216
- jsonrpc: z.literal(JSONRPC_VERSION),
216
+ jsonrpc: z.literal("2.0"),
217
217
  id: RequestIdSchema,
218
218
  result: ResultSchema
219
219
  }).strict();
@@ -228,21 +228,21 @@ const isJSONRPCResultResponse = (value) => JSONRPCResultResponseSchema.safeParse
228
228
  * Error codes defined by the JSON-RPC specification.
229
229
  */
230
230
  var ErrorCode;
231
- (function(ErrorCode$1) {
232
- ErrorCode$1[ErrorCode$1["ConnectionClosed"] = -32e3] = "ConnectionClosed";
233
- ErrorCode$1[ErrorCode$1["RequestTimeout"] = -32001] = "RequestTimeout";
234
- ErrorCode$1[ErrorCode$1["ParseError"] = -32700] = "ParseError";
235
- ErrorCode$1[ErrorCode$1["InvalidRequest"] = -32600] = "InvalidRequest";
236
- ErrorCode$1[ErrorCode$1["MethodNotFound"] = -32601] = "MethodNotFound";
237
- ErrorCode$1[ErrorCode$1["InvalidParams"] = -32602] = "InvalidParams";
238
- ErrorCode$1[ErrorCode$1["InternalError"] = -32603] = "InternalError";
239
- ErrorCode$1[ErrorCode$1["UrlElicitationRequired"] = -32042] = "UrlElicitationRequired";
231
+ (function(ErrorCode) {
232
+ ErrorCode[ErrorCode["ConnectionClosed"] = -32e3] = "ConnectionClosed";
233
+ ErrorCode[ErrorCode["RequestTimeout"] = -32001] = "RequestTimeout";
234
+ ErrorCode[ErrorCode["ParseError"] = -32700] = "ParseError";
235
+ ErrorCode[ErrorCode["InvalidRequest"] = -32600] = "InvalidRequest";
236
+ ErrorCode[ErrorCode["MethodNotFound"] = -32601] = "MethodNotFound";
237
+ ErrorCode[ErrorCode["InvalidParams"] = -32602] = "InvalidParams";
238
+ ErrorCode[ErrorCode["InternalError"] = -32603] = "InternalError";
239
+ ErrorCode[ErrorCode["UrlElicitationRequired"] = -32042] = "UrlElicitationRequired";
240
240
  })(ErrorCode || (ErrorCode = {}));
241
241
  /**
242
242
  * A response to a request that indicates an error occurred.
243
243
  */
244
244
  const JSONRPCErrorResponseSchema = z.object({
245
- jsonrpc: z.literal(JSONRPC_VERSION),
245
+ jsonrpc: z.literal("2.0"),
246
246
  id: RequestIdSchema.optional(),
247
247
  error: z.object({
248
248
  code: z.number().int(),
@@ -1720,7 +1720,7 @@ var Protocol = class {
1720
1720
  });
1721
1721
  }
1722
1722
  _onprogress(notification) {
1723
- const { progressToken,...params } = notification.params;
1723
+ const { progressToken, ...params } = notification.params;
1724
1724
  const messageId = Number(progressToken);
1725
1725
  const handler = this._progressHandlers.get(messageId);
1726
1726
  if (!handler) {
@@ -1834,34 +1834,34 @@ var Protocol = class {
1834
1834
  };
1835
1835
  } else throw new McpError(ErrorCode.InternalError, "Task creation did not return a task");
1836
1836
  while (true) {
1837
- const task$1 = await this.getTask({ taskId }, options);
1837
+ const task = await this.getTask({ taskId }, options);
1838
1838
  yield {
1839
1839
  type: "taskStatus",
1840
- task: task$1
1840
+ task
1841
1841
  };
1842
- if (isTerminal(task$1.status)) {
1843
- if (task$1.status === "completed") yield {
1842
+ if (isTerminal(task.status)) {
1843
+ if (task.status === "completed") yield {
1844
1844
  type: "result",
1845
1845
  result: await this.getTaskResult({ taskId }, resultSchema, options)
1846
1846
  };
1847
- else if (task$1.status === "failed") yield {
1847
+ else if (task.status === "failed") yield {
1848
1848
  type: "error",
1849
1849
  error: new McpError(ErrorCode.InternalError, `Task ${taskId} failed`)
1850
1850
  };
1851
- else if (task$1.status === "cancelled") yield {
1851
+ else if (task.status === "cancelled") yield {
1852
1852
  type: "error",
1853
1853
  error: new McpError(ErrorCode.InternalError, `Task ${taskId} was cancelled`)
1854
1854
  };
1855
1855
  return;
1856
1856
  }
1857
- if (task$1.status === "input_required") {
1857
+ if (task.status === "input_required") {
1858
1858
  yield {
1859
1859
  type: "result",
1860
1860
  result: await this.getTaskResult({ taskId }, resultSchema, options)
1861
1861
  };
1862
1862
  return;
1863
1863
  }
1864
- const pollInterval = task$1.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
1864
+ const pollInterval = task.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
1865
1865
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
1866
1866
  options?.signal?.throwIfAborted();
1867
1867
  }
@@ -1954,7 +1954,7 @@ var Protocol = class {
1954
1954
  options?.signal?.addEventListener("abort", () => {
1955
1955
  cancel(options?.signal?.reason);
1956
1956
  });
1957
- const timeout = options?.timeout ?? DEFAULT_REQUEST_TIMEOUT_MSEC;
1957
+ const timeout = options?.timeout ?? 6e4;
1958
1958
  const timeoutHandler = () => cancel(McpError.fromError(ErrorCode.RequestTimeout, "Request timed out", { timeout }));
1959
1959
  this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler, options?.resetTimeoutOnProgress ?? false);
1960
1960
  const relatedTaskId = relatedTask?.taskId;
@@ -2035,7 +2035,7 @@ var Protocol = class {
2035
2035
  this.assertNotificationCapability(notification.method);
2036
2036
  const relatedTaskId = options?.relatedTask?.taskId;
2037
2037
  if (relatedTaskId) {
2038
- const jsonrpcNotification$1 = {
2038
+ const jsonrpcNotification = {
2039
2039
  ...notification,
2040
2040
  jsonrpc: "2.0",
2041
2041
  params: {
@@ -2048,7 +2048,7 @@ var Protocol = class {
2048
2048
  };
2049
2049
  await this._enqueueTaskMessage(relatedTaskId, {
2050
2050
  type: "notification",
2051
- message: jsonrpcNotification$1,
2051
+ message: jsonrpcNotification,
2052
2052
  timestamp: Date.now()
2053
2053
  });
2054
2054
  return;
@@ -2059,21 +2059,21 @@ var Protocol = class {
2059
2059
  Promise.resolve().then(() => {
2060
2060
  this._pendingDebouncedNotifications.delete(notification.method);
2061
2061
  if (!this._transport) return;
2062
- let jsonrpcNotification$1 = {
2062
+ let jsonrpcNotification = {
2063
2063
  ...notification,
2064
2064
  jsonrpc: "2.0"
2065
2065
  };
2066
- if (options?.relatedTask) jsonrpcNotification$1 = {
2067
- ...jsonrpcNotification$1,
2066
+ if (options?.relatedTask) jsonrpcNotification = {
2067
+ ...jsonrpcNotification,
2068
2068
  params: {
2069
- ...jsonrpcNotification$1.params,
2069
+ ...jsonrpcNotification.params,
2070
2070
  _meta: {
2071
- ...jsonrpcNotification$1.params?._meta || {},
2071
+ ...jsonrpcNotification.params?._meta || {},
2072
2072
  [RELATED_TASK_META_KEY]: options.relatedTask
2073
2073
  }
2074
2074
  }
2075
2075
  };
2076
- this._transport?.send(jsonrpcNotification$1, options).catch((error) => this._onerror(error));
2076
+ this._transport?.send(jsonrpcNotification, options).catch((error) => this._onerror(error));
2077
2077
  });
2078
2078
  return;
2079
2079
  }
@@ -2300,7 +2300,6 @@ var Ajv = class {
2300
2300
  return "";
2301
2301
  }
2302
2302
  };
2303
- var ajv_default = Ajv;
2304
2303
 
2305
2304
  //#endregion
2306
2305
  //#region src/stubs/ajv-formats.ts
@@ -2312,8 +2311,11 @@ function addFormats(_ajv) {}
2312
2311
 
2313
2312
  //#endregion
2314
2313
  //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
2314
+ /**
2315
+ * AJV-based JSON Schema validator provider
2316
+ */
2315
2317
  function createDefaultAjvInstance() {
2316
- const ajv = new ajv_default({
2318
+ const ajv = new Ajv({
2317
2319
  strict: false,
2318
2320
  validateFormats: true,
2319
2321
  validateSchema: false,
@@ -2388,6 +2390,12 @@ var AjvJsonSchemaValidator = class {
2388
2390
  //#endregion
2389
2391
  //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
2390
2392
  /**
2393
+ * Experimental client task features for MCP SDK.
2394
+ * WARNING: These APIs are experimental and may change without notice.
2395
+ *
2396
+ * @experimental
2397
+ */
2398
+ /**
2391
2399
  * Experimental task features for MCP clients.
2392
2400
  *
2393
2401
  * Access via `client.experimental.tasks`:
@@ -3563,8 +3571,8 @@ function getCompleter(schema) {
3563
3571
  return schema[COMPLETABLE_SYMBOL]?.complete;
3564
3572
  }
3565
3573
  var McpZodTypeKind;
3566
- (function(McpZodTypeKind$1) {
3567
- McpZodTypeKind$1["Completable"] = "McpCompletable";
3574
+ (function(McpZodTypeKind) {
3575
+ McpZodTypeKind["Completable"] = "McpCompletable";
3568
3576
  })(McpZodTypeKind || (McpZodTypeKind = {}));
3569
3577
 
3570
3578
  //#endregion
@@ -4336,6 +4344,11 @@ function isCallToolResult(value) {
4336
4344
  function isJsonPrimitive(value) {
4337
4345
  return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
4338
4346
  }
4347
+ function isPermissionsPolicySecurityError(error) {
4348
+ if (!error || typeof error !== "object") return false;
4349
+ const { name, message } = error;
4350
+ return name === "SecurityError" && typeof message === "string" && /permissions policy|feature "tools" is disallowed/i.test(message);
4351
+ }
4339
4352
  function isJsonValue(value) {
4340
4353
  if (isJsonPrimitive(value)) return Number.isFinite(value) || typeof value !== "number";
4341
4354
  if (Array.isArray(value)) return value.every((entry) => isJsonValue(entry));
@@ -4376,13 +4389,15 @@ function withDefaultTimeout(options) {
4376
4389
  /**
4377
4390
  * Browser-optimized MCP Server that speaks WebMCP natively.
4378
4391
  *
4379
- * This server IS navigator.modelContext — it implements the WebMCP standard API
4380
- * (provideContext, registerTool, unregisterTool, clearContext) while retaining
4381
- * full MCP protocol capabilities (resources, prompts, elicitation, sampling)
4382
- * via the inherited BaseMcpServer surface.
4392
+ * Implements `registerTool(tool, options?)` while retaining MCP capabilities
4393
+ * (resources, prompts, elicitation, sampling) via BaseMcpServer.
4394
+ *
4395
+ * Deprecated compatibility (kept for Chrome Beta 147 and existing wrappers,
4396
+ * removed in the next major): `unregisterTool(name)`, `provideContext()`,
4397
+ * `clearContext()`, and the `{ unregister }` handle returned from `registerTool`.
4383
4398
  *
4384
- * When `native` is provided, all tool operations are mirrored to it so that
4385
- * navigator.modelContextTesting (polyfill testing shim) stays in sync.
4399
+ * When `native` is provided, tool operations are mirrored so that
4400
+ * navigator.modelContextTesting stays in sync.
4386
4401
  */
4387
4402
  var BrowserMcpServer = class extends McpServer {
4388
4403
  [SERVER_MARKER_PROPERTY] = true;
@@ -4390,6 +4405,12 @@ var BrowserMcpServer = class extends McpServer {
4390
4405
  _promptSchemas = /* @__PURE__ */ new Map();
4391
4406
  _jsonValidator;
4392
4407
  _publicMethodsBound = false;
4408
+ _provideContextDeprecationWarned = false;
4409
+ _clearContextDeprecationWarned = false;
4410
+ _unregisterToolDeprecationWarned = false;
4411
+ _nativeToolCleanups = /* @__PURE__ */ new Map();
4412
+ _producerEventTarget = new EventTarget();
4413
+ _ontoolchange = null;
4393
4414
  constructor(serverInfo, options) {
4394
4415
  const validator = new PolyfillJsonSchemaValidator();
4395
4416
  const enhancedOptions = {
@@ -4416,8 +4437,12 @@ var BrowserMcpServer = class extends McpServer {
4416
4437
  this.provideContext = this.provideContext.bind(this);
4417
4438
  this.clearContext = this.clearContext.bind(this);
4418
4439
  this.listTools = this.listTools.bind(this);
4440
+ this.getTools = this.getTools.bind(this);
4419
4441
  this.callTool = this.callTool.bind(this);
4420
4442
  this.executeTool = this.executeTool.bind(this);
4443
+ this.addEventListener = this.addEventListener.bind(this);
4444
+ this.removeEventListener = this.removeEventListener.bind(this);
4445
+ this.dispatchEvent = this.dispatchEvent.bind(this);
4421
4446
  this.registerResource = this.registerResource.bind(this);
4422
4447
  this.listResources = this.listResources.bind(this);
4423
4448
  this.readResource = this.readResource.bind(this);
@@ -4478,6 +4503,71 @@ var BrowserMcpServer = class extends McpServer {
4478
4503
  if (typeof candidate.listTools !== "function" || typeof candidate.callTool !== "function") return;
4479
4504
  return candidate;
4480
4505
  }
4506
+ getNativeUnregisterTool() {
4507
+ if (!this.native) return;
4508
+ const unregisterTool = this.native.unregisterTool;
4509
+ if (typeof unregisterTool !== "function") return;
4510
+ return (nameOrTool) => unregisterTool.call(this.native, nameOrTool);
4511
+ }
4512
+ createNativeToolCleanup(signal) {
4513
+ const controller = new AbortController();
4514
+ let removeSignalListener;
4515
+ if (signal) {
4516
+ const abortNativeSignal = () => {
4517
+ controller.abort();
4518
+ };
4519
+ if (signal.aborted) abortNativeSignal();
4520
+ else {
4521
+ signal.addEventListener("abort", abortNativeSignal, { once: true });
4522
+ removeSignalListener = () => signal.removeEventListener("abort", abortNativeSignal);
4523
+ }
4524
+ }
4525
+ return {
4526
+ options: { signal: controller.signal },
4527
+ abort: () => {
4528
+ removeSignalListener?.();
4529
+ if (!controller.signal.aborted) controller.abort();
4530
+ }
4531
+ };
4532
+ }
4533
+ registerNativeToolMirror(tool, signal) {
4534
+ if (!this.native) return;
4535
+ const nativeRegister = this.native.registerTool;
4536
+ const nativeUnregisterTool = this.getNativeUnregisterTool();
4537
+ const cleanup = Boolean(signal) || !nativeUnregisterTool ? this.createNativeToolCleanup(signal) : void 0;
4538
+ try {
4539
+ if (cleanup) nativeRegister.call(this.native, tool, cleanup.options);
4540
+ else nativeRegister.call(this.native, tool);
4541
+ } catch (error) {
4542
+ cleanup?.abort();
4543
+ if (isPermissionsPolicySecurityError(error)) {
4544
+ console.warn("[BrowserMcpServer] Native WebMCP tool mirror is blocked by permissions policy; continuing with WebMCP transport registration only.");
4545
+ return;
4546
+ }
4547
+ throw error;
4548
+ }
4549
+ if (!cleanup) return;
4550
+ const nativeToolCleanup = {
4551
+ abort: cleanup.abort,
4552
+ nativeSignalAccepted: nativeRegister.length >= 2 || !nativeUnregisterTool
4553
+ };
4554
+ this._nativeToolCleanups.set(tool.name, nativeToolCleanup);
4555
+ return nativeToolCleanup;
4556
+ }
4557
+ unregisterNativeToolMirror(name, options) {
4558
+ const cleanup = this._nativeToolCleanups.get(name);
4559
+ this._nativeToolCleanups.delete(name);
4560
+ const nativeUnregisterTool = this.getNativeUnregisterTool();
4561
+ if (options?.preferAbortSignal && cleanup?.nativeSignalAccepted === true || !nativeUnregisterTool) {
4562
+ cleanup?.abort();
4563
+ return;
4564
+ }
4565
+ try {
4566
+ nativeUnregisterTool(name);
4567
+ } finally {
4568
+ cleanup?.abort();
4569
+ }
4570
+ }
4481
4571
  registerToolInServer(tool) {
4482
4572
  const inputSchema = this.toTransportSchema(tool.inputSchema);
4483
4573
  super.registerTool(tool.name, {
@@ -4488,8 +4578,35 @@ var BrowserMcpServer = class extends McpServer {
4488
4578
  }, async (args) => {
4489
4579
  return normalizeToolResponse(await tool.execute(args, { requestUserInteraction: async (cb) => cb() }));
4490
4580
  });
4581
+ this.notifyProducerToolsChanged();
4491
4582
  return { unregister: () => this.unregisterTool(tool.name) };
4492
4583
  }
4584
+ get ontoolchange() {
4585
+ return this._ontoolchange;
4586
+ }
4587
+ set ontoolchange(handler) {
4588
+ this._ontoolchange = handler;
4589
+ }
4590
+ addEventListener(type, listener, options) {
4591
+ this._producerEventTarget.addEventListener(type, listener, options);
4592
+ }
4593
+ removeEventListener(type, listener, options) {
4594
+ this._producerEventTarget.removeEventListener(type, listener, options);
4595
+ }
4596
+ dispatchEvent(event) {
4597
+ return this._producerEventTarget.dispatchEvent(event);
4598
+ }
4599
+ notifyProducerToolsChanged() {
4600
+ queueMicrotask(() => {
4601
+ const event = new Event("toolchange");
4602
+ try {
4603
+ this._ontoolchange?.call(this, event);
4604
+ } catch (error) {
4605
+ console.warn("[BrowserMcpServer] navigator.modelContext.ontoolchange handler threw:", error);
4606
+ }
4607
+ this.dispatchEvent(event);
4608
+ });
4609
+ }
4493
4610
  backfillTools(tools, execute) {
4494
4611
  let synced = 0;
4495
4612
  for (const sourceTool of tools) {
@@ -4507,18 +4624,34 @@ var BrowserMcpServer = class extends McpServer {
4507
4624
  }
4508
4625
  return synced;
4509
4626
  }
4510
- registerTool(tool) {
4511
- if (this.native) this.native.registerTool(tool);
4627
+ registerTool(tool, options) {
4628
+ const signal = options?.signal;
4629
+ if (signal?.aborted) {
4630
+ console.warn(`[BrowserMcpServer] registerTool("${tool?.name ?? "<unknown>"}") skipped: options.signal was already aborted.`);
4631
+ return { unregister: () => {} };
4632
+ }
4633
+ this.registerNativeToolMirror(tool, signal);
4634
+ let handle;
4512
4635
  try {
4513
- return this.registerToolInServer(tool);
4636
+ handle = this.registerToolInServer(tool);
4514
4637
  } catch (error) {
4515
4638
  if (this.native) try {
4516
- this.native.unregisterTool(tool.name);
4639
+ this.unregisterNativeToolMirror(tool.name);
4517
4640
  } catch (rollbackError) {
4518
4641
  console.error("[BrowserMcpServer] Rollback of native tool registration failed:", rollbackError);
4519
4642
  }
4520
4643
  throw error;
4521
4644
  }
4645
+ if (signal) signal.addEventListener("abort", () => {
4646
+ this._parentTools[tool.name]?.remove();
4647
+ try {
4648
+ this.unregisterNativeToolMirror(tool.name, { preferAbortSignal: true });
4649
+ } catch (error) {
4650
+ console.warn("[BrowserMcpServer] Native unregister via abort fallback failed:", error);
4651
+ }
4652
+ this.notifyProducerToolsChanged();
4653
+ }, { once: true });
4654
+ return handle;
4522
4655
  }
4523
4656
  /**
4524
4657
  * Backfill tools that were already registered on the native/polyfill context
@@ -4533,9 +4666,26 @@ var BrowserMcpServer = class extends McpServer {
4533
4666
  arguments: args
4534
4667
  }));
4535
4668
  }
4536
- unregisterTool(name) {
4537
- this._parentTools[name]?.remove();
4538
- if (this.native) this.native.unregisterTool(name);
4669
+ unregisterTool(nameOrTool) {
4670
+ this.warnUnregisterToolDeprecationOnce();
4671
+ const name = this.resolveToolNameForUnregister(nameOrTool);
4672
+ const existing = this._parentTools[name];
4673
+ existing?.remove();
4674
+ if (this.native) this.unregisterNativeToolMirror(name);
4675
+ if (existing) this.notifyProducerToolsChanged();
4676
+ }
4677
+ clearRegisteredTools() {
4678
+ let changed = false;
4679
+ for (const name of Object.keys(this._parentTools)) {
4680
+ this._parentTools[name]?.remove();
4681
+ changed = true;
4682
+ if (this.native) try {
4683
+ this.unregisterNativeToolMirror(name);
4684
+ } catch (error) {
4685
+ console.warn("[BrowserMcpServer] Native unregister during clear failed:", error);
4686
+ }
4687
+ }
4688
+ if (changed) this.notifyProducerToolsChanged();
4539
4689
  }
4540
4690
  registerResource(descriptor) {
4541
4691
  const registered = super.registerResource(descriptor.name, descriptor.uri, {
@@ -4553,13 +4703,33 @@ var BrowserMcpServer = class extends McpServer {
4553
4703
  } };
4554
4704
  }
4555
4705
  provideContext(options) {
4556
- for (const tool of Object.values(this._parentTools)) tool.remove();
4557
- if (this.native) this.native.clearContext();
4706
+ this.warnProvideContextDeprecationOnce();
4707
+ this.clearRegisteredTools();
4558
4708
  for (const tool of options?.tools ?? []) this.registerTool(tool);
4559
4709
  }
4560
4710
  clearContext() {
4561
- for (const tool of Object.values(this._parentTools)) tool.remove();
4562
- if (this.native) this.native.clearContext();
4711
+ this.warnClearContextDeprecationOnce();
4712
+ this.clearRegisteredTools();
4713
+ }
4714
+ resolveToolNameForUnregister(nameOrTool) {
4715
+ if (typeof nameOrTool === "string") return nameOrTool;
4716
+ if (isPlainObject$1(nameOrTool) && typeof nameOrTool.name === "string") return nameOrTool.name;
4717
+ throw new TypeError("Failed to execute 'unregisterTool' on 'ModelContext': parameter 1 must be a string or an object with a string name.");
4718
+ }
4719
+ warnProvideContextDeprecationOnce() {
4720
+ if (this._provideContextDeprecationWarned) return;
4721
+ this._provideContextDeprecationWarned = true;
4722
+ console.warn("[BrowserMcpServer] navigator.modelContext.provideContext() is deprecated and will be removed in the next major version. Register tools individually with registerTool() instead.");
4723
+ }
4724
+ warnClearContextDeprecationOnce() {
4725
+ if (this._clearContextDeprecationWarned) return;
4726
+ this._clearContextDeprecationWarned = true;
4727
+ console.warn("[BrowserMcpServer] navigator.modelContext.clearContext() is deprecated and will be removed in the next major version. Unregister individual tools instead.");
4728
+ }
4729
+ warnUnregisterToolDeprecationOnce() {
4730
+ if (this._unregisterToolDeprecationWarned) return;
4731
+ this._unregisterToolDeprecationWarned = true;
4732
+ console.warn("[BrowserMcpServer] navigator.modelContext.unregisterTool() is deprecated. The April 23, 2026 WebMCP draft removed it in favor of registerTool(tool, { signal }) — pass an AbortSignal and abort it to unregister.");
4563
4733
  }
4564
4734
  listResources() {
4565
4735
  return Object.entries(this._parentResources).filter(([, resource]) => resource.enabled).map(([uri, resource]) => ({
@@ -4609,6 +4779,21 @@ var BrowserMcpServer = class extends McpServer {
4609
4779
  return item;
4610
4780
  });
4611
4781
  }
4782
+ getTools() {
4783
+ return this.listTools().map((tool) => {
4784
+ let inputSchema;
4785
+ try {
4786
+ inputSchema = JSON.stringify(tool.inputSchema ?? DEFAULT_INPUT_SCHEMA);
4787
+ } catch {
4788
+ inputSchema = JSON.stringify(DEFAULT_INPUT_SCHEMA);
4789
+ }
4790
+ return {
4791
+ name: tool.name,
4792
+ description: tool.description ?? "",
4793
+ inputSchema
4794
+ };
4795
+ });
4796
+ }
4612
4797
  /**
4613
4798
  * Override SDK's validateToolInput to handle both Zod schemas and plain JSON Schema.
4614
4799
  * Zod schemas use the SDK's safeParseAsync; plain JSON Schema uses PolyfillJsonSchemaValidator.
@@ -4616,9 +4801,9 @@ var BrowserMcpServer = class extends McpServer {
4616
4801
  async validateToolInput(tool, args, toolName) {
4617
4802
  if (!tool.inputSchema) return void 0;
4618
4803
  if (this.isZodSchema(tool.inputSchema)) {
4619
- const result$1 = await safeParseAsync(tool.inputSchema, args ?? {});
4620
- if (!result$1.success) throw new Error(`Invalid arguments for tool ${toolName}: ${getParseErrorMessage(result$1.error)}`);
4621
- return result$1.data;
4804
+ const result = await safeParseAsync(tool.inputSchema, args ?? {});
4805
+ if (!result.success) throw new Error(`Invalid arguments for tool ${toolName}: ${getParseErrorMessage(result.error)}`);
4806
+ return result.data;
4622
4807
  }
4623
4808
  const result = this._jsonValidator.getValidator(tool.inputSchema)(args ?? {});
4624
4809
  if (!result.valid) throw new Error(`Invalid arguments for tool ${toolName}: ${result.errorMessage}`);