diff --git a/apps/web/src/app/docs/api/page.tsx b/apps/web/src/app/docs/api/page.tsx
new file mode 100644
index 0000000..7e56d95
--- /dev/null
+++ b/apps/web/src/app/docs/api/page.tsx
@@ -0,0 +1,969 @@
+'use client';
+
+import { Badge } from '@tpmjs/ui/Badge/Badge';
+import { Button } from '@tpmjs/ui/Button/Button';
+import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
+import Link from 'next/link';
+import { useEffect, useState } from 'react';
+import { AppHeader } from '~/components/AppHeader';
+
+const NAV_SECTIONS = [
+ {
+ title: 'Getting Started',
+ items: [
+ { id: 'overview', label: 'Overview' },
+ { id: 'quick-start', label: 'Quick Start' },
+ { id: 'authentication', label: 'Authentication' },
+ ],
+ },
+ {
+ title: 'Public Endpoints',
+ items: [
+ { id: 'tools', label: 'Tools' },
+ { id: 'search', label: 'Search' },
+ { id: 'collections', label: 'Collections' },
+ { id: 'agents', label: 'Agents' },
+ { id: 'stats', label: 'Stats' },
+ ],
+ },
+ {
+ title: 'MCP Protocol',
+ items: [
+ { id: 'mcp-overview', label: 'Overview' },
+ { id: 'mcp-initialize', label: 'Initialize' },
+ { id: 'mcp-tools-list', label: 'Tools List' },
+ { id: 'mcp-tools-call', label: 'Tools Call' },
+ ],
+ },
+ {
+ title: 'Execution',
+ items: [
+ { id: 'execute-tool', label: 'Execute Tool' },
+ { id: 'streaming', label: 'Streaming' },
+ ],
+ },
+ {
+ title: 'Response Format',
+ items: [
+ { id: 'success', label: 'Success Response' },
+ { id: 'errors', label: 'Error Handling' },
+ { id: 'pagination', label: 'Pagination' },
+ ],
+ },
+];
+
+function SidebarNav({
+ activeSection,
+ onSectionClick,
+}: {
+ activeSection: string;
+ onSectionClick: (id: string) => void;
+}) {
+ return (
+
+ {NAV_SECTIONS.map((section) => (
+
+
+ {section.title}
+
+
+ {section.items.map((item) => (
+
+ onSectionClick(item.id)}
+ className={`block w-full text-left px-3 py-1.5 text-sm rounded-md transition-colors ${
+ activeSection === item.id
+ ? 'bg-primary/10 text-primary font-medium'
+ : 'text-foreground-secondary hover:text-foreground hover:bg-surface-elevated'
+ }`}
+ >
+ {item.label}
+
+
+ ))}
+
+
+ ))}
+
+ );
+}
+
+function DocSection({
+ id,
+ title,
+ children,
+}: {
+ id: string;
+ title: string;
+ children: React.ReactNode;
+}) {
+ return (
+
+
+ {title}
+
+ {children}
+
+ );
+}
+
+function EndpointCard({
+ method,
+ path,
+ description,
+ children,
+}: {
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
+ path: string;
+ description: string;
+ children?: React.ReactNode;
+}) {
+ const methodColors = {
+ GET: 'bg-green-500/10 text-green-500 border-green-500/30',
+ POST: 'bg-blue-500/10 text-blue-500 border-blue-500/30',
+ PUT: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',
+ DELETE: 'bg-red-500/10 text-red-500 border-red-500/30',
+ };
+
+ return (
+
+
+
+
+ {method}
+
+ {path}
+
+
{description}
+
+ {children &&
{children}
}
+
+ );
+}
+
+function ParamTable({
+ params,
+}: {
+ params: { name: string; type: string; required: boolean; description: string }[];
+}) {
+ return (
+
+
+
+
+ Parameter
+ Type
+ Required
+ Description
+
+
+
+ {params.map((param, i) => (
+
+ {param.name}
+ {param.type}
+
+ {param.required ? (
+
+ Yes
+
+ ) : (
+ No
+ )}
+
+ {param.description}
+
+ ))}
+
+
+
+ );
+}
+
+export default function APIDocsPage(): React.ReactElement {
+ const [activeSection, setActiveSection] = useState('overview');
+ const [mobileNavOpen, setMobileNavOpen] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ setActiveSection(entry.target.id);
+ }
+ });
+ },
+ { rootMargin: '-100px 0px -66%' }
+ );
+
+ NAV_SECTIONS.forEach((section) => {
+ section.items.forEach((item) => {
+ const element = document.getElementById(item.id);
+ if (element) observer.observe(element);
+ });
+ });
+
+ return () => observer.disconnect();
+ }, []);
+
+ const scrollToSection = (id: string) => {
+ const element = document.getElementById(id);
+ if (element) {
+ element.scrollIntoView({ behavior: 'smooth' });
+ setMobileNavOpen(false);
+ }
+ };
+
+ return (
+
+
+
+
+ {/* Mobile Navigation Toggle */}
+
+
setMobileNavOpen(!mobileNavOpen)}
+ className="flex items-center gap-2 text-sm font-medium text-foreground"
+ >
+ {mobileNavOpen ? '✕' : '☰'}
+ API Documentation
+
+ {mobileNavOpen && (
+
+
+
+ )}
+
+
+ {/* Desktop Sidebar */}
+
+
+
+
+ ← Back to Docs
+
+
API Reference
+
REST & MCP
+
+
+
+
+
+ {/* Main Content */}
+
+
+ {/* Hero */}
+
+
+ API
+ v1.0
+
+
+ TPMJS API Reference
+
+
+ REST API and MCP protocol for accessing tools, collections, and agents.
+
+
+
+ Base URL: {' '}
+ https://tpmjs.com/api
+
+
+
+
+ {/* ==================== GETTING STARTED ==================== */}
+
+
+ The TPMJS API provides programmatic access to the tool registry, collections, and
+ agents. There are two ways to interact with the API:
+
+
+
+
REST API
+
+ Standard REST endpoints for listing tools, searching, and executing. No
+ authentication required for public endpoints.
+
+
+
+
MCP Protocol
+
+ JSON-RPC 2.0 over HTTP for AI clients like Claude Desktop, Cursor, and others
+ that support Model Context Protocol.
+
+
+
+
+
+
+
+ Try these examples to get started immediately. All public endpoints work without
+ authentication.
+
+
+
+
+
1. List Tools
+
+
+
+
+
2. Search Tools
+
+
+
+
+
+ 3. Get Tool Details
+
+
+
+
+
+
+ 4. MCP Tools List (Collection)
+
+
+
+
+
+
+
+
+ Most public endpoints don't require authentication. Private endpoints (creating
+ collections, managing agents) require a session cookie from signing in.
+
+
+
+
+
Public (No Auth)
+
+ GET /api/tools - List and search tools
+ GET /api/public/collections - List public collections
+ GET /api/public/agents - List public agents
+ POST /api/mcp/[user]/[slug]/http - MCP protocol for public collections
+ GET /api/stats - Platform statistics
+
+
+
+
+
Authenticated
+
+ POST /api/collections - Create collection
+ POST /api/agents - Create agent
+ PUT /api/collections/[id] - Update collection
+ DELETE /api/agents/[id] - Delete agent
+
+
+
+
+
+ {/* ==================== PUBLIC ENDPOINTS ==================== */}
+
+
+
+
+
+
+
+
+
+
+
+
Response
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Response
+
+
+
+
+
+ {/* ==================== MCP PROTOCOL ==================== */}
+
+
+ TPMJS implements the Model Context Protocol (MCP) for AI clients. Each public
+ collection exposes an MCP endpoint that can be connected to Claude Desktop, Cursor,
+ or any MCP-compatible client.
+
+
+
+
Endpoint Format
+
+ POST https://tpmjs.com/api/mcp/[username]/[collection-slug]/http
+
+
+
+
+
+
Request Headers
+
+ Content-Type: application/json
+
+
+
+
Protocol
+
+ JSON-RPC 2.0 with MCP methods: initialize,{' '}
+ tools/list,{' '}
+ tools/call
+
+
+
+
+
+
+
+ Request
+
+ Response
+
+
+
+
+
+
+ Request
+
+ Response
+
+
+
+
+
+
+ Request
+
+ Response
+
+
+
+
+
Full cURL Example
+
+
+
+
+ {/* ==================== EXECUTION ==================== */}
+
+
+
+
+
+
+
+
+
+
+
+ The execute endpoint returns Server-Sent Events (SSE) for real-time streaming.
+
+
+
+
+
event: chunk
+
+ Streaming text from the AI agent
+
+
+
+
event: tokens
+
Token usage updates
+
+
+
event: complete
+
+ Final result with output and timing
+
+
+
+
event: error
+
Error if execution fails
+
+
+
+ JavaScript Example
+
+
+
+ {/* ==================== RESPONSE FORMAT ==================== */}
+
+
+ All API endpoints return a consistent JSON response format.
+
+
+
+
+
+
+ Errors include a code and message for debugging.
+
+
+
+
HTTP Status Codes
+
+
+ 200
+ Success
+
+
+ 400
+
+ Bad request / validation error
+
+
+
+ 401
+ Authentication required
+
+
+ 404
+ Resource not found
+
+
+ 429
+ Rate limit exceeded
+
+
+ 500
+ Internal server error
+
+
+
+
+
+
+
+ {/* CTA */}
+
+ Need More Help?
+
+ Check out the full documentation or try the interactive playground.
+
+
+
+
+
+
+
+ );
+}