Desarrolladores
Dé herramientas reales a su asistente de IA con MCP
Dé al asistente herramientas reales mediante MCP, el estándar abierto para conectar la IA con sus sistemas. Publíquelo en web, iOS, Android y escritorio. Gestiónelo todo desde cualquier cliente MCP.
claude mcp add --transport http busymate-ai https://busymate.ai/mcpVías de entrada
Elija por dónde empezar
Añada el asistente a su sitio web
Una etiqueta script en cualquier página que usted permita: el lanzador y el chat para invitados funcionan al momento.
Ponga soporte con IA dentro de su app de iOS
Cargue el chat en un WKWebView; un pequeño puente de tres mensajes identifica a sus usuarios.
Ponga soporte con IA dentro de su app de Android
Cargue el chat en un WebView; una sola interfaz de JavaScript identifica a sus usuarios.
Conecte su servidor MCP como herramientas
Su propio servidor MCP se convierte en las acciones del asistente, en nombre de cada cliente.
Gestione cada espacio de trabajo desde su terminal
Maneje la plataforma desde Claude Code, Cursor o cualquier cliente MCP mediante OAuth.
Deje que los agentes de IA lean su sitio
Un mapa en texto plano de su sitio en /llms.txt, escrito para agentes de IA.
01Inicio rápido
Cómo encaja todo
Su aplicación sigue siendo la fuente de la verdad. El asistente recibe un token firmado de corta duración que dice quién está presente y llama a sus herramientas como un actor aparte y acotado.
01
Su aplicación
Conserva la identidad y los datos de cuenta; firma un token de dos minutos que dice quién ha iniciado sesión.
02
El asistente
Aplica los ajustes de su espacio de trabajo: contenido, modelos, niveles de acceso de las herramientas, pasos de confirmación y traspaso.
03
Su servidor MCP
Responde a las herramientas para un usuario cada vez, tomando al usuario del bearer token de la sesión, nunca de los argumentos de la herramienta.
7 formas de conectar, un solo asistente: Embed web · Clientes con sesión iniciada · iOS · Android · Escritorio · API REST · Su servidor MCP
02Clientes con sesión iniciada
Reconozca al cliente que ya ha iniciado sesión
Para que el asistente pueda fiarse de quién pregunta, un endpoint autenticado de su backend firma un token de corta duración (un JWT ES256) con su id de cliente estable y unos pocos campos seguros para mostrar.
El token dura como máximo 120 segundos, lleva un nonce y un jti de un solo uso y nombra a su inquilino. La clave privada y la sesión de su producto nunca llegan al navegador ni al chat.
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 });
});El token dice quién está, no qué puede hacer. Mantenga saldos, dispositivos, ajustes y cada cambio detrás de herramientas que responden para un solo usuario.
03Web y página completa
Un script para un lanzador integrado
El SDK pide la identidad a su backend cuando la necesita, funciona con invitados, se actualiza tras el inicio y el cierre de sesión, abre los enlaces externos fuera del marco y no necesita cookies de terceros.
<!-- 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 el chat a página completa en su dirección
Cuando un usuario con sesión iniciada abre la dirección de su asistente o su dominio propio, pase el token de inicio de sesión en el fragmento de la URL. La página lo borra antes del intercambio.
// 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 con un puente de mensajes reducido
Permita solo los tres mensajes versionados: petición de identidad, respuesta de identidad y URL externa. Emita la identidad a través del cliente de API autenticado que ya tiene la app.
// 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 con una única interfaz permitida
Mantén la navegación en el origen de IA de tu tenant, envía los enlaces externos al navegador del sistema y no expongas métodos nativos de uso general.
// 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.06Escritorio
El mismo protocolo encaja en Electron, Tauri y shells nativos
Use un WebView aislado, bloquee las ventanas nuevas dentro de la vista, abra las URL seguras fuera y responda a las peticiones de identidad desde la capa privilegiada del host.
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" };
});07Herramientas MCP
Dé herramientas al asistente sin darle su base de datos de clientes
Publique esquemas completos en el descubrimiento. Dé a cada herramienta uno de los tres niveles de acceso, marque los cambios que necesitan una tarjeta de confirmación y vuelva a comprobar la autorización en cada llamada.
Público
Cualquiera que esté chateando puede llamarla. Precios, estado, funciones.
Identificado
Requiere un usuario con sesión iniciada. Estado del pedido, respuestas sobre la cuenta.
Delegado
Actúa en nombre del usuario con sesión iniciada mediante un actor token acotado o la propia concesión OAuth del usuario.
Cada cambio se confirma en el servidor. Las herramientas que incluya en confirm_tools se detienen en una tarjeta de confirmación antes de ejecutarse; también lo hace cualquier nombre de herramienta que el asistente no reconozca. Los marcos de widget nunca ejecutan un cambio.
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// 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.Qué habla la plataforma
El mismo conjunto de protocolos se aplica tanto si la plataforma es el cliente de su servidor como si es el servidor de su cliente MCP.
- OAuth 2.1 con PKCE (S256); los clientes públicos se registran de forma dinámica (RFC 7591).
- Descubrimiento mediante los metadatos del servidor de autorización (RFC 8414) y del recurso protegido (RFC 9728).
- Concesiones: authorization_code y refresh_token; la respuesta de autorización lleva el emisor (RFC 9207).
- Indicadores de recurso (RFC 8707) cuando la plataforma es el cliente OAuth de su servidor MCP.
- Intercambio de tokens (RFC 8693) donde esté configurado.
08Traspaso y análisis
Fije las reglas de cuándo interviene una persona
Cuándo hace el traspaso
Un cliente pide hablar con una persona, una herramienta falla, un reembolso supera su límite, aparece una palabra clave o cualquier evento que usted defina.
Cómo se avisa a su equipo
Una sola bandeja de entrada; asignación a mano, por turnos o a quien tenga menos chats abiertos; avisos en la aplicación, por Web Push, APNs y Telegram personal.
Su equipo toma el relevo
Siga la conversación, entre con el contexto y responda en el mismo chat; el asistente no hace ningún cambio mientras hay una persona activa.
Análisis
Preguntas repetidas, conocimiento que falta y caminos fallidos, agrupados a partir de conversaciones reales y con enlaces a la evidencia.
09Inicio de sesión del espacio de trabajo
Conserve su base de usuarios y su autenticación
Configure en la Consola las URL de inicio de sesión y de cuenta del espacio de trabajo. Un invitado que elige Iniciar sesión sale del marco, se autentica en su producto y vuelve exactamente a la URL de origen. Su backend entrega entonces un token de inicio de sesión de un solo uso; Busymate AI nunca recibe la contraseña del usuario ni su clave de firma.
Un cambio solo toca los datos del propio usuario con sesión iniciada. Las herramientas de cuenta toman al cliente del actor delegado, vuelven a comprobar la autorización en cada llamada y piden confirmación en los cambios que usted configure.
10Lista de lanzamiento
Lista de comprobación para el lanzamiento
- 01Configure la marca, el SEO, su dirección web y las preguntas sugeridas.
- 02Registre su inicio de sesión: emisor, JWKS, audiencia, claims y antigüedad del token.
- 03Conecte MCP, fije el nivel de acceso de cada herramienta y compruebe que las lecturas se limitan al propio usuario y que las escrituras se confirman.
- 04Fije las reglas de traspaso, asigne personas a la bandeja de entrada y establezca horarios y objetivos de respuesta.
- 05Pruebe con invitados, usuarios con sesión iniciada, cierre de sesión y cambio de cuenta, tokens reenviados y un id de espacio de trabajo cambiado.
- 06Revise el chat a página completa, el embed, iOS, Android, escritorio, la accesibilidad y los enlaces externos.
- 07Publique solo la versión que ha revisado y vigile el estado de la conexión y del dominio.
¿Listo para configurar su espacio de trabajo?
La página de Integración de la Consola genera el código y los ajustes de cada superficie a partir de sus ajustes publicados.
MCP de gestión
Gestione cada espacio de trabajo desde cualquier cliente MCP
218 herramientas de gestión sobre MCP con OAuth 2.1. El cliente abre un inicio de sesión en el navegador en la primera conexión; no se pega nada.
Documentos de descubrimiento
- Endpoint MCP
- https://busymate.ai/mcp
- Metadatos del servidor de autorización (RFC 8414)
- https://busymate.ai/.well-known/oauth-authorization-server/mcp
- Metadatos del recurso protegido (RFC 9728)
- https://busymate.ai/.well-known/oauth-protected-resource/mcp
La cuenta con la que inicia sesión decide qué espacios de trabajo puede gestionar el cliente. Cada cambio pide confirmación.
Claude Code
claude mcp add --transport http busymate-ai https://busymate.ai/mcpGestiona la plataforma desde cualquier cliente MCP
Cursor, Claude Desktop y cualquier cliente que lea un mcp.json aceptan esta entrada; los clientes que admiten una URL remota toman el endpoint de arriba.
{
"mcpServers": {
"platform-management": {
"type": "http",
"url": "https://busymate.ai/mcp"
}
}
}Últimos cambios
Qué se ha publicado
Conecte su primera herramienta hoy mismo
Registre su servidor MCP, elija quién puede usar cada herramienta y publique. El asistente puede usarla en ese mismo minuto.