Microsoft 365

Interaja com os serviços do Microsoft 365, como Outlook, OneDrive e Teams, usando a Graph API.

Documentação

ms-365-mcp-server

npm version build status license

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:

NuvemDescriçãoEndpoint de AutenticaçãoEndpoint da API Graph
Global (padrão)Microsoft 365 internacionallogin.microsoftonline.comgraph.microsoft.com
China (21Vianet)Microsoft 365 operado pela 21Vianetlogin.chinacloudapi.cnmicrosoftgraph.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 de 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 matriz uniforme (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 de 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 de Conta Pessoal (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 de Conta Organizacional (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

Emojis personalizados do Teams estão disponíveis no modo organizacional por meio de list-custom-emojis e create-custom-emoji (predefinições teams e work). Estes usam a API beta do Microsoft Graph e solicitam as permissões delegadas TeamworkCustomEmoji.Read e TeamworkCustomEmoji.Create, respectivamente. O modo somente leitura expõe apenas a ferramenta de listagem. Implantações existentes podem precisar de consentimento para esses novos escopos e reautenticação; adicionar suporte a ferramentas não atualiza um token já emitido.

A listagem pode retornar contentBytes: null por padrão. Para solicitar imagens PNG/GIF em base64, passe select: "displayName,contentBytes" ou select: ["displayName", "contentBytes"]. Use um top pequeno para manter as respostas de imagem gerenciáveis. Para criar um emoji, passe body: { displayName, contentBytes } com o nome aprovado exato e os bytes do arquivo PNG/GIF em base64. Consulte os contratos de listagem e criação da Microsoft. Estas ferramentas não publicam mensagens ou reações.

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-scopes
  • effectivePermissions: permissões implícitas pelas ferramentas que permanecem habilitadas após --allowed-scopes
  • permissions: alias legado para effectivePermissions, mantido para compatibilidade com scripts existentes
  • allowedScopes: a lista de permissões de escopo configurada, quando fornecida
  • disabledTools: ferramentas ocultas porque seus escopos Graph necessários não são cobertos por allowedScopes
  • missingAllowedScopesForTools: escopos ausentes exclusivos entre ferramentas desabilitadas
  • extraAllowedScopesNotUsedByTools: 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.All e Sites.Manage.All.
  • Sites.Selected do Microsoft Graph, 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 ao SharePoint em sites selecionados 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 explícito 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 recurso protegido; --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 da Softeria declara apenas um conjunto de permissões enxuto e fixo, portanto, solicite escopos adicionais em 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.), habilite 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 conta de trabalho. Sem esta flag, apenas recursos de conta pessoal (e-mail, calendário, OneDrive, etc.) estão disponíveis.

Acesso a Caixa de Correio Compartilhada

Para acessar caixas de correio compartilhadas, você precisa:

  1. Modo organizacional: As ferramentas de caixa de correio compartilhada exigem a flag --org-mode (somente contas de trabalho/escola)
  2. Permissões delegadas: Mail.Read.Shared para ler, Mail.ReadWrite.Shared para criar, atualizar ou mover mensagens, Mail.Send.Shared para enviar, responder ou encaminhar, e Calendars.Read.Shared para as ferramentas de calendário compartilhado
  3. Permissões do Exchange: O usuário conectado deve ter recebido acesso à caixa de correio compartilhada
  4. Uso: Use o endereço de e-mail da caixa de correio compartilhada como o parâmetro user-id nas 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:

Login example

Exemplos

Image

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"]
    }
  }
}

CLI do Claude Code

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.

  1. Inicie o servidor no modo HTTP:

    npx @softeria/ms-365-mcp-server --http
    
  2. No Open WebUI, vá para Configurações de 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
  3. Clique em Registrar Cliente.

Nota: O registro dinâmico de clientes está habilitado por padrão no modo HTTP. Use --no-dynamic-registration (ou defina MS365_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 um segredo use "Web", sem um use "Aplicativos móveis e de desktop" (nunca "Aplicativo de página única").

Configuração de teste rápido 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.

Open WebUI MCP Connection

Executando em Docker atrás de um proxy reverso? Defina --public-url https://your-domain.com para que a URL de autorização OAuth entregue ao navegador do usuário seja acessível de fora da rede do contêiner. Consulte docs/deployment.md para o guia completo.

Desenvolvimento Local

Para desenvolvimento ou teste local:

# 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 build após alterações de código para atualizar a pasta dist/.

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-login para confirmar
  • Login via CLI:
    npx @softeria/ms-365-mcp-server --login
    
    Siga a URL e o prompt de código no terminal.

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 recursos 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-tools para habilitá-las)

