Microsoft 365
Servidor MCP que se conecta a todo o conjunto Microsoft 365 (Microsoft Office, Outlook, Excel) usando a Graph API (incluindo e-mail, arquivos, calendário)
Documentação
ms-365-mcp-server
Servidor MCP do Microsoft 365
Um servidor Model Context Protocol (MCP) para interagir com os serviços do Microsoft 365 e Microsoft Office por meio da API Graph.
Nuvens Suportadas
Este servidor suporta vários ambientes de nuvem da Microsoft:
| Nuvem | Descrição | Endpoint de Autenticação | Endpoint da API Graph |
|---|---|---|---|
| Global (padrão) | Microsoft 365 internacional | login.microsoftonline.com | graph.microsoft.com |
| China (21Vianet) | Microsoft 365 operado pela 21Vianet | login.chinacloudapi.cn | microsoftgraph.chinacloudapi.cn |
Pré-requisitos
- Node.js >= 20 (recomendado)
- Node.js 14+ pode funcionar com avisos de dependência
Recursos
- Autenticação via Microsoft Authentication Library (MSAL)
- Integração abrangente com os serviços do Microsoft 365
- Suporte ao modo somente leitura para operações seguras
- Filtragem de ferramentas para controle de acesso granular
- Predefinições de ferramentas e descoberta dinâmica para reduzir a superfície de ferramentas e o uso de tokens
Formato de Saída: JSON vs TOON
O servidor suporta dois formatos de saída que podem ser configurados globalmente:
Formato JSON (Padrão)
Saída JSON padrão com formatação legível:
{
"value": [
{
"id": "1",
"displayName": "Alice Johnson",
"mail": "alice@example.com",
"jobTitle": "Software Engineer"
}
]
}
Formato TOON (experimental)
Token-Oriented Object Notation para uso eficiente de tokens LLM:
value[1]{id,displayName,mail,jobTitle}:
"1",Alice Johnson,alice@example.com,Software Engineer
Benefícios:
- 30-60% menos tokens em comparação com JSON
- Melhor para dados de array uniformes (listas de e-mails, eventos de calendário, arquivos, etc.)
- Ideal para aplicações sensíveis a custos em escala
Uso: (experimental) Ative o formato TOON globalmente:
Via flag CLI:
npx @softeria/ms-365-mcp-server --toon
Via configuração do Claude Desktop:
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--toon"]
}
}
}
Via variável de ambiente:
MS365_MCP_OUTPUT_FORMAT=toon npx @softeria/ms-365-mcp-server
Serviços e Ferramentas Suportados
O servidor fornece mais de 300 ferramentas cobrindo a maior parte da superfície da API Graph da Microsoft. Cada ferramenta mapeia 1 para 1 para um endpoint da API Graph e é definida declarativamente em src/endpoints.json.
Ferramentas para Contas Pessoais (Disponíveis por padrão)
E-mail (Outlook), Calendário, Arquivos do OneDrive, Excel, OneNote, Tarefas do To Do, Planner, Contatos, Perfil do Usuário, Pesquisa
Ferramentas para Contas Organizacionais (Requer a flag --org-mode)
Teams e Chats, Reuniões Online, Transcrições e Gravações, Relatórios de Presença, Sites e Listas do SharePoint, Caixas de Correio e Calendários Compartilhados, Gerenciamento de Usuários, Presença, Eventos Virtuais
Permissões Necessárias da API Graph
As permissões são solicitadas dinamicamente com base nas ferramentas habilitadas. Use --list-permissions para ver as permissões exatas para sua configuração:
# 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
Isso é útil para ambientes empresariais onde as permissões da API Graph devem ser pré-aprovadas e consentidas pelo administrador antes de implantar uma nova versão.
O JSON --list-permissions inclui:
toolPermissions: permissões implícitas pela superfície de ferramentas antes da filtragem--allowed-scopeseffectivePermissions: permissões implícitas pelas ferramentas que permanecem habilitadas após--allowed-scopespermissions: alias legado paraeffectivePermissions, mantido para compatibilidade com scripts existentesallowedScopes: a lista de permissões de escopo configurada, quando fornecidadisabledTools: ferramentas ocultas porque seus escopos Graph necessários não são cobertos porallowedScopesmissingAllowedScopesForTools: escopos ausentes exclusivos entre ferramentas desabilitadasextraAllowedScopesNotUsedByTools: escopos permitidos que não são usados pela superfície de ferramentas atual
Escopos Permitidos
Por padrão, o MSAL solicita os escopos implícitos pelas ferramentas habilitadas, e a superfície de ferramentas é controlada por --enabled-tools, --preset, --org-mode e --read-only.
Implantações empresariais e headless podem adicionar um limite de escopo com --allowed-scopes ou MS365_MCP_ALLOWED_SCOPES. Quando configurado, o servidor primeiro calcula a superfície normal de ferramentas e depois oculta as ferramentas Graph cujos escopos necessários não são cobertos pela lista de permissões. Os metadados OAuth e os fluxos de login solicitam apenas as permissões efetivas para as ferramentas que permanecem 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'
O valor da CLI tem precedência sobre MS365_MCP_ALLOWED_SCOPES; se nenhum for definido, o comportamento padrão de escopo derivado de ferramentas permanece inalterado. Fornecer um valor vazio falha na inicialização para que as implantações não caiam acidentalmente em uma superfície de ferramentas mais ampla.
A cobertura de escopo é ciente de hierarquia: por exemplo, Mail.ReadWrite cobre ferramentas que exigem Mail.Read, e Files.ReadWrite.All cobre ferramentas que exigem Files.Read.
O SharePoint suporta dois modelos de permissão empresarial:
- Escopos amplos de locatário, como
Sites.Read.All,Sites.ReadWrite.AlleSites.Manage.All. - Microsoft Graph
Sites.Selected, onde o acesso ao site do SharePoint é concedido ao aplicativo em coleções de sites específicas e o Graph avalia as permissões do usuário conectado no momento da solicitação.
O comportamento padrão do modo organizacional continua solicitando os escopos amplos do SharePoint usados pelas implantações existentes. Empresas que desejam acesso seletivo a sites do SharePoint podem definir uma lista de permissões contendo Sites.Selected em vez de escopos amplos Sites.*.All. Ferramentas diretas de site/lista/item que visam um site específico do SharePoint, e as ferramentas de item /drives/{drive-id}/... (listar, obter, enviar, pasta, mover/renomear, copiar, versões) para unidades de um site concedido, podem ser executadas com Sites.Selected; ferramentas de descoberta e pesquisa do SharePoint em todo o locatário ainda exigem escopos amplos do 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'
No modo HTTP, a descoberta OAuth anuncia as permissões filtradas efetivas para que os clientes solicitem a mesma superfície de consentimento. O modo On-Behalf-Of (--obo) ainda anuncia api://<clientId>/access_as_user para metadados de recursos protegidos; --allowed-scopes não substitui o OBO.
Solicitando escopos extras
--allowed-scopes apenas restringe a solicitação de token. Para solicitar um escopo Graph que nenhuma ferramenta incluída precisa — por exemplo, para acionar um endpoint via graph-batch — use --extra-scopes (ou MS365_MCP_EXTRA_SCOPES). Esses escopos são anexados literalmente à solicitação de token, além dos escopos derivados de ferramentas.
npx @softeria/ms-365-mcp-server \
--org-mode \
--extra-scopes 'CopilotPackages.ReadWrite.All'
Isso é para uso com seu próprio registro de aplicativo Azure (MS365_MCP_CLIENT_ID / MS365_MCP_CLIENT_SECRET): o aplicativo padrão Softeria declara apenas um conjunto de permissões enxuto e fixo, portanto, solicite escopos adicionais contra um aplicativo que você controla (seu administrador de locatário consente com eles lá). O valor da CLI tem precedência sobre a variável de ambiente; um valor vazio falha na inicialização.
Modo Organizacional/Trabalho
Para acessar recursos de trabalho/escola (Teams, SharePoint, etc.), ative o modo organizacional usando qualquer uma destas flags:
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
}
}
}
O modo organizacional deve ser habilitado desde o início para acessar recursos de contas de trabalho. Sem esta flag, apenas recursos de contas pessoais (e-mail, calendário, OneDrive, etc.) estão disponíveis.
Acesso a Caixas de Correio Compartilhadas
Para acessar caixas de correio compartilhadas, você precisa:
- Modo organizacional: As ferramentas de caixa de correio compartilhada exigem a flag
--org-mode(somente contas de trabalho/escola) - Permissões delegadas:
Mail.Read.Sharedpara ler,Mail.ReadWrite.Sharedpara criar, atualizar ou mover mensagens,Mail.Send.Sharedpara enviar, responder ou encaminhar, eCalendars.Read.Sharedpara as ferramentas de calendário compartilhado - Permissões do Exchange: O usuário conectado deve ter recebido acesso à caixa de correio compartilhada
- Uso: Use o endereço de e-mail da caixa de correio compartilhada como o parâmetro
user-idnas ferramentas de caixa de correio compartilhada
Encontrando caixas de correio compartilhadas: Use a ferramenta list-users para descobrir usuários disponíveis e caixas de correio compartilhadas em sua organização.
Exemplo: list-shared-mailbox-messages com user-id definido como shared-mailbox@company.com
Exemplo de Início Rápido
Teste o login no Claude Desktop:
Exemplos
Integração
Claude Desktop
Para adicionar este servidor MCP ao Claude Desktop, edite o arquivo de configuração em Configurações > Desenvolvedor.
Conta Pessoal (MSA)
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server"]
}
}
}
Conta de Trabalho/Escola (Global)
{
"mcpServers": {
"ms365": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
}
}
}
Conta de Trabalho/Escola (China 21Vianet)
{
"mcpServers": {
"ms365-china": {
"command": "npx",
"args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode", "--cloud", "china"]
}
}
}
Claude Code CLI
Conta Pessoal (MSA)
claude mcp add ms365 -- npx -y @softeria/ms-365-mcp-server
Conta de Trabalho/Escola (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"
Conta de Trabalho/Escola (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 outras interfaces que suportam MCPs, consulte a documentação respectiva para o método de integração correto.
Open WebUI
O Open WebUI suporta servidores MCP via transporte HTTP com OAuth 2.1.
-
Inicie o servidor com o modo HTTP:
npx @softeria/ms-365-mcp-server --http -
No Open WebUI, vá para Configurações do Administrador → Ferramentas (
/admin/settings/tools) → Adicionar Conexão:- Tipo: MCP Streamable HTTP
- URL: A URL do seu servidor MCP com o caminho
/mcp - Autenticação: OAuth 2.1
-
Clique em Registrar Cliente.
Nota: O registro dinâmico de clientes está habilitado por padrão no modo HTTP. Use
--no-dynamic-registration(ou definaMS365_MCP_DISABLE_DCR=true) para desabilitá-lo. Se estiver usando um aplicativo Azure Entra personalizado, o tipo de plataforma para sua URI de redirecionamento depende de o aplicativo ter um segredo de cliente: com segredo use "Web", sem segredo use "Aplicativos móveis e desktop" (nunca "Aplicativo de página única").
Configuração rápida de teste usando o aplicativo Azure padrão (ID ms-365 e localhost:8080 são pré-configurados):
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
Em seguida, adicione a conexão com URL http://localhost:3000/mcp e ID ms-365.
Executando em Docker atrás de um proxy reverso? Defina
--public-url https://your-domain.compara que a URL de autorização OAuth entregue ao navegador do usuário seja acessível fora da rede do contêiner. Consulte docs/deployment.md para o guia completo.
Desenvolvimento Local
Para desenvolvimento local ou testes:
# From the project directory
claude mcp add ms -- npx tsx src/index.ts --org-mode
Ou configure o Claude Desktop manualmente:
{
"mcpServers": {
"ms365": {
"command": "node",
"args": ["/absolute/path/to/ms-365-mcp-server/dist/index.js", "--org-mode"]
}
}
}
Nota: Execute
npm run buildapós alterações de código para atualizar a pastadist/.
Autenticação
⚠️ Você deve autenticar antes de usar as ferramentas.
O servidor suporta três métodos de autenticação:
1. Fluxo de Código de Dispositivo (Padrão)
Para autenticação interativa via código de dispositivo:
- Login do cliente MCP:
- Chame a ferramenta
login(verifica automaticamente o token existente) - Se necessário, obtenha URL+código, visite no navegador
- Use a ferramenta
verify-loginpara confirmar
- Chame a ferramenta
- Login via CLI:
Siga a URL e o prompt de código no terminal.npx @softeria/ms-365-mcp-server --login
Os tokens são armazenados em cache com segurança no armazenamento de credenciais do seu sistema operacional (fallback para arquivo).
2. Fluxo de Código de Autorização OAuth (somente modo HTTP)
Ao executar com --http, o servidor exige autenticação OAuth:
npx @softeria/ms-365-mcp-server --http 3000
Este modo:
- Anuncia capacidades OAuth aos clientes MCP
- Fornece endpoints OAuth em
/auth/*(autorizar, token, metadados) - Exige
Authorization: Bearer <token>para todas as solicitações MCP - Valida tokens com a API Graph da Microsoft
- Desabilita as ferramentas de login/logout por padrão (use
--enable-auth-toolspara habilitá-las)
Os clientes MCP lidarão automaticamente com o fluxo OAuth quando virem as capacidades anunciadas.
Configurando o Azure AD para Testes OAuth
Para usar o modo OAuth com credenciais Azure personalizadas (recomendado para produção), você precisará configurar um registro de aplicativo Azure AD:
- Crie o Registro de Aplicativo Azure AD:
- Vá para Portal Azure
- Navegue até Azure Active Directory → Registros de aplicativos → Novo registro
- Defina o nome: "MS365 MCP Server"
- Configure as URIs de Redirecionamento:
- Configure a URI de callback OAuth: Vá para o registro do seu aplicativo e, no lado esquerdo, vá para Autenticação.
- Em Configurações de plataforma:
- Clique em Adicionar uma plataforma (se você ainda não vir uma para "Aplicativos móveis e desktop" / "Cliente público").
- Escolha Aplicativos móveis e desktop ou Cliente público/nativo (móvel e desktop) (o rótulo depende da versão do portal).
- Testando com o MCP Inspector (
npm run inspector):
- Vá até o registro do seu aplicativo e, no lado esquerdo, acesse Autenticação.
- Em Configurações de plataforma:
- Clique em Adicionar uma plataforma (se ainda não houver uma para "Web").
- Escolha Web.
- Configure os seguintes URIs de redirecionamento:
http://localhost:6274/oauth/callbackhttp://localhost:6274/oauth/callback/debughttp://localhost:3000/callback(opcional, para callback do servidor)
- Obter Credenciais:
- Copie o ID do aplicativo (cliente) da página Visão geral.
- Vá em Certificados e segredos → Novo segredo do cliente → Copie o valor do segredo (opcional para aplicativos públicos).
- Configurar Variáveis de Ambiente:
Crie um arquivo
.envna raiz do seu projeto: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
Com essas configurações, o servidor usará seu aplicativo Azure personalizado em vez do integrado.
Nota:
.envé lido do diretório em que o servidor é iniciado, e o cliente MCP decide o que isso é. ApenasMS365_MCP_CLIENT_ID,MS365_MCP_CLIENT_SECRET,MS365_MCP_TENANT_IDeMS365_MCP_CLOUD_TYPEsão lidos dele. Todas as outras variáveis listadas acima devem ser definidas no seu shell ou na configuração do cliente MCP; qualquer outra coisa encontrada em um.envé ignorada com um aviso no stderr.
3. Traga Seu Próprio Token (BYOT)
Se você está executando o ms-365-mcp-server como parte de um sistema maior que gerencia tokens OAuth da Microsoft externamente, você pode fornecer um token de acesso diretamente a este servidor MCP:
MS365_MCP_OAUTH_TOKEN=your_oauth_token npx @softeria/ms-365-mcp-server
Este método:
- Ignora os fluxos de autenticação interativos
- Usa seu token OAuth pré-existente para solicitações à API do Microsoft Graph
- Não gerencia a renovação de tokens (a gestão do ciclo de vida do token é sua responsabilidade)
Nota: O modo HTTP exige autenticação. Para testes sem autenticação, use o modo stdio com fluxo de código de dispositivo.
Ferramentas de Autenticação: No modo HTTP, as ferramentas de login/logout são desabilitadas por padrão, pois o OAuth gerencia a autenticação. Use
--enable-auth-toolsse precisar que elas estejam disponíveis.
Suporte a Múltiplas Contas
Use uma única instância do servidor para atender várias contas da Microsoft. Quando mais de uma conta está conectada, um parâmetro account é injetado automaticamente em todas as ferramentas, permitindo que você especifique qual conta usar em cada chamada de ferramenta.
Conectar múltiplas contas (uma vez por conta):
# 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 contas configuradas:
npx @softeria/ms-365-mcp-server --list-accounts
Usar em chamadas de ferramenta: Passe "account": "work@company.com" em qualquer solicitação de ferramenta:
{ "tool": "list-mail-messages", "arguments": { "account": "work@company.com" } }
Comportamento:
- Com uma única conta configurada, ela é selecionada automaticamente (nenhum parâmetro
accounté necessário). - Com múltiplas contas e sem o parâmetro
account, o servidor usa a conta padrão selecionada ou retorna um erro útil listando as contas disponíveis. - 100% compatível com versões anteriores: configurações existentes de conta única funcionam sem alterações.
- O parâmetro
accountaceita endereço de e-mail (ex.:user@outlook.com) ouhomeAccountIddo MSAL.
Fixação Estrita de Conta
Implantações headless em stdio podem fixar o cache MSAL local a uma conta 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
Use --list-accounts para descobrir valores de homeAccountId. A ferramenta list-accounts do MCP oculta intencionalmente IDs de conta, então use a CLI para fixação exata de ID.
A fixação é opcional e apenas para MSAL local:
- Valores da CLI (
--expected-username,--expected-home-account-id) têm precedência sobreMS365_MCP_EXPECTED_USERNAMEeMS365_MCP_EXPECTED_HOME_ACCOUNT_ID. - Fornecer um valor de fixação vazio falha na inicialização em vez de ser ignorado.
- Fixações de nome de usuário são comparadas sem diferenciar maiúsculas/minúsculas; fixações de
homeAccountIdsão exatas. - Se ambas as fixações forem definidas, elas devem resolver para a mesma conta em cache.
- A inicialização local em stdio falha rapidamente quando a conta esperada não está no cache de tokens. Inicialize definindo a fixação, executando
--logine depois iniciando o servidor headless. - Logins por código de dispositivo e navegador rejeitam uma conta ausente ou incompatível antes de persistir a conta selecionada ou o cache de tokens.
- A fixação reduz o modo MCP efetivo para conta única: o servidor não anuncia um parâmetro
accounte as instruções do MCP não sugerem troca de conta. --http,--oboeMS365_MCP_OAUTH_TOKENusam tokens fornecidos na solicitação para chamadas ao Graph, então as fixações de conta são apenas avisos nesses modos. Se as ferramentas de autenticação HTTP estiverem habilitadas, a fixação ainda se aplica aos fluxos auxiliares MSAL locais.--logoutlimpa todas as contas em cache, incluindo a conta fixada. Para limpeza cirúrgica, prefira--remove-account <id>.
Para multiplexadores MCP (Legate, Governor): O modo multi-conta substitui o padrão de N processos. Em vez de iniciar um servidor por conta, uma única instância lida com todas as contas via o parâmetro
account, reduzindo a duplicação de ferramentas de N×110 para 110.
Predefinições de Ferramentas
Para reduzir a sobrecarga inicial de conexão e o uso de tokens, use categorias de ferramentas predefinidas em vez de carregar o conjunto completo de ferramentas:
npx @softeria/ms-365-mcp-server --preset mail
npx @softeria/ms-365-mcp-server --list-presets # See all available presets
Predefinições disponíveis: mail, calendar, files, personal, work, excel, contacts, tasks, onenote, search, users, outlook, onedrive, teams, teams-write, all
Cada endpoint em endpoints.json declara a quais predefinições pertence via um array presets, então cada predefinição é uma lista de permissão exata de nomes de ferramentas que nunca corresponde em excesso entre aplicativos (ex.: mail não inclui ferramentas de caixa de correio compartilhada; essas estão em work). O leitor binário universal download-bytes está incluído em todas as predefinições, exceto teams-write, então o que quer que um aplicativo retorne (um arquivo, um anexo, uma foto, uma gravação) sempre pode ser buscado; get-download-url (uma URL pré-autenticada para arquivos do drive/SharePoint) acompanha as predefinições baseadas em drive. Portanto, uma predefinição que pode encontrar um arquivo sempre pode ler seus bytes.
As predefinições outlook, onedrive e teams são limitadas a aplicativos: elas expõem exatamente um aplicativo Microsoft. Use-as para implantações de "expor exatamente um aplicativo":
# 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
A predefinição teams-write é a contraparte somente envio de --read-only: enviar em chats, enviar/responder em canais, listar chats/equipes/canais por nome e notificações de atividade — sem leitura de mensagens e sem downloaders de bytes. O token solicitado é mínimo por construção (Chat.ReadBasic, os escopos *.Send e listagem básica de equipes/canais — nada que possa ler conteúdo de mensagens):
npx @softeria/ms-365-mcp-server --org-mode --preset teams-write
Descoberta Dinâmica de Ferramentas
Em vez de carregar todas as ferramentas antecipadamente, use a descoberta dinâmica para que o LLM encontre e carregue ferramentas apenas quando precisar delas:
npx @softeria/ms-365-mcp-server --discovery
Mantém o contexto inicial pequeno e reduz o uso de tokens, especialmente útil para sessões longas ou configurações sensíveis a custos (ex.: Open WebUI rodando contra uma API paga).
Opções de CLI
As seguintes opções podem ser usadas ao executar o ms-365-mcp-server diretamente da linha de comando:
--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
Opções do Servidor
Ao executar como servidor MCP, as seguintes opções podem ser usadas:
-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)
Variáveis de ambiente:
READ_ONLY=true|1: Alternativa ao flag --read-onlyENABLED_TOOLS: Filtra ferramentas usando um padrão regex (alternativa ao flag --enabled-tools)MS365_MCP_ORG_MODE=true|1: Habilita o modo organização/trabalho (alternativa ao flag --org-mode)MS365_MCP_FORCE_WORK_SCOPES=true|1: Compatibilidade retroativa para MS365_MCP_ORG_MODEMS365_MCP_OUTPUT_FORMAT=toon: Habilita o formato de saída TOON (alternativa ao flag --toon)MS365_MCP_MAX_TOP=<n>: Limite máximo para$top/topdo Graph em solicitações de listagem (inteiro positivo). Quando o modelo passa um valor maior, o servidor o limita anpara que as respostas permaneçam menores. Exemplo:MS365_MCP_MAX_TOP=15MS365_MCP_MAX_PAGES=<n>: Número máximo de páginas seguidas quando uma ferramenta é chamada comfetchAllPages: true(inteiro positivo, padrão100). Limita memória e latência para grandes conjuntos de resultados.MS365_MCP_MAX_ITEMS=<n>: Número máximo de itens acumulados quandofetchAllPages: true(inteiro positivo, padrão10000). A paginação para e a resposta é truncada quando esse número de itens é coletado.MS365_MCP_ALLOW_PAGINATION=0|false|no: Desabilita completamente o seguimento de múltiplas páginas. Quando definido, o parâmetrofetchAllPagesnão é anunciado nas ferramentas, e qualquer solicitação que ainda o passe retorna apenas a primeira página (padrão: paginação habilitada).MS365_MCP_BODY_FORMAT=html: Retorna corpos de e-mail como HTML em vez de texto simples (padrão: texto)MS365_MCP_MESSAGE_SIGNOFF_PREFIX=<text>: Assinatura prefixada às mensagens enviadas para que os destinatários saibam que foram enviadas por agente, ex.:🤖. Padrão: nenhuma. Equivalente na CLI:--message-signoff-prefix <text>(veja Assinatura de Mensagem abaixo)MS365_MCP_MESSAGE_SIGNOFF_SUFFIX=<text>: Assinatura anexada às mensagens enviadas. Padrão: nenhuma. Equivalente na CLI:--message-signoff-suffix <text>.--no-message-signoffdesabilita ambas (veja Assinatura de Mensagem abaixo)MS365_MCP_RATE_LIMIT_DISABLED=true|1: Desabilita a limitação de taxa por IP no modo HTTP (padrão: habilitada — 30 req/min em/authorize,/token,/register; 120 req/min em/mcp)MS365_MCP_TRUST_PROXY_HOPS=<n>: Número de saltos de proxy reverso confiáveis no modo HTTP (padrão1). A limitação de taxa precisa por IP depende disso corresponder à sua implantação — defina o número de proxies na frente do servidor,0para usar o IP bruto do socket peer, ou uma lista de sub-redes separadas por vírgulasMS365_MCP_ATTACHMENT_PORT=<port>: Serve a rota de anexos em seu próprio listener nesta porta (alternativa ao --attachment-port; requer--enable-attachment-urls)MS365_MCP_ATTACHMENT_HOST=<host>: Interface à qual o listenerMS365_MCP_ATTACHMENT_PORTse vincula (alternativa ao --attachment-host; requer--attachment-port). Padrão: o host ao qual--httpestá vinculado — o que para um--httpcuringa significa que ambas as portas respondem em todos os lugares e a divisão de portas não isola nada. Veja "Dividindo o listener de anexos"MS365_MCP_CLOUD_TYPE=global|china: Ambiente de nuvem da Microsoft (alternativa ao flag --cloud)LOG_LEVEL: Define o nível de log (padrão: 'info')SILENT=true|1: Desabilita a saída no consoleMS365_MCP_REDACT_PII=false|0: Desabilita a limpeza de JWTs, cabeçalhos Bearer, campos de token OAuth e endereços de e-mail das mensagens de log (padrão: habilitada). O servidor lida com tokens Bearer do Graph ao vivo, então a redação está ativa a menos que você opte por sair para depuração local totalmente detalhada.MS365_MCP_CLIENT_ID: ID do cliente do aplicativo Azure personalizado (padrão: aplicativo integrado)MS365_MCP_TENANT_ID: ID de locatário personalizado (padrão: 'common' para multi-locatário). Contas pessoais da Microsoft devem definir isso comoconsumers— a partir de junho de 2026, tokens de atualização emitidos via autoridade 'common' padrão são rejeitados na primeira atualização, então as sessões morrem cerca de uma hora após o loginMS365_MCP_OAUTH_TOKEN: Token OAuth pré-existente para a API do Microsoft Graph (método BYOT)MS365_MCP_KEYVAULT_URL: URL do Azure Key Vault para gerenciamento de segredos (veja a seção Azure Key Vault)MS365_MCP_TOKEN_CACHE_PATH: Caminho de arquivo personalizado para o cache de tokens MSAL (veja Armazenamento de Tokens abaixo)MS365_MCP_SELECTED_ACCOUNT_PATH: Caminho de arquivo personalizado para metadados da conta selecionada (veja Armazenamento de Tokens abaixo)MS365_MCP_AUTH_CACHE_COMMAND: Wrapper executável externo para armazenamento de cache de autenticação neutro de provedor (veja Armazenamento de Tokens abaixo)MS365_MCP_AUTH_CACHE_COMMAND_TIMEOUT_MS: Tempo limite por invocação paraMS365_MCP_AUTH_CACHE_COMMAND(padrão:10000)MS365_MCP_EXPECTED_USERNAME: Exige que a autenticação MSAL local use este nome de usuário da conta Microsoft (sem diferenciar maiúsculas/minúsculas; o flag da CLI tem precedência)MS365_MCP_EXPECTED_HOME_ACCOUNT_ID: Exige que a autenticação MSAL local use este homeAccountId exato do MSAL (o flag da CLI tem precedência)
URLs de Anexos Emitidas pelo Servidor
get-download-url retorna as próprias URLs @microsoft.graph.downloadUrl pré-autenticadas da Microsoft
para itens do OneDrive e SharePoint. O Graph não publica tal URL para anexos de e-mail e calendário,
gravações de reuniões ou qualquer outro endpoint de bytes /$value — para esses, a
única maneira de ler os bytes tem sido download-bytes, que retorna base64 para o
contexto do agente. Um PDF de 73 KB e 3 páginas custa cerca de 24.500 tokens dessa forma, e o modelo
não consegue analisá-los de qualquer maneira.
--enable-attachment-urls (modo HTTP, desativado por padrão) fecha essa lacuna. Quando o Graph não tem
URL própria, get-download-url gera uma que este servidor serve:
GET /attachment?t=<ticket>&dgk=<key-id>&dgx=<expiry>&dgs=<signature>
O ticket tem 32 bytes de saída CSPRNG, uso único, apenas em memória e expira após
MS365_MCP_ATTACHMENT_URL_TTL_S segundos. Resgatá-lo transmite os bytes do Graph com o token
deste próprio servidor; o buscador não envia cabeçalho Authorization e não detém nenhuma
credencial da Microsoft.
Isso não concede nenhuma autoridade que o agente chamador já não tivesse. Todo destino que
pode ser cunhado é um que download-bytes buscaria para o mesmo chamador na mesma conta. O
ticket apenas move esses bytes para fora da janela de contexto e para uma transferência direta.
Configuração
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 não é MS365_MCP_PUBLIC_URL: esse é voltado
para navegador, para redirecionamentos OAuth, enquanto este é buscado servidor a servidor e é
comumente um endereço de contêiner. Uma configuração ausente ou malformada falha na inicialização
em vez de por solicitação — um recurso de assinatura que surgisse sem uma chave cunharia URLs que
nada pode verificar, silenciosamente.
Dividindo o ouvinte de anexos
Por padrão, /attachment é servido pelo mesmo aplicativo Express, na mesma porta, que /mcp.
Isso é aceitável quando os chamadores são autenticados por um token de portador, e é um problema quando
não são. Sob --trust-proxy-auth, o endpoint MCP não lê nenhum cabeçalho Authorization
— alcançabilidade é a autenticação — então uma porta compartilhada significa que o sidecar que você
permitiu para buscar um PDF também pode chamar todas as ferramentas no servidor.
--attachment-port <port> (ou MS365_MCP_ATTACHMENT_PORT) move a rota para um ouvinte
próprio, e --attachment-host <host> (ou MS365_MCP_ATTACHMENT_HOST) indica qual
interface esse ouvinte vincula:
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 /attachmentna 3001 funciona; na 3000 é 404 — o aplicativo MCP nunca a monta./mcpna 3001 é 404, assim como todo o resto: o segundo aplicativo tem a rota de anexos e nada mais. Sem roteador OAuth, sem parsers de corpo, sem CORS, sem verificação de saúde.- O limitador de 60 req/min que protege a rota a acompanha até o novo ouvinte.
trust proxyestá desligado no ouvinte de anexos (eMS365_MCP_TRUST_PROXY_HOPSnão é lido para ele), ao contrário do ouvinte MCP, que confia em um salto. Esta porta deve ser discada diretamente em uma rede de contêineres; honrarX-Forwarded-Forna única superfície não credenciada do servidor permitiria que um chamador escolhesse seu próprio bucket de limite de taxa.
A flag exige --enable-attachment-urls e se recusa a iniciar sem ela — sozinha,
abriria uma porta sem nada nela enquanto o operador acreditasse que as superfícies estavam
separadas. No modo stdio, ela avisa e é ignorada, como a flag da qual depende.
--attachment-host igualmente exige --attachment-port: sozinha, nomearia uma interface
para um ouvinte que não existe.
Duas portas não são duas superfícies a menos que vinculem duas interfaces
Esta é a parte que decide se qualquer coisa acima vale alguma coisa. Leia-a antes de implantar a divisão.
--attachment-port sozinho separa as duas superfícies dentro do processo. Não as separa
na rede. Sem --attachment-host, o ouvinte de anexos herda
qualquer host que --http vinculou — e --http 3000, a forma comum, não nomeia host algum, então o
Node vincula o curinga e ambas as portas respondem em todas as interfaces:
ms-365-mcp-server --http 3000 --trust-proxy-auth \
--enable-attachment-urls --attachment-port 3001 # NOT isolated
Redes de contêineres concedem a um par todas as portas em um contêiner, não uma porta. Coloque um
sidecar de conversão de documentos em uma ponte compartilhada para que ele possa buscar /attachment na 3001, e
esse mesmo sidecar pode discar :3000/mcp — que sob --trust-proxy-auth não lê nenhum
cabeçalho Authorization e devolve o catálogo completo de ferramentas. Nada falha, nada
é registrado como erro, e a configuração parece exatamente como a isolada.
Para torná-lo real, dê aos dois ouvintes endereços diferentes e coloque apenas o endereço de anexos na rede em que o buscador está:
# 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]
A porta MCP é então inalcançável de convert-net por vinculação — não há socket
ouvindo nessa interface — em vez de por uma regra de firewall que precisa continuar correspondendo.
O servidor avisa na inicialização se você executar --trust-proxy-auth com --attachment-port enquanto
ambos os ouvintes ainda respondem em uma interface comum (ou compartilhando um endereço, ou qualquer um
no curinga). Ambos os endereços vinculados são registrados, lidos de volta do socket em vez de
das flags, para que Server listening on … e Attachment listener on … possam ser comparados
diretamente.
--attachment-host aceita um endereço IPv4 puro, endereço IPv6 ([::1] entre colchetes ou
::1 puro) ou nome de host. É recusado em vez de coagido — --attachment-host 10.0.0.5:3001
é um erro nomeando --attachment-port, não uma vinculação a outra coisa. Observe que
MS365_MCP_ATTACHMENT_URL_BASE ainda não deve ser um literal IPv6 (a assinatura de URL cobre
o host e as duas implementações normalizam IPv6 de forma diferente); se você vincular o ouvinte
a um endereço IPv6, nomeie-o na base por nome de host.
Aponte MS365_MCP_ATTACHMENT_URL_BASE para a porta de anexos. O servidor não pode verificar isso
por você: a base é geralmente um nome de contêiner em uma rede que este processo não pode resolver, então
uma porta errada aqui aparece como uma falha de busca no sidecar, não um erro aqui. Tanto a
base quanto a porta vinculada são registradas na inicialização, com uma linha de diferença, exatamente para essa comparação.
A assinatura, e quem verifica o quê
dgk/dgx/dgs não são verificados por este servidor no resgate, e isso é deliberado.
Eles existem para o buscador: um sidecar de conversão de documentos que se recusa a discar um endereço
privado a menos que a URL carregue um HMAC válido de uma origem que foi configurado para confiar.
O que autoriza o resgate aqui é o ticket. Verificar a assinatura no caminho de volta
provaria apenas que cunhamos a URL — o que o ticket já prova — enquanto acoplaria o resgate
ao relógio do sidecar e à chave sobrevivendo a uma reinicialização.
O formato de transmissão é docglean-mcp's
signing.py (canonical_string), e src/lib/url-signing.ts é uma porta dele. A
string canônica é unida por \n: v1, esquema em minúsculas, host em minúsculas, a porta sempre
explícita, o caminho, a consulta restante com dgk/dgx/dgs removidos e o resto classificado
e re-codificado, e a expiração. Os vetores de teste em
test/attachment-url-signing.test.ts foram verificados contra a implementação Python byte
por byte — três lugares onde o JavaScript óbvio discorda do Python (escape de !*'(),
decodificação de + como espaço e ordem de classificação por code-point vs UTF-16) são por que essa verificação
existe em vez de ser assumida.
O ticket viaja na consulta, não no caminho, porque o sidecar verificador mantém o caminho de uma URL buscada em suas mensagens de erro e remove a consulta.
Não disponível no modo OAuth/OBO
A identidade lá chega por solicitação no cabeçalho Authorization do chamador, e um ticket é
resgatado mais tarde por um buscador que não envia nenhum. A cunhagem se recusa com uma explicação em vez
de produzir uma URL que sempre falha.
Armazenamento de Tokens
Os tokens de autenticação são armazenados em um arquivo criptografado (AES-256-GCM). Apenas a chave de criptografia de 32 bytes vai para o armazenamento de credenciais do SO via keytar.
O cache em si é grande demais para alguns armazenamentos de credenciais conterem — um blob do Gerenciador de Credenciais do Windows tem um limite de 2560 bytes e um cache de token real é várias vezes isso, então no Windows a gravação nunca poderia ter sucesso. Uma chave tem 32 bytes independentemente de quantas contas estão conectadas, então isso funciona da mesma forma em todas as plataformas.
Caminhos padrão estão no diretório de configuração por usuário:
| Plataforma | Localização |
|---|---|
| Windows | %APPDATA%\ms-365-mcp-server\ |
| macOS | ~/Library/Application Support/ms-365-mcp-server/ |
| Linux | $XDG_CONFIG_HOME/ms-365-mcp-server/ (ou ~/.config/ms-365-mcp-server/) |
Versões anteriores usavam como padrão um caminho dentro do pacote instalado, que sob npx resolve para um diretório de cache com hash de conteúdo que npm cache clean ou um aumento de versão descarta. Um cache ainda no diretório do pacote é movido para o novo local na primeira execução.
Isso cobre instalações globais e locais, e npx quando o hash não mudou. Não pode alcançar um cache deixado em um diretório de hash de npx anterior, então atualizar uma instalação npx uma última vez significa entrar novamente. Adotar um cache de outro diretório significaria confiar em um diretório que este pacote não pode provar que escreveu, o que não vale um único login salvo.
Substitua os caminhos se precisar:
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"
Os diretórios pai são criados automaticamente. Os arquivos são gravados com permissões 0600.
Sem um armazenamento de credenciais (Linux sem cabeça, a maioria dos contêineres), a chave é gravada em .cache-key ao lado do arquivo de cache, com permissões 0600. Isso impede que os tokens apareçam em um cat perdido, um backup ou um commit acidental. Não protege contra qualquer pessoa que já possa ler o diretório — a chave está bem ali. Use MS365_MCP_AUTH_CACHE_COMMAND abaixo se precisar do cache em um armazenamento de segredos real.
Ignorando o armazenamento de credenciais de propósito:
export MS365_MCP_USE_KEYTAR=0 # also accepts false, no or off
A chave então vai para .cache-key em todas as plataformas, exatamente como onde nenhum armazenamento de credenciais existe, e nada no servidor chama keytar. Útil quando o armazenamento de credenciais solicita a cada início — o macOS re-pergunta sempre que o binário chamador muda, o que sob npx é a cada aumento de versão — ou quando o módulo nativo se comporta mal na sua plataforma em vez de simplesmente falhar ao carregar. Qualquer outro valor deixa o armazenamento de credenciais em uso, e um não reconhecido é avisado em vez de ser ignorado silenciosamente.
Desligá-lo deixa um cache órfão que foi criptografado sob uma chave já no armazenamento de credenciais, já que nada pode alcançar essa chave mais. O servidor diz isso e substitui esse cache no próximo login, o que desconecta todas as contas que ele continha, não apenas aquela em que você entra novamente. Desdefina a variável primeiro se esse cache vale a pena manter.
Apenas um cache que nada na máquina pode abrir é substituído. Um que falha ao descriptografar enquanto uma chave utilizável está bem ali — um arquivo truncado, um downgrade para uma versão mais antiga, um cache de outro lugar — é dano em vez de um cache órfão, e é deixado exatamente como está por padrão.
Duas coisas que ele deliberadamente não faz. Ele nunca exclui o que este servidor já colocou no armazenamento de credenciais, no logout ou de outra forma, porque alcançar o armazenamento é a coisa que você acabou de pedir para parar de fazer — limpe as entradas ms-365-mcp-server manualmente se quiser que elas desapareçam. E um .cache-key que existe mas não pode ser lido (dono errado em um diretório de configuração montado por bind, por exemplo) é tratado como recuperável em vez de ausente: o servidor se recusa tanto a sobrescrever um cache quanto a cunhar uma chave de substituição, e diz isso, em vez de excluir uma chave que funcionaria novamente uma vez que as permissões sejam corrigidas. Corrija as permissões, ou exclua .cache-key você mesmo para recomeçar — o que significa entrar novamente.
Se o cache não puder ser descriptografado — chave perdida, keychain bloqueado, arquivo modificado — você é solicitado a entrar novamente em vez de o servidor falhar ao iniciar. O arquivo de cache é deixado exatamente como estava: não excluído, e não sobrescrito por esse novo login também. Um keychain que está meramente bloqueado geralmente lê bem no próximo início, e o cache ainda está lá quando isso acontece.
O custo é que a nova sessão não é salva enquanto isso durar, então cada início pede que você entre novamente. Se a chave está genuinamente perdida e o cache nunca abrirá, exclua .token-cache.json para recomeçar — o log diz isso e nomeia o caminho.
Ambientes hospedados/sandbox (por exemplo, Anthropic Cowork): Defina
MS365_MCP_TOKEN_CACHE_PATHeMS365_MCP_SELECTED_ACCOUNT_PATHpara um mount persistente para que os tokens sobrevivam entre sessões.
Comando externo de cache de autenticação
Implantações headless com MSAL local podem substituir o armazenamento integrado keytar/arquivo por um comando externo neutro em relação ao provedor:
export MS365_MCP_AUTH_CACHE_COMMAND="/path/to/ms365-auth-cache-store"
export MS365_MCP_AUTH_CACHE_COMMAND_TIMEOUT_MS=10000
Quando MS365_MCP_AUTH_CACHE_COMMAND está definido para um fluxo de autenticação local, o servidor usa apenas esse comando para o cache de token MSAL e os metadados da conta selecionada. Ele não recorre ao keytar ou a arquivos locais. Se o caminho do comando estiver ausente, não for executável em POSIX, sair com código não zero, expirar ou retornar dados malformados, as operações de cache de autenticação falham de forma segura com uma mensagem de erro sanitizada.
O valor deve ser um caminho real para um executável wrapper. Não é uma string de comando de shell e não há uma variável de ambiente de argumentos complementar. Coloque qualquer interpretador, região, perfil ou configurações específicas do provedor dentro do wrapper. Usuários do Windows devem apontar a variável para um executável wrapper ou script que possa ser iniciado diretamente pelo Node sem análise de shell.
O servidor invoca o wrapper com:
$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>não lê stdin. Saída com código0com{"found":true,"value":"<stored envelope string>"}quando presente. Uma ausência é saída com código0com{"found":false}ou stdout vazio.save <key>recebe{"value":"<stamped envelope string>"}no stdin e deve sair com código0somente após o valor ser confirmado de forma durável. Não há salvamentos do tipo "dispare e esqueça" ou coalescidos no v1.delete <key>não lê stdin e sai com código0independentemente de a chave existir ou não.<key>étoken-cacheouselected-account.- Qualquer saída com código não zero é um erro de armazenamento. Não use o código de saída
2para ausências de cache. - O stderr é capturado e truncado em erros sanitizados. Os payloads de stdin e stdout nunca são registrados pelo servidor.
- Os payloads de cache de token podem ser grandes; os wrappers devem lidar com valores de pelo menos 256 KB.
Solicitações Graph HTTP normais sem estado não usam armazenamento de cache de autenticação local. No modo HTTP, o armazenamento de comando é ignorado na inicialização e por solicitação, a menos que as ferramentas de autenticação local sejam explicitamente habilitadas ou um comando de conta local como --login, --verify-login, --list-accounts, --select-account ou --logout seja usado.
Integração com Azure Key Vault
Para implantações de produção, você pode armazenar segredos no Azure Key Vault em vez de variáveis de ambiente. Isso é particularmente útil para Azure Container Apps com identidade gerenciada.
Configuração
-
Crie um Key Vault (se você não tiver um):
az keyvault create --name your-keyvault-name --resource-group your-rg --location eastus -
Adicione segredos ao 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 acesso ao Key Vault:
Para Azure Container Apps com identidade gerenciada:
# 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 desenvolvimento local com Azure CLI:
# Your Azure CLI identity already has access if you have appropriate RBAC roles az login -
Configure o servidor:
MS365_MCP_KEYVAULT_URL=https://your-keyvault-name.vault.azure.net npx @softeria/ms-365-mcp-server
Mapeamento de Nomes de Segredos
| Nome do Segredo no Key Vault | Variável de Ambiente | Obrigatório |
|---|---|---|
| ms365-mcp-client-id | MS365_MCP_CLIENT_ID | Sim |
| ms365-mcp-tenant-id | MS365_MCP_TENANT_ID | Não (padrão: 'common') |
| ms365-mcp-client-secret | MS365_MCP_CLIENT_SECRET | Não |
Autenticação
A integração com Key Vault usa DefaultAzureCredential do SDK de Identidade do Azure, que tenta automaticamente vários métodos de autenticação em ordem:
- Variáveis de ambiente (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
- Identidade Gerenciada (recomendado para Azure Container Apps)
- Credenciais do Azure CLI (para desenvolvimento local)
- Credenciais do Visual Studio Code
- Credenciais do Azure PowerShell
Dependências Opcionais
Os pacotes do Azure Key Vault (@azure/identity e @azure/keyvault-secrets) são dependências opcionais. Eles são carregados somente quando MS365_MCP_KEYVAULT_URL está configurado. Se você não usar Key Vault, esses pacotes não são necessários.
Assinatura de Mensagens
Mensagens de saída podem ser envolvidas em uma assinatura configurável (por exemplo, um prefixo 🤖) para que os destinatários possam distinguir mensagens enviadas por agentes daquelas digitadas por você. Desativado por padrão — ative com --message-signoff-prefix / --message-signoff-suffix (env: MS365_MCP_MESSAGE_SIGNOFF_PREFIX / MS365_MCP_MESSAGE_SIGNOFF_SUFFIX); --no-message-signoff ou um valor de env vazio desativa novamente.
Uma vez configurado, aplica-se a todas as mensagens do Teams (envios, respostas e edições, inclusive via graph-batch), a envios diretos de e-mail (send-mail, responder/encaminhar, suas variantes de caixa de correio compartilhada e respostas em tópicos de grupo) e a rascunhos de e-mail conforme seu conteúdo é escrito — send-draft-message envia um rascunho como está, então um rascunho que você mesmo escreveu sai intacto. Uma mensagem que já carrega o marcador não é assinada duas vezes, e um envio cujo corpo não pode receber a assinatura é recusado em vez de ser enviado sem assinatura.
Os marcadores podem conter marcação (por exemplo, um <span> colorido), desde que renderizem texto visível. Observe que a assinatura é uma proteção contra o uso indevido das ferramentas por um agente, não uma fronteira de segurança rígida — um agente com acesso ao shell na mesma máquina poderia simplesmente reiniciar o servidor sem ela.
Implantação em Produção
Consulte docs/deployment.md para um guia completo de hospedagem do servidor para acesso em toda a organização, incluindo Docker, Azure Container Apps, Azure App Service, registro de aplicativo no Azure AD, configuração de proxy reverso, configuração do cliente e endpoints expostos.
Contribuindo
Aceitamos contribuições! Antes de enviar um pull request, certifique-se de que suas alterações atendem aos nossos padrões de qualidade.
Execute o script de verificação para checar todos os requisitos de qualidade de código:
npm run verify
Para Desenvolvedores
Após clonar o repositório, você pode precisar gerar o código do cliente a partir da especificação OpenAPI do Microsoft Graph:
npm run generate
Projetos Relacionados
- ms-365-admin-mcp-server por @okapi-ca: servidor complementar para cenários de administrador/daemon usando permissões de aplicativo (fluxo de credenciais do cliente), cobrindo alertas de segurança, logs de auditoria, saúde do serviço e relatórios de uso.
Suporte
Se você estiver com problemas ou precisar de ajuda:
- Crie uma issue
- Inicie uma discussão
- E-mail: eirikb@eirikb.no
- Discord: https://discord.gg/WvGVNScrAZ ou @eirikb
Licença
MIT © 2026 Softeria