Busymate AI

Dezvoltatori

Dați-i asistentului dumneavoastră AI instrumente reale, prin MCP

Dați-i asistentului instrumente reale prin MCP, standardul deschis pentru conectarea AI la sistemele dumneavoastră. Lansați-l pe web, iOS, Android și desktop. Administrați totul din orice client MCP.

claude mcp add --transport http busymate-ai https://busymate.ai/mcp
TERMINAL$claude mcp add --transport http busymate-ai https://busymate.ai/mcpconectatJSON-RPC 2.0 · tools/call{ "jsonrpc": "2.0", "id": 12, "method": "tools/call", "params": { "name": "get_my_account", "arguments": {} } }{ "jsonrpc": "2.0", "id": 12, "result": { "content": [{ "type": "text", "text": "…" }] } }

Căi de intrare

Alegeți de unde începeți

Adăugați asistentul pe site-ul dumneavoastră

Un singur script tag pe orice pagină permiteți — launcherul și chatul pentru vizitatori funcționează imediat.

Puneți asistență AI în aplicația dumneavoastră iOS

Încărcați chatul într-un WKWebView; o punte mică, din trei mesaje, vă autentifică utilizatorii.

Puneți asistență AI în aplicația dumneavoastră Android

Încărcați chatul într-un WebView; o singură interfață JavaScript vă autentifică utilizatorii.

Conectați-vă serverul MCP ca instrumente

Propriul dumneavoastră server MCP devine acțiunile asistentului, în numele fiecărui client.

Administrați fiecare spațiu de lucru din terminal

Conduceți platforma din Claude Code, Cursor sau orice client MCP, prin OAuth.

Lăsați agenții AI să vă citească site-ul

O hartă text simplu a site-ului dumneavoastră la /llms.txt, scrisă pentru agenți AI.

01Start rapid

Cum se leagă totul

Aplicația dumneavoastră rămâne sursa de adevăr. Asistentul primește un token semnat, de scurtă durată, care spune cine este prezent, și vă apelează instrumentele ca actor separat, cu drepturi limitate.

Clienții dumneavoastrăSite-ul sau aplicația dumneavoastrăAsistentSistemele dumneavoastrăSetările dumneavoastrăse aplică automat

01

Aplicația dumneavoastră

Păstrează identitatea și datele de cont; semnează un token de două minute care spune cine este autentificat.

02

Asistentul

Aplică setările spațiului dumneavoastră de lucru: conținut, modele, niveluri de acces la instrumente, pași de confirmare, preluare.

03

Serverul dumneavoastră MCP

Răspunde la instrumente pentru un singur utilizator o dată, luând utilizatorul din tokenul bearer al celui autentificat — niciodată din argumentele instrumentului.

7 moduri de conectare, un singur asistent: Embed web · Clienți autentificați · iOS · Android · Desktop · API REST · Serverul dumneavoastră MCP

YOUR HELP SITErobots-aware1–50 pagesIndexRetrieve for an answerwith a source

02Clienți autentificați

Recunoașteți clientul deja autentificat

Pentru ca asistentul să poată avea încredere în cine îl întreabă, un singur endpoint autentificat din backendul dumneavoastră semnează un token de scurtă durată (un JWT ES256) cu id-ul stabil al clientului și câteva câmpuri sigure de afișare.

Tokenul trăiește cel mult 120 secunde, poartă un nonce unic și un jti și numește spațiul dumneavoastră de lucru. Cheia privată și sesiunea produsului dumneavoastră nu ajung niciodată în browser sau în chat.

Your backendThe browserThe assistantsigns the tokenthe key never leavescarries itchecks your JWKS120s maxchecked
server/bmai-identity.tstypescript
import { SignJWT, importJWK } from "jose";

