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

@raisindb/mcp-ui-client

v0.5.3

Published

Tiny, dependency-free, browser-only runtime helper for RaisinDB MCP-UI widgets. Runs inside the widget iframe and abstracts over the ext-apps and MCP-UI host bridges.

Readme

@raisindb/mcp-ui-client

Tiny, dependency-free, browser-only runtime helper for RaisinDB MCP-UI widgets. It runs inside the widget iframe and papers over the two host bridge conventions (MCP Apps / ext-apps and MCP-UI) and the two delivery modes (mode: "html" and mode: "uri-list") a RaisinDB widget can be served under, so widget authors write one call site regardless of host.

This is not the RaisinDB backend SDK. To talk to an MCP server from a Node/TS backend, use McpClient in @raisindb/client. This package has no RaisinDB connection, no auth, and no network calls of its own — it only bridges to whatever host is rendering the widget.

Install

npm install @raisindb/mcp-ui-client

Zero runtime dependencies. Ships ESM + type declarations.

Delivery modes

A RaisinDB tool binds a widget with ui: { mode, entry }:

  • mode: "html" — the host renders raw HTML via srcdoc. There is no navigable URL, so RaisinDB injects window.__RAISIN_INITIAL_ROUTE__ (and, when available, window.__RAISIN_INITIAL_DATA__) before the document.
  • mode: "uri-list" — the host iframes a real URL served from GET /api/static/{repo}/{branch}/{ws}/{*path}. The route rides on location.hash; no globals are injected.

getInitialRoute() / getInitialData() normalize both so your code never needs to know which mode it ran under.

API

All exports are framework-agnostic functions.

getInitialRoute(): string

Returns the widget's initial route. Prefers window.__RAISIN_INITIAL_ROUTE__ (mode: "html"), falls back to location.hash (mode: "uri-list") with a leading # stripped so both modes yield the same form (e.g. "/order-card"). Returns "" when no route is present.

import { getInitialRoute } from '@raisindb/mcp-ui-client';

// Works unchanged in both delivery modes:
const route = getInitialRoute(); // "/order-card"
router.navigate(route);

getInitialData<T>(): T | undefined

Returns the initiating tool's structuredContent as delivered by the host on load, or undefined. Reads window.__RAISIN_INITIAL_DATA__ first, then best-effort ext-apps globals.

import { getInitialData } from '@raisindb/mcp-ui-client';

type Order = { id: string; total: number };
const order = getInitialData<Order>();

callTool(name, args?): Promise<unknown>

Invokes a server tool. Prefers the ext-apps window.callServerTool bridge (awaiting and returning its result); otherwise falls back to the MCP-UI convention — postMessage({ type: 'tool', payload: { toolName, params } }, '*') — and resolves undefined, since under MCP-UI the result arrives asynchronously via onToolResult.

Hosts may require explicit user approval before running a UI-initiated tool call. Keep destructive operations out of the set a widget can trigger without a second confirmation.

onToolResult(cb): () => void

Registers a callback for tool results and returns an unsubscribe function. Wires up both bridges: it installs a single shared window.ontoolresult dispatcher (ext-apps, preserving any pre-existing handler) and listens for MCP-UI message-delivered results.

import { callTool, onToolResult } from '@raisindb/mcp-ui-client';

const off = onToolResult((result) => render(result));
await callTool('approve_order', { orderId: '42' });
// later: off();

updateModelContext(content): Promise<boolean>

Passthrough to the ext-apps window.updateModelContext when the host exposes it, pushing structured content back into the conversation for the model to see. On a host without ext-apps support this is a documented no-op and returns false.

Full example

import {
  getInitialRoute,
  getInitialData,
  callTool,
  onToolResult,
  updateModelContext,
} from '@raisindb/mcp-ui-client';

// One bootstrap that works in mode:html AND mode:uri-list.
const route = getInitialRoute();
const data = getInitialData<{ orderId: string }>();
renderRoute(route, data);

onToolResult((result) => renderRoute(getInitialRoute(), result));

document.querySelector('#approve')?.addEventListener('click', async () => {
  await callTool('approve_order', { orderId: data?.orderId });
  await updateModelContext({
    content: [{ type: 'text', text: 'Order approved from the widget.' }],
  });
});

License

BSL-1.1