Os clientes MCP lidarão automaticamente com o fluxo OAuth quando virem os recursos anunciados.

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:

  1. Criar registro de aplicativo no Azure AD:
  • Acesse o Portal do Azure
  • Navegue até Azure Active Directory → Registros de aplicativo → Novo registro
  • Defina o nome: "MS365 MCP Server"
  1. Configurar URIs de redirecionamento:
  • Configure o URI de retorno OAuth: Vá para o registro do seu aplicativo e, no lado esquerdo, acesse Autenticação.
  • Em Configurações de plataforma:
    • Clique em Adicionar uma plataforma (se você ainda não vir uma para "Aplicativos móveis e de desktop" / "Cliente público").
    • Escolha Aplicativos móveis e de desktop ou Cliente público/nativo (móvel e desktop) (o rótulo depende da versão do portal).
  1. Teste com o MCP Inspector (npm run inspector):
  • Vá para o registro do seu aplicativo e, no lado esquerdo, acesse Autenticação.
  • Em Configurações de plataforma:
    • Clique em Adicionar uma plataforma (se você ainda não vir uma para "Web").
    • Escolha Web.
    • Configure os seguintes URIs de redirecionamento
      • http://localhost:6274/oauth/callback
      • http://localhost:6274/oauth/callback/debug
      • http://localhost:3000/callback (opcional, para retorno do servidor)
  1. Obter credenciais:
  • Copie o ID do aplicativo (cliente) da página Visão geral
  • Vá para Certificados e segredos → Novo segredo do cliente → Copie o valor do segredo (opcional para aplicativos públicos)
  1. Configurar variáveis de ambiente: Crie um arquivo .env na 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.

Observação: .env é lido do diretório em que o servidor é iniciado, e o cliente MCP decide o que isso é. Apenas MS365_MCP_CLIENT_ID, MS365_MCP_CLIENT_SECRET, MS365_MCP_TENANT_ID e MS365_MCP_CLOUD_TYPE sã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ê estiver 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 para 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 lida com a renovação do token (o gerenciamento do ciclo de vida do token é sua responsabilidade)

Observação: O modo HTTP exige autenticação. Para testes não autenticados, 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 lida com a autenticação. Use --enable-auth-tools se precisar que elas estejam disponíveis.

Suporte a Múltiplas Contas

Use uma única instância do servidor para atender a várias contas da Microsoft. Quando mais de uma conta estiver conectada, um parâmetro account é injetado automaticamente em cada ferramenta, permitindo que você especifique qual conta usar em cada chamada de ferramenta.

Conectar várias 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 várias contas e sem o parâmetro account, o servidor usa o padrão selecionado 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 account aceita endereço de e-mail (por exemplo, user@outlook.com) ou homeAccountId do MSAL.

Fixação Estrita de Conta

Implantações headless via 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 os 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 sobre MS365_MCP_EXPECTED_USERNAME e MS365_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 de minúsculas; fixações de homeAccountId são exatas.
  • Se ambas as fixações estiverem definidas, elas devem resolver para a mesma conta em cache.
  • A inicialização local via stdio falha rapidamente quando a conta esperada não está no cache de tokens. Inicialize definindo a fixação, executando --login e 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 account e as instruções do MCP não sugerem troca de conta.
  • --http, --obo e MS365_MCP_OAUTH_TOKEN usam tokens fornecidos na solicitação para chamadas ao Graph, portanto, as fixações de conta são apenas de aviso nesses modos. Se as ferramentas de autenticação HTTP estiverem habilitadas, a fixação ainda se aplica a esses fluxos auxiliares MSAL locais.
  • --logout limpa todas as contas em cache, incluindo a conta fixada. Para limpeza cirúrgica, prefira --remove-account <id>.

