1// How a visitor connects their own AI to the hosted MCP 2// (worker/src/hosted-mcp.ts, OAuth in worker/src/oauth.ts), and what its 3// tools do: one guide, shown at /ai/ (pages/ai.astro, rendered at build 4// time) and on the jev panel's mcp tab (Panel.jsx), so nobody needs to know 5// the address to find it. The scopes and tools are the Worker's own 6// (hosted-tools.ts), so it never drifts from what the server offers. 7// `server` is the MCP's address; /ai/ also rewrites every `.server` to its 8// own origin as it loads, so dev and any other host show theirs. 9import { SCOPES, TOOLS } from '../../../worker/src/hosted-tools'; 10import { siteName } from './site.mjs'; 11 12const scopeWords = { play: 'play', publish: 'publish', null: 'any' }; 13const h = 'font-bold mt-5 mb-1'; 14const pre = 'bg-background border border-muted rounded px-3 py-2 overflow-x-auto my-2 font-mono text-xs'; 15const cell = 'border-t border-muted py-1 pr-2 align-top text-left'; 16 17export function ConnectAi({ server }) { 18 return ( 19 <div className="font-sans leading-relaxed" data-testid="connect-ai"> 20 <p> 21 Connect your own AI to {siteName}: Claude Code, Claude on the web or desktop, or any client that speaks the{' '} 22 <a className="underline" href="https://modelcontextprotocol.io"> 23 Model Context Protocol 24 </a> 25 . It plays Strudel code in your open tab, reads what the song logged, learns from the site's songs, and publishes 26 yours, which Jev screens and then shows to everyone. It is your AI, on your account: you pay for it, we host the 27 songs. 28 </p> 29 30 <h2 className={h}>1. Have an account</h2> 31 <p> 32 Sign in on the site (🔑 sign in, on the jev panel's you tab): a passkey, no password, no email. The app will act 33 as that account. 34 </p> 35 36 <h2 className={h}>2. Connect your AI</h2> 37 <p>The server's address:</p> 38 <pre className={pre}> 39 <code className="server">{server}</code> 40 </pre> 41 <p> 42 <b>Claude Code</b>, in a terminal: 43 </p> 44 <pre className={pre}> 45 <code> 46 claude mcp add --transport http {siteName} <span className="server">{server}</span> 47 </code> 48 </pre> 49 <p> 50 then, inside Claude Code, <code>/mcp</code> → {siteName} → authenticate. Your browser opens {siteName}'s sign-in. 51 </p> 52 <p> 53 <b>Claude</b> (claude.ai, Claude Desktop): <i>Customize → Connectors → Add custom connector</i>, paste the address, 54 and choose to sign in. 55 </p> 56 <p> 57 <b>Anything else</b>: add a remote MCP server over Streamable HTTP with that address. It uses OAuth 2.1 with PKCE, 58 per MCP's authorization spec; clients find everything else from the address. 59 </p> 60 61 <h2 className={h}>3. Allow it</h2> 62 <p>{siteName} shows which app is asking and where its access goes. You choose what it may do:</p> 63 <table className="w-full border-collapse my-2"> 64 <tbody> 65 {Object.entries(SCOPES).map(([scope, what]) => ( 66 <tr key={scope}> 67 <td className={cell}> 68 <code>{scope}</code> 69 </td> 70 <td className={cell}>{what}</td> 71 </tr> 72 ))} 73 </tbody> 74 </table> 75 <p className="opacity-75">Disconnect it any time: the account (👤, on the jev panel's you tab) lists your connected apps.</p> 76 77 <h2 className={h}>4. Open a tab</h2> 78 <p> 79 Open {siteName}, signed in, and click the page once (browsers keep sound off until you do). The jev panel's mcp tab 80 then says your AI is connected, with the tab's id: your AI can now play there. With several tabs open, it asks 81 which. 82 </p> 83 84 <h2 className={h}>5. Ask for a song</h2> 85 <p> 86 "Write me a Strudel song about a fairy who won't stop talking, where Jev picks the chorus", then listen, and ask 87 for changes. When you like it, "publish it". 88 </p> 89 90 <h2 className={h}>What it can do</h2> 91 <table className="w-full border-collapse my-2"> 92 <tbody> 93 <tr> 94 <th className={cell}>tool</th> 95 <th className={cell}>scope</th> 96 <th className={cell}>what it does</th> 97 </tr> 98 {TOOLS.map((t) => ( 99 <tr key={t.name}> 100 <td className={cell}> 101 <code>{t.name}</code> 102 </td> 103 <td className={cell}>{scopeWords[String(t.scope)]}</td> 104 <td className={cell}>{t.description}</td> 105 </tr> 106 ))} 107 </tbody> 108 </table> 109 110 <h2 className={h}>What it cannot do</h2> 111 <ul className="list-disc pl-5 space-y-1"> 112 <li>Reach anyone else's tabs. It reaches only tabs signed in to the account you connected it to.</li> 113 <li> 114 Act as you in the page. The code it plays runs in a sandbox, apart from the page, its cookies and your account, as 115 listeners' songs do; the page shows 🔒 above the editor while it is there. A site song it plays by name is the 116 site's own, as if you had clicked its card. 117 </li> 118 <li> 119 Change what runs. It can change how the editor looks and types (theme, font, keybindings), never your prebake 120 script, how code is evaluated, or where the sound goes. 121 </li> 122 <li> 123 Skip Jev. What it publishes is screened like anything a listener writes: spam, abuse, or code that does anything 124 but make music stays hidden. 125 </li> 126 <li> 127 Spend without limit. Jev's calls from its songs, and screening and scoring what it publishes, count against your 128 daily Jev budget; its requests are rate-limited per account. 129 </li> 130 </ul> 131 </div> 132 ); 133}