Expose an MCP server from your app Your app can be an MCP server: AI assistants (Claude as a connector, Claude Code, LM Studio…) connect to it and call tools you define, authenticated per end-user via OAuth. The platform handles the whole transport (JSON-RPC 2.0 over Streamable HTTP) and the OAuth — you just register tools. One call: mountMcp import { mountMcp, currentUser } from "./.onvibe/helpers.ts"; export default async function handler(req: Request): Promise { const mcp = await mountMcp(req, { auth: "oauth", // authenticate each MCP client per end-user tools: [ { name: "list_notes", description: "List the signed-in user's notes", inputSchema: { type: "object", properties: {} }, handler: async (_args, ctx) => await listNotes(ctx.user!.id), }, { name: "create_note", description: "Create a note", inputSchema: { type: "object", properties: { text: { type: "string" } }, required: ["text"], }, handler: async (args, ctx) => await createNote(ctx.user!.id, String(args.text)), }, ], }); if (mcp) return mcp; // it was an MCP request (/mcp) — handled // ...the rest of your app (normal web UI) } mountMcp returns a Response for MCP requests (path /mcp) and null otherwise, so it composes with your existing routes. It handles initialize, ping, tools/list, tools/call, notifications, batching, CORS and the session headers for you. Each tool handler(args, ctx) receives the call arguments and ctx.user — the authenticated end-user { id, email } (or null if auth: "none"). Use ctx.user.id as the stable key for that person's data. Return a string, a JSON-serializable value, or an MCP content object; mountMcp wraps it. Turning on OAuth (required for auth: "oauth") MCP OAuth authenticates against your app's managed users, so the app must have user accounts: set_access_policy({ project_id: "my-app", policy: "signup" }) // or "allowlist" That's it. The platform then acts as the OAuth Authorization Server for your app: - It serves discovery (/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server), Dynamic Client Registration, and the authorize/token endpoints on your app's domain. - When a user adds your app's /mcp URL in their AI client, they're redirected to **your app's login** (the same managed-auth login), approve access, and a scoped token is issued — no API keys to copy by hand. - That token arrives at your /mcp verified; currentUser() / ctx.user resolves to that end-user. The client's connection URL is https:///mcp (works on the .onvibe.run URL and on custom domains). Notes - The /mcp path is reserved for this — keep your MCP endpoint there. - auth: "none" exposes tools with no authentication (public data only). Prefer oauth for anything user-specific. - Manage who can connect with the usual account tools (create_app_user, add_allowed_email, remove_app_user) — MCP access follows the same accounts as the rest of your app.