Para multiplexadores MCP (Legate, Governor): O modo de múltiplas contas substitui o padrão de N processos. Em vez de iniciar um servidor por conta, uma única instância lida com todas as contas por meio do 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 por meio de uma matriz presets, portanto, cada predefinição é uma lista de permissões exata de nomes de ferramentas que nunca corresponde em excesso entre aplicativos (por exemplo, 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, para que tudo o que um aplicativo retornar (um arquivo, um anexo, uma foto, uma gravação) possa sempre ser buscado; get-download-url (uma URL pré-autenticada para arquivos do drive/SharePoint) acompanha as predefinições com suporte a 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 ao aplicativo: elas expõem exatamente um aplicativo da 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 de 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 o conteúdo das 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 somente 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 (por exemplo, Open WebUI executando 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 um 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. Bound to a loopback host
                  (e.g. --http 127.0.0.1:3000 or --http [::1]:3000) with no --public-url, it
                  rejects requests whose Host or Origin is not localhost (not applied to the
                  --attachment-port listener)
--http-local-file-tools Register download-bytes-to-file over HTTP. Anyone who can reach the port
                  can write files as the server's user (without a valid token, only an empty
                  file that is removed again), so enable it only on a single-user machine.
                  Refused unless --http binds a loopback host with no --public-url and no
                  --trust-proxy-auth
--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 à flag --read-only
  • ENABLED_TOOLS: Filtra ferramentas usando um padrão regex (alternativa à flag --enabled-tools)
  • MS365_MCP_ORG_MODE=true|1: Ativa o modo organização/trabalho (alternativa à flag --org-mode)
  • MS365_MCP_FORCE_WORK_SCOPES=true|1: Compatibilidade reversa para MS365_MCP_ORG_MODE
  • MS365_MCP_OUTPUT_FORMAT=toon: Ativa o formato de saída TOON (alternativa à flag --toon)
  • MS365_MCP_MAX_TOP=<n>: Limite máximo para Graph $top / top em solicitações de lista (inteiro positivo). Quando o modelo passa um valor maior, o servidor o limita a n para que as respostas permaneçam menores. Exemplo: MS365_MCP_MAX_TOP=15
  • MS365_MCP_MAX_PAGES=<n>: Número máximo de páginas seguidas quando uma ferramenta é chamada com fetchAllPages: true (inteiro positivo, padrão 100). Limita memória e latência para grandes conjuntos de resultados.
  • MS365_MCP_MAX_ITEMS=<n>: Número máximo de itens acumulados quando fetchAllPages: true (inteiro positivo, padrão 10000). A paginação para e a resposta é truncada quando esse número de itens é coletado.
  • MS365_MCP_ALLOW_PAGINATION=0|false|no: Desativa completamente o acompanhamento de múltiplas páginas. Quando definido, o parâmetro fetchAllPages não é anunciado nas ferramentas, e qualquer solicitação que ainda o passe retorna apenas a primeira página (padrão: paginação ativada).
  • 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 em mensagens enviadas para que os destinatários saibam que foram enviadas por agente, ex.: 🤖. Padrão: nenhum. Equivalente CLI: --message-signoff-prefix <text> (veja Assinatura de Mensagem abaixo)
  • MS365_MCP_MESSAGE_SIGNOFF_SUFFIX=<text>: Assinatura anexada a mensagens enviadas. Padrão: nenhum. Equivalente CLI: --message-signoff-suffix <text>. --no-message-signoff desativa ambas (veja Assinatura de Mensagem abaixo)
  • MS365_MCP_RATE_LIMIT_DISABLED=true|1: Desativa a limitação de taxa por IP no modo HTTP (padrão: ativado — 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ão 1). A limitação precisa de taxa por IP depende disso corresponder à sua implantação — defina para o número de proxies na frente do servidor, 0 para usar o IP bruto do socket peer, ou uma lista de sub-redes separadas por vírgula
  • MS365_MCP_ATTACHMENT_PORT=<port>: Serve a rota de anexos em seu próprio listener nesta porta (alternativa à --attachment-port; requer --enable-attachment-urls)
  • MS365_MCP_ATTACHMENT_HOST=<host>: Interface à qual o listener MS365_MCP_ATTACHMENT_PORT se vincula (alternativa à --attachment-host; requer --attachment-port). Padrão para o host ao qual --http está vinculado — que para um --http curinga 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_HTTP_LOCAL_FILE_TOOLS=true|1: Registra download-bytes-to-file sobre HTTP (alternativa à --http-local-file-tools; mesmas restrições)
  • MS365_MCP_CLOUD_TYPE=global|china: Ambiente de nuvem da Microsoft (alternativa à flag --cloud)
  • LOG_LEVEL: Define o nível de log (padrão: 'info')
  • SILENT=true|1: Desativa a saída do console
  • MS365_MCP_REDACT_PII=false|0: Desativa a limpeza de JWTs, cabeçalhos Bearer, campos de token OAuth e endereços de e-mail das mensagens de log (padrão: ativado). O servidor lida com tokens Bearer Graph ao vivo, então a redação está ativada a menos que você opte por sair para depuração local totalmente detalhada.
  • MS365_MCP_CLIENT_ID: ID de cliente do aplicativo Azure personalizado (padrão para o aplicativo integrado)
  • MS365_MCP_TENANT_ID: ID de locatário personalizado (padrão para 'common' para multi-locatário). Contas pessoais da Microsoft devem definir isso para consumers — 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 aproximadamente uma hora após o login
  • MS365_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 token MSAL (veja Armazenamento de Token abaixo)
  • MS365_MCP_SELECTED_ACCOUNT_PATH: Caminho de arquivo personalizado para metadados da conta selecionada (veja Armazenamento de Token abaixo)
  • MS365_MCP_AUTH_CACHE_COMMAND: Wrapper executável externo para armazenamento de cache de autenticação neutro de provedor (veja Armazenamento de Token abaixo)
  • MS365_MCP_AUTH_CACHE_COMMAND_TIMEOUT_MS: Tempo limite por invocação para MS365_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 (insensível a maiúsculas/minúsculas; a flag CLI tem precedência)
  • MS365_MCP_EXPECTED_HOME_ACCOUNT_ID: Exige que a autenticação MSAL local use este homeAccountId MSAL exato (a flag CLI tem precedência)

URLs de Anexos Emitidas pelo Servidor

get-download-url retorna as próprias @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 emite uma que este servidor serve:

GET /attachment?t=<ticket>&dgk=<key-id>&dgx=<expiry>&dgs=<signature>

O ticket é 32 bytes de saída CSPRNG, uso único, somente memória, e expira após MS365_MCP_ATTACHMENT_URL_TTL_S segundos. Resgatá-lo transmite os bytes do Graph com o token próprio deste servidor; o buscador não envia cabeçalho Authorization e não possui credencial da Microsoft.

Isso não concede autoridade que o agente chamador já não tivesse. Cada alvo que pode ser emitido é 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 ao 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 aparecesse sem chave emitiria URLs que nada pode verificar, silenciosamente.

Dividindo o listener 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 Bearer, e é um problema quando não são. Sob --trust-proxy-auth, o endpoint MCP não lê nenhum cabeçalho Authorization — a 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 listener próprio, e --attachment-host <host> (ou MS365_MCP_ATTACHMENT_HOST) diz qual interface esse listener 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 /attachment na 3001 funciona; na 3000 é 404 — o aplicativo MCP nunca a monta.
  • /mcp na 3001 é 404, assim como tudo o mais: 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 segue para o novo listener.
  • trust proxy está desativado no listener de anexos (e MS365_MCP_TRUST_PROXY_HOPS não é lido para ele), ao contrário do listener MCP, que confia em um salto. Esta porta é destinada a ser discada diretamente em uma rede de contêineres; honrar X-Forwarded-For na única superfície não credenciada do servidor permitiria que um chamador escolhesse seu próprio bucket de limite de taxa.

A flag requer --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 requer --attachment-port: sozinha, nomearia uma interface para um listener 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 listener de anexos herda qualquer host ao qual --http se 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 cada interface:

ms-365-mcp-server --http 3000 --trust-proxy-auth \
                  --enable-attachment-urls --attachment-port 3001   # NOT isolated

Redes de contêineres concedem a um peer 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 entrega 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 listeners 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 listeners 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 simples, endereço IPv6 (entre colchetes [::1] ou simples ::1) 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 da URL cobre o host e as duas implementações normalizam IPv6 de forma diferente); se você vincular o listener 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, uma linha separada, 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 configurada para confiar. O que autoriza o resgate aqui é o ticket. Verificar a assinatura no caminho de volta provaria apenas que emitimos a URL — o que o ticket já prova — enquanto acopla o resgate ao relógio do sidecar e à chave sobrevivendo a um reinício.