// POST https://YOUR-PRODUCT-DOMAIN/api/bmai/identity — requires YOUR OWN logged-in product session.
app.post("/api/bmai/identity", requireSession, async (req, res) => {
  // Fresh on EVERY mint. Never persist the launch token/nonce in localStorage,
  // sessionStorage, cookies, React state, or module state: every assistant
  // launch consumes this pair exactly once.
  const nonce = typeof req.body?.nonce === "string" ? req.body.nonce : "";
  if (!/^[A-Za-z0-9_-]{32,200}$/.test(nonce)) return res.status(400).json({ error: "invalid_nonce" });
  const key = await importJWK(JSON.parse(process.env.AI_LAUNCH_PRIVATE_JWK), "ES256");
  const token = await new SignJWT({
      "tenant_id": "00000000-0000-0000-0000-000000000000", // Your product's registered tenant claim
      nonce,                               // equals the sibling field below
      name: req.user.displayName,          // optional low-sensitivity display claim
    })
    .setProtectedHeader({ alg: "ES256", kid: process.env.AI_LAUNCH_KEY_ID })
    .setIssuer("https://YOUR-PRODUCT-DOMAIN (set when you register the provider)")
    .setAudience("busymate-ai")
    .setSubject(req.user.id)               // IMMUTABLE internal account id; never email/phone/session id
    .setJti(crypto.randomUUID())           // one-time (replay-protected)
    .setIssuedAt()
    .setExpirationTime("120s")               // <= registered max age (120s)
    .sign(key);
  res.set("Cache-Control", "no-store");
  res.status(201).json({ token, nonce, expiresIn: 120 });
});

Tokenul spune cine este acolo, nu ce are voie să facă. Țineți soldurile, dispozitivele, setările și fiecare modificare în spatele unor instrumente care răspund pentru un singur utilizator.

03Web și pagină întreagă

Un singur script pentru un launcher încorporat

SDK-ul cere identitatea backendului dumneavoastră atunci când are nevoie de una, funcționează pentru vizitatori, se reîmprospătează după autentificare și delogare, deschide linkurile externe în afara cadrului și nu are nevoie de cookie-uri terțe.

index.htmlhtml
<!-- Floating "bro" launcher for Your product.
     Anonymous chat works immediately on the allowed origins. -->
<script>
  function newLaunchNonce() {
    const bytes = new Uint8Array(32);
    crypto.getRandomValues(bytes);
    return btoa(String.fromCharCode(...bytes))
      .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
  }

  window.BusymateAI = {
    getIdentity: async () => {
      const accessToken = await getProductAccessToken(); // YOUR existing auth helper
      if (!accessToken) return null;
      const nonce = newLaunchNonce();
      const returnTo = new URL(location.href); returnTo.search = ""; returnTo.hash = "";
      const r = await fetch("https://YOUR-PRODUCT-DOMAIN/api/bmai/identity", {
        method: "POST", credentials: "include", cache: "no-store",
        headers: { "content-type": "application/json", authorization: "Bearer " + accessToken },
        body: JSON.stringify({ nonce, returnTo: returnTo.href }),
      });
      if (r.status === 401) return null; // signed out -> anonymous chat
      if (!r.ok) throw new Error("AI identity mint failed (" + r.status + ")");
      // MUST be a newly minted { token, nonce } pair on every call. Never
      // persist either value in localStorage, sessionStorage, cookies, React
      // state, or module state.
      const identity = await r.json();
      if (identity.nonce !== nonce) throw new Error("AI identity nonce mismatch");
      return { token: identity.token, nonce: identity.nonce };
    },
  };

  // Call after YOUR product completes login, logout, access-token/session
  // rotation, or account switch. Do not send an identity postMessage directly.
  window.refreshAssistantIdentity = () =>
    window.BusymateAI?.refreshIdentity?.() ?? Promise.resolve();
</script>
<script
  src="https://your-assistant.busymate.ai/embed/v1.js"
  data-assistant="your-assistant"
  data-label="Ask bro"
  async></script>

Deschideți chatul pe pagină întreagă, la adresa dumneavoastră

Când un utilizator autentificat deschide adresa asistentului dumneavoastră sau domeniul propriu, transmiteți tokenul de autentificare în fragmentul URL-ului. Pagina îl șterge înainte de schimb.

