Administra credenciales de conectores
Almacena y gestiona múltiples conjuntos de credenciales para un solo conector, luego llama a las herramientas con credenciales específicas para controlar el acceso en tiempo de ejecución.
Este manual cubre dos patrones de autenticación:
- Token de portador — tokens estáticos (PAT de GitHub), almacenados directamente a través de la API.
- OAuth2 — flujos de autenticación delegada (cuentas de Microsoft), iniciados a través de
get_auth_url.
Estado de la API: La gestión de credenciales utiliza
client.beta.connectors. Este es un endpoint en beta y puede cambiar.
Parte 1: Múltiples credenciales de token de portador (GitHub MCP)
Requisitos previos (Portador)
Instalar
# Python
pip install mistralai
# or with uv
uv add mistralai
Para completar este manual, necesitarás una clave de API de Mistral. En Studio, navega a la sección de claves de API y crea una nueva clave de API.
MISTRAL_API_KEY=your-mistral-api-key
GITHUB_PAT_FULL=ghp_yourFullAccessToken
GITHUB_PAT_LIMITED=ghp_yourLimitedOrInvalidToken
GITHUB_PAT_FULL— un PAT con alcance de lecturarepo, utilizado para listar problemas con éxito.GITHUB_PAT_LIMITED— un PAT sin alcances o con un valor inválido, utilizado para demostrar una llamada rechazada.
Crea tokens de acceso personal de GitHub en tu configuración de desarrollador de GitHub.
Script: python/src/scripts/07_multiple_bearer_authentication.py
Cuándo usar múltiples credenciales de portador
- Probar niveles de acceso — verifica que un token restringido no pueda acceder a recursos que un token completo sí puede.
- Rotar credenciales de forma segura — añade las nuevas credenciales, promuévelas a predeterminadas y luego elimina las antiguas sin tiempo de inactividad.
- Alcance explícito de las llamadas a herramientas — pasa
credentials_nameacall_toolpara elegir qué identidad ejecuta la solicitud.
1. Inicializa el cliente
Python:
import os
from mistralai import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
curl:
export MISTRAL_API_KEY="your-api-key"
export BASE_URL="https://api.mistral.ai"
2. Crea un conector GitHub MCP
Puedes omitir este paso si usas un conector existente con autenticación de portador.
Python:
import asyncio
import json
import os
import subprocess
BASE_URL = "https://api.mistral.ai"
API_KEY = os.environ["MISTRAL_API_KEY"]
async def main() -> None:
result = subprocess.run(
[
"curl", "-s", "-X", "POST",
f"{BASE_URL}/v1/connectors",
"-H", f"Authorization: Bearer {API_KEY}",
"-H", "Content-Type: application/json",
"-d", json.dumps({
"name": "my_github",
"description": "GitHub MCP connector for issue and PR management",
"server": "https://api.githubcopilot.com/mcp/",
"visibility": "private",
"auth_scheme": {"type": "http", "scheme": "Bearer"},
}),
],
capture_output=True,
text=True,
check=True,
)
connector = json.loads(result.stdout)
if "id" not in connector:
raise RuntimeError(f"Failed to create connector: {result.stdout}")
print(f"ID: {connector['id']}")
print(f"Name: {connector['name']}")
asyncio.run(main())
curl:
curl -X POST "${BASE_URL}/v1/connectors" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "my_github",
"description": "GitHub MCP connector for issue and PR management",
"server": "https://api.githubcopilot.com/mcp/",
"visibility": "private",
"auth_scheme": {"type": "http", "scheme": "Bearer"}
}'
Salida:
ID: a1b2c3d4-5678-90ab-cdef-1234567890ab
Name: my_github
| Error | Causa | Solución |
|---|---|---|
409 Conflict |
Ya existe un conector llamado my_github |
Elige un nombre diferente o elimina el existente primero |
3. Obtén los métodos de autenticación
Objetivo: Descubrir qué esquemas de autenticación soporta el conector antes de almacenar las credenciales.
Nota: el
connector_id_or_namees un poco feo y será reemplazado porconnector_refen futuras versiones.
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
methods = await client.beta.connectors.get_authentication_methods_async(
connector_id_or_name="my_github",
)
for method in methods:
print(f"Auth type: {method.method_type}")
asyncio.run(main())
curl:
curl -X GET "${BASE_URL}/v1/connectors/my_github/authentication_methods" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
Ejemplo de salida:
Auth type: bearer
4. Almacena las credenciales de portador
Objetivo: Almacenar credenciales de token de portador con nombre en el conector.
Las credenciales se pueden almacenar en tres ámbitos:
| Ámbito | Método del SDK | Quién puede usarlo |
|---|---|---|
user |
create_or_update_user_credentials |
Solo el usuario autenticado |
workspace |
create_or_update_workspace_credentials |
Todos en el espacio de trabajo |
organization |
create_or_update_organization_credentials |
Todos en la organización |
Python:
import asyncio
import os
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
# Credentials A — full repo read access, set as default
result = await client.beta.connectors.create_or_update_user_credentials_async(
connector_id_or_name="my_github",
name="github-pat-full",
credentials={"bearer_token": os.environ["GITHUB_PAT_FULL"]},
is_default=True,
)
print(result.message)
# Credentials B — no scopes / invalid token
result = await client.beta.connectors.create_or_update_user_credentials_async(
connector_id_or_name="my_github",
name="github-pat-limited",
credentials={"bearer_token": os.environ["GITHUB_PAT_LIMITED"]},
)
print(result.message)
asyncio.run(main())
curl:
# Credentials A — full repo read access (set as default)
curl -X POST "${BASE_URL}/v1/connectors/my_github/user/credentials" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"github-pat-full\",
\"credentials\": {\"bearer_token\": \"${GITHUB_PAT_FULL}\"},
\"is_default\": true
}"
# Credentials B — no scopes / invalid token
curl -X POST "${BASE_URL}/v1/connectors/my_github/user/credentials" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"github-pat-limited\",
\"credentials\": {\"bearer_token\": \"${GITHUB_PAT_LIMITED}\"}
}"
Salida:
Credentials 'github-pat-full' saved successfully
Credentials 'github-pat-limited' saved successfully
Cómo funciona:
is_default: truemarca las credenciales como predeterminadas — las llamadas que omitancredentials_namelas usarán.- Llamar al mismo endpoint de nuevo con un
nameexistente actualiza el token almacenado en su lugar. - El token sin procesar nunca es devuelto por los endpoints de lista o de obtención.
| Error | Causa | Solución |
|---|---|---|
400 Bad Request |
Objeto de credenciales vacío | Proporciona al menos bearer_token |
422 Unprocessable Entity |
Nombre de credenciales inválido | Usa solo nombres alfanuméricos con guiones |
5. Lista las credenciales
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
response = await client.beta.connectors.list_user_credentials_async(
connector_id_or_name="my_github",
)
for cred in response.credentials:
default_marker = " (default)" if cred.is_default else ""
print(f" {cred.name} [{cred.authentication_type}]{default_marker}")
asyncio.run(main())
curl:
curl -X GET "${BASE_URL}/v1/connectors/my_github/user/credentials" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
Salida:
github-pat-full [bearer] (default)
github-pat-limited [bearer]
6. Llama a una herramienta con credenciales específicas
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
# Call with the full-access credentials — should succeed
result = await client.beta.connectors.call_tool_async(
connector_id_or_name="my_github",
tool_name="list_issues",
arguments={"owner": "octocat", "repo": "hello-world", "state": "open"},
credentials_name="github-pat-full",
)
print(f"[github-pat-full] {result.content[:200]}")
# Call with the limited/invalid credentials — access error is in the response content
result = await client.beta.connectors.call_tool_async(
connector_id_or_name="my_github",
tool_name="list_issues",
arguments={"owner": "octocat", "repo": "hello-world", "state": "open"},
credentials_name="github-pat-limited",
)
print(f"[github-pat-limited] {result.content[:200]}")
asyncio.run(main())
curl:
curl -X POST "${BASE_URL}/v1/connectors/my_github/call_tool" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"tool_name": "list_issues",
"arguments": {"owner": "octocat", "repo": "hello-world", "state": "open"},
"credentials_name": "github-pat-full"
}'
Ejemplo de salida:
[github-pat-full] [{"number": 42, "title": "Fix typo in README", "state": "open", ...}]
[github-pat-limited] {"error": "Bad credentials", "status": 401}
Cómo funciona:
credentials_nameselecciona qué credenciales almacenadas recibe el servidor MCP. Omítelo para usar las predeterminadas.- Si las credenciales con nombre no existen, la llamada devuelve un
404.
7. Elimina credenciales
Nota: No puedes eliminar las credenciales predeterminadas mientras existan otras credenciales. Primero, promueve otras credenciales a predeterminadas y luego elimina las antiguas.
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
result = await client.beta.connectors.delete_user_credentials_async(
connector_id_or_name="my_github",
credentials_name="github-pat-limited",
)
print(result.message)
asyncio.run(main())
curl:
curl -X DELETE "${BASE_URL}/v1/connectors/my_github/user/credentials/github-pat-limited" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
Salida:
Credentials 'github-pat-limited' deleted successfully
| Error | Causa | Solución |
|---|---|---|
404 Not Found |
El nombre de las credenciales no existe | Verifica el nombre con list_user_credentials primero |
409 Conflict |
Intentando eliminar las credenciales predeterminadas actuales mientras existen otras | Promueve otras credenciales a predeterminadas primero |
Parte 2: Múltiples credenciales OAuth2 (ej: Outlook Calendar MCP)
Requisitos previos (OAuth2)
MISTRAL_API_KEY=your-mistral-api-key
- El conector
outlook_calendardebe estar habilitado en tu espacio de trabajo. Habilítalo en Studio. - Necesitas dos cuentas de Microsoft para autenticarte por separado.
Script: python/src/scripts/08_multiple_oauth_authentication.py
Cuándo usar múltiples credenciales OAuth2
- Acceso multi-cuenta — permite que un solo usuario se autentique con múltiples identidades (por ejemplo, cuentas de Microsoft de trabajo y personales) y cambie entre ellas en el momento de la llamada.
- Delegación por usuario — cada usuario en un espacio de trabajo autentica su propia cuenta;
credentials_nameenruta las llamadas a herramientas a la correcta. - Rotación segura — autentica la nueva cuenta bajo un nuevo nombre, promuévela a predeterminada y luego revoca la antigua.
1. Obtén el conector de Outlook Calendar
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
connector = await client.beta.connectors.get_async(
connector_id_or_name="outlook_calendar",
)
print(f"ID: {connector.id}")
print(f"Name: {connector.name}")
asyncio.run(main())
curl:
curl -X GET "${BASE_URL}/v1/connectors/outlook_calendar" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
2. Obtén los métodos de autenticación
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
methods = await client.beta.connectors.get_authentication_methods_async(
connector_id_or_name="outlook_calendar",
)
for method in methods:
print(f"Auth type: {method.method_type}")
asyncio.run(main())
curl:
curl -X GET "${BASE_URL}/v1/connectors/outlook_calendar/authentication_methods" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
Ejemplo de salida:
Auth type: oauth2
3. Autentica cuentas vía OAuth2
Objetivo: Obtener URLs de autorización OAuth2 y permitir que cada cuenta complete el flujo del navegador. El parámetro credentials_name controla en qué ranura con nombre se almacena el token resultante. Omitirlo almacena el token como las credenciales predeterminadas.
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
# Account A — stored as the default credentials
result = await client.beta.connectors.get_auth_url_async(
connector_id_or_name="outlook_calendar",
# no credentials_name => stored under name="default"
)
print(f"Follow this link to authenticate account A: {result.auth_url}")
input("Press Enter once done")
# Account B — stored under the name "personal"
result = await client.beta.connectors.get_auth_url_async(
connector_id_or_name="outlook_calendar",
credentials_name="personal",
)
print(f"Follow this link to authenticate account B: {result.auth_url}")
input("Press Enter once done")
asyncio.run(main())
curl:
# Account A — default credentials
curl -X GET "${BASE_URL}/v1/connectors/outlook_calendar/auth_url" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
# Account B — named "personal"
curl -X GET "${BASE_URL}/v1/connectors/outlook_calendar/auth_url?credentials_name=personal" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
Cómo funciona:
get_auth_urldevuelve una URL que el usuario debe abrir en un navegador para completar el flujo de consentimiento de OAuth2.- Una vez que el flujo se completa, el token se almacena automáticamente bajo el
credentials_namedado (o comodefaultsi se omite). - El script se pausa con
input()para darle tiempo al usuario de completar el flujo del navegador antes de continuar.
4. Lista las credenciales
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
response = await client.beta.connectors.list_user_credentials_async(
connector_id_or_name="outlook_calendar",
)
for cred in response.credentials:
default_marker = " (default)" if cred.is_default else ""
print(f" {cred.name} [{cred.authentication_type}]{default_marker}")
asyncio.run(main())
Salida:
default [oauth2] (default)
personal [oauth2]
5. Llama a una herramienta con credenciales específicas
Objetivo: Invocar una herramienta de calendario usando credenciales con nombre para consultar el calendario de una cuenta específica.
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
# Query the default account
result = await client.beta.connectors.call_tool_async(
connector_id_or_name="outlook_calendar",
tool_name="search_calendar_events",
arguments={"query": "meeting"},
credentials_name="default",
)
print(f"[default] {result.content[:300]}")
# Query the personal account
result = await client.beta.connectors.call_tool_async(
connector_id_or_name="outlook_calendar",
tool_name="search_calendar_events",
arguments={"query": "meeting"},
credentials_name="personal",
)
print(f"[personal] {result.content[:300]}")
asyncio.run(main())
curl:
curl -X POST "${BASE_URL}/v1/connectors/outlook_calendar/call_tool" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"tool_name": "search_calendar_events", "arguments": {"query": "meeting"}, "credentials_name": "default"}'
6. Promueve credenciales a predeterminadas
Para cambiar qué cuenta se usa cuando se omite credentials_name, actualiza is_default sin proporcionar un nuevo token — el token OAuth2 almacenado se conserva.
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
await client.beta.connectors.create_or_update_user_credentials_async(
connector_id_or_name="outlook_calendar",
name="personal",
is_default=True,
)
print("Promoted 'personal' to default")
# Now call without specifying credentials — uses personal account
result = await client.beta.connectors.call_tool_async(
connector_id_or_name="outlook_calendar",
tool_name="search_calendar_events",
arguments={"query": "meeting"},
)
print(f"[default] {result.content[:300]}")
asyncio.run(main())
7. Elimina credenciales
Nota: No puedes eliminar las credenciales predeterminadas mientras existan otras credenciales. Primero, promueve otras credenciales a predeterminadas.
Python:
import asyncio
from mistralai import Mistral
client = Mistral(api_key="your-api-key")
async def main() -> None:
for name in ("default", "personal"):
result = await client.beta.connectors.delete_user_credentials_async(
connector_id_or_name="outlook_calendar",
credentials_name=name,
)
print(result.message)
asyncio.run(main())
curl:
curl -X DELETE "${BASE_URL}/v1/connectors/outlook_calendar/user/credentials/personal" \
-H "Authorization: Bearer ${MISTRAL_API_KEY}"
Convenciones de nombres
| Concepto | Python |
|---|---|
| Obtener conector | client.beta.connectors.get_async(connector_id_or_name=) |
| Obtener métodos de autenticación | get_authentication_methods_async(connector_id_or_name=) |
| Obtener URL de OAuth2 | get_auth_url_async(connector_id_or_name=, credentials_name=) |
| Almacenar credenciales de portador | create_or_update_user_credentials_async(connector_id_or_name=, name=, credentials={"bearer_token": ...}, is_default=) |
| Promover a predeterminado | create_or_update_user_credentials_async(connector_id_or_name=, name=, is_default=True) |
| Listar credenciales de usuario | list_user_credentials_async(connector_id_or_name=) |
| Eliminar credenciales de usuario | delete_user_credentials_async(connector_id_or_name=, credentials_name=) |
| Llamar herramienta | call_tool_async(connector_id_or_name=, tool_name=, arguments=, credentials_name=) |
| Ámbito: espacio de trabajo | *_workspace_credentials* |
| Ámbito: organización | *_organization_credentials* |
Solución de problemas
Las credenciales no surten efecto al llamar a una herramienta
- Verifica que las credenciales se hayan guardado:
list_user_credentials. - Comprueba que
credentials_namecoincida exactamente con el nombre almacenado (distingue mayúsculas y minúsculas). - Si se omite
credentials_name, se usan las credenciales predeterminadas — confirma cuáles son las predeterminadas conlist_user_credentials.
El token OAuth2 no se almacena después de completar el flujo del navegador
- Asegúrate de haber presionado Enter después de completar el consentimiento en el navegador, no antes.
- Si la URL de autenticación expiró, llama a
get_auth_urlde nuevo para obtener una nueva.
401 Unauthorized del servidor MCP (GitHub)
- El PAT puede haber expirado. Vuelve a ejecutar
create_or_update_user_credentialscon el mismo nombre para rotarlo en su lugar. - El PAT puede carecer de los alcances requeridos.
No se pueden eliminar las credenciales predeterminadas
- Promueve otras credenciales a predeterminadas primero:
create_or_update_user_credentials(..., is_default=True), luego elimina las antiguas.
403 Forbidden en los endpoints de gestión de credenciales
- Las credenciales a nivel de organización requieren el permiso de organización
ModifyConnector. - Las credenciales a nivel de espacio de trabajo requieren el permiso de espacio de trabajo
ModifyConnector. - Las credenciales a nivel de usuario solo requieren autenticación.
Referencia de códigos de error
| Estado HTTP | Cuándo ocurre | Qué hacer |
|---|---|---|
400 Bad Request |
Objeto de credenciales vacío, o is_default: false en las únicas credenciales existentes |
Proporciona bearer_token; siempre mantén una credencial como predeterminada |
401 Unauthorized |
Clave de API de Mistral inválida, o el servidor MCP rechazó el token almacenado | Verifica tu MISTRAL_API_KEY; rota las credenciales |
403 Forbidden |
Permisos insuficientes para el ámbito elegido | Usa un ámbito inferior o solicita el permiso ModifyConnector |
404 Not Found |
El nombre de las credenciales o del conector no existe | Verifica los nombres con list_user_credentials |
409 Conflict |
El nombre del conector ya está en uso, o se está eliminando el predeterminado activo | Cambia el nombre del conector o promueve otras credenciales a predeterminadas primero |
422 Unprocessable Entity |
Formato de nombre de credenciales inválido | Usa solo caracteres alfanuméricos y guiones |
Resumen
Este manual cubrió cómo almacenar y gestionar múltiples conjuntos de credenciales para un solo Conector —tanto tokens de portador (PAT de GitHub) como OAuth2 (Outlook Calendar)— y cómo enrutar llamadas de herramientas específicas a credenciales específicas en tiempo de ejecución.
Lo que cubre este manual:
- Almacenar múltiples credenciales de token de portador para un conector GitHub MCP
- Almacenar múltiples credenciales OAuth2 para un conector Outlook Calendar MCP
- Listar, seleccionar y eliminar credenciales
- Promover credenciales a predeterminadas
- Llamar a herramientas con una credencial con nombre específico
Características de Mistral utilizadas:
- API de Conectores — gestión de credenciales (beta)
Otros servicios:
- GitHub MCP — Conector autenticado por portador (tokens de acceso personal)
- Outlook Calendar MCP — Conector autenticado por OAuth2
Consulta tus Conectores en Studio.