Busymate AI

Desenvolvedores

Dê ferramentas reais ao seu assistente de IA com MCP

Dê ferramentas reais ao assistente por meio do MCP, o padrão aberto para conectar IA aos seus sistemas. Publique na web, no iOS, no Android e no desktop. Gerencie tudo por qualquer cliente MCP.

claude mcp add --transport http busymate-ai https://busymate.ai/mcp
TERMINAL$claude mcp add --transport http busymate-ai https://busymate.ai/mcpconectadoJSON-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": "…" }] } }

Caminhos de entrada

Escolha por onde começar

Adicione o assistente ao seu site

Uma tag de script em qualquer página que você permitir — o launcher e o chat para visitantes já funcionam.

Coloque suporte com IA dentro do seu app iOS

Carregue o chat em uma WKWebView; uma pequena ponte de três mensagens conecta seus usuários.

Coloque suporte com IA dentro do seu app Android

Carregue o chat em uma WebView; uma interface JavaScript conecta seus usuários.

Conecte seu servidor MCP como ferramentas

Seu próprio servidor MCP vira as ações do assistente, em nome de cada cliente.

Gerencie todo espaço de trabalho pelo terminal

Controle a plataforma pelo Claude Code, Cursor ou qualquer cliente MCP por OAuth.

Deixe agentes de IA lerem seu site

Um mapa em texto puro do seu site em /llms.txt, escrito para agentes de IA.

01Início rápido

Como tudo se encaixa

Seu app continua sendo a fonte da verdade. O assistente recebe um token assinado de curta duração que diz quem está presente e chama suas ferramentas como um ator separado e com escopo próprio.

Seus clientesSeu site ou appAssistenteSeus sistemasSuas configuraçõesaplicadas automaticamente

01

Seu app

Guarda a identidade e os dados da conta; assina um token de dois minutos dizendo quem está conectado.

02

O assistente

Aplica as configurações do seu espaço de trabalho: conteúdo, modelos, níveis de acesso das ferramentas, etapas de confirmação, transferência.

03

Seu servidor MCP

Responde as ferramentas para um usuário por vez, identificando-o pelo bearer token do login — nunca pelos argumentos da ferramenta.

7 formas de conectar, um assistente: Embed web · Clientes conectados · iOS · Android · Desktop · API REST · Seu servidor MCP

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

02Clientes conectados

Reconheça o cliente que já está conectado

Para que o assistente confie em quem está perguntando, um endpoint autenticado no seu backend assina um token de curta duração (um JWT ES256) com o seu id estável de cliente e alguns campos de exibição seguros.

O token dura no máximo 120 segundos, carrega um nonce e um jti de uso único e nomeia o seu tenant. A chave privada e a sessão do seu produto nunca chegam ao navegador nem ao 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 });
});

O token diz quem está ali, não o que essa pessoa pode fazer. Mantenha saldos, aparelhos, configurações e toda alteração atrás de ferramentas que respondem por um único usuário.

03Web e página inteira

Um script para um launcher embutido

O SDK pede a identidade ao seu backend quando precisa, funciona para visitantes, atualiza depois do login e do logout, abre links externos fora do frame e não precisa de cookies de terceiros.

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>

Abra o chat em página inteira no seu endereço

Quando um usuário conectado abre o endereço do seu assistente ou o seu domínio próprio, passe o token de login no fragmento da URL. A página o apaga antes da troca.

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 com uma ponte de mensagens estreita

Permita apenas as três mensagens versionadas: pedido de identidade, resposta de identidade e URL externa. Gere a identidade pelo cliente de API autenticado que o app já tem.

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 com uma única interface permitida

Mantenha a navegação na origem de IA do tenant, envie links externos ao navegador do sistema e não exponha métodos nativos de uso geral.

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

O mesmo protocolo serve para Electron, Tauri e shells nativos

Use uma WebView isolada, bloqueie novas janelas na view, abra URLs seguras fora do app e responda aos pedidos de identidade pela camada privilegiada do host.

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" };
});

07Ferramentas MCP

Dê ferramentas ao assistente sem dar a ele o seu banco de clientes

Publique schemas completos na descoberta. Dê a cada ferramenta um de três níveis de acesso, marque as alterações que precisam de cartão de confirmação e reconfira a autorização a cada chamada.

Pública

Qualquer pessoa no chat pode chamá-la. Preços, status, recursos.

Identificada

Precisa de um usuário conectado. Status de pedido, respostas sobre a conta.

