'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { apiFetch } from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Input, Label, Textarea } from '@/components/input'; import { StreamingLogs } from '@/components/streaming-logs'; import { InstallSnippets } from '@/components/install-snippets'; import { CodeBlock } from '@/components/code-block'; const EXAMPLE_PROMPTS = [ 'Read-only Postgres reader for the users and orders tables at db.example.com', 'Search and read pages from our Notion workspace via the Notion API', 'Wrap our internal HTTP API at api.acme.com — endpoints /search and /lookup', 'Stripe charges and customers (read-only)', ]; type Step = 'prompt' | 'building' | 'done'; interface BuildResult { serverId: string; publicUrl: string | null; } export default function NewServerPage() { const router = useRouter(); const [step, setStep] = useState('prompt'); const [name, setName] = useState(''); const [slug, setSlug] = useState(''); const [prompt, setPrompt] = useState(''); const [secretRows, setSecretRows] = useState<{ key: string; value: string }[]>([{ key: '', value: '' }]); const [error, setError] = useState(null); const [buildId, setBuildId] = useState(null); const [serverId, setServerId] = useState(null); const [result, setResult] = useState(null); const trySlug = (n: string) => n.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 32); async function submit() { setError(null); if (!name || !slug || prompt.length < 10) { setError('Name, slug and a prompt of at least 10 characters are required.'); return; } const secrets: Record = {}; for (const row of secretRows) { if (row.key && row.value) secrets[row.key.trim()] = row.value; } try { const res = await apiFetch<{ server: { id: string }; build: { id: string } }>( '/v1/servers', { method: 'POST', body: JSON.stringify({ name, slug, prompt, secrets }) }, ); setBuildId(res.build.id); setServerId(res.server.id); setStep('building'); } catch (e) { const detail = (e as { detail?: { error?: string } }).detail; setError(detail?.error ?? (e as Error).message); } } return (

New MCP server

STEP {step === 'prompt' ? '1' : step === 'building' ? '2' : '3'} / 3
{step === 'prompt' && (