Building Your First App
Complete step-by-step tutorial for creating a PACE-powered product storefront.
What We're Building
A conversational storefront for MCP (Model Context Protocol) servers with:
- ✅ Product catalog with search and categories
- ✅ AI-powered chat guide
- ✅ About page with origin story
- ✅ Executive summary tracking
- ✅ Purple gradient theme
- ✅ Fully functional routing
Time: 30-45 minutes
Prerequisites
- Node.js 18+
- NPM or Yarn
- Code editor (VS Code recommended)
- Basic JavaScript/HTML knowledge
Part 1: Project Setup
1. Create Project Directory
mkdir mcp-storefront
cd mcp-storefront
npm init -y2. Install PACE.js
npm install @semanticintent/pace-pattern3. Create Project Structure
mkdir public
touch public/index.html
touch public/app.js
touch public/products.json
touch public/about.jsonYour structure:
mcp-storefront/
├── package.json
├── public/
│ ├── index.html
│ ├── app.js
│ ├── products.json
│ └── about.jsonPart 2: Create Product Data
public/products.json
Create realistic MCP server products:
{
"products": [
{
"id": "sql-mcp",
"name": "SQL MCP",
"tagline": "Query databases with natural language",
"category": "Database Tools",
"description": "## SQL MCP\n\nConnect Claude to your databases and query them using natural language.\n\n### Features\n- PostgreSQL, MySQL, SQLite support\n- Natural language → SQL translation\n- Query result formatting\n- Safe read-only mode\n\n### Installation\n```bash\nnpm install -g sql-mcp\n```\n\n### Usage\nAdd to your Claude Desktop config:\n```json\n{\n \"mcpServers\": {\n \"sql\": {\n \"command\": \"sql-mcp\",\n \"args\": [\"--db\", \"postgresql://localhost/mydb\"]\n }\n }\n}\n```",
"action_label": "Install",
"action_url": "https://github.com/example/sql-mcp"
},
{
"id": "github-mcp",
"name": "GitHub MCP",
"tagline": "Interact with GitHub repositories",
"category": "Developer Tools",
"description": "## GitHub MCP\n\nManage GitHub repositories, issues, and PRs through Claude.\n\n### Features\n- Repository browsing\n- Issue management\n- PR creation and review\n- Code search\n\n### Installation\n```bash\nnpm install -g github-mcp\n```\n\n### Authentication\nRequires GitHub personal access token.",
"action_label": "Get Started",
"action_url": "https://github.com/example/github-mcp"
},
{
"id": "filesystem-mcp",
"name": "Filesystem MCP",
"tagline": "Safe file operations through Claude",
"category": "System Tools",
"description": "## Filesystem MCP\n\nLet Claude read and write files securely.\n\n### Features\n- Read/write files\n- Directory listing\n- File search\n- Safe mode (read-only)\n\n### Security\n- Configurable allowed paths\n- Deny dangerous operations\n- Audit logging",
"action_label": "Learn More",
"action_url": "https://github.com/example/filesystem-mcp"
},
{
"id": "api-mcp",
"name": "API MCP",
"tagline": "Connect to REST APIs",
"category": "Integration",
"description": "## API MCP\n\nCall external APIs through Claude.\n\n### Features\n- REST API calls\n- OAuth support\n- Response parsing\n- Rate limiting\n\n### Use Cases\n- Weather data\n- Stock prices\n- News feeds\n- Custom APIs",
"action_label": "Explore",
"action_url": "https://github.com/example/api-mcp"
},
{
"id": "analytics-mcp",
"name": "Analytics MCP",
"tagline": "Query analytics platforms",
"category": "Data & Analytics",
"description": "## Analytics MCP\n\nConnect to Google Analytics, Mixpanel, etc.\n\n### Supported Platforms\n- Google Analytics 4\n- Mixpanel\n- Amplitude\n- Custom sources\n\n### Example Queries\n- \"Show me last week's traffic\"\n- \"What's our conversion rate?\"\n- \"Top pages by views\"",
"action_label": "Connect",
"action_url": "https://github.com/example/analytics-mcp"
}
]
}Part 3: Create About Content
public/about.json
{
"title": "About MCP Hub",
"sections": [
{
"title": "What is MCP Hub?",
"content": "## What is MCP Hub?\n\nMCP Hub is a conversational storefront for discovering Model Context Protocol (MCP) servers.\n\n### What are MCP Servers?\n\nMCP servers are plugins that extend Claude's capabilities by connecting it to external tools, databases, APIs, and services.\n\n### Why This Exists\n\nFinding the right MCP server shouldn't require browsing dozens of repositories. Let our guide help you discover what you need through conversation."
},
{
"title": "The PACE Pattern",
"content": "## Built with PACE\n\nThis site implements the **PACE Pattern** — Pattern for Agentic Conversational Experience.\n\n### Four Principles:\n\n- **Proactive** — Guide initiates conversation\n- **Adaptive** — Matches your expertise level\n- **Contextual** — Remembers what you've discussed\n- **Efficient** — Concise, actionable responses\n\n[Learn more about PACE →](https://pace.cormorantforaging.dev)"
},
{
"title": "Open Source",
"content": "## Open Source\n\nMCP Hub is built with PACE.js, an open-source framework.\n\n- **Framework:** [PACE.js](https://github.com/semanticintent/pace.js)\n- **Pattern:** [PACE Pattern](https://zenodo.org/records/18049371)\n- **License:** MIT\n\nContributions welcome!"
}
],
"links": [
{
"label": "PACE.js on GitHub",
"url": "https://github.com/semanticintent/pace.js"
},
{
"label": "MCP Protocol Docs",
"url": "https://modelcontextprotocol.io"
}
]
}Part 4: Create HTML
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MCP Hub - Find Your Perfect MCP Server</title>
<!-- PACE.js CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@semanticintent/pace-pattern/dist/pace.min.css">
<!-- Custom overrides -->
<style>
body {
margin: 0;
font-family: Inter, system-ui, sans-serif;
}
/* Optional: Override PACE colors */
:root {
--pace-primary: #667eea;
--pace-accent: #764ba2;
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="app.js"></script>
</body>
</html>Part 5: Initialize PACE.js
public/app.js (Basic Version)
Start without AI:
import { PACE } from '@semanticintent/pace-pattern'
// Initialize PACE
const pace = new PACE({
container: '#app',
products: './products.json',
greeting: 'Welcome to MCP Hub! What kind of MCP server are you looking for?',
defaultView: 'product'
})
// Mount to DOM
pace.mount()
// Listen to events
pace.on('ready', () => {
console.log('MCP Hub is ready!')
})
pace.on('product:select', ({ product }) => {
console.log('User selected:', product.name)
})
pace.on('product:search', ({ query, results }) => {
console.log(`Search for "${query}" found ${results.length} results`)
})Part 6: Test Basic Functionality
Start Development Server
npx serve publicTest These Features
✅ Product catalog displays all 5 MCP servers ✅ Search works (try "database" or "github") ✅ Products grouped by category ✅ Sidebar navigation works ✅ URLs update with hash routing ✅ About page shows custom content
Part 7: Add AI (Claude)
Update app.js with Claude
import { PACE, ClaudeAdapter } from '@semanticintent/pace-pattern'
// Create Claude adapter
const claudeAdapter = new ClaudeAdapter({
apiKey: process.env.CLAUDE_API_KEY, // Use environment variable
model: 'claude-3-sonnet-20240229'
})
// Initialize PACE with AI
const pace = new PACE({
container: '#app',
products: './products.json',
aiAdapter: claudeAdapter,
greeting: 'Welcome to MCP Hub! What are you fishing for?',
// Pass product context to AI
context: {
storeName: 'MCP Hub',
storeDescription: 'A curated collection of MCP servers for Claude',
totalProducts: 5
}
})
pace.mount()
// Track chat interactions
pace.on('chat:message', ({ message }) => {
console.log('User:', message)
})
pace.on('chat:response', ({ message, metadata }) => {
console.log('Guide:', message)
console.log('Detected expertise:', metadata.expertise)
})Set Environment Variable
export CLAUDE_API_KEY='your-api-key-here'Test AI Features
✅ Chat with the guide ✅ Ask "What's the best database tool?" ✅ Ask "I'm new to MCP, where should I start?" ✅ Notice adaptive responses (beginner vs advanced) ✅ Executive summary tracks conversation
Part 8: Customize Theme
Add Custom Styling
Create public/custom.css:
/* Override PACE.js theme */
:root {
--pace-primary: #2563eb; /* Blue instead of purple */
--pace-accent: #3b82f6;
--pace-font: 'Roboto', system-ui, sans-serif;
}
/* Custom product cards */
.pace-product-card {
border-left: 4px solid var(--pace-primary);
transition: transform 0.2s;
}
.pace-product-card:hover {
transform: scale(1.02);
box-shadow: 0 8px 24px rgba(37, 99, 235, 0.15);
}
/* Custom chat messages */
.pace-chat-message.assistant {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
}
/* Custom navigation */
.pace-nav-item.active {
border-left: 4px solid var(--pace-primary);
}Link in HTML:
<link rel="stylesheet" href="custom.css">Part 9: Add Analytics
Track User Behavior
// Analytics plugin
const analyticsPlugin = {
name: 'analytics',
install(pace) {
// Track product views
pace.on('product:select', ({ product }) => {
gtag('event', 'product_view', {
product_id: product.id,
product_name: product.name,
product_category: product.category
})
})
// Track searches
pace.on('product:search', ({ query, results }) => {
gtag('event', 'search', {
search_term: query,
results_count: results.length
})
})
// Track chat engagement
pace.on('chat:message', ({ message }) => {
gtag('event', 'chat_message', {
message_length: message.length
})
})
}
}
// Use plugin
pace.use(analyticsPlugin).mount()Part 10: Deploy
Build for Production
- Bundle with Vite
npm install -D viteUpdate package.json:
{
"scripts": {
"dev": "vite public",
"build": "vite build public",
"preview": "vite preview"
}
}- Build
npm run build- Deploy to Netlify
netlify deploy --prodOr GitHub Pages, Vercel, Cloudflare Pages — all work great with PACE.js!
Complete Code
Final app.js
import { PACE, ClaudeAdapter } from '@semanticintent/pace-pattern'
const pace = new PACE({
container: '#app',
products: './products.json',
aiAdapter: new ClaudeAdapter({
apiKey: process.env.CLAUDE_API_KEY,
model: 'claude-3-sonnet-20240229'
}),
greeting: 'Welcome to MCP Hub! What are you fishing for?',
defaultView: 'product',
theme: {
primary: '#667eea',
accent: '#764ba2'
},
context: {
storeName: 'MCP Hub',
productCount: 5
}
})
// Analytics plugin
pace.use({
name: 'analytics',
install(p) {
p.on('product:select', ({ product }) => {
console.log('Product viewed:', product.name)
})
}
})
pace.mount()
// Debug events
if (import.meta.env.DEV) {
pace.on('*', (event, payload) => {
console.log('[PACE]', event, payload)
})
}What You Built
🎉 Congratulations! You've built a fully functional PACE-powered storefront with:
- ✅ 5 MCP server products with rich descriptions
- ✅ AI-powered conversational guide
- ✅ Search and category filtering
- ✅ Custom About page
- ✅ Executive summary tracking
- ✅ Analytics integration
- ✅ Custom theming
- ✅ Production-ready deployment
Next Steps
Continue Learning
- Customize Themes — Deep dive into styling
- AI Adapters — Advanced AI configuration
- State Management — Working with PACE state
- MillPond Example — See a production implementation
You've built your first PACE app! 🚀