=== DONE === - MCP Apps UI system added (11 apps with _meta.ui.resourceUri) - 19 new tool modules added - Tool count: 269 → 461 across 38 categories - Upstream changes merged - All tools tagged with _meta labels - Package lock updated === TO-DO === - [ ] Fix 42 failing edge case tests (BLOCKER — Stage 11) - [ ] Live API testing with GHL credentials - [ ] App design approval for Stage 7→8
264 lines
14 KiB
Markdown
264 lines
14 KiB
Markdown
# MCP UI Kit — React Rewrite Plan
|
|
|
|
## Vision
|
|
Build a **generic, reusable MCP UI component library** using React + ext-apps SDK. Any MCP server (GHL, HubSpot, Salesforce, etc.) can use this component kit to render AI-generated interactive UIs. GHL is the first implementation. The library is CRM-agnostic — interactive components accept tool names as props so each server configures its own tool mappings.
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Goose / Claude Desktop (MCP Host) │
|
|
│ │
|
|
│ tools/call → GHL MCP Server → GHL API │
|
|
│ ↑ ↓ │
|
|
│ tools/call structuredContent (JSON UI tree) │
|
|
│ ↑ ↓ │
|
|
│ ┌─────────────────────────────────────────────┐ │
|
|
│ │ React App (iframe via ext-apps SDK) │ │
|
|
│ │ │ │
|
|
│ │ useApp() hook ← ontoolresult (UI tree) │ │
|
|
│ │ ↓ │ │
|
|
│ │ MCPAppProvider (React Context) │ │
|
|
│ │ - uiTree state │ │
|
|
│ │ - formState (inputs, selections) │ │
|
|
│ │ - callTool(name, args) → MCP server │ │
|
|
│ │ ↓ │ │
|
|
│ │ <UITreeRenderer tree={uiTree} /> │ │
|
|
│ │ - Looks up component by type │ │
|
|
│ │ - Renders React component with props │ │
|
|
│ │ - Recursively renders children │ │
|
|
│ │ ↓ │ │
|
|
│ │ 42 Display Components (pure, CRM-agnostic) │ │
|
|
│ │ + 8 Interactive Components (tool-configurable)│ │
|
|
│ │ - ContactPicker(searchTool="search_contacts")│ │
|
|
│ │ - InvoiceBuilder(createTool="create_invoice")│ │
|
|
│ │ - KanbanBoard(onMoveTool="update_opportunity")│ │
|
|
│ │ - EditableField(saveTool=props.saveTool) │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## File Structure (New)
|
|
|
|
```
|
|
src/ui/react-app/ # GENERIC MCP UI KIT (no GHL references)
|
|
├── package.json # React + ext-apps SDK deps
|
|
├── vite.config.ts # Vite + singlefile + React
|
|
├── tsconfig.json
|
|
├── index.html # Entry point
|
|
├── src/
|
|
│ ├── App.tsx # Root — useApp hook, MCPAppProvider
|
|
│ ├── types.ts # UITree, UIElement, component prop interfaces
|
|
│ ├── context/
|
|
│ │ └── MCPAppContext.tsx # React Context — uiTree, formState, callTool
|
|
│ ├── hooks/
|
|
│ │ ├── useCallTool.ts # Hook wrapping app.callServerTool
|
|
│ │ ├── useFormState.ts # Shared form state management
|
|
│ │ └── useSizeReporter.ts # Auto-report content size to host
|
|
│ ├── renderer/
|
|
│ │ ├── UITreeRenderer.tsx # Recursive tree → React component resolver
|
|
│ │ └── registry.ts # Component name → React component map
|
|
│ ├── components/
|
|
│ │ ├── layout/ # PageHeader, Card, SplitLayout, Section, StatsGrid
|
|
│ │ ├── data/ # DataTable, KanbanBoard, MetricCard, StatusBadge,
|
|
│ │ │ # Timeline, ProgressBar, KeyValueList, etc.
|
|
│ │ ├── charts/ # BarChart, LineChart, PieChart, FunnelChart, Sparkline
|
|
│ │ ├── comms/ # ChatThread, EmailPreview, TranscriptView, etc.
|
|
│ │ ├── viz/ # CalendarView, FlowDiagram, TreeView, MediaGallery, etc.
|
|
│ │ ├── interactive/ # ContactPicker, InvoiceBuilder, EditableField, etc.
|
|
│ │ │ # All accept tool names as PROPS (CRM-agnostic)
|
|
│ │ └── shared/ # ActionButton, Toast, Modal (React portals)
|
|
│ └── styles/
|
|
│ ├── base.css # Reset, variables, typography
|
|
│ ├── components.css # Component-specific styles (compact for chat)
|
|
│ └── interactive.css # Drag/drop, modals, toasts, form styles
|
|
```
|
|
|
|
### CRM-Agnostic Design Principle
|
|
- NO component imports GHL types or references GHL tool names
|
|
- Interactive components receive tool names via props:
|
|
- `ContactPicker` → `searchTool="search_contacts"` (GHL) or `"hubspot_search_contacts"` (HubSpot)
|
|
- `KanbanBoard` → `moveTool="update_opportunity"` (GHL) or `"move_deal"` (Pipedrive)
|
|
- `InvoiceBuilder` → `createTool="create_invoice"` (any billing system)
|
|
- The MCP server's AI prompt tells Claude which tool names to use in the UI tree
|
|
- Components call `callTool(props.toolName, args)` — they don't know or care what CRM is behind it
|
|
|
|
## Component Inventory
|
|
|
|
### Existing 42 (string → React conversion)
|
|
|
|
**Layout (5):** PageHeader, Card, StatsGrid, SplitLayout, Section
|
|
**Data Display (10):** DataTable, KanbanBoard, MetricCard, StatusBadge, Timeline, ProgressBar, DetailHeader, KeyValueList, LineItemsTable, InfoBlock
|
|
**Navigation (3):** SearchBar, FilterChips, TabGroup
|
|
**Actions (2):** ActionButton, ActionBar
|
|
**Extended Data (6):** CurrencyDisplay, TagList, CardGrid, AvatarGroup, StarRating, StockIndicator
|
|
**Communications (6):** ChatThread, EmailPreview, ContentPreview, TranscriptView, AudioPlayer, ChecklistView
|
|
**Visualization (5):** CalendarView, FlowDiagram, TreeView, MediaGallery, DuplicateCompare
|
|
**Charts (5):** BarChart, LineChart, PieChart, FunnelChart, SparklineChart
|
|
|
|
### New Interactive Components (8)
|
|
|
|
| Component | Purpose | MCP Tools Used |
|
|
|-----------|---------|----------------|
|
|
| **ContactPicker** | Searchable dropdown, fetches contacts on type | `search_contacts` |
|
|
| **InvoiceBuilder** | Line items, totals, contact auto-fill | `create_invoice`, `get_contact` |
|
|
| **OpportunityEditor** | Inline edit deal name/value/status/stage | `update_opportunity` |
|
|
| **AppointmentBooker** | Calendar slot picker + booking form | `get_calendar`, `create_appointment` |
|
|
| **EditableField** | Click-to-edit any text/number field | varies (generic) |
|
|
| **SelectDropdown** | Generic select with async option loading | varies |
|
|
| **FormGroup** | Group of form fields with validation | varies |
|
|
| **AmountInput** | Currency-formatted number input | — (local state) |
|
|
|
|
---
|
|
|
|
## Agent Team Plan
|
|
|
|
### Phase 1: Foundation (Sequential — 1 agent)
|
|
|
|
**Agent Alpha — Project Scaffold + App Shell**
|
|
- Create `src/ui/react-app/` with package.json, vite.config, tsconfig
|
|
- Install deps: react, react-dom, @modelcontextprotocol/ext-apps, @vitejs/plugin-react, vite-plugin-singlefile
|
|
- Build `App.tsx` with `useApp` hook — handles ontoolresult, ontoolinput, host context
|
|
- Build `GHLContext.tsx` — React context providing uiTree, formState, callTool
|
|
- Build `useCallTool.ts` — wrapper around `app.callServerTool` with loading/error states
|
|
- Build `useFormState.ts` — shared form state hook
|
|
- Build `useSizeReporter.ts` — auto-measures content, sends `ui/notifications/size-changed`
|
|
- Build `UITreeRenderer.tsx` — recursive renderer that resolves component types from registry
|
|
- Build `registry.ts` — component map (stubs for now, filled by other agents)
|
|
- Build `types.ts` — UITree, UIElement, all component prop interfaces
|
|
- Build base CSS (`base.css`) — reset, variables, compact typography
|
|
- Update outer build pipeline in GoHighLevel-MCP `package.json` to build React app
|
|
- **Output:** Working scaffold that renders a loading state, connects to host via ext-apps
|
|
|
|
### Phase 2: Components (Parallel — 4 agents)
|
|
|
|
**Agent Bravo — Layout + Core Data Components (15)**
|
|
Files: `components/layout/`, `components/data/` (first half)
|
|
- PageHeader, Card, StatsGrid, SplitLayout, Section
|
|
- DataTable (with clickable rows, sortable columns)
|
|
- KanbanBoard (with FULL drag-and-drop via React state — no DOM hacking)
|
|
- MetricCard, StatusBadge, Timeline
|
|
- Register all in registry.ts
|
|
- Component CSS in `components.css`
|
|
|
|
**Agent Charlie — Data Display + Navigation + Actions (15)**
|
|
Files: `components/data/` (second half), `components/shared/`
|
|
- ProgressBar, DetailHeader, KeyValueList, LineItemsTable, InfoBlock
|
|
- SearchBar, FilterChips, TabGroup
|
|
- ActionButton, ActionBar
|
|
- CurrencyDisplay, TagList, CardGrid, AvatarGroup, StarRating, StockIndicator
|
|
- Register all in registry.ts
|
|
|
|
**Agent Delta — Comms + Viz + Charts (16)**
|
|
Files: `components/comms/`, `components/viz/`, `components/charts/`
|
|
- ChatThread, EmailPreview, ContentPreview, TranscriptView, AudioPlayer, ChecklistView
|
|
- CalendarView, FlowDiagram, TreeView, MediaGallery, DuplicateCompare
|
|
- BarChart, LineChart, PieChart, FunnelChart, SparklineChart
|
|
- All chart components use inline SVG (same approach, just JSX)
|
|
- Register all in registry.ts
|
|
|
|
**Agent Echo — Interactive Components + Forms (8)**
|
|
Files: `components/interactive/`, `hooks/`
|
|
- ContactPicker — searchable dropdown, calls `search_contacts` on keystroke with debounce
|
|
- InvoiceBuilder — line items table + contact selection + auto-total
|
|
- OpportunityEditor — inline edit form for deal fields, saves via `update_opportunity`
|
|
- AppointmentBooker — date/time picker + contact + calendar selection
|
|
- EditableField — click-to-edit wrapper for any field
|
|
- SelectDropdown — generic async select
|
|
- FormGroup — form layout with labels + validation
|
|
- AmountInput — formatted currency input
|
|
- Shared: Toast component, Modal component (proper React portals)
|
|
- Integrate with GHLContext for tool calling
|
|
|
|
### Phase 3: Integration (Sequential — 1 agent)
|
|
|
|
**Agent Foxtrot — Wire Everything Together**
|
|
- Merge all component registrations into `registry.ts`
|
|
- Update `src/apps/index.ts`:
|
|
- Add new tool definitions for interactive components (`create_invoice`, `create_appointment`)
|
|
- Update resource handler for `ui://ghl/dynamic-view` to serve React build
|
|
- Add new resource URIs if needed
|
|
- Update `src/server.ts` if new tools need routing
|
|
- Update system prompt: add new interactive component catalog entries
|
|
- Update Goose config `available_tools` if needed
|
|
- Full build: React app → singlefile HTML → server TypeScript
|
|
- Test: verify JSON UI trees render correctly, interactive components call tools, drag-and-drop works
|
|
- Write brief README for the new architecture
|
|
|
|
---
|
|
|
|
## Key Technical Decisions
|
|
|
|
### State Management
|
|
- **React Context** (not Redux) — app is small enough, context + useReducer is perfect
|
|
- `GHLContext` holds: current UITree, form values, loading states, selected entities
|
|
- Any component can `const { callTool } = useGHL()` to interact with the MCP server
|
|
|
|
### Tool Calling Pattern
|
|
```tsx
|
|
// Any component can call MCP tools:
|
|
const { callTool, isLoading } = useCallTool();
|
|
|
|
const handleDrop = async (cardId: string, newStageId: string) => {
|
|
await callTool('update_opportunity', {
|
|
opportunityId: cardId,
|
|
pipelineStageId: newStageId,
|
|
});
|
|
};
|
|
```
|
|
|
|
### Drag & Drop (KanbanBoard)
|
|
- Pure React state — no global DOM event handlers
|
|
- `onDragStart`, `onDragOver`, `onDrop` on React elements
|
|
- Optimistic UI update (move card immediately, revert on error)
|
|
|
|
### Dynamic Sizing
|
|
- `useSizeReporter` hook — ResizeObserver on `#app`
|
|
- Sends `ui/notifications/size-changed` on every size change
|
|
- Caps at 600px height
|
|
|
|
### CSS Strategy
|
|
- Plain CSS files (not CSS modules, not Tailwind) — keeps bundle simple
|
|
- Same compact sizing as current (12px base, tight padding)
|
|
- All in `styles/` directory, imported in App.tsx
|
|
- Interactive styles (drag states, modals, toasts) in separate file
|
|
|
|
### Build Pipeline
|
|
```bash
|
|
# In src/ui/react-app/
|
|
npm run build
|
|
# → Vite builds React app → vite-plugin-singlefile → single HTML file
|
|
# → Output: ../../dist/app-ui/dynamic-view.html
|
|
|
|
# In GoHighLevel-MCP root
|
|
npm run build
|
|
# → Builds React UI first, then compiles TypeScript server
|
|
```
|
|
|
|
---
|
|
|
|
## Timeline Estimate
|
|
|
|
| Phase | Agents | Est. Time | Depends On |
|
|
|-------|--------|-----------|------------|
|
|
| Phase 1: Foundation | Alpha (1) | ~20 min | — |
|
|
| Phase 2: Components | Bravo, Charlie, Delta, Echo (4 parallel) | ~25 min | Phase 1 |
|
|
| Phase 3: Integration | Foxtrot (1) | ~15 min | Phase 2 |
|
|
| **Total** | **6 agents** | **~60 min** | |
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
1. ✅ All 42 existing components render identically to current version
|
|
2. ✅ JSON UI trees from Claude work without any format changes
|
|
3. ✅ KanbanBoard drag-and-drop moves deals and persists via `update_opportunity`
|
|
4. ✅ ContactPicker fetches real contacts from GHL on keystroke
|
|
5. ✅ InvoiceBuilder creates invoices with real contact data
|
|
6. ✅ EditableField saves changes via appropriate MCP tool
|
|
7. ✅ Dynamic sizing works — views fit in chat
|
|
8. ✅ Single HTML file output (vite-plugin-singlefile)
|
|
9. ✅ ext-apps handshake completes with Goose
|
|
10. ✅ All existing `view_*` tools still work alongside `generate_ghl_view`
|