feat: add interactive tutorial slideshows for Agents and MCP

- Add /docs/tutorials page with tutorial index
- Create step-by-step Agents tutorial (7 slides)
  - API key setup
  - Agent creation
  - Tool attachment
  - Chat interface usage
- Create step-by-step MCP tutorial (8 slides)
  - What is MCP
  - Creating collections
  - Configuring Claude Desktop
  - Configuring Cursor
  - Using tools

Each tutorial features:
- Progress bar and slide indicators
- Previous/Next navigation
- Direct links to relevant dashboard pages
This commit is contained in:
Ajax Davis 2026-01-02 21:21:13 +10:00
parent 0b1bb7725d
commit bfed830187
3 changed files with 1141 additions and 0 deletions

View file

@ -0,0 +1,478 @@
'use client';
import { Button } from '@tpmjs/ui/Button/Button';
import { Icon } from '@tpmjs/ui/Icon/Icon';
import Link from 'next/link';
import { useState } from 'react';
import { AppFooter } from '~/components/AppFooter';
import { AppHeader } from '~/components/AppHeader';
interface Slide {
id: string;
title: string;
subtitle?: string;
content: React.ReactNode;
icon?: string;
}
const slides: Slide[] = [
{
id: 'intro',
title: 'Build Your First AI Agent',
subtitle: 'A step-by-step guide to creating custom AI assistants with TPMJS',
icon: '🤖',
content: (
<div className="text-center space-y-6">
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
AI Agents are custom assistants that can use tools from TPMJS to accomplish tasks. In just
5 steps, you'll have your own agent up and running.
</p>
<div className="flex flex-wrap justify-center gap-4 mt-8">
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span>🔑</span>
<span className="text-sm">Add API Key</span>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span></span>
<span className="text-sm">Create Agent</span>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span>🔧</span>
<span className="text-sm">Add Tools</span>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span>💬</span>
<span className="text-sm">Start Chatting</span>
</div>
</div>
</div>
),
},
{
id: 'step-1-api-key',
title: 'Step 1: Get Your API Key',
subtitle: 'You bring your own AI provider key',
icon: '🔑',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
TPMJS supports multiple AI providers. Get an API key from any of these:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 max-w-4xl mx-auto">
{[
{ name: 'OpenAI', url: 'platform.openai.com/api-keys', models: 'GPT-4o, GPT-4 Turbo' },
{
name: 'Anthropic',
url: 'console.anthropic.com/settings/keys',
models: 'Claude 3.5 Sonnet',
},
{ name: 'Google', url: 'aistudio.google.com/apikey', models: 'Gemini 2.0 Flash' },
{ name: 'Groq', url: 'console.groq.com/keys', models: 'Llama 3.3 70B' },
{ name: 'Mistral', url: 'console.mistral.ai/api-keys', models: 'Mistral Large' },
].map((provider) => (
<div
key={provider.name}
className="p-4 bg-surface-secondary rounded-lg border border-border"
>
<h4 className="font-semibold text-foreground">{provider.name}</h4>
<p className="text-sm text-foreground-tertiary mt-1">{provider.models}</p>
<a
href={`https://${provider.url}`}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-primary hover:underline mt-2 inline-block"
>
Get key
</a>
</div>
))}
</div>
<div className="text-center">
<p className="text-foreground-secondary">
💡 We recommend <strong>OpenAI</strong> or <strong>Anthropic</strong> for the best
tool-calling support.
</p>
</div>
</div>
),
},
{
id: 'step-2-add-key',
title: 'Step 2: Add Your API Key to TPMJS',
subtitle: 'Your key is encrypted and stored securely',
icon: '🔐',
content: (
<div className="space-y-8">
<div className="max-w-2xl mx-auto space-y-6">
<div className="flex items-start gap-4 p-4 bg-surface-secondary rounded-lg">
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center text-primary font-bold">
1
</div>
<div>
<p className="text-foreground font-medium">Go to Settings</p>
<p className="text-foreground-secondary text-sm">
Navigate to{' '}
<span className="font-mono bg-background px-2 py-0.5 rounded">
Dashboard Settings API Keys
</span>
</p>
</div>
</div>
<div className="flex items-start gap-4 p-4 bg-surface-secondary rounded-lg">
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center text-primary font-bold">
2
</div>
<div>
<p className="text-foreground font-medium">Click "Add Key" for your provider</p>
<p className="text-foreground-secondary text-sm">
Each provider card has an "Add Key" button
</p>
</div>
</div>
<div className="flex items-start gap-4 p-4 bg-surface-secondary rounded-lg">
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center text-primary font-bold">
3
</div>
<div>
<p className="text-foreground font-medium">Paste your API key and save</p>
<p className="text-foreground-secondary text-sm">
Your key is encrypted with AES-256 before storage
</p>
</div>
</div>
</div>
<div className="text-center">
<Link href="/dashboard/settings/api-keys">
<Button variant="default">Go to API Keys Settings </Button>
</Link>
</div>
</div>
),
},
{
id: 'step-3-create-agent',
title: 'Step 3: Create Your Agent',
subtitle: 'Configure your AI assistant',
icon: '✨',
content: (
<div className="space-y-8">
<div className="max-w-3xl mx-auto grid md:grid-cols-2 gap-6">
<div className="space-y-4">
<h4 className="text-lg font-semibold text-foreground">Basic Info</h4>
<div className="space-y-3">
<div className="p-3 bg-surface-secondary rounded-lg">
<p className="text-sm font-medium text-foreground">Name</p>
<p className="text-sm text-foreground-tertiary">
e.g., "Code Helper", "Data Analyst"
</p>
</div>
<div className="p-3 bg-surface-secondary rounded-lg">
<p className="text-sm font-medium text-foreground">Description</p>
<p className="text-sm text-foreground-tertiary">What does your agent do?</p>
</div>
</div>
</div>
<div className="space-y-4">
<h4 className="text-lg font-semibold text-foreground">Model Settings</h4>
<div className="space-y-3">
<div className="p-3 bg-surface-secondary rounded-lg">
<p className="text-sm font-medium text-foreground">Provider & Model</p>
<p className="text-sm text-foreground-tertiary">
Choose from your configured providers
</p>
</div>
<div className="p-3 bg-surface-secondary rounded-lg">
<p className="text-sm font-medium text-foreground">System Prompt</p>
<p className="text-sm text-foreground-tertiary">
Define your agent's personality & capabilities
</p>
</div>
</div>
</div>
</div>
<div className="max-w-2xl mx-auto p-4 bg-primary/5 border border-primary/20 rounded-lg">
<p className="text-sm text-foreground">
<strong>💡 Tip:</strong> Start with the default settings (temperature 0.7) and adjust
based on results. Lower temperature = more focused, higher = more creative.
</p>
</div>
<div className="text-center">
<Link href="/dashboard/agents">
<Button variant="default">Create an Agent </Button>
</Link>
</div>
</div>
),
},
{
id: 'step-4-add-tools',
title: 'Step 4: Add Tools to Your Agent',
subtitle: 'Give your agent superpowers',
icon: '🔧',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
Tools let your agent take actions: run code, search the web, fetch data, and more.
</p>
<div className="max-w-3xl mx-auto grid md:grid-cols-2 gap-6">
<div className="p-6 bg-surface-secondary rounded-lg border border-border">
<h4 className="text-lg font-semibold text-foreground mb-3">📦 Individual Tools</h4>
<p className="text-foreground-secondary text-sm mb-4">
Add specific tools one at a time. Great for focused agents.
</p>
<ul className="space-y-2 text-sm text-foreground-secondary">
<li className="flex items-center gap-2">
<span className="text-green-500"></span>
<span>Execute JavaScript/Python</span>
</li>
<li className="flex items-center gap-2">
<span className="text-green-500"></span>
<span>Fetch web pages</span>
</li>
<li className="flex items-center gap-2">
<span className="text-green-500"></span>
<span>Web search</span>
</li>
</ul>
</div>
<div className="p-6 bg-surface-secondary rounded-lg border border-border">
<h4 className="text-lg font-semibold text-foreground mb-3">📚 Tool Collections</h4>
<p className="text-foreground-secondary text-sm mb-4">
Add entire collections of related tools at once.
</p>
<ul className="space-y-2 text-sm text-foreground-secondary">
<li className="flex items-center gap-2">
<span className="text-green-500"></span>
<span>Pre-curated tool sets</span>
</li>
<li className="flex items-center gap-2">
<span className="text-green-500"></span>
<span>One-click to add many tools</span>
</li>
<li className="flex items-center gap-2">
<span className="text-green-500"></span>
<span>Community collections</span>
</li>
</ul>
</div>
</div>
<div className="text-center">
<Link href="/tools">
<Button variant="secondary">Browse Available Tools </Button>
</Link>
</div>
</div>
),
},
{
id: 'step-5-chat',
title: 'Step 5: Start Chatting!',
subtitle: 'Your agent is ready to help',
icon: '💬',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
Click the "Chat" button on your agent to start a conversation. Your agent will use its
tools to help you.
</p>
<div className="max-w-2xl mx-auto bg-surface-secondary rounded-lg border border-border overflow-hidden">
<div className="p-4 bg-background border-b border-border">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-primary/20 rounded-lg flex items-center justify-center">
<span className="text-sm">🤖</span>
</div>
<div>
<p className="font-medium text-foreground">Code Helper</p>
<p className="text-xs text-foreground-tertiary">OpenAI GPT-4o</p>
</div>
</div>
</div>
<div className="p-4 space-y-4">
<div className="flex justify-end">
<div className="bg-primary text-primary-foreground rounded-lg px-4 py-2 max-w-[80%]">
<p className="text-sm">
Can you run this JavaScript and tell me the result: [1,2,3].map(x =&gt; x * 2)
</p>
</div>
</div>
<div className="flex justify-start">
<div className="bg-background rounded-lg px-4 py-2 max-w-[80%] border border-border">
<p className="text-sm text-foreground-secondary mb-2">[Using: code-executor]</p>
<p className="text-sm text-foreground">
The result is <code className="bg-surface-secondary px-1 rounded">[2, 4, 6]</code>{' '}
- each element was multiplied by 2.
</p>
</div>
</div>
</div>
</div>
<div className="max-w-2xl mx-auto p-4 bg-green-500/10 border border-green-500/20 rounded-lg">
<p className="text-sm text-foreground text-center">
🎉 <strong>Conversations are automatically saved</strong> pick up where you left off
anytime!
</p>
</div>
</div>
),
},
{
id: 'complete',
title: "You're All Set!",
subtitle: 'Start building amazing AI agents',
icon: '🚀',
content: (
<div className="space-y-8 text-center">
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
You now know everything you need to create powerful AI agents with TPMJS.
</p>
<div className="flex flex-wrap justify-center gap-4">
<Link href="/dashboard/agents">
<Button size="lg">Create Your First Agent</Button>
</Link>
<Link href="/docs/agents">
<Button variant="secondary" size="lg">
View Full Documentation
</Button>
</Link>
</div>
<div className="max-w-2xl mx-auto pt-8 border-t border-border mt-8">
<h4 className="text-lg font-semibold text-foreground mb-4">What's Next?</h4>
<div className="grid md:grid-cols-3 gap-4 text-left">
<div className="p-4 bg-surface-secondary rounded-lg">
<p className="font-medium text-foreground">Use the API</p>
<p className="text-sm text-foreground-secondary">Integrate agents into your apps</p>
</div>
<div className="p-4 bg-surface-secondary rounded-lg">
<p className="font-medium text-foreground">Create Collections</p>
<p className="text-sm text-foreground-secondary">
Curate tools for specific use cases
</p>
</div>
<div className="p-4 bg-surface-secondary rounded-lg">
<p className="font-medium text-foreground">Publish Tools</p>
<p className="text-sm text-foreground-secondary">
Add your own tools to the registry
</p>
</div>
</div>
</div>
</div>
),
},
];
export default function AgentsTutorialPage(): React.ReactElement {
const [currentSlide, setCurrentSlide] = useState(0);
const goToSlide = (index: number) => {
setCurrentSlide(Math.max(0, Math.min(slides.length - 1, index)));
};
const nextSlide = () => goToSlide(currentSlide + 1);
const prevSlide = () => goToSlide(currentSlide - 1);
const slide = slides[currentSlide];
const progress = ((currentSlide + 1) / slides.length) * 100;
if (!slide) {
return <></>;
}
return (
<div className="min-h-screen bg-background flex flex-col">
<AppHeader />
{/* Progress bar */}
<div className="w-full h-1 bg-surface-secondary">
<div
className="h-full bg-primary transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
<main className="flex-1 flex flex-col">
{/* Navigation header */}
<div className="border-b border-border">
<div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
<Link
href="/docs/tutorials"
className="flex items-center gap-2 text-foreground-secondary hover:text-foreground transition-colors"
>
<Icon icon="arrowLeft" size="sm" />
<span>Back to Tutorials</span>
</Link>
<div className="text-sm text-foreground-secondary">
{currentSlide + 1} / {slides.length}
</div>
</div>
</div>
{/* Slide content */}
<div className="flex-1 flex items-center justify-center px-4 py-8">
<div className="w-full max-w-5xl">
{/* Slide header */}
<div className="text-center mb-12">
{slide.icon && <span className="text-6xl mb-4 block">{slide.icon}</span>}
<h1 className="text-3xl md:text-4xl font-bold text-foreground mb-3">{slide.title}</h1>
{slide.subtitle && (
<p className="text-lg text-foreground-secondary">{slide.subtitle}</p>
)}
</div>
{/* Slide content */}
<div className="mb-12">{slide.content}</div>
</div>
</div>
{/* Navigation footer */}
<div className="border-t border-border">
<div className="max-w-6xl mx-auto px-4 py-4">
{/* Slide indicators */}
<div className="flex justify-center gap-2 mb-4">
{slides.map((s, index) => (
<button
key={s.id}
type="button"
onClick={() => goToSlide(index)}
className={`w-3 h-3 rounded-full transition-colors ${
index === currentSlide
? 'bg-primary'
: index < currentSlide
? 'bg-primary/40'
: 'bg-surface-secondary'
}`}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
{/* Navigation buttons */}
<div className="flex items-center justify-between">
<Button
variant="secondary"
onClick={prevSlide}
disabled={currentSlide === 0}
className="min-w-[120px]"
>
<Icon icon="arrowLeft" size="xs" className="mr-2" />
Previous
</Button>
{currentSlide === slides.length - 1 ? (
<Link href="/dashboard/agents">
<Button className="min-w-[120px]">Get Started </Button>
</Link>
) : (
<Button onClick={nextSlide} className="min-w-[120px]">
Next
</Button>
)}
</div>
</div>
</div>
</main>
<AppFooter />
</div>
);
}

View file

@ -0,0 +1,536 @@
'use client';
import { Button } from '@tpmjs/ui/Button/Button';
import { Icon } from '@tpmjs/ui/Icon/Icon';
import Link from 'next/link';
import { useState } from 'react';
import { AppFooter } from '~/components/AppFooter';
import { AppHeader } from '~/components/AppHeader';
interface Slide {
id: string;
title: string;
subtitle?: string;
content: React.ReactNode;
icon?: string;
}
const slides: Slide[] = [
{
id: 'intro',
title: 'Connect TPMJS Tools to Your AI',
subtitle: 'Use MCP to add powerful tools to Claude Desktop, Cursor, and more',
icon: '🔌',
content: (
<div className="text-center space-y-6">
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
The Model Context Protocol (MCP) lets AI assistants use external tools. TPMJS provides an
MCP server that gives your AI access to our entire tool registry.
</p>
<div className="flex flex-wrap justify-center gap-4 mt-8">
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span>🎯</span>
<span className="text-sm">Create Collection</span>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span>📋</span>
<span className="text-sm">Copy MCP URL</span>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span></span>
<span className="text-sm">Add to Config</span>
</div>
<div className="flex items-center gap-2 px-4 py-2 bg-surface-secondary rounded-full">
<span></span>
<span className="text-sm">Use Tools</span>
</div>
</div>
<div className="pt-6">
<p className="text-sm text-foreground-tertiary">
Works with: Claude Desktop Cursor Any MCP-compatible client
</p>
</div>
</div>
),
},
{
id: 'what-is-mcp',
title: 'What is MCP?',
subtitle: 'A simple way for AI assistants to use tools',
icon: '📖',
content: (
<div className="space-y-8">
<div className="max-w-3xl mx-auto grid md:grid-cols-2 gap-8">
<div className="p-6 bg-surface-secondary rounded-lg border border-border">
<h4 className="text-lg font-semibold text-foreground mb-3">Without MCP</h4>
<ul className="space-y-3 text-foreground-secondary">
<li className="flex items-start gap-2">
<span className="text-red-500 mt-0.5"></span>
<span>AI can only process text</span>
</li>
<li className="flex items-start gap-2">
<span className="text-red-500 mt-0.5"></span>
<span>No access to external data</span>
</li>
<li className="flex items-start gap-2">
<span className="text-red-500 mt-0.5"></span>
<span>Can't take real actions</span>
</li>
<li className="flex items-start gap-2">
<span className="text-red-500 mt-0.5"></span>
<span>Limited to knowledge cutoff</span>
</li>
</ul>
</div>
<div className="p-6 bg-primary/5 rounded-lg border border-primary/20">
<h4 className="text-lg font-semibold text-foreground mb-3">With MCP + TPMJS</h4>
<ul className="space-y-3 text-foreground-secondary">
<li className="flex items-start gap-2">
<span className="text-green-500 mt-0.5"></span>
<span>Execute code in 40+ languages</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-500 mt-0.5"></span>
<span>Fetch data from any URL</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-500 mt-0.5"></span>
<span>Search the web in real-time</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-500 mt-0.5"></span>
<span>Use specialized tools</span>
</li>
</ul>
</div>
</div>
<div className="text-center">
<p className="text-foreground-secondary">
MCP is an <strong>open protocol</strong> by Anthropic for connecting AI to external
capabilities.
</p>
</div>
</div>
),
},
{
id: 'step-1-collection',
title: 'Step 1: Create a Collection',
subtitle: 'Group the tools you want to use',
icon: '📦',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
Collections bundle related tools together. Create one with the tools you need.
</p>
<div className="max-w-2xl mx-auto space-y-6">
<div className="flex items-start gap-4 p-4 bg-surface-secondary rounded-lg">
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center text-primary font-bold">
1
</div>
<div>
<p className="text-foreground font-medium">Go to Collections</p>
<p className="text-foreground-secondary text-sm">
Navigate to{' '}
<span className="font-mono bg-background px-2 py-0.5 rounded">
Dashboard Collections
</span>
</p>
</div>
</div>
<div className="flex items-start gap-4 p-4 bg-surface-secondary rounded-lg">
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center text-primary font-bold">
2
</div>
<div>
<p className="text-foreground font-medium">Create New Collection</p>
<p className="text-foreground-secondary text-sm">
Give it a name like "My Development Tools" or "Research Assistant"
</p>
</div>
</div>
<div className="flex items-start gap-4 p-4 bg-surface-secondary rounded-lg">
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center text-primary font-bold">
3
</div>
<div>
<p className="text-foreground font-medium">Add Tools</p>
<p className="text-foreground-secondary text-sm">
Search for and add tools you want: code execution, web fetching, etc.
</p>
</div>
</div>
</div>
<div className="text-center">
<Link href="/dashboard/collections">
<Button variant="default">Create a Collection </Button>
</Link>
</div>
</div>
),
},
{
id: 'step-2-mcp-url',
title: 'Step 2: Get Your MCP URL',
subtitle: 'Each collection has a unique MCP endpoint',
icon: '🔗',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
Your collection page shows the MCP URL. Just copy it!
</p>
<div className="max-w-3xl mx-auto">
<div className="bg-surface-secondary rounded-lg border border-border overflow-hidden">
<div className="p-4 border-b border-border bg-background">
<p className="font-medium text-foreground">Collection: My Dev Tools</p>
<p className="text-sm text-foreground-tertiary">5 tools</p>
</div>
<div className="p-4">
<p className="text-sm font-medium text-foreground mb-2">MCP Server URL</p>
<div className="flex items-center gap-2">
<code className="flex-1 px-3 py-2 bg-background rounded border border-border text-sm font-mono text-foreground-secondary overflow-x-auto">
https://tpmjs.com/mcp/c/your-collection-uid
</code>
<Button variant="secondary" size="sm">
<Icon icon="copy" size="xs" className="mr-1" />
Copy
</Button>
</div>
</div>
</div>
</div>
<div className="max-w-2xl mx-auto p-4 bg-primary/5 border border-primary/20 rounded-lg">
<p className="text-sm text-foreground">
<strong>💡 Tip:</strong> The URL format is{' '}
<code className="bg-background px-1.5 py-0.5 rounded text-xs">
tpmjs.com/mcp/c/{'{collection-uid}'}
</code>
you can also find it on your collection's detail page.
</p>
</div>
</div>
),
},
{
id: 'step-3-claude',
title: 'Step 3: Configure Claude Desktop',
subtitle: 'Add the MCP server to your config file',
icon: '🖥️',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
Open your Claude Desktop config file and add the TPMJS MCP server.
</p>
<div className="max-w-3xl mx-auto space-y-4">
<div className="p-3 bg-surface-secondary rounded-lg">
<p className="text-sm font-medium text-foreground mb-1">Config File Location</p>
<div className="space-y-1 text-sm text-foreground-secondary font-mono">
<p>
<span className="text-foreground-tertiary">macOS:</span> ~/Library/Application
Support/Claude/claude_desktop_config.json
</p>
<p>
<span className="text-foreground-tertiary">Windows:</span>{' '}
%APPDATA%\Claude\claude_desktop_config.json
</p>
</div>
</div>
<div className="bg-background rounded-lg border border-border overflow-hidden">
<div className="px-4 py-2 bg-surface-secondary border-b border-border">
<p className="text-sm font-medium text-foreground">claude_desktop_config.json</p>
</div>
<pre className="p-4 text-sm overflow-x-auto">
<code className="text-foreground-secondary">{`{
"mcpServers": {
"tpmjs-dev-tools": {
"command": "npx",
"args": [
"mcp-remote",
"https://tpmjs.com/mcp/c/your-collection-uid"
]
}
}
}`}</code>
</pre>
</div>
</div>
<div className="text-center space-y-2">
<p className="text-foreground-secondary text-sm">
Replace <code className="bg-surface-secondary px-1.5 rounded">your-collection-uid</code>{' '}
with your actual collection UID
</p>
<p className="text-foreground-tertiary text-sm">
💡 Restart Claude Desktop after saving the config
</p>
</div>
</div>
),
},
{
id: 'step-3-cursor',
title: 'Alternative: Configure Cursor',
subtitle: 'Same concept, slightly different config',
icon: '✏️',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
Cursor also supports MCP! Add the server in Cursor settings.
</p>
<div className="max-w-3xl mx-auto space-y-4">
<div className="p-3 bg-surface-secondary rounded-lg">
<p className="text-sm font-medium text-foreground mb-1">Open Cursor Settings</p>
<p className="text-sm text-foreground-secondary">
<code className="bg-background px-1.5 py-0.5 rounded">
Settings Features MCP Servers + Add Server
</code>
</p>
</div>
<div className="bg-background rounded-lg border border-border overflow-hidden">
<div className="px-4 py-2 bg-surface-secondary border-b border-border">
<p className="text-sm font-medium text-foreground">mcp.json (or via Settings UI)</p>
</div>
<pre className="p-4 text-sm overflow-x-auto">
<code className="text-foreground-secondary">{`{
"mcpServers": {
"tpmjs": {
"command": "npx",
"args": [
"mcp-remote",
"https://tpmjs.com/mcp/c/your-collection-uid"
]
}
}
}`}</code>
</pre>
</div>
</div>
<div className="max-w-2xl mx-auto p-4 bg-primary/5 border border-primary/20 rounded-lg">
<p className="text-sm text-foreground">
<strong>Any MCP client works!</strong> The URL format is the same regardless of which
client you're using. Check your client's documentation for config file location.
</p>
</div>
</div>
),
},
{
id: 'step-4-use-tools',
title: 'Step 4: Use Your Tools!',
subtitle: 'Ask Claude to use any tool in your collection',
icon: '🎉',
content: (
<div className="space-y-8">
<p className="text-lg text-foreground-secondary text-center max-w-2xl mx-auto">
After restarting, Claude will have access to all the tools in your collection.
</p>
<div className="max-w-3xl mx-auto">
<div className="bg-surface-secondary rounded-lg border border-border overflow-hidden">
<div className="p-4 border-b border-border bg-background">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-orange-500/20 rounded-lg flex items-center justify-center">
<span className="text-sm">🦊</span>
</div>
<p className="font-medium text-foreground">Claude Desktop</p>
</div>
</div>
<div className="p-4 space-y-4">
<div className="flex justify-end">
<div className="bg-primary text-primary-foreground rounded-lg px-4 py-2 max-w-[80%]">
<p className="text-sm">
Run this Python code and show me the output: print("Hello from TPMJS!")
</p>
</div>
</div>
<div className="flex justify-start">
<div className="bg-background rounded-lg px-4 py-2 max-w-[80%] border border-border">
<p className="text-xs text-primary mb-2">
Using tool: unsandbox-executeCodeAsync
</p>
<p className="text-sm text-foreground">Here's the result:</p>
<pre className="mt-2 p-2 bg-surface-secondary rounded text-xs font-mono">
Hello from TPMJS!
</pre>
</div>
</div>
</div>
</div>
</div>
<div className="flex justify-center gap-3 text-sm text-foreground-secondary">
<span className="flex items-center gap-1">
<span className="text-green-500"></span> Code execution
</span>
<span className="flex items-center gap-1">
<span className="text-green-500"></span> Web fetching
</span>
<span className="flex items-center gap-1">
<span className="text-green-500"></span> Web search
</span>
<span className="flex items-center gap-1">
<span className="text-green-500"></span> And more!
</span>
</div>
</div>
),
},
{
id: 'complete',
title: "You're Connected!",
subtitle: 'Your AI now has superpowers',
icon: '🚀',
content: (
<div className="space-y-8 text-center">
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
That's it! Your AI assistant can now use any tool in your TPMJS collection.
</p>
<div className="flex flex-wrap justify-center gap-4">
<Link href="/dashboard/collections">
<Button size="lg">Manage Collections</Button>
</Link>
<Link href="/docs">
<Button variant="secondary" size="lg">
View Full Documentation
</Button>
</Link>
</div>
<div className="max-w-2xl mx-auto pt-8 border-t border-border mt-8">
<h4 className="text-lg font-semibold text-foreground mb-4">Quick Reference</h4>
<div className="grid md:grid-cols-2 gap-4 text-left">
<div className="p-4 bg-surface-secondary rounded-lg">
<p className="font-medium text-foreground">Collection MCP URL</p>
<code className="text-xs text-foreground-tertiary font-mono">
tpmjs.com/mcp/c/{'{uid}'}
</code>
</div>
<div className="p-4 bg-surface-secondary rounded-lg">
<p className="font-medium text-foreground">Individual Tool MCP URL</p>
<code className="text-xs text-foreground-tertiary font-mono">
tpmjs.com/mcp/t/{'{tool-slug}'}
</code>
</div>
</div>
<p className="text-sm text-foreground-tertiary mt-4">
You can also use individual tools without creating a collection!
</p>
</div>
</div>
),
},
];
export default function McpTutorialPage(): React.ReactElement {
const [currentSlide, setCurrentSlide] = useState(0);
const goToSlide = (index: number) => {
setCurrentSlide(Math.max(0, Math.min(slides.length - 1, index)));
};
const nextSlide = () => goToSlide(currentSlide + 1);
const prevSlide = () => goToSlide(currentSlide - 1);
const slide = slides[currentSlide];
const progress = ((currentSlide + 1) / slides.length) * 100;
if (!slide) {
return <></>;
}
return (
<div className="min-h-screen bg-background flex flex-col">
<AppHeader />
{/* Progress bar */}
<div className="w-full h-1 bg-surface-secondary">
<div
className="h-full bg-primary transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
<main className="flex-1 flex flex-col">
{/* Navigation header */}
<div className="border-b border-border">
<div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
<Link
href="/docs/tutorials"
className="flex items-center gap-2 text-foreground-secondary hover:text-foreground transition-colors"
>
<Icon icon="arrowLeft" size="sm" />
<span>Back to Tutorials</span>
</Link>
<div className="text-sm text-foreground-secondary">
{currentSlide + 1} / {slides.length}
</div>
</div>
</div>
{/* Slide content */}
<div className="flex-1 flex items-center justify-center px-4 py-8">
<div className="w-full max-w-5xl">
{/* Slide header */}
<div className="text-center mb-12">
{slide.icon && <span className="text-6xl mb-4 block">{slide.icon}</span>}
<h1 className="text-3xl md:text-4xl font-bold text-foreground mb-3">{slide.title}</h1>
{slide.subtitle && (
<p className="text-lg text-foreground-secondary">{slide.subtitle}</p>
)}
</div>
{/* Slide content */}
<div className="mb-12">{slide.content}</div>
</div>
</div>
{/* Navigation footer */}
<div className="border-t border-border">
<div className="max-w-6xl mx-auto px-4 py-4">
{/* Slide indicators */}
<div className="flex justify-center gap-2 mb-4">
{slides.map((s, index) => (
<button
key={s.id}
type="button"
onClick={() => goToSlide(index)}
className={`w-3 h-3 rounded-full transition-colors ${
index === currentSlide
? 'bg-primary'
: index < currentSlide
? 'bg-primary/40'
: 'bg-surface-secondary'
}`}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
{/* Navigation buttons */}
<div className="flex items-center justify-between">
<Button
variant="secondary"
onClick={prevSlide}
disabled={currentSlide === 0}
className="min-w-[120px]"
>
<Icon icon="arrowLeft" size="xs" className="mr-2" />
Previous
</Button>
{currentSlide === slides.length - 1 ? (
<Link href="/dashboard/collections">
<Button className="min-w-[120px]">Get Started </Button>
</Link>
) : (
<Button onClick={nextSlide} className="min-w-[120px]">
Next
</Button>
)}
</div>
</div>
</div>
</main>
<AppFooter />
</div>
);
}

View file

@ -0,0 +1,127 @@
import { Icon } from '@tpmjs/ui/Icon/Icon';
import Link from 'next/link';
import { AppFooter } from '~/components/AppFooter';
import { AppHeader } from '~/components/AppHeader';
interface Tutorial {
title: string;
description: string;
icon: string;
href: string;
duration: string;
steps: number;
}
const tutorials: Tutorial[] = [
{
title: 'Build Your First AI Agent',
description:
'Create a custom AI assistant with tool integration and persistent conversations. Learn how to set up API keys, configure agents, and attach tools.',
icon: '🤖',
href: '/docs/tutorials/agents',
duration: '5 min',
steps: 7,
},
{
title: 'Connect MCP to Your AI',
description:
'Add TPMJS tools to Claude Desktop, Cursor, or any MCP-compatible client. Create collections and configure your AI to use external tools.',
icon: '🔌',
href: '/docs/tutorials/mcp',
duration: '4 min',
steps: 8,
},
];
export default function TutorialsPage(): React.ReactElement {
return (
<div className="min-h-screen bg-background flex flex-col">
<AppHeader />
<main className="flex-1">
<div className="max-w-4xl mx-auto px-4 py-12">
{/* Header */}
<div className="mb-12">
<div className="flex items-center gap-4 mb-6">
<Link
href="/docs"
className="text-foreground-secondary hover:text-foreground transition-colors"
>
<Icon icon="arrowLeft" size="sm" />
</Link>
<div>
<h1 className="text-3xl font-bold text-foreground">Tutorials</h1>
<p className="text-foreground-secondary mt-1">
Step-by-step guides to get you started with TPMJS
</p>
</div>
</div>
</div>
{/* Tutorial Cards */}
<div className="space-y-6">
{tutorials.map((tutorial) => (
<Link key={tutorial.href} href={tutorial.href} className="block group">
<div className="p-6 bg-surface-secondary rounded-lg border border-border hover:border-primary/50 transition-all hover:shadow-lg">
<div className="flex items-start gap-6">
<div className="text-5xl">{tutorial.icon}</div>
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<h2 className="text-xl font-semibold text-foreground group-hover:text-primary transition-colors">
{tutorial.title}
</h2>
</div>
<p className="text-foreground-secondary mb-4">{tutorial.description}</p>
<div className="flex items-center gap-4 text-sm text-foreground-tertiary">
<span className="flex items-center gap-1"> {tutorial.duration}</span>
<span className="flex items-center gap-1">📄 {tutorial.steps} steps</span>
</div>
</div>
<div className="flex items-center text-foreground-tertiary group-hover:text-primary transition-colors text-xl">
</div>
</div>
</div>
</Link>
))}
</div>
{/* More Resources */}
<div className="mt-12 pt-8 border-t border-border">
<h3 className="text-lg font-semibold text-foreground mb-4">More Resources</h3>
<div className="grid md:grid-cols-2 gap-4">
<Link href="/docs">
<div className="p-4 bg-background border border-border rounded-lg hover:border-primary/50 transition-colors">
<div className="flex items-center gap-3">
<span className="text-2xl">📚</span>
<div>
<p className="font-medium text-foreground">Full Documentation</p>
<p className="text-sm text-foreground-secondary">
Complete API reference and guides
</p>
</div>
</div>
</div>
</Link>
<Link href="/docs/agents">
<div className="p-4 bg-background border border-border rounded-lg hover:border-primary/50 transition-colors">
<div className="flex items-center gap-3">
<span className="text-2xl">🤖</span>
<div>
<p className="font-medium text-foreground">Agents Documentation</p>
<p className="text-sm text-foreground-secondary">
In-depth AI agents reference
</p>
</div>
</div>
</div>
</Link>
</div>
</div>
</div>
</main>
<AppFooter />
</div>
);
}