npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luchibei/webmcp-sdk

v0.2.0

Published

Core SDK primitives for WebMCP tools

Readme

@luchibei/webmcp-sdk

WebMCP SDK for defining and registering robust tools in the browser.

@luchibei/webmcp-sdk wraps the WebMCP APIs with:

  • Zod-first tool definitions
  • automatic JSON Schema generation (zod-to-json-schema)
  • safe runtime wrappers (no-op when WebMCP is unavailable)
  • optional risk labels (read / write / payment)
  • tool registration policy checks (createToolPolicy)
  • consistent error helpers (ok / fail)

What is WebMCP?

WebMCP allows websites to expose high-level tools to browser AI agents through navigator.modelContext.

This SDK targets these API names/fields:

  • navigator.modelContext.provideContext({ tools })
  • navigator.modelContext.registerTool(tool)
  • navigator.modelContext.clearContext()
  • navigator.modelContext.unregisterTool(name)
  • tool = { name, description, inputSchema, execute(input, client), annotations? }

The WebIDL may describe undefined returns, but real implementations can be sync/async. This SDK treats all of them as void | Promise<void> and always awaits internally.


5-minute setup

1) Install

pnpm add @luchibei/webmcp-sdk zod

2) Define a tool

import { defineTool, ok } from "@luchibei/webmcp-sdk";
import { z } from "zod";

export const searchProductsTool = defineTool({
  name: "searchProducts",
  description: "Search products by keyword and optional price range",
  risk: "read",
  input: z.object({
    query: z.string().min(1),
    maxPrice: z.number().positive().optional()
  }),
  readOnlyHint: true,
  execute: async (input) => {
    const items = await searchProducts(input.query, input.maxPrice);
    return ok(items);
  }
});

3) Register safely

import { registerToolSafe } from "@luchibei/webmcp-sdk";

const handle = await registerToolSafe(searchProductsTool);

// later
await handle.unregister();

4) Register multiple tools

import { registerToolsSafe } from "@luchibei/webmcp-sdk";

const { unregisterAll } = await registerToolsSafe([searchProductsTool]);

// later
await unregisterAll();

5) Apply a registration policy

import { createToolPolicy, registerToolsSafe } from "@luchibei/webmcp-sdk";

const policy = createToolPolicy({
  defaultDenyWrite: false,
  requireConfirmationForRisk: ["payment"]
});

await registerToolsSafe([searchProductsTool], { policy });

API summary

  • defineTool(options)
  • ok(data)
  • fail(code, message, details?)
  • getModelContext()
  • isWebMcpSupported()
  • provideContextSafe({ tools })
  • clearContextSafe()
  • registerToolSafe(tool, { policy? })
  • unregisterToolSafe(name)
  • registerToolsSafe(tools, { policy? })
  • createToolPolicy(options)

ToolResponse

type ToolResponse<T> =
  | { ok: true; data: T; metadata?: { risk?: "read" | "write" | "payment" } }
  | {
      ok: false;
      error: { code: string; message: string; details?: unknown };
      metadata?: { risk?: "read" | "write" | "payment" };
    };

defineTool always validates input and returns a standardized failure response for validation/runtime errors. For successful execution, you can return your own payload or use ok(data).


Security best practices

  1. Set readOnlyHint: true for read-only tools.
    • or use risk: "read" (auto-maps to annotations.readOnlyHint = true)
  2. Use explicit user confirmation before sensitive actions (checkout, payment, profile update).
    • use risk: "payment" for payment tools and enforce policy at registration time
  3. Keep tool inputs high-level and validated (avoid low-level click/selector operations).
  4. Do not expose secrets in tool output.

For sensitive actions, request user interaction in the execution flow via WebMCP client capabilities:

await client.requestUserInteraction(async () => {
  // ask user confirmation in UI, then proceed
});

中文说明(简版)

@luchibei/webmcp-sdk 用于把网站能力封装成 WebMCP 工具,核心特性:

  • 用 Zod 定义输入,自动生成 inputSchema
  • 自动校验输入 + 统一错误结构
  • registerTool/provideContext/clearContext/unregisterTool 全部有安全封装
  • WebMCP 不可用时自动 no-op,不会导致页面崩溃

建议:

  • 只读工具加 readOnlyHint: true
  • 下单/支付等敏感操作必须走确认步骤(client.requestUserInteraction

FAQ

Q: Browser does not support WebMCP. What should I do?

Use the safe wrappers:

  • registerToolSafe
  • registerToolsSafe
  • provideContextSafe
  • clearContextSafe

They no-op when WebMCP is unavailable, so your app still works.

Q: Should I expose write/payment tools by default?

No. Prefer explicit policies:

const policy = createToolPolicy({
  defaultDenyWrite: true,
  requireConfirmationForRisk: ["payment"]
});

Q: Do risk labels change WebMCP spec fields?

No. risk is an upper-layer convention. Spec compatibility remains through annotations.readOnlyHint.