O formato de fio é 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 query 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 !*'(), decodificação + como espaço, e ordem de classificação code-point vs UTF-16) são por que essa verificação existe em vez de ser assumida.

O ticket viaja na query, não no caminho, porque o sidecar verificador mantém o caminho de uma URL buscada em suas mensagens de erro e remove a query.

Não disponível no modo OAuth/OBO

A identidade chega conforme solicitado no cabeçalho Authorization do chamador, e um ticket é resgatado posteriormente por um buscador que não envia nenhum. A cunhagem 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 sistema operacional via keytar.

O cache em si é grande demais para alguns armazenamentos de credenciais — um blob do Gerenciador de Credenciais do Windows tem um limite de 2560 bytes, e um cache de tokens real é várias vezes maior que 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 ficam no diretório de configuração por usuário:

PlataformaLocalizaçã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 presente 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 é possível alcançar um cache deixado para trás 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 gravou, o que não vale um único login economizado.

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, em um backup ou em 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 acontece onde não existe armazenamento de credenciais, e nada no servidor chama keytar. Útil quando o armazenamento de credenciais solicita confirmação a cada inicialização — o macOS pergunta novamente 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 mantém o armazenamento de credenciais em uso, e um valor não reconhecido gera um aviso em vez de ser ignorado silenciosamente.

