shopping-assistant-mcp-sdk
v1.1.1
Published
Shopping Assistant SDK - Vanilla JS Core + React Wrapper
Maintainers
Readme
Shopping Assistant SDK v5.0 🛒✨
A powerful, framework-agnostic JavaScript SDK for integrating AI-powered shopping assistance into any web application. Built with TypeScript and Web Components for maximum compatibility and modern development practices.
📖 Table of Contents
- What is Shopping Assistant SDK v5?
- Key Features
- Installation
- Quick Start
- Configuration
- Framework Integration
- Events & API Reference
- Advanced Features
- Troubleshooting
- Examples
🌟 What is Shopping Assistant SDK v5?
The Shopping Assistant SDK v5 is a comprehensive solution that provides intelligent shopping assistance through a modern, embeddable chat interface. It combines AI-powered natural language processing with rich UI components to create seamless shopping experiences.
✨ Core Capabilities
- 🤖 AI-Powered Chat Interface: Intelligent shopping assistance with natural language processing
- 📱 Multiple Display Modes: Sidebar, overlay, and full-page chat interfaces
- ⚡ Real-time Streaming: Live text streaming with Server-Sent Events (SSE) support
- 🎨 Rich Resource Rendering: Advanced UI resource rendering using MCP (Model Context Protocol)
- 🔧 Framework Agnostic: Works with React, Vue, Angular, vanilla JavaScript, or any web framework
- 📝 TypeScript Support: Full type safety and IntelliSense support
- 🎯 Customizable UI: Configurable themes, action chips, and suggestions
- 🛒 Shopping Cart Integration: Built-in cart management with real API integration
- 🔄 Event-Driven Architecture: Comprehensive event system for all interactions
🚀 Key Features
✅ Display Modes
1. Sidebar Mode (Default)
- 30% viewport width with responsive design
- Minimum width: 40rem, Maximum width: 500px
- Toggle button positioned at right center
- Persistent across page navigation
- Close and reset functionality
2. Overlay Mode
- Configurable dimensions and positioning
- Bottom-right positioned by default
- Modal-style interaction with smooth animations
- Toggle button at bottom-right
3. Full-Page Mode
- Takes full viewport for dedicated chat pages
- No external toggle button needed
- Ideal for standalone chat applications
✅ Advanced Capabilities
- 🔄 Streaming Support: Real-time text chunk accumulation with loading animations
- 📦 Resource Management: Handles HTML, URIs, and rich interactive content
- 🎯 MCP Integration: Uses
@mcp-ui/clientfor advanced resource rendering - 🎤 Voice Assistant: Built-in speech recognition for hands-free shopping queries
- 📡 Event System: Comprehensive event handling for all user interactions
- 🖼️ Auto-iframe Resizing: Dynamic content sizing for embedded resources
- ♿ Accessibility: ARIA-compliant components with keyboard navigation
- 🎨 Loading States: Beautiful animated loading indicators during AI responses
- 🔄 Intent Handling: Automatic handling of product interactions (view details, add to cart)
📦 Installation
NPM Installation (Recommended)
# Using npm
npm install @shopping-assistant/sdk
# Using yarn
yarn add @shopping-assistant/sdk
# Using pnpm
pnpm add @shopping-assistant/sdk📦 NPM Registry: https://www.npmjs.com/package/shopping-assistant-mcp-sdk
Local Development
# Clone and build locally
git clone https://github.com/varadharajan007/new-mcpui-nextjs.git
cd new-mcpui-nextjs/sdk-v5
npm install
npm run build🔗 GitHub Repository: https://github.com/varadharajan007/new-mcpui-nextjs
Note: The SDK includes all necessary dependencies including MCP UI Resource Renderer. No additional setup required!
🚀 Quick Start
Basic HTML Integration
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Store with Shopping Assistant</title>
</head>
<body>
<header>
<h1>Welcome to My Store</h1>
</header>
<main>
<!-- Your store content here -->
<div id="assistant-container"></div>
</main>
<script type="module">
// Initialize the Shopping Assistant SDK with Web Component
const initializeAssistant = async () => {
try {
console.log('🚀 Initializing Shopping Assistant Web Component SDK...');
// Dynamic import to avoid SSR issues
const { ShoppingAssistant } = await import('@shopping-assistant/sdk');
const assistantInstance = new ShoppingAssistant({
apiKey: 'demo-key',
userId: '123',
container: document.getElementById('assistant-container'),
theme: {
primaryColor: '#000',
backgroundColor: '#ffffff'
},
// Streaming mode: 'builtin' (default) or 'external'
streamingMode: 'builtin' // Default - SDK handles everything automatically
});
// Set up event listeners
assistantInstance.on('assistant:ready', () => {
console.log('✅ Shopping Assistant is ready!');
});
assistantInstance.on('assistant:userQuery', async (data) => {
// Only handle userQuery in external mode
if (assistantInstance.getStreamingMode() === 'external') {
console.log('🔍 User query received (External Mode):', data);
// Use these events to stream data to chat window
assistantInstance.streamData(/* your streaming data */);
assistantInstance.completeStreaming();
} else {
console.log('🚀 Built-in mode active - SDK will handle the query internally');
}
});
assistantInstance.on('assistant:action', (data) => {
console.log('🔗 MCP Resource action:', data);
// Handle different intent actions
if (data.action === 'view_details') {
console.log('👀 Product view details requested:', data.params);
// The SDK will automatically handle the view_details intent internally
// Parent apps can also add custom logic here if needed
} else if (data.action === 'add_to_cart') {
console.log('🛒 Add to cart requested:', data.params);
// Handle real add to cart API call
handleAddToCart(data.params);
}
});
assistantInstance.on('assistant:error', (error) => {
console.error('❌ Assistant error:', error);
});
assistantInstance.on('assistant:reset', (data) => {
console.log('🔄 Assistant was reset:', data);
});
assistantInstance.on('assistant:closed', (data) => {
console.log('✕ Assistant was closed by user:', data);
});
// Auto-open the assistant once page loaded
setTimeout(() => {
assistantInstance.open();
}, 1000);
} catch (error) {
console.error('Failed to initialize Shopping Assistant:', error);
}
};
initializeAssistant();
</script>
</body>
</html>⚙️ Configuration
ShoppingAssistantConfig Interface
interface ShoppingAssistantConfig {
// Required
apiKey: string; // Your API key
// Optional
apiBaseUrl?: string; // API endpoint URL
userId?: string; // User identifier
mode?: 'sidebar' | 'overlay' | 'full-page'; // Display mode
container?: string | HTMLElement; // Container element for the assistant
// UI Customization
customChips?: Array<{ // Custom action buttons
label: string;
callback: string;
}>;
defaultSuggestions?: Array<{ // Initial suggestions
name: string;
icon: string;
description: string;
}>;
theme?: { // UI theming
primaryColor?: string;
backgroundColor?: string;
};
// Streaming Configuration
streamingMode?: 'builtin' | 'external'; // Streaming mode (defaults to 'builtin')
}Example Configuration
const assistant = new ShoppingAssistant({
apiKey: 'your-api-key',
apiBaseUrl: 'https://api.yourstore.com',
userId: 'user-123',
mode: 'sidebar',
container: '#assistant-container', // or document.getElementById('container')
// Streaming mode (defaults to 'builtin')
streamingMode: 'builtin', // 'builtin' | 'external'
// Custom action chips
customChips: [
{ label: 'Track Order', callback: 'onTrackOrder' },
{ label: 'Size Guide', callback: 'onSizeGuide' },
{ label: 'Customer Support', callback: 'onCustomerSupport' }
],
// Custom default suggestions
defaultSuggestions: [
{ name: 'Tops', icon: '👚', description: 'Stylish tops for every occasion' },
{ name: 'Dresses', icon: '👗', description: 'Beautiful dresses for any event' },
{ name: 'Jeans', icon: '👖', description: 'Comfortable and stylish jeans' }
],
// Custom theme
theme: {
primaryColor: '#007bff',
backgroundColor: '#ffffff'
}
});
// Define global callback functions
window.onTrackOrder = () => {
window.location.href = '/orders';
};
window.onSizeGuide = () => {
// Open size guide modal
openSizeGuideModal();
};
window.onCustomerSupport = () => {
// Open support chat
window.open('/support', '_blank');
};🔧 Framework Integration
React Integration
// components/ShoppingAssistant.tsx
import React, { useEffect, useRef, useState } from 'react';
import { ShoppingAssistant } from '@shopping-assistant/sdk';
interface Props {
apiKey: string;
userId?: string;
mode?: 'sidebar' | 'overlay' | 'full-page';
streamingMode?: 'builtin' | 'external';
}
export const ShoppingAssistantComponent: React.FC<Props> = ({
apiKey,
userId,
mode = 'sidebar',
streamingMode = 'builtin'
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const [assistant, setAssistant] = useState<ShoppingAssistant | null>(null);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
const initializeAssistant = async () => {
try {
const assistantInstance = new ShoppingAssistant({
apiKey,
userId: userId || 'user-123',
container: containerRef.current,
mode,
streamingMode,
theme: {
primaryColor: '#007bff',
backgroundColor: '#ffffff'
}
});
// Set up event listeners
assistantInstance.on('assistant:ready', () => {
console.log('✅ Shopping Assistant is ready!');
setIsConnected(true);
});
assistantInstance.on('assistant:userQuery', async (data: any) => {
if (streamingMode === 'external') {
console.log('🔍 User query received (External Mode):', data);
// Handle external streaming here
// assistantInstance.streamData(/* your data */);
// assistantInstance.completeStreaming();
} else {
console.log('🚀 Built-in mode active - SDK handles internally');
}
});
assistantInstance.on('assistant:action', (data: any) => {
console.log('🔗 MCP Resource action:', data);
if (data.action === 'add_to_cart') {
console.log('🛒 Add to cart requested:', data.params);
// Handle add to cart logic
handleAddToCart(data.params);
}
});
assistantInstance.on('assistant:error', (error: any) => {
console.error('❌ Assistant error:', error);
});
assistantInstance.on('assistant:reset', () => {
console.log('🔄 Assistant was reset');
});
assistantInstance.on('assistant:closed', () => {
console.log('✕ Assistant was closed by user');
});
setAssistant(assistantInstance);
// Auto-open the assistant
setTimeout(() => {
assistantInstance.open();
}, 1000);
} catch (error) {
console.error('Failed to initialize Shopping Assistant:', error);
}
};
initializeAssistant();
// Cleanup
return () => {
if (assistant) {
assistant.destroy();
}
};
}, [apiKey, userId, mode, streamingMode]);
const handleAddToCart = async (params: any) => {
// Your add to cart implementation
console.log('Adding to cart:', params);
};
return (
<div
ref={containerRef}
style={{
width: '100%',
height: '100%',
position: 'relative'
}}
>
{!isConnected && (
<div style={{ padding: '20px', textAlign: 'center' }}>
Loading Shopping Assistant...
</div>
)}
</div>
);
};Angular Integration
// shopping-assistant.component.ts
import { Component, Input, OnInit, OnDestroy, ElementRef, ViewChild } from '@angular/core';
import { ShoppingAssistant } from '@shopping-assistant/sdk';
@Component({
selector: 'app-shopping-assistant',
template: `
<div #assistantContainer
style="width: 100%; height: 100%; position: relative;">
<div *ngIf="!isConnected" style="padding: 20px; text-align: center;">
Loading Shopping Assistant...
</div>
</div>
`
})
export class ShoppingAssistantComponent implements OnInit, OnDestroy {
@Input() apiKey!: string;
@Input() userId?: string;
@Input() mode: 'sidebar' | 'overlay' | 'full-page' = 'sidebar';
@Input() streamingMode: 'builtin' | 'external' = 'builtin';
@ViewChild('assistantContainer', { static: true })
containerRef!: ElementRef<HTMLDivElement>;
private assistant: ShoppingAssistant | null = null;
public isConnected = false;
async ngOnInit() {
try {
this.assistant = new ShoppingAssistant({
apiKey: this.apiKey,
userId: this.userId || 'user-123',
container: this.containerRef.nativeElement,
mode: this.mode,
streamingMode: this.streamingMode,
theme: {
primaryColor: '#007bff',
backgroundColor: '#ffffff'
}
});
// Set up event listeners
this.assistant.on('assistant:ready', () => {
console.log('✅ Shopping Assistant is ready!');
this.isConnected = true;
});
this.assistant.on('assistant:userQuery', async (data: any) => {
if (this.streamingMode === 'external') {
console.log('🔍 User query received (External Mode):', data);
// Handle external streaming here
// this.assistant.streamData(/* your data */);
// this.assistant.completeStreaming();
} else {
console.log('🚀 Built-in mode active - SDK handles internally');
}
});
this.assistant.on('assistant:action', (data: any) => {
console.log('🔗 MCP Resource action:', data);
if (data.action === 'add_to_cart') {
console.log('🛒 Add to cart requested:', data.params);
this.handleAddToCart(data.params);
}
});
this.assistant.on('assistant:error', (error: any) => {
console.error('❌ Assistant error:', error);
});
this.assistant.on('assistant:reset', () => {
console.log('🔄 Assistant was reset');
});
this.assistant.on('assistant:closed', () => {
console.log('✕ Assistant was closed by user');
});
// Auto-open the assistant
setTimeout(() => {
this.assistant?.open();
}, 1000);
} catch (error) {
console.error('Failed to initialize Shopping Assistant:', error);
}
}
ngOnDestroy() {
if (this.assistant) {
this.assistant.destroy();
}
}
private handleAddToCart(params: any) {
// Your add to cart implementation
console.log('Adding to cart:', params);
}
}📡 Events & API Reference
Core Methods
create(options?)
Creates and mounts the shopping assistant component.
assistant.create({
container: '#my-container' // string selector or HTMLElement
});open(options?)
Opens the chat interface.
assistant.open({
productId: 'product-123',
initialMessage: 'Tell me about this product'
});close()
Closes the chat interface.
assistant.close();toggle()
Toggles the chat interface open/closed state.
assistant.toggle();streamData(data)
Sends streaming data to the chat interface.
assistant.streamData({
type: 'text_chunk',
text: 'Hello from server',
is_complete: true
});completeStreaming()
Completes the current streaming session.
assistant.completeStreaming();sendMessagePublic(messageText)
Programmatically send a message to the assistant.
assistant.sendMessagePublic('view cart');resetChat()
Programmatically reset the chat history.
assistant.resetChat();destroy()
Destroys the assistant instance and cleans up resources.
assistant.destroy();Event System
User Interaction Events
assistant:userQuery
Fired when user sends a message (only in external mode).
assistant.on('assistant:userQuery', (data: {
query: string;
conversationHistory: ChatMessage[];
userId: string;
}) => {
console.log('User query:', data.query);
// Only handle in external mode - builtin mode handles automatically
if (assistant.getStreamingMode() === 'external') {
// Handle the query and stream response back
handleUserQuery(data);
}
});assistant:action
Fired when a resource action is triggered (product interactions, cart actions).
assistant.on('assistant:action', (data: {
action: string; // 'view_details', 'add_to_cart', 'remove_from_cart'
params: any;
timestamp: string;
intentId: string;
}) => {
console.log('Resource action:', data.action, data.params);
if (data.action === 'add_to_cart') {
handleAddToCart(data.params);
} else if (data.action === 'view_details') {
handleViewDetails(data.params);
} else if (data.action === 'remove_from_cart') {
handleRemoveFromCart(data.params);
}
});assistant:chipsListener
Fired when custom action chips are clicked.
assistant.on('assistant:chipsListener', (data: {
chipLabel: string;
callback: string;
}) => {
console.log('Chip clicked:', data.chipLabel);
// Handle custom chip actions
if (window[data.callback]) {
window[data.callback]();
}
});System Events
assistant:ready
Fired when the assistant is fully initialized and ready.
assistant.on('assistant:ready', () => {
console.log('Assistant is ready!');
});assistant:reset
Fired when the chat is reset (reset button clicked).
assistant.on('assistant:reset', (data: {
timestamp: string;
}) => {
console.log('Assistant was reset at:', data.timestamp);
});assistant:closed
Fired when the user closes the assistant using the close button.
assistant.on('assistant:closed', (data: {
timestamp: string;
}) => {
console.log('Assistant was closed by user at:', data.timestamp);
});assistant:error
Fired when an error occurs in the assistant.
assistant.on('assistant:error', (error: {
message: string;
timestamp: string;
}) => {
console.error('Assistant error:', error.message);
});Streaming Data Format
Text Chunk (Streaming)
{
type: 'text_chunk',
text: 'Accumulated text content',
resource: null,
is_complete: boolean
}Resource (Interactive Components)
{
type: 'resource',
text: null,
resource: {
uri: 'https://example.com/product-catalog.html',
mimeType: 'text/uri-list',
text: 'Resource content'
},
is_complete: true
}Complete Text
{
type: 'text',
text: 'Complete text message',
resource: null,
is_complete: true
}🔥 Advanced Features
Intent Handling System
The SDK automatically handles product interactions from embedded resources:
// When user clicks a product in a catalog, the SDK automatically:
// 1. Dispatches 'mcp-resource:action' event with action 'view_details'
// 2. Sends internal message "show me the details of [product]"
// 3. Streams product details from your API
// 4. Handles add-to-cart actions from product detail pages
assistant.on('mcp-resource:action', (data) => {
if (data.action === 'view_details') {
console.log('User wants to view:', data.params.product);
// SDK handles this automatically, but you can add custom logic
}
if (data.action === 'add_to_cart') {
// Handle real cart API call
handleAddToCart(data.params);
}
});Real-time Cart Integration
const handleAddToCart = async (params) => {
try {
const cartItem = {
productId: params.productId,
name: params.name,
price: params.price,
quantity: params.quantity || 1,
size: params.size,
color: params.color,
image: params.image
};
const response = await fetch('http://localhost:8080/api/cart/add?userId=123', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cartItem })
});
const result = await response.json();
if (result.success) {
alert(`✅ ${cartItem.name} added to cart!`);
// Automatically show cart after successful add
setTimeout(() => {
assistant.sendMessagePublic('view cart');
}, 1000);
} else {
alert('❌ Failed to add item to cart');
}
} catch (error) {
console.error('Error adding to cart:', error);
alert('❌ Error adding item to cart');
}
};Loading States & Animations
The SDK includes beautiful loading animations that appear during AI responses:
- Animated dots: Three pulsing dots with staggered timing
- Message-level loading: Appears as a chat bubble where the response will be
- Automatic replacement: Loading disappears when streaming starts
- Consistent styling: Matches the overall chat design
Resource Deduplication
The SDK prevents multiple loading of the same resources during streaming:
// Automatically handled by the SDK:
// - Tracks processed resource URIs
// - Reuses existing resource elements
// - Prevents duplicate MCP UI component creation
// - Maintains chat history integrityVoice Assistant 🎤
The SDK includes built-in speech recognition for hands-free shopping:
Features
- 🎤 Speech-to-Text: Convert voice commands to chat messages
- 🔴 Recording Indicator: Visual feedback in the header during recording
- 🌐 Browser Support: Works in Chrome, Edge, Safari (with limitations)
- ❌ Error Handling: Graceful fallback for unsupported browsers
Usage
// Voice assistant is automatically enabled
// Users click the 🎤 microphone button in the input area
// Speak their query: "Show me red dresses under $50"
// Voice is converted to text and sent as a chat messageVoice Commands Examples
- "Show me the latest arrivals"
- "I want to see tops in blue color"
- "Add this item to my cart"
- "What's in my shopping cart?"
- "Find dresses under fifty dollars"
Browser Compatibility
- ✅ Chrome/Chromium: Full support
- ✅ Edge: Full support
- ⚠️ Safari: Limited support (iOS restrictions)
- ⚠️ Firefox: Requires manual enabling in some versions
Public Methods
// Toggle voice recognition programmatically
assistant.toggleVoiceRecognition();
// Check if voice is currently listening
const isListening = assistant.isListening; // Read-only propertyClose & Reset Functionality
The SDK includes built-in UI controls:
- Close Button (✕): Hides the sidebar, shows chat icon, preserves chat history
- Reset Button (🔄): Clears all chat history, shows default questions
- Event Dispatching: Both actions dispatch events for parent app handling
🛠 Troubleshooting
Common Issues
Web Component Not Rendering
// Check browser compatibility
import { isSupported } from '@shopping-assistant/sdk';
if (!isSupported) {
console.error('Shopping Assistant not supported in this browser');
// Provide fallback UI
}Events Not Firing
// Make sure to set up event listeners before creating the component
assistant.on('userQuery', handleUserQuery);
assistant.on('mcp-resource:action', handleResourceAction);
assistant.create({ container: '#container' });API Connection Issues
// Verify API configuration
const assistant = new ShoppingAssistant({
apiKey: 'your-valid-api-key',
apiBaseUrl: 'https://your-correct-endpoint.com'
});
// Check network requests in browser dev tools
// Ensure CORS is properly configured on your APILoading Animation Not Showing
// Ensure you're calling completeStreaming() after streaming is done
assistant.on('userQuery', async (data) => {
try {
// ... handle streaming ...
} finally {
assistant.completeStreaming(); // Always call this
}
});MCP Resources Not Loading
<!-- Ensure MCP UI component is loaded before SDK -->
<script src="https://cdn.jsdelivr.net/gh/varadharajan007/[email protected]/sdk/src/mcp-ui-resource-component.js"></script>
<script type="module">
import { ShoppingAssistant } from '@shopping-assistant/sdk';
// ... your code
</script>Browser Compatibility
- Modern Browsers: Chrome 70+, Firefox 65+, Safari 12+, Edge 79+
- Required Features:
- Web Components (Custom Elements)
- ES6 Modules
- Fetch API
- Promises
- Shadow DOM
Performance Optimization
// Dynamic import for better performance
const initializeAssistant = async () => {
const { ShoppingAssistant } = await import('@shopping-assistant/sdk');
const assistant = new ShoppingAssistant({
apiKey: 'your-key'
});
assistant.create();
};
// Initialize on user interaction
document.addEventListener('click', initializeAssistant, { once: true });📚 Examples
Complete E-commerce Integration
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Complete E-commerce with Shopping Assistant</title>
<!-- Load MCP UI Resource Renderer -->
<script src="https://cdn.jsdelivr.net/gh/varadharajan007/[email protected]/sdk/src/mcp-ui-resource-component.js"></script>
</head>
<body>
<header>
<h1>My Fashion Store</h1>
<div id="cart-badge">🛒 <span id="cart-count">0</span></div>
</header>
<main>
<section class="hero">
<h2>Welcome to Our Store</h2>
<p>Find the perfect outfit with our AI shopping assistant!</p>
</section>
<section class="products">
<!-- Your product grid here -->
</section>
</main>
<script type="module">
import { ShoppingAssistant } from '@shopping-assistant/sdk';
// Initialize the assistant
const assistant = new ShoppingAssistant({
apiKey: 'your-api-key',
apiBaseUrl: 'http://localhost:8080',
userId: 'user-' + Date.now(),
mode: 'sidebar',
customChips: [
{ label: 'Track Order', callback: 'onTrackOrder' },
{ label: 'Size Guide', callback: 'onSizeGuide' },
{ label: 'Returns', callback: 'onReturns' }
],
defaultSuggestions: [
{ name: 'Tops', icon: '👚', description: 'Stylish tops for every occasion' },
{ name: 'Dresses', icon: '👗', description: 'Beautiful dresses for any event' },
{ name: 'Jeans', icon: '👖', description: 'Comfortable and stylish jeans' },
{ name: 'Shoes', icon: '👠', description: 'Trendy footwear collection' }
],
theme: {
primaryColor: '#e74c3c',
backgroundColor: '#ffffff'
}
});
// Global callback functions
window.onTrackOrder = () => {
window.location.href = '/orders';
};
window.onSizeGuide = () => {
openModal('size-guide');
};
window.onReturns = () => {
window.location.href = '/returns';
};
// Create the assistant
assistant.create();
// Handle user queries with streaming
assistant.on('userQuery', async (data) => {
console.log('🔍 User query received:', data.query);
try {
const response = await fetch('/api/copilot-chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: data.query,
conversationHistory: data.conversationHistory || []
})
});
if (!response.body) {
throw new Error('No response body');
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim() !== '');
for (const line of lines) {
if (line.startsWith('data: ')) {
try {
const eventData = JSON.parse(line.substring(6));
assistant.streamData(eventData);
} catch (parseError) {
console.error('Error parsing SSE data:', parseError);
}
} else if (line === 'event: done') {
assistant.completeStreaming();
return;
}
}
}
assistant.completeStreaming();
} catch (error) {
console.error('Error handling user query:', error);
assistant.completeStreaming();
}
});
// Handle resource actions (product interactions)
assistant.on('mcp-resource:action', (data) => {
console.log('🔗 MCP Resource action:', data.action, data.params);
if (data.action === 'add_to_cart') {
handleAddToCart(data.params);
} else if (data.action === 'view_details') {
console.log('👀 User wants to view product details:', data.params.productId);
// SDK handles this automatically by streaming product details
} else if (data.action === 'buy_now') {
handleBuyNow(data.params);
}
});
// Handle navigation requests
assistant.on('navigationRequest', (data) => {
console.log('🧭 Navigation requested:', data.action);
switch (data.action) {
case 'viewCart':
window.location.href = '/cart';
break;
case 'checkout':
window.location.href = '/checkout';
break;
}
});
// Handle assistant lifecycle events
assistant.on('assistant:opened', () => {
console.log('✅ Assistant opened');
// Track analytics
gtag('event', 'assistant_opened');
});
assistant.on('assistant:closed-by-user', () => {
console.log('❌ Assistant closed by user');
gtag('event', 'assistant_closed');
});
assistant.on('assistant:reset', () => {
console.log('🔄 Assistant reset');
gtag('event', 'assistant_reset');
});
// Add to cart handler
const handleAddToCart = async (params) => {
try {
const cartItem = {
productId: params.productId,
name: params.name,
price: parseFloat(params.price?.replace(/[^0-9.]/g, '') || '0'),
quantity: params.quantity || 1,
size: params.size,
color: params.color,
image: params.image
};
console.log('🛒 Adding to cart:', cartItem);
const response = await fetch(`http://localhost:8080/api/cart/add?userId=123`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cartItem })
});
const result = await response.json();
if (result.success && result.data) {
// Update cart badge
updateCartBadge(result.data.items?.length || 0);
// Show success message
showNotification(`✅ ${cartItem.name} added to cart!`, 'success');
// Automatically show cart after 1 second
setTimeout(() => {
assistant.sendMessagePublic('view cart');
}, 1000);
} else {
showNotification('❌ Failed to add item to cart', 'error');
}
} catch (error) {
console.error('Error adding to cart:', error);
showNotification('❌ Error adding item to cart', 'error');
}
};
// Buy now handler
const handleBuyNow = (params) => {
// Add to cart first, then redirect to checkout
handleAddToCart(params).then(() => {
setTimeout(() => {
window.location.href = '/checkout';
}, 500);
});
};
// Utility functions
const updateCartBadge = (count) => {
const cartCountElement = document.getElementById('cart-count');
if (cartCountElement) {
cartCountElement.textContent = count.toString();
}
};
const showNotification = (message, type) => {
// Create and show notification
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 24px;
border-radius: 8px;
color: white;
font-weight: 500;
z-index: 10000;
background-color: ${type === 'success' ? '#28a745' : '#dc3545'};
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
};
const openModal = (modalId) => {
// Your modal opening logic
console.log('Opening modal:', modalId);
};
</script>
</body>
</html>🔒 Security Considerations
- Always validate API keys on your backend
- Implement rate limiting for API calls
- Sanitize user inputs before processing
- Use HTTPS for all API communications
- Regularly update the SDK to latest version
- Implement proper CORS policies
- Validate all resource URLs before rendering
📈 Performance Best Practices
- Lazy Loading: Load the SDK only when needed
- Resource Deduplication: Automatically handled by the SDK
- Streaming Optimization: Throttled UI updates during streaming
- Memory Management: Automatic cleanup on component destruction
- Code Splitting: Use dynamic imports for better performance
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support & Resources
- Documentation: SDK Documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: [email protected]
Built with ❤️ by the Shopping Assistant Team
Transform your e-commerce experience with AI-powered shopping assistance!
