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

@mcp-apps-kit/ui-react

v0.5.0

Published

React bindings for MCP applications

Downloads

46

Readme

@mcp-apps-kit/ui-react

npm node license

React bindings for MCP applications.

@mcp-apps-kit/ui-react builds on @mcp-apps-kit/ui to provide React context and hooks for tool calls, tool results, and host context.

Table of Contents

Background

React widgets often need host-aware APIs for tool calls and UI state. This package provides a React-first wrapper around the vanilla UI SDK so you can use hooks instead of manual subscriptions.

Features

  • AppsProvider context wrapper
  • Hooks for tools, host context, and widget state
  • Typed tool calls with generics
  • Optional debug logger hook
  • Host capabilities - Query what the host supports (theming, display modes, file upload, etc.)
  • Size notifications - Automatic resize observer integration
  • Partial tool input - React to streaming tool inputs

Compatibility

  • Hosts: MCP Apps and ChatGPT (OpenAI Apps SDK)
  • Node.js: >= 18 for tooling/builds (browser runtime)
  • Peer dependencies: react and react-dom ^18 || ^19

Install

npm install @mcp-apps-kit/ui-react

Usage

Quick start

import { AppsProvider, useAppsClient, useToolResult, useHostContext } from "@mcp-apps-kit/ui-react";

function Widget() {
  const client = useAppsClient();
  const result = useToolResult();
  const host = useHostContext();

  return (
    <div data-theme={host.theme}>
      <button onClick={() => client.callTool("greet", { name: "Alice" })}>Greet</button>
      <pre>{JSON.stringify(result, null, 2)}</pre>
    </div>
  );
}

export function App() {
  return (
    <AppsProvider>
      <Widget />
    </AppsProvider>
  );
}

Typed tools and results

Use ClientToolsFromCore from @mcp-apps-kit/core for end-to-end type safety:

import { AppsProvider, useAppsClient, useToolResult } from "@mcp-apps-kit/ui-react";
import type { AppClientTools } from "../server"; // Exported from your server

function Widget() {
  // Typed client - callTool arguments and return types are inferred
  const client = useAppsClient<AppClientTools>();

  // Typed results - result?.greet?.message is typed as string | undefined
  const result = useToolResult<AppClientTools>();

  const handleGreet = async () => {
    // Option 1: Using callTool with tool name string
    await client.callTool("greet", { name: "Alice" });

    // Option 2: Using the typed tools proxy (recommended)
    await client.tools.callGreet({ name: "Alice" });
  };

  if (result?.greet) {
    return (
      <div>
        <p>{result.greet.message}</p>
        <p>at {result.greet.timestamp}</p>
      </div>
    );
  }

  return <button onClick={handleGreet}>Greet</button>;
}

export function App() {
  return (
    <AppsProvider>
      <Widget />
    </AppsProvider>
  );
}

Automatic size notifications

By default, the MCP adapter automatically reports UI size changes to the host using a ResizeObserver. This feature is only supported in MCP Apps and is silently ignored in ChatGPT.

To disable automatic resizing:

export function App() {
  return (
    <AppsProvider autoResize={false}>
      <Widget />
    </AppsProvider>
  );
}

Note: The autoResize option is only applied during initial mount. Changing it at runtime has no effect.

The AppClientTools type is generated in your server code:

// server/index.ts
import { createApp, defineTool, type ClientToolsFromCore } from "@mcp-apps-kit/core";

const app = createApp({
  tools: {
    greet: defineTool({
      input: z.object({ name: z.string() }),
      output: z.object({ message: z.string(), timestamp: z.string() }),
      handler: async (input) => ({ ... }),
    }),
  },
});

// Export for UI code
export type AppClientTools = ClientToolsFromCore<typeof app.tools>;

Examples

API

Provider

  • AppsProvider - Context wrapper for all hooks
    • client? - Pre-initialized client instance (optional)
    • forceAdapter? - Force a specific adapter ("mcp" | "openai" | "mock")
    • autoResize? - Enable/disable automatic size change notifications (default: true). Only supported in MCP Apps; ignored in ChatGPT. Note: changing this prop after initial mount has no effect.
    • fallback? - Component to show while client initializes
    • errorFallback? - Component to show on initialization error

Core Hooks

| Hook | Description | | ---------------- | ----------------------------------------- | | useAppsClient | Client instance for tool calls | | useToolResult | Current tool result data | | useToolInput | Tool input parameters | | useHostContext | Host info (theme, viewport, locale, etc.) | | useWidgetState | Persisted state across reloads | | useDisplayMode | Fullscreen/panel mode control | | useDebugLogger | Debug logging configuration |

Typed Tools Proxy

The client returned by useAppsClient includes a tools property with typed method wrappers:

import { useAppsClient } from "@mcp-apps-kit/ui-react";
import type { AppClientTools } from "../server";

function Widget() {
  const client = useAppsClient<AppClientTools>();

  const handleClick = async () => {
    // Tool name "greet" becomes method "callGreet"
    const result = await client.tools.callGreet({ name: "Alice" });
    console.log(result.message);
  };

  return <button onClick={handleClick}>Greet</button>;
}

Method names are generated by prepending "call" and capitalizing the first letter of the tool name (e.g., greetcallGreet, searchRestaurantscallSearchRestaurants).

Host Capabilities & Version

import { useHostCapabilities, useHostVersion } from "@mcp-apps-kit/ui-react";

function Widget() {
  const capabilities = useHostCapabilities();
  const version = useHostVersion();

  // Common capabilities (both platforms)
  const themes = capabilities?.theming?.themes; // ["light", "dark"]
  const modes = capabilities?.displayModes?.modes; // ["inline", "fullscreen", "pip"]

  // MCP Apps specific
  const hasPartialInput = !!capabilities?.partialToolInput;

  // ChatGPT specific
  const hasFileUpload = !!capabilities?.fileUpload;

  // Host version (MCP Apps only)
  // { name: "MCP Host", version: "1.0.0" }
  return <div>Host: {version?.name}</div>;
}

Size Notifications (MCP Apps)

import { useSizeChangedNotifications } from "@mcp-apps-kit/ui-react";

function Widget() {
  // Attach to container to auto-report size changes
  const containerRef = useSizeChangedNotifications();

  return <div ref={containerRef}>Content that may resize</div>;
}

Partial Tool Input (MCP Apps)

import { useOnToolInputPartial } from "@mcp-apps-kit/ui-react";

function Widget() {
  useOnToolInputPartial((input) => {
    // React to streaming partial input from the model
    console.log("Partial input:", input);
  });

  return <div>Streaming input widget</div>;
}

Theme & Style Hooks

| Hook | Description | | ----------------------- | --------------------------------- | | useHostStyleVariables | Apply host-provided CSS variables | | useDocumentTheme | Sync document theme with host | | useSafeAreaInsets | Safe area insets (ChatGPT) |

Lifecycle Hooks

| Hook | Description | | -------------------- | -------------------------------------- | | useOnToolCancelled | Callback when tool is cancelled | | useOnTeardown | Cleanup callback before widget removal |

File Operations (ChatGPT)

| Hook | Description | | ----------------- | ---------------------- | | useFileUpload | Upload files to host | | useFileDownload | Get file download URLs |

Layout (ChatGPT)

| Hook | Description | | -------------------- | --------------------------- | | useIntrinsicHeight | Set widget intrinsic height | | useView | View management |

Modals (ChatGPT)

| Hook | Description | | ---------- | ----------------------- | | useModal | Modal dialog management |

Contributing

See ../../CONTRIBUTING.md for development setup and guidelines. Issues and pull requests are welcome.

License

MIT