open-assistant.tstypescript
// Full-page open with identity in the URL FRAGMENT — never sent in the
// request line, referrer, or logs; the destination strips it before exchange.
function newLaunchNonce() {
  const bytes = new Uint8Array(32);
  crypto.getRandomValues(bytes);
  return btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}

const nonce = newLaunchNonce();
const accessToken = await getProductAccessToken(); // YOUR existing auth helper
if (!accessToken) throw new Error("Sign in before opening an identified assistant");
const returnTo = new URL(location.href); returnTo.search = ""; returnTo.hash = "";
const response = await fetch("https://YOUR-PRODUCT-DOMAIN/api/bmai/identity", {
  method: "POST", credentials: "include", cache: "no-store",
  headers: { "content-type": "application/json", authorization: "Bearer " + accessToken },
  body: JSON.stringify({ nonce, returnTo: returnTo.href }),
});
if (response.status === 401) throw new Error("Sign in before opening an identified assistant");
if (!response.ok) throw new Error("AI identity mint failed (" + response.status + ")");
const identity = await response.json();
if (typeof identity.token !== "string" || typeof identity.nonce !== "string") {
  throw new Error("AI identity mint returned an invalid response");
}
if (identity.nonce !== nonce) throw new Error("AI identity nonce mismatch");

const url = new URL("https://your-assistant.busymate.ai/");
url.hash = new URLSearchParams({
  bmai_token: identity.token,
  bmai_nonce: identity.nonce,
}).toString();
location.assign(url);

04iPhone

WKWebView cu o punte de mesaje îngustă

Permiteți doar cele trei mesaje versionate: cerere de identitate, răspuns de identitate și URL extern. Emiteți identitatea prin clientul API autentificat existent al aplicației.

AssistantBridge.swiftswift
// SDK source: https://busymate.ai/sdk/v1/ios/BusymateAI.swift
// Load https://your-assistant.busymate.ai/?channel=ios in a WKWebView.
final class AssistantBridge: NSObject, WKScriptMessageHandler {
  let webView: WKWebView

  func userContentController(_ controller: WKUserContentController,
                             didReceive message: WKScriptMessage) {
    guard message.name == "BusymateAI",
          let body = message.body as? [String: Any],
          body["type"] as? String == "busymate.ai.v1.identity_request"
    else { return }

    Task { // mint through YOUR authenticated API — never a key in the app
      let identity = try await api.mintLaunchIdentity()
      let payload: [String: Any] = [
        "type": "busymate.ai.v1.identity",
        "token": identity.token,
        "nonce": identity.nonce,
      ]
      let data = try JSONSerialization.data(withJSONObject: payload)
      let json = String(decoding: data, as: UTF8.self)
      await webView.evaluateJavaScript("window.postMessage(\(json), '*')")
    }
  }
}

05Android

WebView cu o singură interfață permisă

Păstrează navigarea pe originea AI a tenantului, trimite linkurile externe în browserul sistemului și nu expune metode native generice.

AssistantBridge.ktkotlin
// SDK source: https://busymate.ai/sdk/v1/android/BusymateAI.kt
// Load https://your-assistant.busymate.ai/?channel=android in a WebView.
class AssistantBridge(private val webView: WebView) {
  @JavascriptInterface
  fun postMessage(raw: String) {
    val message = JSONObject(raw)
    if (message.optString("type") != "busymate.ai.v1.identity_request") return

    lifecycleScope.launch { // mint through YOUR authenticated API client
      val identity = api.mintLaunchIdentity()
      val response = JSONObject()
        .put("type", "busymate.ai.v1.identity")
        .put("token", identity.token)
        .put("nonce", identity.nonce)
      webView.evaluateJavascript(
        "window.postMessage(${JSONObject.quote(response.toString())}, '*')", null
      )
    }
  }
}

webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(AssistantBridge(webView), "BusymateAINative")
// SupportChatNative + support.chat.v1.* remain accepted for shipped apps.

06Desktop

Același protocol se potrivește cu Electron, Tauri și shell-uri native