Delegada

Age em nome do usuário conectado por um token de ator com escopo ou pela permissão OAuth do próprio usuário.

Toda alteração é confirmada no servidor. As ferramentas listadas em confirm_tools param em um cartão de confirmação antes de rodar; o mesmo vale para qualquer nome de ferramenta que o assistente não reconheça. Os frames de widget nunca executam uma alteração.

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.

O que a plataforma fala

O mesmo conjunto de protocolos vale tanto quando a plataforma é o cliente do seu servidor quanto quando é o servidor do seu cliente MCP.

  • OAuth 2.1 com PKCE (S256); clientes públicos se registram dinamicamente (RFC 7591).
  • Descoberta por metadados do servidor de autorização (RFC 8414) e metadados do recurso protegido (RFC 9728).
  • Grants: authorization_code e refresh_token; a resposta de autorização carrega o issuer (RFC 9207).
  • Resource indicators (RFC 8707) quando a plataforma é o cliente OAuth do seu servidor MCP.
  • Troca de tokens (RFC 8693) onde estiver configurado.

08Transferência e insights

Defina as regras de quando uma pessoa entra

Quando ele transfere

Um cliente pede uma pessoa, uma ferramenta falha, um reembolso passa do seu limite, uma palavra-chave aparece, ou qualquer evento que você definir.

Como sua equipe é avisada

Uma Caixa de entrada; atribuição à mão, por rodízio ou para quem tiver menos conversas abertas; alertas no app, por Web Push, APNs e Telegram pessoal.

Sua equipe assume

Acompanhe a conversa, entre com o contexto, responda no mesmo chat; o assistente não faz alterações enquanto uma pessoa está ativa.

Insights

Perguntas repetidas, lacunas de conhecimento e caminhos que falharam, agrupados a partir de conversas reais com links para os registros.

09Login do espaço de trabalho

Mantenha sua própria base de usuários e autenticação

Configure no Console as URLs de login e de conta do espaço de trabalho. Um visitante que escolhe Entrar sai do frame, se autentica no seu produto e volta exatamente para a URL de origem. Seu backend então fornece um token de login de uso único; o Busymate AI nunca recebe a senha do usuário nem a sua chave de assinatura.

Uma alteração só toca nos dados do próprio usuário conectado. As ferramentas de conta identificam o cliente pelo ator delegado, reconferem a autorização a cada chamada e pedem confirmação nas alterações que você configurar.

10Checklist de lançamento

Checklist de lançamento em produção

  1. 01Configure marca, SEO, seu endereço web e perguntas sugeridas.
  2. 02Registre seu login: issuer, JWKS, audience, claims e tempo de vida do token.
  3. 03Conecte o MCP, defina o nível de acesso de cada ferramenta, confirme que as leituras ficam no escopo do próprio usuário e que as escritas exigem confirmação.
  4. 04Defina as regras de transferência, escale a equipe na Caixa de entrada, ajuste horários e metas de resposta.
  5. 05Teste visitantes, usuários conectados, logout e troca de conta, tokens reaproveitados e um id de espaço de trabalho trocado.
  6. 06Confira o chat em página inteira, o embed, iOS, Android, desktop, acessibilidade e links externos.
  7. 07Publique só a versão que você conferiu; acompanhe a saúde da conexão e do domínio.

Pronto para montar seu espaço de trabalho?

A página de Integração do Console gera o código e as configurações de cada canal a partir das suas configurações publicadas.

Abrir o Console

MCP de gestão

Gerencie todo espaço de trabalho por qualquer cliente MCP

218 ferramentas de gestão por MCP com OAuth 2.1. O cliente abre um login no navegador na primeira conexão; nada é colado à mão.

Documentos de descoberta

Metadados do servidor de autorização (RFC 8414)
https://busymate.ai/.well-known/oauth-authorization-server/mcp
Metadados do recurso protegido (RFC 9728)
https://busymate.ai/.well-known/oauth-protected-resource/mcp

A conta com que você entra define quais espaços de trabalho o cliente pode gerenciar. Toda alteração pede confirmação.

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

Gerencie a plataforma em qualquer cliente MCP

Cursor, Claude Desktop e qualquer cliente que leia um mcp.json aceitam esta entrada; clientes que recebem uma URL remota usam o endpoint acima.

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

Conecte sua primeira ferramenta hoje

Registre seu servidor MCP, escolha quem pode usar cada ferramenta, publique. O assistente já pode usá-la no mesmo minuto.