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
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 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-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. Sites.Selecteddo 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:
- 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"]
}
}
}
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.
-
Inicie o servidor no modo HTTP:
npx @softeria/ms-365-mcp-server --http -
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
-
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 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.
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 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 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 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-toolspara 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:
- 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"
- 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).
- 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/callbackhttp://localhost:6274/oauth/callback/debughttp://localhost:3000/callback(opcional, para retorno do servidor)
- 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)
- 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.
Observação:
.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ê 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-toolsse 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
accountnecessá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
accountaceita endereço de e-mail (por exemplo,user@outlook.com) ouhomeAccountIddo 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 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 de minúsculas; fixações de
homeAccountIdsã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
--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, 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.--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 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-onlyENABLED_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_MODEMS365_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/topem solicitações de lista (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: Desativa completamente o acompanhamento 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 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-signoffdesativa 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ão1). 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,0para usar o IP bruto do socket peer, ou uma lista de sub-redes separadas por vírgulaMS365_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 listenerMS365_MCP_ATTACHMENT_PORTse vincula (alternativa à --attachment-host; requer--attachment-port). Padrão para o host ao qual--httpestá vinculado — 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_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 consoleMS365_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 paraconsumers— 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 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 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 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 (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 /attachmentna 3001 funciona; na 3000 é 404 — o aplicativo MCP nunca a monta./mcpna 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 proxyestá desativado no listener de anexos (eMS365_MCP_TRUST_PROXY_HOPSnã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; 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 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:
| 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 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_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 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 com0com{"found":true,"value":"<stored envelope string>"}quando presente. Uma ausência é sair com0com{"found":false}ou stdout vazio.save <key>recebe{"value":"<stamped envelope string>"}no stdin e deve sair com0somente 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 com0independentemente de a chave existir ou não.<key>étoken-cacheouselected-account.- Qualquer saída diferente de 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 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
-
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 Azure Identity, 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 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:
- Crie uma issue
- Inicie uma discussão
- E-mail: eirikb@eirikb.no
- Discord: https://discord.gg/WvGVNScrAZ ou @eirikb
Licença
MIT © 2026 Softeria