Folosiți un WebView izolat, blocați ferestrele noi în cadru, deschideți URL-urile sigure în exterior și răspundeți cererilor de identitate prin stratul privilegiat al aplicației.

assistant-renderer.tstypescript
import { mountBusymateAI } from "https://busymate.ai/sdk/v1/index.js";

// productAuth is a narrow preload/Tauri command bridge. It calls YOUR
// authenticated backend; no cookie, signing key, or refresh token is exposed
// to the renderer.
const assistant = await mountBusymateAI({
  assistant: "your-assistant",
  origin: "https://your-assistant.busymate.ai",
  label: "Ask bro",
  getIdentity: () => window.productAuth.mintAssistantIdentity(),
});

window.productAuth.onSessionChanged(() => assistant.refreshIdentity());
assistant.open();

// Electron main process (Tauri: use the equivalent shell/open allowlist):
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
  const target = new URL(url);
  if (target.protocol === "https:" || target.protocol === "http:") {
    void shell.openExternal(target.href);
  }
  return { action: "deny" };
});

07Instrumente MCP

Dați-i asistentului instrumente fără să-i dați baza de date cu clienți

Publicați scheme complete la descoperire. Dați fiecărui instrument unul dintre cele trei niveluri de acces, marcați modificările care au nevoie de un card de confirmare și reverificați autorizarea la fiecare apel.

Public

Oricine conversează îl poate apela. Prețuri, stare, funcții.

Identificat

Necesită un utilizator autentificat. Starea comenzilor, răspunsuri despre cont.

Delegat

Acționează în numele utilizatorului autentificat, printr-un token de actor cu drepturi limitate sau prin permisiunea OAuth a utilizatorului însuși.

Fiecare modificare este confirmată pe server. Instrumentele pe care le enumerați în confirm_tools se opresc la un card de confirmare înainte să ruleze; la fel și orice nume de instrument pe care asistentul nu îl recunoaște. Cadrele widget nu execută niciodată o modificare.

oauth-requirements.txttext
MCP endpoint ............ https://YOUR-DOMAIN/mcp
RFC 8707 resource ....... https://YOUR-DOMAIN/mcp   (the token is audience-bound to this)
AS metadata (RFC 8414) .. https://YOUR-DOMAIN/.well-known/oauth-authorization-server
Resource meta (RFC 9728)  https://YOUR-DOMAIN/.well-known/oauth-protected-resource
Client registration ..... Dynamic (RFC 7591) — public client, no secret
PKCE .................... S256 required (RFC 7636)
Authorization response .. iss parameter checked (RFC 9207)
Grants .................. authorization_code + refresh_token
Delegated tools/call .... no bearer -> 401; user derived from the bearer,
                          NEVER from an account id in tool arguments
Customer experience ..... one separate Authorize account tools action is expected;
                          use signed_actor_token instead for automatic SSO
delegated-call.jsonjson
// POST https://YOUR-DOMAIN/mcp
// Authorization: Bearer <the per-user OAuth token bro obtained>
{
  "jsonrpc": "2.0",
  "id": 12,
  "method": "tools/call",
  "params": { "name": "get_my_account", "arguments": {} }
}
// Your server verifies the bearer, derives the user from its signed subject,
// and returns ONLY that user's data.

Ce vorbește platforma

Același set de protocoale se aplică indiferent dacă platforma este clientul serverului dumneavoastră sau serverul clientului dumneavoastră MCP.

  • OAuth 2.1 cu PKCE (S256); clienții publici se înregistrează dinamic (RFC 7591).
  • Descoperire prin metadatele serverului de autorizare (RFC 8414) și metadatele resursei protejate (RFC 9728).
  • Grants: authorization_code și refresh_token; răspunsul de autorizare poartă issuer-ul (RFC 9207).
  • Indicatori de resursă (RFC 8707) atunci când platforma este clientul OAuth către serverul dumneavoastră MCP.
  • Schimb de tokenuri (RFC 8693) acolo unde este configurat.

08Preluare și analize

Stabiliți regulile pentru momentul în care intervine un om

Când predă discuția

