Microsoft 365
Servidor MCP que se conecta a todo el conjunto de Microsoft 365 (Microsoft Office, Outlook, Excel) mediante Graph API (incluyendo correo, archivos, calendario)
Documentación
ms-365-mcp-server
Servidor MCP de Microsoft 365
Un servidor de Protocolo de Contexto de Modelo (MCP) para interactuar con los servicios de Microsoft 365 y Microsoft Office a través de la API de Graph.
Nubes compatibles
Este servidor admite múltiples entornos de nube de Microsoft:
| Nube | Descripción | Punto de conexión de autenticación | Punto de conexión de API de Graph |
|---|---|---|---|
| Global (predeterminada) | Microsoft 365 internacional | login.microsoftonline.com | graph.microsoft.com |
| China (21Vianet) | Microsoft 365 operado por 21Vianet | login.chinacloudapi.cn | microsoftgraph.chinacloudapi.cn |
Requisitos previos
- Node.js >= 20 (recomendado)
- Node.js 14+ puede funcionar con advertencias de dependencias
Características
- Autenticación mediante la Biblioteca de Autenticación de Microsoft (MSAL)
- Integración integral de servicios de Microsoft 365
- Soporte de modo de solo lectura para operaciones seguras
- Filtrado de herramientas para control de acceso granular
- Presets de herramientas y descubrimiento dinámico para reducir la superficie de herramientas y el uso de tokens
Formato de salida: JSON vs TOON
El servidor admite dos formatos de salida que se pueden configurar globalmente:
Formato JSON (predeterminado)
Salida JSON estándar con formato legible:
{
"value": [
{
"id": "1",
"displayName": "Alice Johnson",
"mail": "alice@example.com",
"jobTitle": "Software Engineer"
}
]
}
Formato TOON (experimental)
Notación de Objetos Orientada a Tokens para un uso eficiente de tokens LLM:
value[1]{id,displayName,mail,jobTitle}:
"1",Alice Johnson,alice@example.com,Software Engineer
Beneficios:
- 30-60% menos tokens en comparación con JSON
- Mejor para datos de arreglos uniformes (listas de correos electrónicos, eventos de calendario, archivos, etc.)
- Ideal para aplicaciones sensibles a costos a escala
Uso: (experimental) Habilitar el formato TOON globalmente:
Mediante el indicador CLI:
npx @softeria/ms-365-mcp-server --toon
Mediante la configuración de Claude Desktop:
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--toon"]
}
}
}
Mediante variable de entorno:
MS365_MCP_OUTPUT_FORMAT=toon npx @softeria/ms-365-mcp-server
Servicios y herramientas compatibles
El servidor proporciona más de 300 herramientas que cubren la mayor parte de la superficie de la API de Microsoft Graph. Cada herramienta se asigna 1 a 1 a un punto de conexión de la API de Graph y se define declarativamente en src/endpoints.json.
Herramientas de cuenta personal (disponibles de forma predeterminada)
Correo electrónico (Outlook), Calendario, Archivos de OneDrive, Excel, OneNote, Tareas de To Do, Planner, Contactos, Perfil de usuario, Búsqueda
Herramientas de cuenta organizacional (requiere el indicador --org-mode)
Teams y Chats, Reuniones en línea, Transcripciones y grabaciones, Informes de asistencia, Sitios y listas de SharePoint, Buzones y calendarios compartidos, Gestión de usuarios, Presencia, Eventos virtuales
Permisos requeridos de la API de Graph
Los permisos se solicitan dinámicamente según las herramientas habilitadas. Use --list-permissions para ver los permisos exactos para su configuración:
# Personal mode (default)
npx @softeria/ms-365-mcp-server --list-permissions
# Organization mode (includes Teams, SharePoint, etc.)
npx @softeria/ms-365-mcp-server --org-mode --list-permissions
# Filtered by preset
npx @softeria/ms-365-mcp-server --preset mail --list-permissions
Esto es útil para entornos empresariales donde los permisos de la API de Graph deben preaprobarse y contar con consentimiento del administrador antes de implementar una nueva versión.
El JSON de --list-permissions incluye:
toolPermissions: permisos implícitos por la superficie de herramientas antes del filtrado de--allowed-scopeseffectivePermissions: permisos implícitos por las herramientas que permanecen habilitadas después de--allowed-scopespermissions: alias heredado paraeffectivePermissions, mantenido para compatibilidad con scripts existentesallowedScopes: la lista de permitidos de alcance configurada, cuando se proporcionadisabledTools: herramientas ocultas porque sus alcances de Graph requeridos no están cubiertos porallowedScopesmissingAllowedScopesForTools: alcances faltantes únicos en todas las herramientas deshabilitadasextraAllowedScopesNotUsedByTools: alcances permitidos que no son utilizados por la superficie de herramientas actual
Alcances permitidos
De forma predeterminada, MSAL solicita los alcances implícitos por las herramientas habilitadas, y la superficie de herramientas se controla mediante --enabled-tools, --preset, --org-mode y --read-only.
Las implementaciones empresariales y sin interfaz gráfica pueden agregar un límite de alcance con --allowed-scopes o MS365_MCP_ALLOWED_SCOPES. Cuando se configura, el servidor primero calcula la superficie de herramientas normal y luego oculta las herramientas de Graph cuyos alcances requeridos no están cubiertos por la lista de permitidos. Los metadatos de OAuth y los flujos de inicio de sesión solicitan solo los permisos efectivos para las herramientas que permanecen habilitadas.
npx @softeria/ms-365-mcp-server \
--org-mode \
--enabled-tools '^(list-mail-messages|get-mail-message|list-drives|get-drive-item|download-bytes)$' \
--allowed-scopes 'User.Read Mail.Read Files.Read'
El valor CLI tiene prioridad sobre MS365_MCP_ALLOWED_SCOPES; si no se establece ninguno, el comportamiento predeterminado de alcance derivado de herramientas no cambia. Proporcionar un valor vacío falla al inicio para que las implementaciones no caigan accidentalmente en una superficie de herramientas más amplia.
La cobertura de alcance es consciente de la jerarquía: por ejemplo, Mail.ReadWrite cubre herramientas que requieren Mail.Read, y Files.ReadWrite.All cubre herramientas que requieren Files.Read.
SharePoint admite dos modelos de permisos empresariales:
- Alcances amplios de inquilino como
Sites.Read.All,Sites.ReadWrite.AllySites.Manage.All. Sites.Selectedde Microsoft Graph, donde el acceso al sitio de SharePoint se otorga a la aplicación en colecciones de sitios específicas y Graph evalúa los permisos propios del usuario con sesión iniciada en el momento de la solicitud.
El comportamiento predeterminado del modo de organización continúa solicitando los alcances amplios de SharePoint utilizados por las implementaciones existentes. Las empresas que desean acceso a sitios seleccionados de SharePoint pueden establecer una lista de permitidos que contenga Sites.Selected en lugar de alcances amplios de Sites.*.All. Las herramientas directas de sitio/lista/ítem que apuntan a un sitio de SharePoint explícito, y las herramientas de ítems de /drives/{drive-id}/... (listar, obtener, cargar, carpeta, mover/renombrar, copiar, versiones) para unidades de un sitio concedido, pueden ejecutarse con Sites.Selected; las herramientas de descubrimiento y búsqueda de SharePoint en todo el inquilino aún requieren alcances amplios de SharePoint.
npx @softeria/ms-365-mcp-server \
--org-mode \
--read-only \
--enabled-tools 'sharepoint|site|drive|planner' \
--allowed-scopes 'User.Read Files.Read Notes.Read Tasks.Read Sites.Selected'
En modo HTTP, el descubrimiento de OAuth anuncia los permisos filtrados efectivos para que los clientes soliciten la misma superficie de consentimiento. El modo En-Nombre-De (--obo) aún anuncia api://<clientId>/access_as_user para metadatos de recursos protegidos; --allowed-scopes no anula OBO.
Solicitud de alcances adicionales
--allowed-scopes solo reduce la solicitud de tokens. Para solicitar un alcance de Graph que ninguna herramienta incluida necesita — por ejemplo, para impulsar un punto de conexión mediante graph-batch — use --extra-scopes (o MS365_MCP_EXTRA_SCOPES). Estos alcances se agregan textualmente a la solicitud de tokens, además de los alcances derivados de herramientas.
npx @softeria/ms-365-mcp-server \
--org-mode \
--extra-scopes 'CopilotPackages.ReadWrite.All'
Esto es para usar con su propio registro de aplicación de Azure (MS365_MCP_CLIENT_ID / MS365_MCP_CLIENT_SECRET): la aplicación Softeria predeterminada solo declara un conjunto de permisos fijo y reducido, por lo que solicite alcances adicionales contra una aplicación que usted controle (su administrador de inquilino otorga consentimiento allí). El valor CLI tiene prioridad sobre la variable de entorno; un valor vacío falla al inicio.
Modo de organización/trabajo
Para acceder a funciones de trabajo/escuela (Teams, SharePoint, etc.), habilite el modo de organización usando cualquiera de estos indicadores:
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
}
}
}
El modo de organización debe habilitarse desde el inicio para acceder a las funciones de cuenta de trabajo. Sin este indicador, solo están disponibles las funciones de cuenta personal (correo electrónico, calendario, OneDrive, etc.).
Acceso a buzones compartidos
Para acceder a buzones compartidos, necesita:
- Modo de organización: Las herramientas de buzón compartido requieren el indicador
--org-mode(solo cuentas de trabajo/escuela) - Permisos delegados:
Mail.Read.Sharedpara leer,Mail.ReadWrite.Sharedpara crear, actualizar o mover mensajes,Mail.Send.Sharedpara enviar, responder o reenviar, yCalendars.Read.Sharedpara las herramientas de calendario compartido - Permisos de Exchange: El usuario con sesión iniciada debe tener acceso concedido al buzón compartido
- Uso: Use la dirección de correo electrónico del buzón compartido como parámetro
user-iden las herramientas de buzón compartido
Cómo encontrar buzones compartidos: Use la herramienta list-users para descubrir usuarios disponibles y buzones compartidos en su organización.
Ejemplo: list-shared-mailbox-messages con user-id establecido en shared-mailbox@company.com
Ejemplo de inicio rápido
Probar inicio de sesión en Claude Desktop:
Ejemplos
Integración
Claude Desktop
Para agregar este servidor MCP a Claude Desktop, edite el archivo de configuración en Configuración > Desarrollador.
Cuenta personal (MSA)
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server"]
}
}
}
Cuenta de trabajo/escuela (Global)
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
}
}
}
Cuenta de trabajo/escuela (China 21Vianet)
{
"mcpServers": {
"ms365-china": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode", "--cloud", "china"]
}
}
}
CLI de Claude Code
Cuenta personal (MSA)
claude mcp add ms365 -- npx -y @softeria/ms-365-mcp-server
Cuenta de trabajo/escuela (Global)
# macOS/Linux
claude mcp add ms365 -- npx -y @softeria/ms-365-mcp-server --org-mode
# Windows (use cmd /c wrapper)
claude mcp add ms365 -s user -- cmd /c "npx -y @softeria/ms-365-mcp-server --org-mode"
Cuenta de trabajo/escuela (China 21Vianet)
# macOS/Linux
claude mcp add ms365-china -- npx -y @softeria/ms-365-mcp-server --org-mode --cloud china
# Windows (use cmd /c wrapper)
claude mcp add ms365-china -s user -- cmd /c "npx -y @softeria/ms-365-mcp-server --org-mode --cloud china"
Para otras interfaces que admiten MCP, consulte su documentación respectiva para el método de integración correcto.
Open WebUI
Open WebUI admite servidores MCP mediante transporte HTTP con OAuth 2.1.
-
Inicie el servidor con modo HTTP:
npx @softeria/ms-365-mcp-server --http -
En Open WebUI, vaya a Configuración de administrador → Herramientas (
/admin/settings/tools) → Agregar conexión:- Tipo: MCP Streamable HTTP
- URL: La URL de su servidor MCP con la ruta
/mcp - Autenticación: OAuth 2.1
-
Haga clic en Registrar cliente.
Nota: El registro dinámico de clientes está habilitado de forma predeterminada en modo HTTP. Use
--no-dynamic-registration(o establezcaMS365_MCP_DISABLE_DCR=true) para deshabilitarlo. Si usa una aplicación personalizada de Azure Entra, el tipo de plataforma para su URI de redireccionamiento depende de si la aplicación tiene un secreto de cliente: con un secreto use "Web", sin uno use "Aplicaciones móviles y de escritorio" (nunca "Aplicación de página única").
Configuración de prueba rápida usando la aplicación de Azure predeterminada (ID ms-365 y localhost:8080 están preconfigurados):
docker run -d -p 8080:8080 \
-e WEBUI_AUTH=false \
-e OPENAI_API_KEY \
ghcr.io/open-webui/open-webui:main
npx @softeria/ms-365-mcp-server --http
Luego agregue la conexión con URL http://localhost:3000/mcp e ID ms-365.
¿Ejecutando en Docker detrás de un proxy inverso? Establezca
--public-url https://your-domain.compara que la URL de autorización de OAuth entregada al navegador del usuario sea accesible desde fuera de la red del contenedor. Consulte docs/deployment.md para la guía completa.
Desarrollo local
Para desarrollo local o pruebas:
# From the project directory
claude mcp add ms -- npx tsx src/index.ts --org-mode
O configure Claude Desktop manualmente:
{
"mcpServers": {
"ms365": {
"command": "node",
"args": ["/absolute/path/to/ms-365-mcp-server/dist/index.js", "--org-mode"]
}
}
}
Nota: Ejecute
npm run builddespués de cambios de código para actualizar la carpetadist/.
Autenticación
⚠️ Debe autenticarse antes de usar las herramientas.
El servidor admite tres métodos de autenticación:
1. Flujo de código de dispositivo (predeterminado)
Para autenticación interactiva mediante código de dispositivo:
- Inicio de sesión del cliente MCP:
- Llame a la herramienta
login(verifica automáticamente el token existente) - Si es necesario, obtenga URL+código, visite en el navegador
- Use la herramienta
verify-loginpara confirmar
- Llame a la herramienta
- Inicio de sesión CLI:
Siga la URL y el indicador de código en la terminal.npx @softeria/ms-365-mcp-server --login
Los tokens se almacenan en caché de forma segura en su almacén de credenciales del sistema operativo (respaldo en archivo).
2. Flujo de código de autorización OAuth (solo modo HTTP)
Cuando se ejecuta con --http, el servidor requiere autenticación OAuth:
npx @softeria/ms-365-mcp-server --http 3000
Este modo:
- Anuncia capacidades de OAuth a los clientes MCP
- Proporciona puntos de conexión de OAuth en
/auth/*(autorizar, token, metadatos) - Requiere
Authorization: Bearer <token>para todas las solicitudes MCP - Valida tokens con la API de Microsoft Graph
- Deshabilita las herramientas de inicio/cierre de sesión de forma predeterminada (use
--enable-auth-toolspara habilitarlas)
Los clientes MCP manejarán automáticamente el flujo de OAuth cuando vean las capacidades anunciadas.
Configuración de Azure AD para pruebas de OAuth
Para usar el modo OAuth con credenciales personalizadas de Azure (recomendado para producción), deberá configurar un registro de aplicación de Azure AD:
- Crear registro de aplicación de Azure AD:
- Vaya a Portal de Azure
- Navegue a Azure Active Directory → Registros de aplicaciones → Nuevo registro
- Establezca el nombre: "MS365 MCP Server"
- Configurar URI de redireccionamiento:
- Configure el URI de devolución de llamada de OAuth: Vaya a su registro de aplicación y en el lado izquierdo, vaya a Autenticación.
- En Configuraciones de plataforma:
- Haga clic en Agregar una plataforma (si aún no ve una para "Aplicaciones móviles y de escritorio" / "Cliente público").
- Elija Aplicaciones móviles y de escritorio o Cliente público/nativo (móvil y escritorio) (la etiqueta depende de la versión del portal).
- Pruebas con MCP Inspector (
npm run inspector):
- Ve a tu registro de aplicación y, en el lado izquierdo, ve a Autenticación.
- En Configuraciones de plataforma:
- Haz clic en Agregar una plataforma (si aún no ves una para "Web").
- Elige Web.
- Configura las siguientes URI de redirección:
http://localhost:6274/oauth/callbackhttp://localhost:6274/oauth/callback/debughttp://localhost:3000/callback(opcional, para la devolución de llamada del servidor)
- Obtener credenciales:
- Copia el ID de aplicación (cliente) desde la página de Información general.
- Ve a Certificados y secretos → Nuevo secreto de cliente → Copia el valor del secreto (opcional para aplicaciones públicas).
- Configurar variables de entorno:
Crea un archivo
.enven la raíz de tu proyecto:MS365_MCP_CLIENT_ID=your-azure-ad-app-client-id-here MS365_MCP_CLIENT_SECRET=your-secret-here # Optional for public apps MS365_MCP_TENANT_ID=common
Con esto configurado, el servidor usará tu aplicación personalizada de Azure en lugar de la integrada.
Nota:
.envse lee desde el directorio donde se inicia el servidor, y el cliente MCP decide qué es ese directorio. SoloMS365_MCP_CLIENT_ID,MS365_MCP_CLIENT_SECRET,MS365_MCP_TENANT_IDyMS365_MCP_CLOUD_TYPEse leen desde allí. Cada otra variable listada arriba debe configurarse en tu shell o en la configuración del cliente MCP; cualquier otra cosa encontrada en un.envse ignora con una advertencia en stderr.
3. Trae tu propio token (BYOT)
Si estás ejecutando ms-365-mcp-server como parte de un sistema más grande que gestiona tokens OAuth de Microsoft externamente, puedes proporcionar un token de acceso directamente a este servidor MCP:
MS365_MCP_OAUTH_TOKEN=your_oauth_token npx @softeria/ms-365-mcp-server
Este método:
- Omite los flujos de autenticación interactivos.
- Usa tu token OAuth preexistente para las solicitudes a Microsoft Graph API.
- No gestiona la renovación de tokens (la gestión del ciclo de vida del token es tu responsabilidad).
Nota: El modo HTTP requiere autenticación. Para pruebas sin autenticación, usa el modo stdio con el flujo de código de dispositivo.
Herramientas de autenticación: En modo HTTP, las herramientas de inicio/cierre de sesión están deshabilitadas por defecto, ya que OAuth gestiona la autenticación. Usa
--enable-auth-toolssi las necesitas disponibles.
Soporte multi-cuenta
Usa una única instancia del servidor para atender múltiples cuentas de Microsoft. Cuando hay más de una cuenta iniciada, se inyecta automáticamente un parámetro account en cada herramienta, lo que te permite especificar qué cuenta usar en cada llamada.
Iniciar sesión con múltiples cuentas (una vez por cuenta):
# Login first account (device code flow)
npx @softeria/ms-365-mcp-server --login
# Follow the device code prompt, sign in as personal@outlook.com
# Login second account
npx @softeria/ms-365-mcp-server --login
# Follow the device code prompt, sign in as work@company.com
Listar cuentas configuradas:
npx @softeria/ms-365-mcp-server --list-accounts
Usar en llamadas a herramientas: Pasa "account": "work@company.com" en cualquier solicitud de herramienta:
{ "tool": "list-mail-messages", "arguments": { "account": "work@company.com" } }
Comportamiento:
- Con una sola cuenta configurada, se selecciona automáticamente (no se necesita el parámetro
account). - Con múltiples cuentas y sin el parámetro
account, el servidor usa la cuenta predeterminada seleccionada o devuelve un error útil listando las cuentas disponibles. - 100% compatible hacia atrás: las configuraciones de cuenta única existentes funcionan sin cambios.
- El parámetro
accountacepta una dirección de correo electrónico (p. ej.,user@outlook.com) o elhomeAccountIdde MSAL.
Fijación estricta de cuenta
Las implementaciones headless de stdio pueden fijar la caché local de MSAL a una única cuenta de Microsoft esperada:
# Username matching is case-insensitive
MS365_MCP_EXPECTED_USERNAME=work@company.com npx @softeria/ms-365-mcp-server --login
# Or pin the exact MSAL homeAccountId shown by --list-accounts
npx @softeria/ms-365-mcp-server --expected-home-account-id <homeAccountId> --login
Usa --list-accounts para descubrir los valores de homeAccountId. La herramienta list-accounts de MCP oculta intencionalmente los IDs de cuenta, así que usa la CLI para fijar el ID exacto.
La fijación es opcional y solo para MSAL local:
- Los valores de CLI (
--expected-username,--expected-home-account-id) tienen prioridad sobreMS365_MCP_EXPECTED_USERNAMEyMS365_MCP_EXPECTED_HOME_ACCOUNT_ID. - Proporcionar un valor de fijación vacío falla al inicio en lugar de ignorarse.
- Las fijaciones de nombre de usuario se comparan sin distinguir mayúsculas; las fijaciones de
homeAccountIdson exactas. - Si ambas fijaciones están configuradas, deben resolverse en la misma cuenta en caché.
- El inicio de stdio local falla rápidamente cuando la cuenta esperada no está en la caché de tokens. Inicializa configurando la fijación, ejecutando
--loginy luego iniciando el servidor headless. - Los inicios de sesión por código de dispositivo y navegador rechazan una cuenta faltante o no coincidente antes de persistir la cuenta seleccionada o la caché de tokens.
- La fijación reduce el modo MCP efectivo a una sola cuenta: el servidor no anuncia un parámetro
accounty las instrucciones de MCP no sugieren cambiar de cuenta. --http,--oboyMS365_MCP_OAUTH_TOKENusan tokens proporcionados en la solicitud para las llamadas a Graph, por lo que las fijaciones de cuenta son solo de advertencia en esos modos. Si las herramientas de autenticación HTTP están habilitadas, la fijación aún se aplica a esos flujos auxiliares locales de MSAL.--logoutborra todas las cuentas en caché, incluida la cuenta fijada. Para una limpieza quirúrgica, prefiere--remove-account <id>.
Para multiplexores MCP (Legate, Governor): El modo multi-cuenta reemplaza el patrón de N procesos. En lugar de generar un servidor por cuenta, una única instancia maneja todas las cuentas mediante el parámetro
account, reduciendo la duplicación de herramientas de N×110 a 110.
Presets de herramientas
Para reducir la sobrecarga inicial de conexión y el uso de tokens, usa categorías de herramientas predefinidas en lugar de cargar el conjunto completo de herramientas:
npx @softeria/ms-365-mcp-server --preset mail
npx @softeria/ms-365-mcp-server --list-presets # See all available presets
Presets disponibles: mail, calendar, files, personal, work, excel, contacts, tasks, onenote, search, users, outlook, onedrive, teams, teams-write, all
Cada endpoint en endpoints.json declara a qué presets pertenece mediante un array presets, por lo que cada preset es una lista de permitidos de nombres de herramientas exacta que nunca coincide en exceso entre aplicaciones (p. ej., mail no incluye herramientas de buzones compartidos; esas están en work). El lector binario universal download-bytes se incluye en todos los presets excepto teams-write, por lo que cualquier cosa que devuelva una aplicación (un archivo, un adjunto, una foto, una grabación) siempre se puede obtener; get-download-url (una URL preautenticada para archivos de drive/SharePoint) viaja con los presets respaldados por drive. Así, un preset que puede encontrar un archivo siempre puede leer sus bytes.
Los presets outlook, onedrive y teams están limitados por aplicación: exponen exactamente una aplicación de Microsoft. Úsalos para implementaciones de "exponer exactamente una aplicación":
# Outlook only (mail + calendar + contacts; no shared mailboxes, no files)
npx @softeria/ms-365-mcp-server --preset outlook
# Teams only (requires --org-mode)
npx @softeria/ms-365-mcp-server --org-mode --preset teams
El preset teams-write es la contraparte solo de envío de --read-only: enviar en chats, enviar/responder en canales, listar chats/equipos/canales por nombre y notificaciones de actividad; sin lectura de mensajes ni descargadores de bytes. El token solicitado es mínimo por construcción (Chat.ReadBasic, los ámbitos *.Send y listado básico de equipos/canales; nada que pueda leer contenido de mensajes):
npx @softeria/ms-365-mcp-server --org-mode --preset teams-write
Descubrimiento dinámico de herramientas
En lugar de cargar cada herramienta por adelantado, usa el descubrimiento dinámico para que el LLM encuentre y cargue herramientas solo cuando las necesite:
npx @softeria/ms-365-mcp-server --discovery
Mantiene el contexto inicial pequeño y reduce el uso de tokens, especialmente útil para sesiones largas o configuraciones sensibles al costo (p. ej., Open WebUI ejecutándose contra una API de pago).
Opciones de CLI
Las siguientes opciones se pueden usar al ejecutar ms-365-mcp-server directamente desde la línea de comandos:
--login Login using device code flow
--logout Log out and clear saved credentials
--verify-login Verify login without starting the server
--list-permissions List required Graph API permissions and exit (respects --org-mode, --preset, --enabled-tools, --allowed-scopes)
--org-mode Enable organization/work mode from start (includes Teams, SharePoint, etc.)
--work-mode Alias for --org-mode
--force-work-scopes Backwards compatibility alias for --org-mode (deprecated)
--cloud <type> Microsoft cloud environment: global (default) or china (21Vianet)
--allowed-scopes <scopes> Limit exposed tools to Graph scopes covered by this allowlist
--extra-scopes <scopes> Append additional Graph scopes to the token request (for use with your own app registration + graph-batch)
--expected-username <username> Require local MSAL auth to use this account username
--expected-home-account-id <id> Require local MSAL auth to use this exact homeAccountId
Opciones del servidor
Cuando se ejecuta como servidor MCP, se pueden usar las siguientes opciones:
-v Enable verbose logging
--read-only Start server in read-only mode, disabling write operations
--http [port] Use Streamable HTTP transport instead of stdio (optionally specify port, default: 3000)
Starts Express.js server with MCP endpoint at /mcp
--enable-auth-tools Enable login/logout tools when using HTTP mode (disabled by default in HTTP mode)
--enable-attachment-urls Let get-download-url mint a server-served URL for byte resources Graph
exposes no pre-authenticated URL for (see "Server-Minted Attachment URLs")
--attachment-port <port> Serve /attachment on its own listener on this port instead of on the
MCP app, so a fetcher that can read attachments cannot also reach /mcp
(requires --enable-attachment-urls; see "Splitting the attachment listener")
--attachment-host <host> Interface the --attachment-port listener binds. Defaults to whatever
--http bound, which with a wildcard --http leaves BOTH ports on every
interface and so isolates nothing — set this to make the split real
(requires --attachment-port; see "Splitting the attachment listener")
--no-dynamic-registration Disable OAuth Dynamic Client Registration (enabled by default in HTTP mode)
--enabled-tools <pattern> Filter tools using regex pattern (e.g., "excel|contact" to enable Excel and Contact tools)
--preset <names> Use preset tool categories (comma-separated). See "Tool Presets" section above
--list-presets List all available presets and exit
--toon (experimental) Enable TOON output format for 30-60% token reduction
--discovery Dynamic tool discovery: loads tools on demand to reduce initial token usage (see "Dynamic Tool Discovery" above)
--public-url <url> Public base URL for OAuth when behind a reverse proxy (see Open WebUI section and docs/deployment.md)
Variables de entorno:
READ_ONLY=true|1: Alternativa a la bandera --read-onlyENABLED_TOOLS: Filtra herramientas usando un patrón regex (alternativa a la bandera --enabled-tools)MS365_MCP_ORG_MODE=true|1: Habilita el modo organización/trabajo (alternativa a la bandera --org-mode)MS365_MCP_FORCE_WORK_SCOPES=true|1: Compatibilidad hacia atrás para MS365_MCP_ORG_MODEMS365_MCP_OUTPUT_FORMAT=toon: Habilita el formato de salida TOON (alternativa a la bandera --toon)MS365_MCP_MAX_TOP=<n>: Límite máximo para Graph$top/topen solicitudes de listado (entero positivo). Cuando el modelo pasa un valor mayor, el servidor lo limita anpara que las respuestas sean más pequeñas. Ejemplo:MS365_MCP_MAX_TOP=15MS365_MCP_MAX_PAGES=<n>: Número máximo de páginas seguidas cuando se llama a una herramienta confetchAllPages: true(entero positivo, predeterminado100). Limita la memoria y la latencia para conjuntos de resultados grandes.MS365_MCP_MAX_ITEMS=<n>: Número máximo de elementos acumulados cuandofetchAllPages: true(entero positivo, predeterminado10000). La paginación se detiene y la respuesta se trunca una vez que se recopilan esta cantidad de elementos.MS365_MCP_ALLOW_PAGINATION=0|false|no: Deshabilita el seguimiento de múltiples páginas por completo. Cuando se configura, el parámetrofetchAllPagesno se anuncia en las herramientas, y cualquier solicitud que aún lo pase devuelve solo la primera página (predeterminado: paginación habilitada).MS365_MCP_BODY_FORMAT=html: Devuelve los cuerpos de correo como HTML en lugar de texto plano (predeterminado: texto)MS365_MCP_MESSAGE_SIGNOFF_PREFIX=<text>: Firma antepuesta a los mensajes salientes para que los destinatarios puedan saber que fueron enviados por un agente, p. ej.,🤖. Predeterminado: ninguno. Equivalente de CLI:--message-signoff-prefix <text>(ver Firma de mensajes abajo)MS365_MCP_MESSAGE_SIGNOFF_SUFFIX=<text>: Firma añadida al final de los mensajes salientes. Predeterminado: ninguno. Equivalente de CLI:--message-signoff-suffix <text>.--no-message-signoffdeshabilita ambas (ver Firma de mensajes abajo)MS365_MCP_RATE_LIMIT_DISABLED=true|1: Deshabilita la limitación de velocidad por IP en modo HTTP (predeterminado: habilitada — 30 req/min en/authorize,/token,/register; 120 req/min en/mcp)MS365_MCP_TRUST_PROXY_HOPS=<n>: Número de saltos de proxy inverso de confianza en modo HTTP (predeterminado1). La limitación de velocidad precisa por IP depende de que esto coincida con tu implementación — configúralo con el número de proxies frente al servidor,0para usar la IP del socket peer sin procesar, o una lista de subredes separadas por comasMS365_MCP_ATTACHMENT_PORT=<port>: Sirve la ruta de adjuntos en su propio listener en este puerto (alternativa a --attachment-port; requiere--enable-attachment-urls)MS365_MCP_ATTACHMENT_HOST=<host>: Interfaz a la que se vincula el listenerMS365_MCP_ATTACHMENT_PORT(alternativa a --attachment-host; requiere--attachment-port). Se predetermina al host al que--httpestá vinculado — lo que para un--httpcomodín significa que ambos puertos responden en todas partes y la división de puertos no aísla nada. Ver "Dividir el listener de adjuntos"MS365_MCP_CLOUD_TYPE=global|china: Entorno de nube de Microsoft (alternativa a la bandera --cloud)LOG_LEVEL: Configura el nivel de registro (predeterminado: 'info')SILENT=true|1: Deshabilita la salida de consolaMS365_MCP_REDACT_PII=false|0: Deshabilita la depuración de JWTs, encabezados Bearer, campos de tokens OAuth y direcciones de correo electrónico de los mensajes de registro (predeterminado: habilitada). El servidor maneja tokens Bearer de Graph en vivo, por lo que la redacción está activa a menos que optes por no hacerlo para depuración local completamente detallada.MS365_MCP_CLIENT_ID: ID de cliente de aplicación personalizada de Azure (se predetermina a la aplicación integrada)MS365_MCP_TENANT_ID: ID de inquilino personalizado (se predetermina a 'common' para multi-inquilino). Las cuentas personales de Microsoft deben configurar esto enconsumers— a partir de junio de 2026, los tokens de actualización emitidos a través de la autoridad 'common' predeterminada se rechazan en la primera actualización, por lo que las sesiones mueren aproximadamente una hora después del inicio de sesiónMS365_MCP_OAUTH_TOKEN: Token OAuth preexistente para Microsoft Graph API (método BYOT)MS365_MCP_KEYVAULT_URL: URL de Azure Key Vault para la gestión de secretos (ver sección Azure Key Vault)MS365_MCP_TOKEN_CACHE_PATH: Ruta de archivo personalizada para la caché de tokens de MSAL (ver Almacenamiento de tokens abajo)MS365_MCP_SELECTED_ACCOUNT_PATH: Ruta de archivo personalizada para los metadatos de la cuenta seleccionada (ver Almacenamiento de tokens abajo)MS365_MCP_AUTH_CACHE_COMMAND: Ejecutable externo para el almacenamiento de caché de autenticación neutral al proveedor (ver Almacenamiento de tokens abajo)MS365_MCP_AUTH_CACHE_COMMAND_TIMEOUT_MS: Tiempo de espera por invocación paraMS365_MCP_AUTH_CACHE_COMMAND(predeterminado:10000)MS365_MCP_EXPECTED_USERNAME: Requiere que la autenticación MSAL local use este nombre de usuario de cuenta de Microsoft (sin distinguir mayúsculas; la bandera de CLI tiene prioridad)MS365_MCP_EXPECTED_HOME_ACCOUNT_ID: Requiere que la autenticación MSAL local use este homeAccountId exacto de MSAL (la bandera de CLI tiene prioridad)
URLs de adjuntos emitidas por el servidor
get-download-url devuelve las @microsoft.graph.downloadUrl preautenticadas propias de Microsoft
para elementos de OneDrive y SharePoint. Graph no publica tal URL para adjuntos de correo y calendario,
grabaciones de reuniones o cualquier otro endpoint de bytes /$value — para esos, la
única forma de leer los bytes ha sido download-bytes, que devuelve base64 al
contexto del agente. Un PDF de 73 KB y 3 páginas cuesta alrededor de 24,500 tokens de esa manera, y el modelo
no puede analizarlos de todos modos.
--enable-attachment-urls (modo HTTP, desactivado por defecto) cierra esa brecha. Cuando Graph no tiene
una URL propia, get-download-url genera una que este servidor sirve:
GET /attachment?t=<ticket>&dgk=<key-id>&dgx=<expiry>&dgs=<signature>
El ticket son 32 bytes de salida CSPRNG, de un solo uso, solo en memoria, y expira después de
MS365_MCP_ATTACHMENT_URL_TTL_S segundos. Canjearlo transmite los bytes de Graph con el token propio de este
servidor; el buscador no envía ningún encabezado Authorization y no posee ninguna credencial de
Microsoft.
Esto no otorga ninguna autoridad que el agente llamante no tuviera ya. Cada destino que puede
ser acuñado es uno que download-bytes obtendría para el mismo llamante en la misma cuenta. El
ticket solo mueve esos bytes fuera de la ventana de contexto y hacia una transferencia directa.
Configuración
MS365_MCP_ATTACHMENT_URL_BASE=http://m365-mcp:3000 # required
MS365_MCP_ATTACHMENT_URL_KEY=... # required (or _KEY_FILE=/path)
MS365_MCP_ATTACHMENT_URL_KEY_ID=1 # optional, default 1
MS365_MCP_ATTACHMENT_URL_TTL_S=120 # optional, default 120, max 300
MS365_MCP_ATTACHMENT_URL_BASE deliberadamente no es MS365_MCP_PUBLIC_URL: ese es
orientado al navegador, para redirecciones OAuth, mientras que este se obtiene de servidor a
servidor y comúnmente es una dirección de contenedor. Una configuración faltante o malformada
falla al inicio en lugar de por solicitud — una característica de firma que aparece sin una clave
acuñaría URLs que nada puede verificar, silenciosamente.
Dividiendo el listener de adjuntos
Por defecto /attachment es servido por la misma aplicación Express, en el mismo puerto, que /mcp.
Eso está bien cuando los llamantes están autenticados por un token portador, y es un problema cuando
no lo están. Bajo --trust-proxy-auth el endpoint MCP no lee ningún encabezado Authorization
en absoluto — la alcanzabilidad es la autenticación — así que un puerto compartido significa que el
sidecar que permitiste para obtener un PDF también puede llamar a cada herramienta en el servidor.
--attachment-port <port> (o MS365_MCP_ATTACHMENT_PORT) mueve la ruta a un listener
propio, y --attachment-host <host> (o MS365_MCP_ATTACHMENT_HOST) indica qué
interfaz enlaza ese listener:
ms-365-mcp-server --http 10.89.0.2:3000 --trust-proxy-auth \
--enable-attachment-urls \
--attachment-port 3001 --attachment-host 10.89.1.2
MS365_MCP_ATTACHMENT_URL_BASE=http://m365-mcp:3001 # note: the attachment port
GET /attachmenten 3001 funciona; en 3000 es 404 — la aplicación MCP nunca lo monta./mcpen 3001 es 404, como todo lo demás: la segunda aplicación tiene la ruta de adjuntos y nada más. Sin router OAuth, sin analizadores de cuerpo, sin CORS, sin verificación de salud.- El limitador de 60 req/min que protege la ruta la sigue al nuevo listener.
trust proxyestá desactivado en el listener de adjuntos (yMS365_MCP_TRUST_PROXY_HOPSno se lee para él), a diferencia del listener MCP, que confía en un salto. Este puerto está destinado a ser marcado directamente en una red de contenedores; honrarX-Forwarded-Foren la única superficie sin credenciales del servidor permitiría a un llamante elegir su propio cubo de límite de tasa.
La bandera requiere --enable-attachment-urls y se niega a iniciar sin ella — por sí sola
abriría un puerto sin nada en él mientras el operador creía que las superficies estaban
separadas. En modo stdio advierte y se ignora, como la bandera de la que depende.
--attachment-host igualmente requiere --attachment-port: sola nombraría una interfaz
para un listener que no existe.
Dos puertos no son dos superficies a menos que enlacen dos interfaces
Esta es la parte que decide si algo de lo anterior vale algo. Léelo antes de implementar la división.
--attachment-port por sí solo separa las dos superficies dentro del proceso. No las
separa en la red. Sin --attachment-host el listener de adjuntos hereda
el host que --http enlazó — y --http 3000, la forma común, no nombra ningún host en absoluto, así que
Node enlaza el comodín y ambos puertos responden en cada interfaz:
ms-365-mcp-server --http 3000 --trust-proxy-auth \
--enable-attachment-urls --attachment-port 3001 # NOT isolated
Las redes de contenedores otorgan a un par cada puerto en un contenedor, no un puerto. Pon un
sidecar de conversión de documentos en un puente compartido para que pueda obtener /attachment en 3001, y
ese mismo sidecar puede marcar :3000/mcp — que bajo --trust-proxy-auth no lee ningún
encabezado Authorization en absoluto y devuelve el catálogo completo de herramientas. Nada falla, nada
se registra como un error, y la configuración se ve exactamente como la aislada.
Para hacerlo real, da a los dos listeners direcciones diferentes, y pon solo la dirección de adjuntos en la red en la que está el buscador:
# docker compose — the MCP port on the agent's own bridge, the attachment port on the
# bridge shared with the converter. The converter can reach 3001 and cannot route to 3000.
services:
m365-mcp:
networks: { agent-net: { ipv4_address: 10.89.0.2 }, convert-net: { ipv4_address: 10.89.1.2 } }
command: >
--http 10.89.0.2:3000 --trust-proxy-auth
--enable-attachment-urls
--attachment-port 3001 --attachment-host 10.89.1.2
docglean:
networks: [convert-net]
El puerto MCP es entonces inalcanzable desde convert-net por enlace — no hay socket
escuchando en esa interfaz — en lugar de por una regla de firewall que tiene que seguir coincidiendo.
El servidor advierte al inicio si ejecutas --trust-proxy-auth con --attachment-port mientras
ambos listeners aún responden en una interfaz común (ya sea compartiendo una dirección, o cualquiera
en el comodín). Ambas direcciones enlazadas se registran, leídas del socket en lugar de
las banderas, para que Server listening on … y Attachment listener on … puedan compararse
directamente.
--attachment-host toma una dirección IPv4 simple, dirección IPv6 (entre corchetes [::1] o simple
::1) o nombre de host. Se rechaza en lugar de forzarse — --attachment-host 10.0.0.5:3001
es un error que nombra --attachment-port, no un enlace a otra cosa. Ten en cuenta que
MS365_MCP_ATTACHMENT_URL_BASE aún no debe ser un literal IPv6 (la firma de URL cubre
el host y las dos implementaciones normalizan IPv6 de manera diferente); si enlazas el listener
a una dirección IPv6, nómbrala en la base por nombre de host.
Apunta MS365_MCP_ATTACHMENT_URL_BASE al puerto de adjuntos. El servidor no puede verificar esto
por ti: la base suele ser un nombre de contenedor en una red que este proceso no puede resolver, así que
un puerto incorrecto aquí aparece como un fallo de obtención en el sidecar, no un error aquí. Tanto la
base como el puerto enlazado se registran al inicio, a una línea de distancia, exactamente para esa comparación.
La firma, y quién verifica qué
dgk/dgx/dgs no son verificados por este servidor al canjear, y eso es deliberado.
Existen para el buscador: un sidecar de conversión de documentos que se niega a marcar una dirección
privada a menos que la URL lleve un HMAC válido de un origen que ha sido configurado para confiar.
Lo que autoriza el canje aquí es el ticket. Verificar la firma en el camino de regreso
probaría solo que acuñamos la URL — que el ticket ya prueba — mientras acopla
el canje al reloj del sidecar y a la clave que sobrevive un reinicio.
El formato de cable es docglean-mcp's
signing.py (canonical_string), y src/lib/url-signing.ts es un puerto de él. La
cadena canónica está unida por \n: v1, esquema en minúsculas, host en minúsculas, el puerto siempre
explícito, la ruta, la consulta restante con dgk/dgx/dgs eliminados y el resto ordenado
y re-codificado, y la expiración. Los vectores de prueba en
test/attachment-url-signing.test.ts se verificaron contra la implementación de Python byte
por byte — tres lugares donde el JavaScript obvio difiere de Python (!*'()
escapado, + decodificado como un espacio, y orden de clasificación de puntos de código vs UTF-16) son por qué esa verificación
existe en lugar de asumirse.
El ticket viaja en la consulta, no en la ruta, porque el sidecar verificador mantiene la ruta de una URL obtenida en sus mensajes de error y elimina la consulta.
No disponible en modo OAuth/OBO
La identidad allí llega por solicitud en el encabezado Authorization del llamante, y un ticket se
canjea más tarde por un buscador que no envía ninguno. La acuñación se niega con una explicación en lugar
de producir una URL que siempre falla.
Almacenamiento de tokens
Los tokens de autenticación se almacenan en un archivo cifrado (AES-256-GCM). Solo la clave de cifrado de 32 bytes va al almacén de credenciales del sistema operativo a través de keytar.
La caché en sí es demasiado grande para que algunos almacenes de credenciales la contengan — un blob del Administrador de credenciales de Windows tiene un límite de 2560 bytes y una caché de tokens real es varias veces eso, así que en Windows la escritura nunca podría tener éxito. Una clave es de 32 bytes independientemente de cuántas cuentas estén conectadas, así que esto funciona igual en cada plataforma.
Rutas predeterminadas están en el directorio de configuración por usuario:
| Plataforma | Ubicación |
|---|---|
| Windows | %APPDATA%\ms-365-mcp-server\ |
| macOS | ~/Library/Application Support/ms-365-mcp-server/ |
| Linux | $XDG_CONFIG_HOME/ms-365-mcp-server/ (o ~/.config/ms-365-mcp-server/) |
Versiones anteriores usaban por defecto una ruta dentro del paquete instalado, que bajo npx resuelve a un directorio de caché con hash de contenido que npm cache clean o un aumento de versión descarta. Una caché que aún está en el directorio del paquete se mueve a la nueva ubicación en el primer inicio.
Eso cubre instalaciones globales y locales, y npx cuando el hash no ha cambiado. No puede alcanzar una caché dejada en un directorio de hash de npx anterior, así que actualizar una instalación de npx una última vez significa iniciar sesión de nuevo. Adoptar una caché de otro directorio significaría confiar en un directorio que este paquete no puede probar que escribió, lo que no vale un inicio de sesión guardado.
Anula las rutas si lo necesitas:
export MS365_MCP_TOKEN_CACHE_PATH="$HOME/.config/ms365-mcp/.token-cache.json"
export MS365_MCP_SELECTED_ACCOUNT_PATH="$HOME/.config/ms365-mcp/.selected-account.json"
Los directorios padre se crean automáticamente. Los archivos se escriben con permisos 0600.
Sin un almacén de credenciales (Linux sin cabeza, la mayoría de los contenedores) la clave se escribe en .cache-key junto al archivo de caché, con permisos 0600. Eso evita que los tokens aparezcan en un cat perdido, una copia de seguridad o una confirmación accidental. No protege contra cualquiera que ya pueda leer el directorio — la clave está justo ahí. Usa MS365_MCP_AUTH_CACHE_COMMAND a continuación si necesitas la caché en un almacén de secretos real.
Omitiendo el almacén de credenciales a propósito:
export MS365_MCP_USE_KEYTAR=0 # also accepts false, no or off
La clave entonces va a .cache-key en cada plataforma, exactamente como donde no existe un almacén de credenciales, y nada en el servidor llama a keytar. Útil cuando el almacén de credenciales solicita en cada inicio — macOS vuelve a preguntar cada vez que el binario llamante cambia, que bajo npx es cada aumento de versión — o cuando el módulo nativo se comporta mal en tu plataforma en lugar de simplemente fallar al cargar. Cualquier otro valor deja el almacén de credenciales en uso, y uno no reconocido se advierte en lugar de pasarse por alto silenciosamente.
Apagarlo deja varada una caché que fue cifrada bajo una clave ya en el almacén de credenciales, ya que nada puede alcanzar esa clave más. El servidor lo dice y reemplaza esa caché en el próximo inicio de sesión, que cierra la sesión de cada cuenta que contenía, no solo la que inicias de nuevo. Desactiva la variable primero si esa caché vale la pena conservarla.
Solo una caché que nada en la máquina puede abrir se reemplaza. Una que falla al descifrar mientras una clave utilizable está justo ahí — un archivo truncado, una degradación a una compilación más antigua, una caché de otro lugar — es daño en lugar de una caché varada, y se deja sola exactamente como está por defecto.
Dos cosas que deliberadamente no hace. Nunca elimina lo que este servidor ya puso en el almacén de credenciales, al cerrar sesión o de otro modo, porque alcanzar el almacén es lo que acabas de pedirle que deje de hacer — limpia las entradas de ms-365-mcp-server a mano si quieres que se vayan. Y un .cache-key que existe pero no puede leerse (propietario incorrecto en un directorio de configuración montado por bind, por ejemplo) se trata como recuperable en lugar de faltante: el servidor se niega tanto a sobrescribir una caché como a acuñar una clave de reemplazo, y lo dice, en lugar de eliminar una clave que funcionaría de nuevo una vez que los permisos se arreglen. Arregla los permisos, o elimina .cache-key tú mismo para empezar de nuevo — lo que sí significa iniciar sesión de nuevo.
Si la caché no puede descifrarse — clave perdida, llavero bloqueado, archivo modificado — se te pide iniciar sesión de nuevo en lugar de que el servidor falle al iniciar. El archivo de caché se deja exactamente como estaba: no eliminado, y no sobrescrito por ese nuevo inicio de sesión tampoco. Un llavero que solo está bloqueado generalmente se lee bien en el próximo inicio, y la caché sigue ahí cuando lo hace.
El costo es que la nueva sesión no se guarda mientras esto dure, así que cada inicio te pide iniciar sesión de nuevo. Si la clave realmente se ha ido y la caché nunca se abrirá, elimina .token-cache.json para empezar de nuevo — el registro lo dice, y nombra la ruta.
Entornos alojados/en sandbox (p. ej. Anthropic Cowork): Establece
MS365_MCP_TOKEN_CACHE_PATHyMS365_MCP_SELECTED_ACCOUNT_PATHa un montaje persistente para que los tokens sobrevivan entre sesiones.
Comando externo de caché de autenticación
Las implementaciones headless de MSAL local pueden reemplazar el almacenamiento integrado de keytar/archivos con un comando externo neutral respecto al proveedor:
export MS365_MCP_AUTH_CACHE_COMMAND="/path/to/ms365-auth-cache-store"
export MS365_MCP_AUTH_CACHE_COMMAND_TIMEOUT_MS=10000
Cuando MS365_MCP_AUTH_CACHE_COMMAND está configurado para un flujo de autenticación local, el servidor utiliza únicamente ese comando para la caché de tokens de MSAL y los metadatos de la cuenta seleccionada. No recurre a keytar ni a archivos locales. Si la ruta del comando no existe, no es ejecutable en POSIX, sale con código distinto de cero, se agota el tiempo de espera o devuelve datos malformados, las operaciones de caché de autenticación fallan de forma segura con un mensaje de error saneado.
El valor debe ser una ruta real a un ejecutable contenedor. No es una cadena de comando de shell, y no existe una variable de entorno de argumentos complementaria. Coloque cualquier intérprete, región, perfil o configuración específica del proveedor dentro del contenedor. Los usuarios de Windows deben apuntar la variable a un ejecutable o script contenedor que Node pueda lanzar directamente sin análisis de shell.
El servidor invoca el contenedor con:
$MS365_MCP_AUTH_CACHE_COMMAND load token-cache
$MS365_MCP_AUTH_CACHE_COMMAND save token-cache
$MS365_MCP_AUTH_CACHE_COMMAND delete token-cache
$MS365_MCP_AUTH_CACHE_COMMAND load selected-account
$MS365_MCP_AUTH_CACHE_COMMAND save selected-account
$MS365_MCP_AUTH_CACHE_COMMAND delete selected-account
Protocolo v1:
load <key>no lee stdin. Sale con0y{"found":true,"value":"<stored envelope string>"}cuando está presente. Un fallo es salir con0y{"found":false}o stdout vacío.save <key>recibe{"value":"<stamped envelope string>"}en stdin y debe salir con0solo después de que el valor se haya confirmado de forma duradera. No hay guardados de tipo "dispara y olvida" ni combinados en v1.delete <key>no lee stdin y sale con0tanto si la clave existía como si no.<key>estoken-cacheoselected-account.- Cualquier salida distinta de cero es un error de almacenamiento. No use el código de salida
2para fallos de caché. - Stderr se captura y se trunca en errores saneados. El servidor nunca registra las cargas útiles de stdin y stdout.
- Las cargas útiles de la caché de tokens pueden ser grandes; los contenedores deben manejar valores de al menos 256 KB.
Las solicitudes normales de Graph HTTP sin estado no utilizan el almacenamiento de caché de autenticación local. En modo HTTP, el almacenamiento de comandos se omite al inicio y por solicitud, a menos que las herramientas de autenticación local estén explícitamente habilitadas o se use un comando de cuenta local como --login, --verify-login, --list-accounts, --select-account o --logout.
Integración con Azure Key Vault
Para implementaciones de producción, puede almacenar secretos en Azure Key Vault en lugar de variables de entorno. Esto es particularmente útil para Azure Container Apps con identidad administrada.
Configuración
-
Cree un Key Vault (si no tiene uno):
az keyvault create --name your-keyvault-name --resource-group your-rg --location eastus -
Agregue secretos al Key Vault:
az keyvault secret set --vault-name your-keyvault-name --name ms365-mcp-client-id --value "your-client-id" az keyvault secret set --vault-name your-keyvault-name --name ms365-mcp-tenant-id --value "your-tenant-id" # Optional: if using confidential client flow az keyvault secret set --vault-name your-keyvault-name --name ms365-mcp-client-secret --value "your-secret" -
Conceda acceso al Key Vault:
Para Azure Container Apps con identidad administrada:
# Get the managed identity principal ID PRINCIPAL_ID=$(az containerapp show --name your-app --resource-group your-rg --query identity.principalId -o tsv) # Grant access to Key Vault secrets az keyvault set-policy --name your-keyvault-name --object-id $PRINCIPAL_ID --secret-permissions get listPara desarrollo local con Azure CLI:
# Your Azure CLI identity already has access if you have appropriate RBAC roles az login -
Configure el servidor:
MS365_MCP_KEYVAULT_URL=https://your-keyvault-name.vault.azure.net npx @softeria/ms-365-mcp-server
Mapeo de nombres de secretos
| Nombre del secreto en Key Vault | Variable de entorno | ¿Requerido? |
|---|---|---|
| ms365-mcp-client-id | MS365_MCP_CLIENT_ID | Sí |
| ms365-mcp-tenant-id | MS365_MCP_TENANT_ID | No (por defecto 'common') |
| ms365-mcp-client-secret | MS365_MCP_CLIENT_SECRET | No |
Autenticación
La integración con Key Vault utiliza DefaultAzureCredential del SDK de Azure Identity, que automáticamente prueba múltiples métodos de autenticación en orden:
- Variables de entorno (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
- Identidad administrada (recomendado para Azure Container Apps)
- Credenciales de Azure CLI (para desarrollo local)
- Credenciales de Visual Studio Code
- Credenciales de Azure PowerShell
Dependencias opcionales
Los paquetes de Azure Key Vault (@azure/identity y @azure/keyvault-secrets) son dependencias opcionales. Solo se cargan cuando MS365_MCP_KEYVAULT_URL está configurado. Si no usa Key Vault, estos paquetes no son necesarios.
Firma de mensajes
Los mensajes salientes pueden envolverse en una firma configurable (por ejemplo, un prefijo 🤖) para que los destinatarios puedan distinguir los mensajes enviados por agentes de los que usted mismo escribió. Desactivada por defecto — actívela con --message-signoff-prefix / --message-signoff-suffix (env: MS365_MCP_MESSAGE_SIGNOFF_PREFIX / MS365_MCP_MESSAGE_SIGNOFF_SUFFIX); --no-message-signoff o un valor de entorno vacío la desactiva nuevamente.
Una vez configurada, se aplica a todos los mensajes de Teams (envíos, respuestas y ediciones, incluso mediante graph-batch), a los envíos directos de correo (send-mail, responder/reenviar, sus variantes de buzón compartido y respuestas en hilos de grupo), y a los borradores de correo a medida que se escribe su contenido — send-draft-message envía un borrador tal cual, por lo que un borrador que usted mismo escribió sale sin modificar. Un mensaje que ya lleva el marcador no se firma dos veces, y un envío cuyo cuerpo no puede llevar la firma se rechaza en lugar de enviarse sin firmar.
Los marcadores pueden contener marcado (por ejemplo, un <span> de color) siempre que muestren texto visible. Tenga en cuenta que la firma es una salvaguarda contra el mal uso de las herramientas por parte de un agente, no un límite de seguridad estricto — un agente con acceso de shell en la misma máquina podría simplemente reiniciar el servidor sin ella.
Implementación en producción
Consulte docs/deployment.md para una guía completa sobre cómo alojar el servidor para acceso a nivel organizacional, incluidos Docker, Azure Container Apps, Azure App Service, registro de aplicaciones de Azure AD, configuración de proxy inverso, configuración de clientes y endpoints expuestos.
Contribuciones
¡Agradecemos las contribuciones! Antes de enviar una solicitud de extracción, asegúrese de que sus cambios cumplan con nuestros estándares de calidad.
Ejecute el script de verificación para comprobar todos los requisitos de calidad del código:
npm run verify
Para desarrolladores
Después de clonar el repositorio, es posible que necesite generar el código del cliente a partir de la especificación OpenAPI de Microsoft Graph:
npm run generate
Proyectos relacionados
- ms-365-admin-mcp-server por @okapi-ca: servidor complementario para escenarios de administrador/daemon que usan permisos de aplicación (flujo de credenciales de cliente), que cubre alertas de seguridad, registros de auditoría, estado del servicio e informes de uso.
Soporte
Si tiene problemas o necesita ayuda:
- Cree un issue
- Inicie una discusión
- Correo electrónico: eirikb@eirikb.no
- Discord: https://discord.gg/WvGVNScrAZ o @eirikb
Licencia
MIT © 2026 Softeria