> ## Documentation Index
> Fetch the complete documentation index at: https://docs.leanmcp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# @leanmcp/ui

> MCP-native React components and hooks for building MCP Apps

# @leanmcp/ui

Build rich, interactive MCP Apps with React components designed for the Model Context Protocol. Features first-class tool integration, streaming support, and automatic host theming.

## Features

<CardGroup cols={2}>
  <Card title="MCP-Native Components" icon="cube">
    ToolButton, ToolDataGrid, ToolForm - components that directly integrate with MCP tools
  </Card>

  <Card title="Dual Platform Support" icon="laptop">
    Works with ext-apps hosts (Claude Desktop) and ChatGPT GPT Actions
  </Card>

  <Card title="Host Theming" icon="palette">
    Automatic theme sync with host application (light/dark mode)
  </Card>

  <Card title="Testing Utilities" icon="flask">
    MockAppProvider for unit testing MCP App components
  </Card>
</CardGroup>

## Installation

```bash theme={null}
npm install @leanmcp/ui
```

Import the styles in your app entry point:

```tsx theme={null}
import '@leanmcp/ui/styles.css';
```

## Two App Paradigms

`@leanmcp/ui` supports two different host environments:

### ext-apps (Claude Desktop, MCP Hosts)

Uses the `@modelcontextprotocol/ext-apps` protocol for iframe-based communication.

```tsx theme={null}
import { AppProvider, ToolButton } from '@leanmcp/ui';
import '@leanmcp/ui/styles.css';

function MyApp() {
  return (
    <AppProvider appInfo={{ name: 'MyApp', version: '1.0.0' }}>
      <ToolButton tool="refresh-data" resultDisplay="toast">
        Refresh Data
      </ToolButton>
    </AppProvider>
  );
}
```

### ChatGPT GPT Actions

Uses ChatGPT's native `window.openai` SDK.

```tsx theme={null}
import { GPTAppProvider, useGptTool } from '@leanmcp/ui';
import '@leanmcp/ui/styles.css';

function MyGPTApp() {
  return (
    <GPTAppProvider appName="MyApp">
      <DataDisplay />
    </GPTAppProvider>
  );
}

function DataDisplay() {
  const { call, result, loading } = useGptTool('get-data');
  
  return (
    <button onClick={() => call()} disabled={loading}>
      {loading ? 'Loading...' : 'Fetch Data'}
    </button>
  );
}
```

## Quick Start Example

Here's a complete example showing a tool-linked UI component:

```tsx theme={null}
import { AppProvider, ToolDataGrid, RequireConnection } from '@leanmcp/ui';
import '@leanmcp/ui/styles.css';

function UsersApp() {
  return (
    <AppProvider appInfo={{ name: 'UsersApp', version: '1.0.0' }}>
      <RequireConnection>
        <ToolDataGrid
          dataTool="list-users"
          columns={[
            { key: 'name', header: 'Name', sortable: true },
            { key: 'email', header: 'Email' },
            { key: 'status', header: 'Status' }
          ]}
          transformData={(result) => ({
            rows: result.users,
            total: result.total
          })}
          rowActions={[
            { label: 'Edit', tool: 'edit-user' },
            { label: 'Delete', tool: 'delete-user', variant: 'destructive' }
          ]}
          pagination
        />
      </RequireConnection>
    </AppProvider>
  );
}
```

## Server-Side Integration

Link UI components to tools using the `@UIApp` decorator (for ext-apps) or `@GPTApp` decorator (for ChatGPT):

```typescript theme={null}
import { Tool } from '@leanmcp/core';
import { UIApp } from '@leanmcp/ui';

class WeatherService {
  @Tool({ description: 'Get weather for a city' })
  @UIApp({ component: './WeatherCard' })
  async getWeather(args: { city: string }) {
    return { city: args.city, temperature: 22, condition: 'Sunny' };
  }
}
```

When the tool is called, the host will render the linked UI component with the tool result.

## Testing

Use `MockAppProvider` for unit testing:

```tsx theme={null}
import { MockAppProvider } from '@leanmcp/ui/testing';
import { render, screen } from '@testing-library/react';

test('WeatherCard displays temperature', () => {
  render(
    <MockAppProvider 
      toolResult={{ city: 'London', temperature: 20 }}
      isConnected={true}
    >
      <WeatherCard />
    </MockAppProvider>
  );
  expect(screen.getByText('20°C')).toBeInTheDocument();
});
```

## What's Next

<CardGroup cols={2}>
  <Card title="Components" icon="shapes" href="/sdk/ui-components">
    ToolButton, ToolDataGrid, ToolForm, and more
  </Card>

  <Card title="Hooks" icon="code" href="/sdk/ui-hooks">
    useTool, useResource, useMessage, useHostContext
  </Card>

  <Card title="GPT Apps & Decorators" icon="robot" href="/sdk/ui-gpt-apps">
    ChatGPT integration, @UIApp, @GPTApp decorators
  </Card>

  <Card title="Examples" icon="code-branch" href="/sdk/examples">
    Complete working examples
  </Card>
</CardGroup>

## Links

* [GitHub Repository](https://github.com/LeanMCP/leanmcp-sdk)
* [NPM Package](https://www.npmjs.com/package/@leanmcp/ui)
* [MCP Specification](https://modelcontextprotocol.io/specification/2025-11-25)