Un client cere un om, un instrument eșuează, o rambursare depășește limita dumneavoastră, apare un cuvânt-cheie sau orice eveniment definit de dumneavoastră.

Cum este anunțată echipa dumneavoastră

Un singur Inbox; alocare manuală, pe rând sau către cel cu cele mai puține discuții deschise; alerte în aplicație, prin Web Push, APNs și Telegram personal.

Echipa dumneavoastră preia

Urmăriți conversația, intrați cu tot contextul, răspundeți în același chat; asistentul nu face nicio modificare cât timp un om este activ.

Analize

Întrebări repetate, cunoștințe lipsă și trasee eșuate, grupate din conversații reale, cu linkuri către dovezi.

09Login pentru spațiul de lucru

Păstrați-vă propria bază de utilizatori și propria autentificare

Configurați URL-urile de login și de cont ale spațiului de lucru în Consolă. Un vizitator care alege Autentificare părăsește cadrul, se autentifică în produsul dumneavoastră și revine exact la URL-ul de plecare. Backendul dumneavoastră furnizează apoi un token de autentificare de unică folosință; Busymate AI nu primește niciodată parola utilizatorului sau cheia dumneavoastră de semnare.

O modificare atinge întotdeauna doar datele proprii ale utilizatorului autentificat. Instrumentele de cont preiau clientul din actorul delegat, reverifică autorizarea la fiecare apel și cer confirmare pentru modificările pe care le configurați.

10Listă de verificare la lansare

Lista de verificare înainte de lansare

  1. 01Configurați brandingul, SEO, adresa web și întrebările sugerate.
  2. 02Înregistrați-vă autentificarea: issuer, JWKS, audiență, claims și vechimea tokenului.
  3. 03Conectați MCP, stabiliți nivelul de acces al fiecărui instrument, dovediți că citirile sunt limitate la propriul utilizator și că scrierile sunt confirmate.
  4. 04Stabiliți regulile de preluare, alocați oameni în Inbox, definiți programul și țintele de răspuns.
  5. 05Testați vizitatorii, utilizatorii autentificați, delogarea și schimbarea de cont, tokenurile reluate și un id de spațiu de lucru schimbat.
  6. 06Verificați chatul pe pagină întreagă, embedul, iOS, Android, desktopul, accesibilitatea și linkurile externe.
  7. 07Publicați doar versiunea pe care ați verificat-o; urmăriți starea conexiunilor și a domeniilor.

Sunteți gata să vă configurați spațiul de lucru?

Pagina Integrare din Consolă generează codul și setările pentru fiecare suprafață pornind de la setările dumneavoastră publicate.

Deschideți Consola

MCP de administrare

Administrați fiecare spațiu de lucru din orice client MCP

218 instrumente de administrare prin MCP, cu OAuth 2.1. Clientul deschide o autentificare în browser la prima conectare; nu se lipește nimic manual.

Documente de descoperire

Metadate ale serverului de autorizare (RFC 8414)
https://busymate.ai/.well-known/oauth-authorization-server/mcp
Metadate ale resursei protejate (RFC 9728)
https://busymate.ai/.well-known/oauth-protected-resource/mcp

Contul cu care vă autentificați decide ce spații de lucru poate administra clientul. Fiecare modificare cere confirmare.

Your MCP clientcreate_artifactJSON-RPCcreated: truehttps://your-assistant.busymate.ai/artifact/…VISIBILITYSitemapGallery

Claude Code

claude-code.shbash
claude mcp add --transport http busymate-ai https://busymate.ai/mcp

Administrează platforma din orice client MCP

Cursor, Claude Desktop și orice client care citește un mcp.json acceptă această intrare; clienții care primesc un URL remote folosesc endpointul de mai sus.

mcp.jsonjson
{
  "mcpServers": {
    "platform-management": {
      "type": "http",
      "url": "https://busymate.ai/mcp"
    }
  }
}

Conectați primul instrument chiar astăzi

Înregistrați-vă serverul MCP, alegeți cine poate folosi fiecare instrument, publicați. Asistentul îl poate folosi în același minut.