update readme
This commit is contained in:
parent
3d82cda68e
commit
312f60758c
140
README.md
140
README.md
@ -2,52 +2,143 @@
|
|||||||
|
|
||||||
Build interactive React UIs for MCP tools.
|
Build interactive React UIs for MCP tools.
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) enables AI assistants to interact with external tools and data. The [mcp-ui](https://github.com/anthropics/mcp-ui) project extends this with rich, interactive UI components that can be rendered directly in the AI chat.
|
||||||
|
|
||||||
|
**mcp-ui-kit** simplifies building these UI components by:
|
||||||
|
|
||||||
|
- **Bundling on-demand** — Write React components, they're bundled automatically when the tool is called
|
||||||
|
- **Zero config** — No webpack/vite setup needed, just `createUI()` and point to your `.tsx` file
|
||||||
|
- **Props from server** — Pass data from your MCP tool directly to React via `useProps()`
|
||||||
|
- **Two-way communication** — Components can `sendPrompt()` to the AI or `callTool()` to invoke other MCP tools
|
||||||
|
|
||||||
|
Built on top of [@mcp-ui/server](https://www.npmjs.com/package/@mcp-ui/server).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install mcp-ui-kit
|
npm install mcp-ui-kit @modelcontextprotocol/sdk
|
||||||
```
|
```
|
||||||
|
|
||||||
## Server Usage
|
## Server Usage
|
||||||
|
|
||||||
Create UI components that bundle on-demand:
|
Create UI components that bundle on-demand within your MCP server:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { createUI } from 'mcp-ui-kit/server';
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||||
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||||
|
import { createUI } from 'mcp-ui-kit/server'; // 👈 mcp-ui-kit
|
||||||
|
|
||||||
const dashboardUI = createUI('my-dashboard', import.meta.resolve('./MyComponent.tsx'));
|
// Create the MCP server
|
||||||
|
const server = new McpServer({
|
||||||
|
name: 'my-server',
|
||||||
|
version: '1.0.0'
|
||||||
|
});
|
||||||
|
|
||||||
server.registerTool('dashboard', {
|
// Create a UI component // 👈 mcp-ui-kit
|
||||||
|
const dashboardUI = createUI( // 👈 mcp-ui-kit
|
||||||
|
'my-dashboard', // 👈 mcp-ui-kit
|
||||||
|
import.meta.resolve('./MyComponent.tsx') // 👈 mcp-ui-kit
|
||||||
|
); // 👈 mcp-ui-kit
|
||||||
|
|
||||||
|
// Register a tool with the UI
|
||||||
|
server.registerTool(
|
||||||
|
'dashboard',
|
||||||
|
{
|
||||||
description: 'Interactive dashboard',
|
description: 'Interactive dashboard',
|
||||||
_meta: dashboardUI.meta
|
_meta: dashboardUI.meta // 👈 mcp-ui-kit
|
||||||
}, async () => ({
|
},
|
||||||
|
async () => ({
|
||||||
content: [
|
content: [
|
||||||
{ type: 'text', text: 'Dashboard loaded' },
|
{ type: 'text', text: 'Dashboard loaded' },
|
||||||
await dashboardUI.component({ props: { title: 'Hello' } })
|
await dashboardUI.component({ // 👈 mcp-ui-kit
|
||||||
|
props: { title: 'Hello' }, // 👈 mcp-ui-kit
|
||||||
|
frameSize: ['700px', '500px'] // 👈 mcp-ui-kit
|
||||||
|
}) // 👈 mcp-ui-kit
|
||||||
]
|
]
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
await server.connect(transport);
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Input Schema
|
||||||
|
|
||||||
|
Tools can accept parameters via `inputSchema` and pass them to your UI component:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { createUI } from 'mcp-ui-kit/server'; // 👈 mcp-ui-kit
|
||||||
|
|
||||||
|
const stockUI = createUI('stocks', import.meta.resolve('./StockDashboard.tsx')); // 👈 mcp-ui-kit
|
||||||
|
|
||||||
|
server.registerTool(
|
||||||
|
'stock_portfolio',
|
||||||
|
{
|
||||||
|
description: 'View stock portfolio with charts',
|
||||||
|
_meta: stockUI.meta, // 👈 mcp-ui-kit
|
||||||
|
inputSchema: {
|
||||||
|
symbols: z.array(z.string()).default(['AAPL', 'GOOGL']),
|
||||||
|
timeframe: z.enum(['1D', '1W', '1M', '1Y']).default('1M'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ symbols, timeframe }) => ({
|
||||||
|
content: [
|
||||||
|
{ type: 'text', text: `Showing ${symbols.join(', ')} for ${timeframe}` },
|
||||||
|
await stockUI.component({ // 👈 mcp-ui-kit
|
||||||
|
props: { symbols, timeframe }, // 👈 mcp-ui-kit (params → props)
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Client Usage
|
## Client Usage
|
||||||
|
|
||||||
Helper functions for your React components:
|
Helper functions for your React components (the ones you pass to `createUI`):
|
||||||
|
|
||||||
```typescript
|
```tsx
|
||||||
import { sendPrompt, callTool, useProps } from 'mcp-ui-kit/ui';
|
// StockDashboard.tsx
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { sendPrompt, callTool, useProps } from 'mcp-ui-kit/ui'; // 👈 mcp-ui-kit
|
||||||
|
|
||||||
function MyComponent() {
|
function StockDashboard() {
|
||||||
const { title } = useProps({ title: 'Default' });
|
const [analysis, setAnalysis] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// Get props passed from server (matches inputSchema params) // 👈 mcp-ui-kit
|
||||||
|
const { symbols, timeframe } = useProps({ // 👈 mcp-ui-kit
|
||||||
|
symbols: ['AAPL'], // 👈 mcp-ui-kit
|
||||||
|
timeframe: '1M' // 👈 mcp-ui-kit
|
||||||
|
}); // 👈 mcp-ui-kit
|
||||||
|
|
||||||
|
const handleAnalyze = (symbol: string) => {
|
||||||
|
// Send a message to the AI chat // 👈 mcp-ui-kit
|
||||||
|
sendPrompt(`Analyze ${symbol} stock performance over ${timeframe}`); // 👈 mcp-ui-kit
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRefresh = async (symbol: string) => {
|
||||||
|
// Call another MCP tool // 👈 mcp-ui-kit
|
||||||
|
callTool('get_stock_price', { symbol }); // 👈 mcp-ui-kit
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>{title}</h1>
|
<h1>Stock Portfolio ({timeframe})</h1>
|
||||||
<button onClick={() => sendPrompt('Analyze this data')}>
|
{symbols.map(symbol => (
|
||||||
Ask AI
|
<div key={symbol}>
|
||||||
|
<span>{symbol}</span>
|
||||||
|
<button onClick={() => handleAnalyze(symbol)}>
|
||||||
|
Ask AI to Analyze
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => callTool('get_data', { id: 123 })}>
|
<button onClick={() => handleRefresh(symbol)}>
|
||||||
Fetch Data
|
Refresh Price
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -57,15 +148,18 @@ function MyComponent() {
|
|||||||
### Server (`mcp-ui-kit/server`)
|
### Server (`mcp-ui-kit/server`)
|
||||||
|
|
||||||
**`createUI(name, entryUrl)`** - Creates a UI component
|
**`createUI(name, entryUrl)`** - Creates a UI component
|
||||||
- `name`: Component identifier
|
- `name`: Component identifier (used in the `ui://` URI)
|
||||||
- `entryUrl`: Path to the component entry file
|
- `entryUrl`: Path to the component entry file
|
||||||
- Returns: `{ component(opts?) }` where opts: `{ props?, frameSize? }`
|
- Returns: `{ meta, component(opts?) }`
|
||||||
|
- `meta`: Object to spread into tool's `_meta` for UI resource linking
|
||||||
|
- `component(opts?)`: Async function returning the UI resource
|
||||||
|
- `opts.props`: Data to pass to your React component
|
||||||
|
- `opts.frameSize`: `[width, height]` e.g. `['700px', '500px']`
|
||||||
|
|
||||||
The `entryUrl` parameter accepts both formats:
|
The `entryUrl` parameter accepts both formats:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// ESM (recommended) - using import.meta.resolve()
|
// ESM (recommended) - using import.meta.resolve()
|
||||||
// Requires "type": "module" in package.json
|
|
||||||
createUI('dashboard', import.meta.resolve('./MyComponent.tsx'));
|
createUI('dashboard', import.meta.resolve('./MyComponent.tsx'));
|
||||||
|
|
||||||
// CommonJS - using require.resolve() or absolute paths
|
// CommonJS - using require.resolve() or absolute paths
|
||||||
@ -75,7 +169,7 @@ createUI('dashboard', path.join(__dirname, './MyComponent.tsx'));
|
|||||||
|
|
||||||
### UI (`mcp-ui-kit/ui`)
|
### UI (`mcp-ui-kit/ui`)
|
||||||
|
|
||||||
- **`useProps(defaults)`** - Get props passed from the server
|
- **`useProps(defaults)`** - Get props passed from the server via `component({ props })`
|
||||||
- **`sendPrompt(message)`** - Send a message to the AI chat
|
- **`sendPrompt(message)`** - Send a message to the AI chat
|
||||||
- **`callTool(name, params)`** - Invoke an MCP tool
|
- **`callTool(name, params)`** - Invoke an MCP tool
|
||||||
|
|
||||||
|
|||||||
BIN
nanobot.db
BIN
nanobot.db
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user