From 0bc13de5c851d0a221f767dae1bc9059cbd1bef5 Mon Sep 17 00:00:00 2001 From: Enrico Toniato <2827496+tonxxd@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:12:42 +0200 Subject: [PATCH 1/3] fix: export server from mcp-use/server due to edge runtime --- INSPECTOR_INTEGRATION.md | 2 +- .../src/templates/ui/src/server.ts | 2 +- .../src/templates/ui/tsconfig.json | 2 +- packages/inspector/src/server/middleware.ts | 2 +- .../examples/server/simple/src/server.ts | 2 +- packages/mcp-use/index.ts | 13 - pnpm-lock.yaml | 58 +++ pnpm-workspace.yaml | 1 + test_app/README.md | 454 ++++++++++++++++++ test_app/index.ts | 12 + test_app/package.json | 45 ++ test_app/resources/kanban-board.tsx | 306 ++++++++++++ test_app/src/server.ts | 67 +++ test_app/tsconfig.json | 20 + 14 files changed, 968 insertions(+), 18 deletions(-) create mode 100644 test_app/README.md create mode 100644 test_app/index.ts create mode 100644 test_app/package.json create mode 100644 test_app/resources/kanban-board.tsx create mode 100644 test_app/src/server.ts create mode 100644 test_app/tsconfig.json diff --git a/INSPECTOR_INTEGRATION.md b/INSPECTOR_INTEGRATION.md index 4038f635..f1a7c336 100644 --- a/INSPECTOR_INTEGRATION.md +++ b/INSPECTOR_INTEGRATION.md @@ -33,7 +33,7 @@ The MCP Inspector is now automatically mounted at `/inspector` for all MCP serve When developers create a new MCP server: ```typescript -import { createMCPServer } from 'mcp-use' +import { createMCPServer } from 'mcp-use/server' const server = createMCPServer('my-server', { version: '1.0.0', diff --git a/packages/create-mcp-use-app/src/templates/ui/src/server.ts b/packages/create-mcp-use-app/src/templates/ui/src/server.ts index 8a150b09..e33eb641 100644 --- a/packages/create-mcp-use-app/src/templates/ui/src/server.ts +++ b/packages/create-mcp-use-app/src/templates/ui/src/server.ts @@ -1,4 +1,4 @@ -import { createMCPServer } from 'mcp-use' +import { createMCPServer } from 'mcp-use/server' import { createUIResource } from '@mcp-ui/server'; // Create an MCP server (which is also an Express app) diff --git a/packages/create-mcp-use-app/src/templates/ui/tsconfig.json b/packages/create-mcp-use-app/src/templates/ui/tsconfig.json index 5a2c6947..cafb2cf5 100644 --- a/packages/create-mcp-use-app/src/templates/ui/tsconfig.json +++ b/packages/create-mcp-use-app/src/templates/ui/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES2022", "jsx": "react-jsx", "module": "ESNext", - "moduleResolution": "node", + "moduleResolution": "bundler", "allowJs": true, "strict": true, "declaration": true, diff --git a/packages/inspector/src/server/middleware.ts b/packages/inspector/src/server/middleware.ts index 1f5cb86b..2fbe428d 100644 --- a/packages/inspector/src/server/middleware.ts +++ b/packages/inspector/src/server/middleware.ts @@ -13,7 +13,7 @@ import { checkClientFiles, getClientDistPath, getContentType, handleChatRequest * * @example * ```typescript - * import { createMCPServer } from 'mcp-use' + * import { createMCPServer } from 'mcp-use/server' * import { mountInspector } from '@mcp-use/inspector' * * const server = createMCPServer('my-server') diff --git a/packages/mcp-use/examples/server/simple/src/server.ts b/packages/mcp-use/examples/server/simple/src/server.ts index 50c4bb67..10cc2be2 100644 --- a/packages/mcp-use/examples/server/simple/src/server.ts +++ b/packages/mcp-use/examples/server/simple/src/server.ts @@ -1,4 +1,4 @@ -import { createMCPServer } from 'mcp-use' +import { createMCPServer } from 'mcp-use/server' // Create an MCP server (which is also an Express app) // The MCP Inspector is automatically mounted at /inspector diff --git a/packages/mcp-use/index.ts b/packages/mcp-use/index.ts index 3ec34719..b447e02d 100644 --- a/packages/mcp-use/index.ts +++ b/packages/mcp-use/index.ts @@ -20,19 +20,6 @@ export * from './src/managers/tools/index.js' // Export observability utilities export { type ObservabilityConfig, ObservabilityManager } from './src/observability/index.js' -// Export server utilities -export { createMCPServer } from './src/server/index.js' - -export type { - InputDefinition, - PromptDefinition, - PromptHandler, - ResourceDefinition, - ResourceHandler, - ServerConfig, - ToolDefinition, - ToolHandler, -} from './src/server/types.js' // Export telemetry utilities export { setTelemetrySource, Telemetry } from './src/telemetry/index.js' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71b5735e..10c81d68 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -516,6 +516,64 @@ importers: specifier: ^5.0.0 version: 5.9.3 + test_app: + dependencies: + '@mcp-ui/server': + specifier: ^5.11.0 + version: 5.11.0(patch_hash=5d24b4104a7d6d537b7de1dc183b27e42d9c1b3fde96a28dbeb722713ba85f11) + cors: + specifier: ^2.8.5 + version: 2.8.5 + express: + specifier: ^4.18.0 + version: 4.21.2 + mcp-use: + specifier: workspace:* + version: link:../packages/mcp-use + devDependencies: + '@mcp-use/cli': + specifier: workspace:* + version: link:../packages/cli + '@mcp-use/inspector': + specifier: workspace:* + version: link:../packages/inspector + '@types/cors': + specifier: ^2.8.0 + version: 2.8.19 + '@types/express': + specifier: ^4.17.0 + version: 4.17.23 + '@types/node': + specifier: ^20.0.0 + version: 20.19.19 + '@types/react': + specifier: ^18.0.0 + version: 18.3.26 + '@types/react-dom': + specifier: ^18.0.0 + version: 18.3.7(@types/react@18.3.26) + concurrently: + specifier: ^8.0.0 + version: 8.2.2 + esbuild: + specifier: ^0.23.0 + version: 0.23.1 + globby: + specifier: ^14.0.2 + version: 14.1.0 + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + tsx: + specifier: ^4.0.0 + version: 4.20.6 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + packages: '@ai-sdk/provider-utils@2.2.8': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 28363ba3..cd64b37d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,3 +3,4 @@ packages: - 'packages/mcp-use/examples/client/react' - 'packages/mcp-use/examples/server/simple' - 'packages/create-mcp-use-app/src/templates/ui' + - 'test_app' diff --git a/test_app/README.md b/test_app/README.md new file mode 100644 index 00000000..a6d31caa --- /dev/null +++ b/test_app/README.md @@ -0,0 +1,454 @@ +# UI MCP Server + +An MCP server with React UI widgets created with `create-mcp-app` that provides interactive web components for MCP clients. + +## Features + +- **🎨 React Components**: Interactive UI widgets built with React +- **🔥 Hot Reloading**: Development server with instant updates +- **📦 Production Builds**: Optimized bundles for production +- **🌐 Web Endpoints**: Serve widgets at `/mcp-use/widgets/{widget-name}` +- **🛠️ Development Tools**: Full TypeScript support and modern tooling + +## Getting Started + +### Development + +```bash +# Install dependencies +npm install + +# Start development server with hot reloading +npm run dev +``` + +This will start: + +- MCP server on port 3000 +- Vite dev server on port 3001 with hot reloading + +### Production + +```bash +# Build the server and UI components +npm run build + +# Run the built server +npm start +``` + +## Available Widgets + +### 1. Kanban Board (`/mcp-use/widgets/kanban-board`) + +Interactive Kanban board for task management. + +**Features:** + +- Drag and drop tasks between columns +- Add/remove tasks +- Priority levels and assignees +- Real-time updates + +**Usage:** + +```typescript +mcp.tool({ + name: 'show-kanban', + inputs: [{ name: 'tasks', type: 'string', required: true }], + fn: async ({ tasks }) => { + // Display Kanban board with tasks + } +}) +``` + +### 2. Todo List (`/mcp-use/widgets/todo-list`) + +Interactive todo list with filtering and sorting. + +**Features:** + +- Add/complete/delete todos +- Filter by status (all/active/completed) +- Sort by priority, due date, or creation time +- Progress tracking +- Categories and due dates + +**Usage:** + +```typescript +mcp.tool({ + name: 'show-todo-list', + inputs: [{ name: 'todos', type: 'string', required: true }], + fn: async ({ todos }) => { + // Display todo list with todos + } +}) +``` + +### 3. Data Visualization (`/mcp-use/widgets/data-visualization`) + +Interactive charts and data visualization. + +**Features:** + +- Bar charts, line charts, and pie charts +- Add/remove data points +- Interactive legends +- Data table view +- Multiple chart types + +**Usage:** + +```typescript +mcp.tool({ + name: 'show-data-viz', + inputs: [ + { name: 'data', type: 'string', required: true }, + { name: 'chartType', type: 'string', required: false } + ], + fn: async ({ data, chartType }) => { + // Display data visualization + } +}) +``` + +## Development Workflow + +### 1. Create a New Widget + +1. **Create the React component:** + + ```bash + # Create resources/my-widget.tsx + touch resources/my-widget.tsx + ``` + +2. **Create the HTML entry point:** + + ```bash + # Create resources/my-widget.html + touch resources/my-widget.html + ``` + +3. **Add to Vite config:** + + ```typescript + // vite.config.ts + rollupOptions: { + input: { + 'my-widget': resolve(__dirname, 'resources/my-widget.html') + } + } + ``` + +4. **Add MCP resource:** + ```typescript + // src/server.ts + mcp.resource({ + uri: 'ui://widget/my-widget', + name: 'My Widget', + mimeType: 'text/html+skybridge', + fn: async () => { + const widgetUrl = `http://localhost:${PORT}/mcp-use/widgets/my-widget` + return `
` + } + }) + ``` + +### 2. Development with Hot Reloading + +```bash +# Start development +npm run dev + +# Visit your widget +open http://localhost:3001/my-widget.html +``` + +Changes to your React components will automatically reload! + +### 3. Widget Development Best Practices + +#### Component Structure + +```typescript +import React, { useState, useEffect } from 'react' +import { createRoot } from 'react-dom/client' + +interface MyWidgetProps { + initialData?: any +} + +const MyWidget: React.FC = ({ initialData = [] }) => { + const [data, setData] = useState(initialData) + + // Load data from URL parameters + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search) + const dataParam = urlParams.get('data') + + if (dataParam) { + try { + const parsedData = JSON.parse(decodeURIComponent(dataParam)) + setData(parsedData) + } catch (error) { + console.error('Error parsing data:', error) + } + } + }, []) + + return ( +
+ {/* Your widget content */} +
+ ) +} + +// Render the component +const container = document.getElementById('my-widget-root') +if (container) { + const root = createRoot(container) + root.render() +} +``` + +#### Styling Guidelines + +- Use inline styles for simplicity +- Follow the existing design system +- Ensure responsive design +- Use consistent color palette + +#### Data Handling + +- Accept data via URL parameters +- Provide sensible defaults +- Handle errors gracefully +- Use TypeScript for type safety + +### 4. Production Deployment + +```bash +# Build everything +npm run build + +# The built files will be in dist/ +# - dist/index.js (MCP server entry point) +# - dist/src/server.js (MCP server implementation) +# - dist/resources/ (Compiled TypeScript + UI widget bundles) +``` + +## Project Structure + +``` +my-ui-server/ +├── index.ts # Entry point (re-exports server) +├── src/ +│ └── server.ts # MCP server with UI endpoints +├── resources/ # React components (TSX widgets) +│ ├── kanban-board.tsx +│ ├── todo-list.tsx +│ └── data-visualization.tsx +├── dist/ # Built files +│ ├── index.js # Entry point +│ ├── src/ +│ │ └── server.js # Server implementation +│ └── resources/ # TypeScript output + bundled widgets +├── package.json +├── tsconfig.json +└── README.md +``` + +## API Reference + +### MCP Resources + +All UI widgets are available as MCP resources: + +- `ui://status` - Server status and available widgets +- `ui://widget/kanban-board` - Kanban board widget +- `ui://widget/todo-list` - Todo list widget +- `ui://widget/data-visualization` - Data visualization widget + +### MCP Tools + +- `show-kanban` - Display Kanban board with tasks +- `show-todo-list` - Display todo list with items +- `show-data-viz` - Display data visualization + +### MCP Prompts + +- `ui-development` - Generate UI development guidance + +## Customization + +### Adding New Dependencies + +```bash +# Add React libraries +npm install @types/react-router-dom react-router-dom + +# Add UI libraries +npm install @mui/material @emotion/react @emotion/styled +``` + +### Environment Variables + +Create a `.env` file: + +```bash +# Server configuration +PORT=3000 +NODE_ENV=development + +# UI configuration +VITE_API_URL=http://localhost:3000 +``` + +### Custom Build Configuration + +```typescript +// vite.config.ts +export default defineConfig({ + plugins: [react()], + build: { + rollupOptions: { + input: { + 'my-custom-widget': resolve(__dirname, 'resources/my-custom-widget.html') + } + } + } +}) +``` + +## Troubleshooting + +### Common Issues + +1. **"Cannot find module" errors** + + - Make sure all dependencies are installed: `npm install` + - Check that TypeScript paths are correct + +2. **Hot reloading not working** + + - Ensure Vite dev server is running on port 3001 + - Check that the widget HTML file exists + +3. **Widget not loading** + + - Verify the widget is added to vite.config.ts + - Check that the MCP resource is properly configured + +4. **Build errors** + - Run `npm run build` to see detailed error messages + - Check that all imports are correct + +### Development Tips + +- Use browser dev tools to debug React components +- Check the Network tab for failed requests +- Use React DevTools browser extension +- Monitor console for errors + +## Learn More + +- [React Documentation](https://react.dev/) +- [Vite Documentation](https://vitejs.dev/) +- [MCP Documentation](https://modelcontextprotocol.io) +- [mcp-use Documentation](https://docs.mcp-use.io) + +## Examples + +### Simple Counter Widget + +```typescript +// resources/counter.tsx +import React, { useState } from 'react' +import { createRoot } from 'react-dom/client' + +const Counter: React.FC = () => { + const [count, setCount] = useState(0) + + return ( +
+

