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

@webmcpui/core

v0.3.1

Published

Agent-aware, framework-agnostic web components for the WebMCP era — accessible, form-associated controls an AI agent can fill, with Standard Schema validation.

Readme

@webmcpui/core

Framework-agnostic, WebMCP-native custom elements. Every <wmcp-*> element is a proper, accessible HTML control first and, when you opt in, also registers an imperative WebMCP tool an agent can call.

Two families of primitives:

  • Form controls expose a value an agent can set — <wmcp-input>, <wmcp-textarea>, <wmcp-select>, <wmcp-checkbox>, <wmcp-radio> / <wmcp-radio-group>. Shared behavior (form association via ElementInternals, Standard Schema validation, a11y, theming) lives in a WmcpFormControl base.
  • Interaction primitives expose an action an agent can trigger — <wmcp-button>, <wmcp-dialog>, <wmcp-menu>, <wmcp-tabs>, <wmcp-popover>, <wmcp-switch>, <wmcp-tooltip> — or, for <wmcp-toast>, a reading an agent can perceive. They share a WmcpAction / WmcpExposable base.
  • Presentational primitives are plain accessible controls (no agent surface) that round out the kit — <wmcp-badge>, <wmcp-separator>, <wmcp-alert>, <wmcp-progress>, <wmcp-avatar>.

One source of truth (vanilla custom elements built with Lit), two distribution channels: an ESM package for build tools, and a single-file CDN bundle for no-build environments (Webflow, WordPress, plain HTML).

Using React or Vue? Typed, idiomatic wrappers ship as @webmcpui/react and @webmcpui/vue — same elements, same WebMCP exposure, with framework-native props, v-model/state, and events. See the Frameworks guide.

Install (build-tool consumers)

pnpm add @webmcpui/core @webmcpui/tokens
import { defineComponents } from '@webmcpui/core';
import '@webmcpui/tokens/css'; // the theme tokens (CSS custom properties)

defineComponents(); // registers every <wmcp-*> element
<wmcp-input label="Email" name="email" type="email"></wmcp-input>
<wmcp-button variant="primary">Save</wmcp-button>

Importing the package does not register elements — you call defineComponents() so you control timing. (The CDN bundle below registers automatically.)

No build? Drop a script tag

For Webflow / WordPress / hand-written HTML — one tag, elements auto-register:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@webmcpui/tokens/dist/css/tokens.css" />
<script src="https://cdn.jsdelivr.net/npm/@webmcpui/core/dist/webmcpui.global.js"></script>

<wmcp-input label="Email" name="email" type="email"></wmcp-input>

See examples/plain-html.html for a working local version.

Standard Schema validation (form controls)

Bring any Standard Schema validator — Zod, Valibot, ArkType — set it as the schema property. No bespoke schema language.

import { z } from 'zod';

const input = document.querySelector('wmcp-input')!;
input.schema = z.string().email('Enter a valid email');

Validation runs on input and during native form validation; failures set aria-invalid, render an error message in a live region, and propagate to the containing <form> via ElementInternals.

WebMCP exposure

Opt in with expose. The element registers an imperative WebMCP tool on connect and unregisters on disconnect. It is feature-detected — preferring document.modelContext (canonical as of the Chrome 149+ origin trial) and falling back to the deprecated navigator.modelContext — and a complete no-op when no host is present, so the element is always a good control first.

<!-- form control → a "fill" tool that sets a value -->
<wmcp-input label="Email" name="email" expose></wmcp-input>

<!-- interaction primitive → an "action" tool the agent can trigger -->
<wmcp-button tool-name="book_appointment" expose>Book</wmcp-button>

<!-- a menu → a parameterized action (the agent picks which item) -->
<wmcp-menu name="row_action" label="Actions" expose>
  <option value="edit">Edit</option>
  <option value="delete">Delete</option>
</wmcp-menu>

Consequential steps stay a deliberate human action: an agent can set a value or open a dialog, but submitting/confirming is the person's to make.

Testing without a real agent

No mainstream agent calls WebMCP broadly yet, so @webmcpui/core/testing ships a fake host to exercise exposure end to end:

import { installFakeAgent } from '@webmcpui/core/testing';

const agent = installFakeAgent();
// ... connect a <wmcp-input expose> / <wmcp-button expose> ...
await agent.call('fill_email', { value: '[email protected]' });
await agent.call('click_button');
agent.restore();

Documentation

Full docs, live demos for every element, and llms.txt at webmcpui.com.

Build & test

pnpm build        # tsup → dist/ (ESM + IIFE + d.ts)
pnpm typecheck    # tsc --noEmit
pnpm test         # @web/test-runner in real Chromium
pnpm test:smoke   # node smoke check against the built dist

Tests run in a genuine browser via the Playwright launcher — form-associated custom elements and ElementInternals don't work under jsdom. First run needs the browser binary:

pnpm exec playwright install chromium