Desativá-lo deixa um cache órfão que foi criptografado com uma chave já no armazenamento de credenciais, já que nada mais pode alcançar essa chave. O servidor informa isso e substitui esse cache no próximo login, o que desconecta todas as contas que ele continha, não apenas aquela com a qual você entra novamente. Desative a variável primeiro se esse cache vale a pena manter.

Apenas um cache que nada na máquina consegue 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 é exatamente o que você acabou de pedir para ele 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 substituta, e informa isso, em vez de excluir uma chave que voltaria a funcionar assim que as permissões fossem 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, chaveiro 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 chaveiro meramente bloqueado geralmente lê normalmente na próxima inicialização, 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 inicialização pede que você entre novamente. Se a chave realmente se foi e o cache nunca abrirá, exclua .token-cache.json para recomeçar — o log informa isso e nomeia o caminho.

Ambientes hospedados/sandbox (ex.: Anthropic Cowork): Defina MS365_MCP_TOKEN_CACHE_PATH e MS365_MCP_SELECTED_ACCOUNT_PATH para um mount persistente para que os tokens sobrevivam entre sessões.

Comando externo de cache de autenticação

Implantações locais de MSAL sem cabeça podem substituir o armazenamento integrado keytar/arquivo por um comando externo neutro de 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 tokens MSAL e os metadados de conta selecionada. Ele não recorre a keytar ou arquivos locais. Se o caminho do comando estiver ausente, não for executável no POSIX, sair com código diferente de zero, expirar ou retornar dados malformados, as operações de cache de autenticação falham de forma fechada com uma mensagem de erro sanitizada.

O valor deve ser um caminho real de um executável wrapper. Não é uma string de comando de shell e não há variável de ambiente de argumentos complementar. Coloque quaisquer configurações de interpretador, região, perfil ou 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. Sai com 0 com {"found":true,"value":"<stored envelope string>"} quando presente. Uma ausência é sair com 0 com {"found":false} ou stdout vazio.
  • save <key> recebe {"value":"<stamped envelope string>"} no stdin e deve sair com 0 somente 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 0 independentemente de a chave existir ou não.
  • <key> é token-cache ou selected-account.
  • Qualquer saída diferente de zero é um erro de armazenamento. Não use o código de saída 2 para 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 tokens podem ser grandes; os wrappers devem lidar com valores de pelo menos 256 KB.

Requisiçõ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 requisição, a menos que as ferramentas de autenticação local estejam 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

  1. Crie um Key Vault (se você não tiver um):

    az keyvault create --name your-keyvault-name --resource-group your-rg --location eastus
    
  2. 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"
    
  3. 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 list
    

    Para desenvolvimento local com Azure CLI:

    # Your Azure CLI identity already has access if you have appropriate RBAC roles
    az login
    
  4. 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 VaultVariável de AmbienteObrigatório
ms365-mcp-client-idMS365_MCP_CLIENT_IDSim
ms365-mcp-tenant-idMS365_MCP_TENANT_IDNão (padrão: 'common')
ms365-mcp-client-secretMS365_MCP_CLIENT_SECRETNão

Autenticação

A integração com Key Vault usa DefaultAzureCredential do SDK Azure Identity, que tenta automaticamente vários métodos de autenticação em ordem:

  1. Variáveis de ambiente (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
  2. Identidade gerenciada (recomendado para Azure Container Apps)
  3. Credenciais do Azure CLI (para desenvolvimento local)
  4. Credenciais do Visual Studio Code
  5. 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 usa 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 (ex.: um prefixo 🤖) para que os destinatários possam distinguir mensagens enviadas por agentes daquelas que você digitou. Desativada por padrão — ative-a 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 a desativa novamente.

Uma vez configurada, ela se aplica 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 intocado. 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 enviado sem ela.

Os marcadores podem conter marcação (ex.: um <span> colorido) desde que renderizem texto visível. Observe que a assinatura é uma salvaguarda contra um agente que usa indevidamente as ferramentas que recebeu, 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 de 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 de cliente), cobrindo alertas de segurança, logs de auditoria, saúde do serviço e relatórios de uso.

Suporte

Se você está tendo problemas ou precisa de ajuda:

Licença

MIT © 2026 Softeria