Counter: {count}

+ + +
+ ) +} + +const container = document.getElementById('counter-root') +if (container) { + const root = createRoot(container) + root.render() +} +``` + +### Data Table Widget + +```typescript +// resources/data-table.tsx +import React, { useState, useEffect } from 'react' +import { createRoot } from 'react-dom/client' + +interface TableData { + id: string + name: string + value: number +} + +const DataTable: React.FC = () => { + const [data, setData] = useState([]) + + useEffect(() => { + // Load data from URL or use defaults + const urlParams = new URLSearchParams(window.location.search) + const dataParam = urlParams.get('data') + + if (dataParam) { + try { + setData(JSON.parse(decodeURIComponent(dataParam))) + } catch (error) { + console.error('Error parsing data:', error) + } + } + }, []) + + return ( +
+

Data Table

+ + + + + + + + + {data.map(row => ( + + + + + ))} + +
NameValue
{row.name}{row.value}
+
+ ) +} + +const container = document.getElementById('data-table-root') +if (container) { + const root = createRoot(container) + root.render() +} +``` + +Happy coding! 🚀 diff --git a/test_app/index.ts b/test_app/index.ts new file mode 100644 index 00000000..6f48dc04 --- /dev/null +++ b/test_app/index.ts @@ -0,0 +1,12 @@ +/** + * MCP Server Entry Point + * + * This file serves as the main entry point for the MCP server application. + * It re-exports all functionality from the server implementation, allowing + * the CLI and other tools to locate and start the server. + * + * The server is automatically started when this module is imported, making + * it suitable for both direct execution and programmatic usage. + */ +export * from './src/server.js' + diff --git a/test_app/package.json b/test_app/package.json new file mode 100644 index 00000000..0fc2f058 --- /dev/null +++ b/test_app/package.json @@ -0,0 +1,45 @@ +{ + "name": "test_app", + "type": "module", + "version": "1.0.0", + "description": "MCP server: test_app", + "author": "", + "license": "MIT", + "keywords": [ + "mcp", + "server", + "ui", + "react", + "widgets", + "ai", + "tools" + ], + "main": "dist/index.js", + "scripts": { + "build": "mcp-use build", + "dev": "mcp-use dev", + "start": "mcp-use start" + }, + "dependencies": { + "@mcp-ui/server": "^5.11.0", + "cors": "^2.8.5", + "express": "^4.18.0", + "mcp-use": "workspace:*" + }, + "devDependencies": { + "@mcp-use/cli": "workspace:*", + "@mcp-use/inspector": "workspace:*", + "@types/cors": "^2.8.0", + "@types/express": "^4.17.0", + "@types/node": "^20.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "concurrently": "^8.0.0", + "esbuild": "^0.23.0", + "globby": "^14.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", + "tsx": "^4.0.0", + "typescript": "^5.0.0" + } +} \ No newline at end of file diff --git a/test_app/resources/kanban-board.tsx b/test_app/resources/kanban-board.tsx new file mode 100644 index 00000000..5a4454cb --- /dev/null +++ b/test_app/resources/kanban-board.tsx @@ -0,0 +1,306 @@ +import React, { useEffect, useState } from 'react' +import { createRoot } from 'react-dom/client' + +interface Task { + id: string + title: string + description: string + status: 'todo' | 'in-progress' | 'done' + priority: 'low' | 'medium' | 'high' + assignee?: string +} + +interface KanbanBoardProps { + initialTasks?: Task[] +} + +const KanbanBoard: React.FC = ({ initialTasks = [] }) => { + const [tasks, setTasks] = useState(initialTasks) + const [newTask, setNewTask] = useState({ title: '', description: '', priority: 'medium' as Task['priority'] }) + + // Load tasks from URL parameters or use defaults + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search) + const tasksParam = urlParams.get('tasks') + + if (tasksParam) { + try { + const parsedTasks = JSON.parse(decodeURIComponent(tasksParam)) + setTasks(parsedTasks) + } + catch (error) { + console.error('Error parsing tasks from URL:', error) + } + } + else { + // Default tasks for demo + setTasks([ + { id: '1', title: 'Design UI mockups', description: 'Create wireframes for the new dashboard', status: 'todo', priority: 'high', assignee: 'Alice' }, + { id: '2', title: 'Implement authentication', description: 'Add login and registration functionality', status: 'in-progress', priority: 'high', assignee: 'Bob' }, + { id: '3', title: 'Write documentation', description: 'Document the API endpoints', status: 'done', priority: 'medium', assignee: 'Charlie' }, + { id: '4', title: 'Setup CI/CD', description: 'Configure automated testing and deployment', status: 'todo', priority: 'medium' }, + { id: '5', title: 'Code review', description: 'Review pull requests from the team', status: 'in-progress', priority: 'low', assignee: 'David' }, + ]) + } + }, []) + + const addTask = () => { + if (newTask.title.trim()) { + const task: Task = { + id: Date.now().toString(), + title: newTask.title, + description: newTask.description, + status: 'todo', + priority: newTask.priority, + } + setTasks([...tasks, task]) + setNewTask({ title: '', description: '', priority: 'medium' }) + } + } + + const moveTask = (taskId: string, newStatus: Task['status']) => { + setTasks(tasks.map(task => + task.id === taskId ? { ...task, status: newStatus } : task, + )) + } + + const deleteTask = (taskId: string) => { + setTasks(tasks.filter(task => task.id !== taskId)) + } + + const getTasksByStatus = (status: Task['status']) => { + return tasks.filter(task => task.status === status) + } + + const getPriorityColor = (priority: Task['priority']) => { + switch (priority) { + case 'high': return '#ff4757' + case 'medium': return '#ffa502' + case 'low': return '#2ed573' + default: return '#57606f' + } + } + + const columns = [ + { id: 'todo', title: 'To Do', color: '#57606f' }, + { id: 'in-progress', title: 'In Progress', color: '#ffa502' }, + { id: 'done', title: 'Done', color: '#2ed573' }, + ] as const + + return ( +
+
+

Kanban Board

+ + {/* Add new task form */} +
+

Add New Task

+
+ setNewTask({ ...newTask, title: e.target.value })} + style={{ + padding: '8px 12px', + border: '1px solid #ddd', + borderRadius: '4px', + flex: '1', + minWidth: '200px', + }} + /> + setNewTask({ ...newTask, description: e.target.value })} + style={{ + padding: '8px 12px', + border: '1px solid #ddd', + borderRadius: '4px', + flex: '1', + minWidth: '200px', + }} + /> + + +
+
+
+ + {/* Kanban columns */} +
+ {columns.map(column => ( +
+
+ {column.title} + + {getTasksByStatus(column.id).length} + +
+ +
+ {getTasksByStatus(column.id).map(task => ( +
{ + e.dataTransfer.setData('text/plain', task.id) + }} + onDragOver={e => e.preventDefault()} + onDrop={(e) => { + e.preventDefault() + const taskId = e.dataTransfer.getData('text/plain') + if (taskId === task.id) { + // Move to next column + const currentIndex = columns.findIndex(col => col.id === column.id) + const nextColumn = columns[currentIndex + 1] + if (nextColumn) { + moveTask(taskId, nextColumn.id) + } + } + }} + > +
+

{task.title}

+ +
+ + {task.description && ( +

+ {task.description} +

+ )} + +
+
+ {task.priority.toUpperCase()} +
+ + {task.assignee && ( + + {task.assignee} + + )} +
+
+ ))} + + {getTasksByStatus(column.id).length === 0 && ( +
+ No tasks in this column +
+ )} +
+
+ ))} +
+
+ ) +} + +// Mount the component +const container = document.getElementById('widget-root') +if (container) { + const root = createRoot(container) + root.render() +} diff --git a/test_app/src/server.ts b/test_app/src/server.ts new file mode 100644 index 00000000..e33eb641 --- /dev/null +++ b/test_app/src/server.ts @@ -0,0 +1,67 @@ +import { createMCPServer } from 'mcp-use/server' +import { createUIResource } from '@mcp-ui/server'; + +// Create an MCP server (which is also an Express app) +// The MCP Inspector is automatically mounted at /inspector +const server = createMCPServer('ui-mcp-server', { + version: '1.0.0', + description: 'An MCP server with React UI widgets', +}) + +const PORT = process.env.PORT || 3000 + + +server.tool({ + name: 'test-tool', + description: 'Test tool', + inputs: [ + { + name: 'test', + type: 'string', + description: 'Test input', + required: true, + }, + ], + fn: async () => { + const uiResource = createUIResource({ + uri: 'ui://widget/kanban-board', + content: { + type: 'externalUrl', + iframeUrl: `http://localhost:${PORT}/mcp-use/widgets/kanban-board` + }, + encoding: 'text', + }) + return { + content: [uiResource] + } + }, +}) + + +// MCP Resource for Kanban Board widget +server.resource({ + name: 'Kanban Board Widget', + uri: 'ui://widget/kanban-board', + title: 'Kanban Board Widget', + mimeType: 'text/html+skybridge', + description: 'Interactive Kanban board widget', + annotations: { + audience: ['user', 'assistant'], + priority: 0.7 + }, + fn: async () => { + const widgetUrl = `http://localhost:${PORT}/mcp-use/widgets/kanban-board` + return { + contents: [{ + uri: 'ui://widget/kanban-board', + mimeType: 'text/uri-list', + text: widgetUrl + }] + } + }, +}) + + + +// Start the server (MCP endpoints auto-mounted at /mcp) +server.listen(PORT) diff --git a/test_app/tsconfig.json b/test_app/tsconfig.json new file mode 100644 index 00000000..cafb2cf5 --- /dev/null +++ b/test_app/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2022", + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "bundler", + "allowJs": true, + "strict": true, + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "sourceMap": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true + }, + "include": ["index.ts", "src/**/*", "resources/**/*"], + "exclude": ["node_modules", "dist"] +} From a2ec48edbf9d3c6382314b3f570febb340b43305 Mon Sep 17 00:00:00 2001 From: Enrico Toniato <2827496+tonxxd@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:13:26 +0200 Subject: [PATCH 2/3] chore: update versions --- packages/cli/CHANGELOG.md | 8 ++++++++ packages/cli/package.json | 2 +- packages/create-mcp-use-app/CHANGELOG.md | 6 ++++++ packages/create-mcp-use-app/package.json | 2 +- packages/inspector/CHANGELOG.md | 8 ++++++++ packages/inspector/package.json | 2 +- packages/mcp-use/CHANGELOG.md | 8 ++++++++ packages/mcp-use/package.json | 4 ++-- 8 files changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 3c5bfda4..f56f4444 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,13 @@ # @mcp-use/cli +## 2.1.7 + +### Patch Changes + +- Updated dependencies + - @mcp-use/inspector@0.3.7 + - mcp-use@1.0.3 + ## 2.1.6 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 440ba8e1..57ee2a5e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@mcp-use/cli", - "version": "2.1.6", + "version": "2.1.7", "description": "Build tool for MCP UI widgets - bundles React components into standalone HTML pages for Model Context Protocol servers", "author": "mcp-use, Inc.", "license": "MIT", diff --git a/packages/create-mcp-use-app/CHANGELOG.md b/packages/create-mcp-use-app/CHANGELOG.md index 649f6c12..e1cd6b71 100644 --- a/packages/create-mcp-use-app/CHANGELOG.md +++ b/packages/create-mcp-use-app/CHANGELOG.md @@ -1,5 +1,11 @@ # create-mcp-use-app +## 0.3.3 + +### Patch Changes + +- fix: export server from mcp-use/server due to edge runtime + ## 0.3.2 ### Patch Changes diff --git a/packages/create-mcp-use-app/package.json b/packages/create-mcp-use-app/package.json index 9876718c..f7828082 100644 --- a/packages/create-mcp-use-app/package.json +++ b/packages/create-mcp-use-app/package.json @@ -1,6 +1,6 @@ { "name": "create-mcp-use-app", - "version": "0.3.2", + "version": "0.3.3", "type": "module", "description": "Create MCP-Use apps with one command", "author": "mcp-use, Inc.", diff --git a/packages/inspector/CHANGELOG.md b/packages/inspector/CHANGELOG.md index 0e7493af..c93d6a57 100644 --- a/packages/inspector/CHANGELOG.md +++ b/packages/inspector/CHANGELOG.md @@ -1,5 +1,13 @@ # @mcp-use/inspector +## 0.3.7 + +### Patch Changes + +- fix: export server from mcp-use/server due to edge runtime +- Updated dependencies + - mcp-use@1.0.3 + ## 0.3.6 ### Patch Changes diff --git a/packages/inspector/package.json b/packages/inspector/package.json index bb37bbb9..c2c25957 100644 --- a/packages/inspector/package.json +++ b/packages/inspector/package.json @@ -1,7 +1,7 @@ { "name": "@mcp-use/inspector", "type": "module", - "version": "0.3.6", + "version": "0.3.7", "description": "MCP Inspector - A tool for inspecting and debugging MCP servers", "author": "", "license": "MIT", diff --git a/packages/mcp-use/CHANGELOG.md b/packages/mcp-use/CHANGELOG.md index 4014344e..99d6075c 100644 --- a/packages/mcp-use/CHANGELOG.md +++ b/packages/mcp-use/CHANGELOG.md @@ -1,5 +1,13 @@ # mcp-use +## 1.0.3 + +### Patch Changes + +- fix: export server from mcp-use/server due to edge runtime +- Updated dependencies + - @mcp-use/inspector@0.3.7 + ## 1.0.2 ### Patch Changes diff --git a/packages/mcp-use/package.json b/packages/mcp-use/package.json index a22b418b..36fb768c 100644 --- a/packages/mcp-use/package.json +++ b/packages/mcp-use/package.json @@ -1,7 +1,7 @@ { "name": "mcp-use", "type": "module", - "version": "1.0.2", + "version": "1.0.3", "packageManager": "pnpm@10.6.1", "description": "Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents and Clients + MCP Servers with support for MCP-UI.", "author": "mcp-use, Inc.", @@ -88,7 +88,7 @@ "example:observability": "tsx examples/client/observability.ts" }, "peerDependencies": { - "@mcp-use/inspector": "^0.3.6", + "@mcp-use/inspector": "^0.3.7", "cors": "^2.8.5", "express": "^4.18.2", "langfuse": "^3.32.0", From 83e39f671c38e83a33a1111a73d7418ed3437d25 Mon Sep 17 00:00:00 2001 From: Enrico Toniato <2827496+tonxxd@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:18:23 +0200 Subject: [PATCH 3/3] chore: remove test app --- .gitignore | 4 +- test_app/README.md | 454 ---------------------------- test_app/index.ts | 12 - test_app/package.json | 45 --- test_app/resources/kanban-board.tsx | 306 ------------------- test_app/src/server.ts | 67 ---- test_app/tsconfig.json | 20 -- 7 files changed, 3 insertions(+), 905 deletions(-) delete mode 100644 test_app/README.md delete mode 100644 test_app/index.ts delete mode 100644 test_app/package.json delete mode 100644 test_app/resources/kanban-board.tsx delete mode 100644 test_app/src/server.ts delete mode 100644 test_app/tsconfig.json diff --git a/.gitignore b/.gitignore index 3750d9b8..3ab3cf96 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,6 @@ conf.yaml # Agents .cursor .cursorrules -.claude \ No newline at end of file +.claude + +test_app \ No newline at end of file diff --git a/test_app/README.md b/test_app/README.md deleted file mode 100644 index a6d31caa..00000000 --- a/test_app/README.md +++ /dev/null @@ -1,454 +0,0 @@ -# UI MCP Server - -An MCP server with React UI widgets created with `create-mcp-app` that provides interactive web components for MCP clients. - -## Features - -- **🎨 React Components**: Interactive UI widgets built with React -- **🔥 Hot Reloading**: Development server with instant updates -- **📦 Production Builds**: Optimized bundles for production -- **🌐 Web Endpoints**: Serve widgets at `/mcp-use/widgets/{widget-name}` -- **🛠️ Development Tools**: Full TypeScript support and modern tooling - -## Getting Started - -### Development - -```bash -# Install dependencies -npm install - -# Start development server with hot reloading -npm run dev -``` - -This will start: - -- MCP server on port 3000 -- Vite dev server on port 3001 with hot reloading - -### Production - -```bash -# Build the server and UI components -npm run build - -# Run the built server -npm start -``` - -## Available Widgets - -### 1. Kanban Board (`/mcp-use/widgets/kanban-board`) - -Interactive Kanban board for task management. - -**Features:** - -- Drag and drop tasks between columns -- Add/remove tasks -- Priority levels and assignees -- Real-time updates - -**Usage:** - -```typescript -mcp.tool({ - name: 'show-kanban', - inputs: [{ name: 'tasks', type: 'string', required: true }], - fn: async ({ tasks }) => { - // Display Kanban board with tasks - } -}) -``` - -### 2. Todo List (`/mcp-use/widgets/todo-list`) - -Interactive todo list with filtering and sorting. - -**Features:** - -- Add/complete/delete todos -- Filter by status (all/active/completed) -- Sort by priority, due date, or creation time -- Progress tracking -- Categories and due dates - -**Usage:** - -```typescript -mcp.tool({ - name: 'show-todo-list', - inputs: [{ name: 'todos', type: 'string', required: true }], - fn: async ({ todos }) => { - // Display todo list with todos - } -}) -``` - -### 3. Data Visualization (`/mcp-use/widgets/data-visualization`) - -Interactive charts and data visualization. - -**Features:** - -- Bar charts, line charts, and pie charts -- Add/remove data points -- Interactive legends -- Data table view -- Multiple chart types - -**Usage:** - -```typescript -mcp.tool({ - name: 'show-data-viz', - inputs: [ - { name: 'data', type: 'string', required: true }, - { name: 'chartType', type: 'string', required: false } - ], - fn: async ({ data, chartType }) => { - // Display data visualization - } -}) -``` - -## Development Workflow - -### 1. Create a New Widget - -1. **Create the React component:** - - ```bash - # Create resources/my-widget.tsx - touch resources/my-widget.tsx - ``` - -2. **Create the HTML entry point:** - - ```bash - # Create resources/my-widget.html - touch resources/my-widget.html - ``` - -3. **Add to Vite config:** - - ```typescript - // vite.config.ts - rollupOptions: { - input: { - 'my-widget': resolve(__dirname, 'resources/my-widget.html') - } - } - ``` - -4. **Add MCP resource:** - ```typescript - // src/server.ts - mcp.resource({ - uri: 'ui://widget/my-widget', - name: 'My Widget', - mimeType: 'text/html+skybridge', - fn: async () => { - const widgetUrl = `http://localhost:${PORT}/mcp-use/widgets/my-widget` - return `
` - } - }) - ``` - -### 2. Development with Hot Reloading - -```bash -# Start development -npm run dev - -# Visit your widget -open http://localhost:3001/my-widget.html -``` - -Changes to your React components will automatically reload! - -### 3. Widget Development Best Practices - -#### Component Structure - -```typescript -import React, { useState, useEffect } from 'react' -import { createRoot } from 'react-dom/client' - -interface MyWidgetProps { - initialData?: any -} - -const MyWidget: React.FC = ({ initialData = [] }) => { - const [data, setData] = useState(initialData) - - // Load data from URL parameters - useEffect(() => { - const urlParams = new URLSearchParams(window.location.search) - const dataParam = urlParams.get('data') - - if (dataParam) { - try { - const parsedData = JSON.parse(decodeURIComponent(dataParam)) - setData(parsedData) - } catch (error) { - console.error('Error parsing data:', error) - } - } - }, []) - - return ( -
- {/* Your widget content */} -
- ) -} - -// Render the component -const container = document.getElementById('my-widget-root') -if (container) { - const root = createRoot(container) - root.render() -} -``` - -#### Styling Guidelines - -- Use inline styles for simplicity -- Follow the existing design system -- Ensure responsive design -- Use consistent color palette - -#### Data Handling - -- Accept data via URL parameters -- Provide sensible defaults -- Handle errors gracefully -- Use TypeScript for type safety - -### 4. Production Deployment - -```bash -# Build everything -npm run build - -# The built files will be in dist/ -# - dist/index.js (MCP server entry point) -# - dist/src/server.js (MCP server implementation) -# - dist/resources/ (Compiled TypeScript + UI widget bundles) -``` - -## Project Structure - -``` -my-ui-server/ -├── index.ts # Entry point (re-exports server) -├── src/ -│ └── server.ts # MCP server with UI endpoints -├── resources/ # React components (TSX widgets) -│ ├── kanban-board.tsx -│ ├── todo-list.tsx -│ └── data-visualization.tsx -├── dist/ # Built files -│ ├── index.js # Entry point -│ ├── src/ -│ │ └── server.js # Server implementation -│ └── resources/ # TypeScript output + bundled widgets -├── package.json -├── tsconfig.json -└── README.md -``` - -## API Reference - -### MCP Resources - -All UI widgets are available as MCP resources: - -- `ui://status` - Server status and available widgets -- `ui://widget/kanban-board` - Kanban board widget -- `ui://widget/todo-list` - Todo list widget -- `ui://widget/data-visualization` - Data visualization widget - -### MCP Tools - -- `show-kanban` - Display Kanban board with tasks -- `show-todo-list` - Display todo list with items -- `show-data-viz` - Display data visualization - -### MCP Prompts - -- `ui-development` - Generate UI development guidance - -## Customization - -### Adding New Dependencies - -```bash -# Add React libraries -npm install @types/react-router-dom react-router-dom - -# Add UI libraries -npm install @mui/material @emotion/react @emotion/styled -``` - -### Environment Variables - -Create a `.env` file: - -```bash -# Server configuration -PORT=3000 -NODE_ENV=development - -# UI configuration -VITE_API_URL=http://localhost:3000 -``` - -### Custom Build Configuration - -```typescript -// vite.config.ts -export default defineConfig({ - plugins: [react()], - build: { - rollupOptions: { - input: { - 'my-custom-widget': resolve(__dirname, 'resources/my-custom-widget.html') - } - } - } -}) -``` - -## Troubleshooting - -### Common Issues - -1. **"Cannot find module" errors** - - - Make sure all dependencies are installed: `npm install` - - Check that TypeScript paths are correct - -2. **Hot reloading not working** - - - Ensure Vite dev server is running on port 3001 - - Check that the widget HTML file exists - -3. **Widget not loading** - - - Verify the widget is added to vite.config.ts - - Check that the MCP resource is properly configured - -4. **Build errors** - - Run `npm run build` to see detailed error messages - - Check that all imports are correct - -### Development Tips - -- Use browser dev tools to debug React components -- Check the Network tab for failed requests -- Use React DevTools browser extension -- Monitor console for errors - -## Learn More - -- [React Documentation](https://react.dev/) -- [Vite Documentation](https://vitejs.dev/) -- [MCP Documentation](https://modelcontextprotocol.io) -- [mcp-use Documentation](https://docs.mcp-use.io) - -## Examples - -### Simple Counter Widget - -```typescript -// resources/counter.tsx -import React, { useState } from 'react' -import { createRoot } from 'react-dom/client' - -const Counter: React.FC = () => { - const [count, setCount] = useState(0) - - return ( -
-

