{"schema":"brainfor/v1","product":"brainfor.ai","surface":"mcp_onboarding","transport":"mcp_jsonrpc — POST /mcp (Streamable HTTP JSON responses) + stdio (`npm run mcp`); REST /mcp/tools/* kept for curl; Smithery URL package + MCP OAuth 2.1/PKCE","tools":["start_onboarding","get_onboarding_status","get_invite_link","set_invite_alias","disable_invite_link","enable_invite_link","rotate_send_me_link","get_send_me_link","set_notification_email","confirm_notification_email"],"endpoints":{"discovery":"https://api.brainfor.ai/mcp","mcp_jsonrpc":"https://api.brainfor.ai/mcp","start_onboarding":"https://api.brainfor.ai/mcp/tools/start_onboarding","get_onboarding_status":"https://api.brainfor.ai/mcp/tools/get_onboarding_status","get_invite_link":"https://api.brainfor.ai/mcp/tools/get_invite_link","set_invite_alias":"https://api.brainfor.ai/mcp/tools/set_invite_alias","disable_invite_link":"https://api.brainfor.ai/mcp/tools/disable_invite_link","enable_invite_link":"https://api.brainfor.ai/mcp/tools/enable_invite_link","rotate_send_me_link":"https://api.brainfor.ai/mcp/tools/rotate_send_me_link","get_send_me_link":"https://api.brainfor.ai/mcp/tools/get_send_me_link","set_notification_email":"https://api.brainfor.ai/mcp/tools/set_notification_email","confirm_notification_email":"https://api.brainfor.ai/mcp/tools/confirm_notification_email","verify_notification_email":"https://api.brainfor.ai/onboarding/verify-email","human_how_to":"https://api.brainfor.ai/onboarding/human-how-to","server_card":"https://api.brainfor.ai/.well-known/mcp/server-card.json","oauth_protected_resource":"https://api.brainfor.ai/.well-known/oauth-protected-resource","oauth_authorization_server":"https://api.brainfor.ai/.well-known/oauth-authorization-server","oauth_authorize":"https://api.brainfor.ai/oauth/authorize","oauth_token":"https://api.brainfor.ai/oauth/token","oauth_register":"https://api.brainfor.ai/oauth/register","agent":"https://api.brainfor.ai/agent","invite_status":"https://api.brainfor.ai/invite/status","invite_sync":"https://api.brainfor.ai/invite/sync","invite_alias_join":"https://api.brainfor.ai/join/u/{alias}","github_connect":"https://api.brainfor.ai/connect","github_app_installations":"https://github.com/settings/installations","app_install_setup_callback":"https://api.brainfor.ai/app/install/callback"},"client_config":{"streamable_http":{"url":"https://api.brainfor.ai/mcp","note":"POST JSON-RPC 2.0 (initialize, tools/list, tools/call). Prefer Authorization: Bearer from MCP OAuth. GET returns this discovery document."},"stdio":{"command":"npm","args":["run","mcp","-w","@brainfor/api"],"cwd":"<path-to-brainfor-monorepo>","note":"Local first-party fallback when the client only supports stdio. Loads .env; shares Postgres registry when DATABASE_URL is set. Stdio does not use MCP OAuth."},"smithery":{"server_card":"https://api.brainfor.ai/.well-known/mcp/server-card.json","publish_example":"smithery mcp publish \"https://api.brainfor.ai/mcp\" -n @your-org/brainfor","note":"Host this API on public HTTPS, then publish the /mcp URL to Smithery (or equivalent). Server card lists join tools for scan-without-auth."}},"oauth":{"require_auth":true,"preferred_identity":"bearer","github_login_demo_only":true,"refresh_supported":true,"access_token_ttl_seconds":3600,"refresh_token_ttl_seconds":2592000,"reauthorize_note":"Prefer grant_type=refresh_token when access expires. Full /oauth/authorize reuses Connect session; no session auto-forwards to /auth/github (skips Connect page); same client_id skips consent within the browser session (prompt=consent forces the Approve page).","protected_resource_metadata":"https://api.brainfor.ai/.well-known/oauth-protected-resource","authorization_server_metadata":"https://api.brainfor.ai/.well-known/oauth-authorization-server","authorization_endpoint":"https://api.brainfor.ai/oauth/authorize","token_endpoint":"https://api.brainfor.ai/oauth/token","registration_endpoint":"https://api.brainfor.ai/oauth/register","scopes":["mcp:join"]},"invite_protocol":{"decision_rule":"Invite accept/reject decisions MUST be made through Git (commit + push of command files under 00_System/invites/). Projection files and this API status are read-only knowledge. Editing a projection status field does not authorize or accept. Route Grants are created only by the service after a validated accept.","surface":"github_first_git","authorization":"route_grant_required","paths":{"outbound_request":"00_System/invites/outbound/<peer>.request.json","outbound_projection":"00_System/invites/outbound/<invite_id>.json","inbound_projection":"00_System/invites/inbound/<invite_id>.json","inbound_accept":"00_System/invites/inbound/<invite_id>.accept.json","inbound_reject":"00_System/invites/inbound/<invite_id>.reject.json"},"accept_example":{"path":"00_System/invites/inbound/<invite_id>.accept.json","body":{"schema":"brainfor/v1","type":"invite_accept","invite_id":"<invite_id>"}},"reliability":{"after_edit":"Accept is incomplete until git commit AND push to the default branch succeed. Local edits alone do nothing.","webhook":"Live path: GitHub push webhook → service validates → grants + re-projects both repos.","sync":"If webhook/tunnel is down: after push, POST https://api.brainfor.ai/invite/sync (session) to re-read *.accept.json / *.request.json from GitHub and apply + re-project."},"endpoints":{"agent":"https://api.brainfor.ai/agent","invite_status":"https://api.brainfor.ai/invite/status","invite_sync":"https://api.brainfor.ai/invite/sync","mcp":"https://api.brainfor.ai/mcp"}},"notes":["Invite accept/reject decisions MUST be made through Git (commit + push of command files under 00_System/invites/). Projection files and this API status are read-only knowledge. Editing a projection status field does not authorize or accept. Route Grants are created only by the service after a validated accept.","Join only via MCP tools: start_onboarding → human connectUrl + installUrl → get_onboarding_status (includes invites statuses).","Human how-to: start_onboarding + get_onboarding_status always return humanManual (chat summary + path + openUrl). GET /onboarding/human-how-to serves the same markdown pre-workspace. Agents paste summary; best-effort open URL.","Readiness: status/start return readiness.blockers[] + readiness.next (stable codes) + humanTasks (MCP authorize / Connect / App install). HTTP 401 under require-auth includes blocker (mcp_oauth_required). If 401 or readiness.next: do not loop tools — one human action.","Permanent invite: get_invite_link returns /join/u/{alias} anytime (auto default if missing); set_invite_alias renames under once/30d policy; disable/enable_invite_link pause without quota. Projection 00_System/invites/invite-link.json.","Legacy send-me dual-read: rotate_send_me_link issues /join?token=… (secret once); get_send_me_link status/grace. Prefer get_invite_link for sharing.","Notification email: get_onboarding_status.notificationEmail.githubPrefill may show GitHub profile email from Connect; set_notification_email (email optional when prefill present) → verify (GET /onboarding/verify-email or confirm_notification_email). Never auto-verify; notify-only; never authorizes. Digests + verified + profile prefill in Postgres when DATABASE_URL set.","Invite accept/reject: Git command files under 00_System/invites/ then push; POST /invite/sync if webhook missed. No MCP accept tools.","Auth: MCP OAuth 2.1 + PKCE Bearer is preferred identity (identity.preferred=oauth). github_login is demo-only (identity.demoShortcut=true when used). Prefer refresh_token over full re-authorize; browser re-authorize skips consent for already-approved client_id in the same session; GET /oauth/authorize with no session auto-forwards to /auth/github.","Forbidden: list/read/search context, arbitrary Git writes, invite/accept MCP tools."]}