Counter: {count}

- - -
- ) -} - -const container = document.getElementById('counter-root') -if (container) { - const root = createRoot(container) - root.render() -} -``` - -### Data Table Widget - -```typescript -// resources/data-table.tsx -import React, { useState, useEffect } from 'react' -import { createRoot } from 'react-dom/client' - -interface TableData { - id: string - name: string - value: number -} - -const DataTable: React.FC = () => { - const [data, setData] = useState([]) - - useEffect(() => { - // Load data from URL or use defaults - const urlParams = new URLSearchParams(window.location.search) - const dataParam = urlParams.get('data') - - if (dataParam) { - try { - setData(JSON.parse(decodeURIComponent(dataParam))) - } catch (error) { - console.error('Error parsing data:', error) - } - } - }, []) - - return ( -
-

Data Table

- - - - - - - - - {data.map(row => ( - - - - - ))} - -
NameValue
{row.name}{row.value}
-
- ) -} - -const container = document.getElementById('data-table-root') -if (container) { - const root = createRoot(container) - root.render() -} -``` - -Happy coding! 🚀 diff --git a/test_app/index.ts b/test_app/index.ts deleted file mode 100644 index 6f48dc04..00000000 --- a/test_app/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * MCP Server Entry Point - * - * This file serves as the main entry point for the MCP server application. - * It re-exports all functionality from the server implementation, allowing - * the CLI and other tools to locate and start the server. - * - * The server is automatically started when this module is imported, making - * it suitable for both direct execution and programmatic usage. - */ -export * from './src/server.js' - diff --git a/test_app/package.json b/test_app/package.json deleted file mode 100644 index 0fc2f058..00000000 --- a/test_app/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "test_app", - "type": "module", - "version": "1.0.0", - "description": "MCP server: test_app", - "author": "", - "license": "MIT", - "keywords": [ - "mcp", - "server", - "ui", - "react", - "widgets", - "ai", - "tools" - ], - "main": "dist/index.js", - "scripts": { - "build": "mcp-use build", - "dev": "mcp-use dev", - "start": "mcp-use start" - }, - "dependencies": { - "@mcp-ui/server": "^5.11.0", - "cors": "^2.8.5", - "express": "^4.18.0", - "mcp-use": "workspace:*" - }, - "devDependencies": { - "@mcp-use/cli": "workspace:*", - "@mcp-use/inspector": "workspace:*", - "@types/cors": "^2.8.0", - "@types/express": "^4.17.0", - "@types/node": "^20.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "concurrently": "^8.0.0", - "esbuild": "^0.23.0", - "globby": "^14.0.2", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "tsx": "^4.0.0", - "typescript": "^5.0.0" - } -} \ No newline at end of file diff --git a/test_app/resources/kanban-board.tsx b/test_app/resources/kanban-board.tsx deleted file mode 100644 index 5a4454cb..00000000 --- a/test_app/resources/kanban-board.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { createRoot } from 'react-dom/client' - -interface Task { - id: string - title: string - description: string - status: 'todo' | 'in-progress' | 'done' - priority: 'low' | 'medium' | 'high' - assignee?: string -} - -interface KanbanBoardProps { - initialTasks?: Task[] -} - -const KanbanBoard: React.FC = ({ initialTasks = [] }) => { - const [tasks, setTasks] = useState(initialTasks) - const [newTask, setNewTask] = useState({ title: '', description: '', priority: 'medium' as Task['priority'] }) - - // Load tasks from URL parameters or use defaults - useEffect(() => { - const urlParams = new URLSearchParams(window.location.search) - const tasksParam = urlParams.get('tasks') - - if (tasksParam) { - try { - const parsedTasks = JSON.parse(decodeURIComponent(tasksParam)) - setTasks(parsedTasks) - } - catch (error) { - console.error('Error parsing tasks from URL:', error) - } - } - else { - // Default tasks for demo - setTasks([ - { id: '1', title: 'Design UI mockups', description: 'Create wireframes for the new dashboard', status: 'todo', priority: 'high', assignee: 'Alice' }, - { id: '2', title: 'Implement authentication', description: 'Add login and registration functionality', status: 'in-progress', priority: 'high', assignee: 'Bob' }, - { id: '3', title: 'Write documentation', description: 'Document the API endpoints', status: 'done', priority: 'medium', assignee: 'Charlie' }, - { id: '4', title: 'Setup CI/CD', description: 'Configure automated testing and deployment', status: 'todo', priority: 'medium' }, - { id: '5', title: 'Code review', description: 'Review pull requests from the team', status: 'in-progress', priority: 'low', assignee: 'David' }, - ]) - } - }, []) - - const addTask = () => { - if (newTask.title.trim()) { - const task: Task = { - id: Date.now().toString(), - title: newTask.title, - description: newTask.description, - status: 'todo', - priority: newTask.priority, - } - setTasks([...tasks, task]) - setNewTask({ title: '', description: '', priority: 'medium' }) - } - } - - const moveTask = (taskId: string, newStatus: Task['status']) => { - setTasks(tasks.map(task => - task.id === taskId ? { ...task, status: newStatus } : task, - )) - } - - const deleteTask = (taskId: string) => { - setTasks(tasks.filter(task => task.id !== taskId)) - } - - const getTasksByStatus = (status: Task['status']) => { - return tasks.filter(task => task.status === status) - } - - const getPriorityColor = (priority: Task['priority']) => { - switch (priority) { - case 'high': return '#ff4757' - case 'medium': return '#ffa502' - case 'low': return '#2ed573' - default: return '#57606f' - } - } - - const columns = [ - { id: 'todo', title: 'To Do', color: '#57606f' }, - { id: 'in-progress', title: 'In Progress', color: '#ffa502' }, - { id: 'done', title: 'Done', color: '#2ed573' }, - ] as const - - return ( -
-
-

Kanban Board

- - {/* Add new task form */} -
-

Add New Task

-
- setNewTask({ ...newTask, title: e.target.value })} - style={{ - padding: '8px 12px', - border: '1px solid #ddd', - borderRadius: '4px', - flex: '1', - minWidth: '200px', - }} - /> - setNewTask({ ...newTask, description: e.target.value })} - style={{ - padding: '8px 12px', - border: '1px solid #ddd', - borderRadius: '4px', - flex: '1', - minWidth: '200px', - }} - /> - - -
-
-
- - {/* Kanban columns */} -
- {columns.map(column => ( -
-
- {column.title} - - {getTasksByStatus(column.id).length} - -
- -
- {getTasksByStatus(column.id).map(task => ( -
{ - e.dataTransfer.setData('text/plain', task.id) - }} - onDragOver={e => e.preventDefault()} - onDrop={(e) => { - e.preventDefault() - const taskId = e.dataTransfer.getData('text/plain') - if (taskId === task.id) { - // Move to next column - const currentIndex = columns.findIndex(col => col.id === column.id) - const nextColumn = columns[currentIndex + 1] - if (nextColumn) { - moveTask(taskId, nextColumn.id) - } - } - }} - > -
-

{task.title}

- -
- - {task.description && ( -

- {task.description} -

- )} - -
-
- {task.priority.toUpperCase()} -
- - {task.assignee && ( - - {task.assignee} - - )} -
-
- ))} - - {getTasksByStatus(column.id).length === 0 && ( -
- No tasks in this column -
- )} -
-
- ))} -
-
- ) -} - -// Mount the component -const container = document.getElementById('widget-root') -if (container) { - const root = createRoot(container) - root.render() -} diff --git a/test_app/src/server.ts b/test_app/src/server.ts deleted file mode 100644 index e33eb641..00000000 --- a/test_app/src/server.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { createMCPServer } from 'mcp-use/server' -import { createUIResource } from '@mcp-ui/server'; - -// Create an MCP server (which is also an Express app) -// The MCP Inspector is automatically mounted at /inspector -const server = createMCPServer('ui-mcp-server', { - version: '1.0.0', - description: 'An MCP server with React UI widgets', -}) - -const PORT = process.env.PORT || 3000 - - -server.tool({ - name: 'test-tool', - description: 'Test tool', - inputs: [ - { - name: 'test', - type: 'string', - description: 'Test input', - required: true, - }, - ], - fn: async () => { - const uiResource = createUIResource({ - uri: 'ui://widget/kanban-board', - content: { - type: 'externalUrl', - iframeUrl: `http://localhost:${PORT}/mcp-use/widgets/kanban-board` - }, - encoding: 'text', - }) - return { - content: [uiResource] - } - }, -}) - - -// MCP Resource for Kanban Board widget -server.resource({ - name: 'Kanban Board Widget', - uri: 'ui://widget/kanban-board', - title: 'Kanban Board Widget', - mimeType: 'text/html+skybridge', - description: 'Interactive Kanban board widget', - annotations: { - audience: ['user', 'assistant'], - priority: 0.7 - }, - fn: async () => { - const widgetUrl = `http://localhost:${PORT}/mcp-use/widgets/kanban-board` - return { - contents: [{ - uri: 'ui://widget/kanban-board', - mimeType: 'text/uri-list', - text: widgetUrl - }] - } - }, -}) - - - -// Start the server (MCP endpoints auto-mounted at /mcp) -server.listen(PORT) diff --git a/test_app/tsconfig.json b/test_app/tsconfig.json deleted file mode 100644 index cafb2cf5..00000000 --- a/test_app/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "jsx": "react-jsx", - "module": "ESNext", - "moduleResolution": "bundler", - "allowJs": true, - "strict": true, - "declaration": true, - "declarationMap": true, - "outDir": "./dist", - "sourceMap": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true - }, - "include": ["index.ts", "src/**/*", "resources/**/*"], - "exclude": ["node_modules", "dist"] -}