Skip to main content
Glama

Microsoft Master (MM)

Unified Microsoft 365 MCP server for AI assistants. One server, two tools, all of M365.

Prerequisites

Requirement

Why

Python 3.10+

MCP server runtime (mm/server.py)

Docker

Session pool runs PowerShell modules in containers

An Azure AD (Entra ID) app registration

Both tools authenticate via device code flow against your app

MCPJungle (or any MCP host)

Hosts the mm MCP server for your AI assistant

Quick Start

1. Create an Azure AD app registration

Every tenant you want to manage needs an app registration. This is how MM authenticates — there are no shared/default apps.

Option A: Azure Portal (recommended for first-time setup)

  1. Go to Azure Portal > App Registrations > New registration

  2. Name it something like MM-CLI (or whatever you want)

  3. Set Supported account types to "Accounts in this organizational directory only"

  4. Leave Redirect URI blank (device code flow doesn't need one)

  5. Click Register

  6. Copy the Application (client) ID — this is your appId

  7. Copy the Directory (tenant) ID — this is your tenantId

  8. Go to API permissions > Add a permission > Microsoft Graph > Delegated permissions and add:

Permission

For

Mail.ReadWrite

Email (read, send, manage)

Calendars.ReadWrite

Calendar operations

Files.ReadWrite.All

OneDrive / SharePoint files

Sites.ReadWrite.All

SharePoint sites

User.Read

Basic profile

User.ReadBasic.All

Look up other users

Contacts.ReadWrite

Contacts

Tasks.ReadWrite

To Do / Planner tasks

Notes.ReadWrite.All

OneNote

Chat.ReadWrite

Teams chat

Team.ReadBasic.All

Teams team info

Channel.ReadBasic.All

Teams channels

ChannelMessage.Send

Send Teams messages

  1. Click Grant admin consent (requires admin role)

No client secret needed. MM uses device code flow (public client), not client credentials.

Option B: CLI for Microsoft 365

npm install -g @pnp/cli-microsoft365
m365 setup   # Creates the app registration interactively

See docs/M365-CLI-SETUP.md for details.

2. Configure the connection registry

The connection registry tells MM which tenants exist and how to reach them.

# Create your first connection interactively
./mm-connections add Contoso-GA

This creates/updates ~/.m365-connections.json. You can also create it manually:

{
  "connections": {
    "Contoso-GA": {
      "appId": "your-app-client-id",
      "tenant": "contoso.com",
      "tenantId": "your-tenant-guid",
      "expectedEmail": "admin@contoso.com",
      "description": "Contoso Global Admin",
      "mcps": ["mm"]
    }
  }
}

Connection fields:

Field

Required

Description

appId

Yes

Application (client) ID from your app registration

tenant

Yes

Domain (contoso.com) or tenantId

tenantId

Yes

Directory (tenant) ID GUID

expectedEmail

Recommended

Expected sign-in email — MM warns if you auth as the wrong account

description

Yes

Human-readable label

mcps

Yes

Which MCP servers can use this connection (["mm"])

skipSignatureStrip

No

Set true to skip email signature stripping (default: false)

Connection naming convention:

  • GA — Global Admin (tenant admin operations)

  • Individual — Your user account on a work tenant

  • Personal — Your own personal tenant

Managing connections:

./mm-connections list                          # List all connections
./mm-connections add Contoso-GA                # Add interactively
./mm-connections edit Contoso-GA appId abc-123  # Set a field
./mm-connections duplicate Contoso-GA Contoso-Individual  # Copy
./mm-connections remove Old-Connection         # Delete

3. Install Python dependencies

cd mm
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

4. Start the session pool

The session pool runs PowerShell modules (Exchange, SharePoint, Azure, Teams) in Docker containers.

cd session-pool
docker compose -p m365-session-pool -f docker-compose.unified.yml up -d

Verify it's running:

curl http://localhost:5200/health | jq

5. Register with your MCP host

cp mm/mcpjungle-config.example.json mm/mcpjungle-config.json
# Edit mm/mcpjungle-config.json — update paths to match your system
mcpjungle register --conf mm/mcpjungle-config.json

The example config expects a venv at mm/.venv/bin/python. Update the command and args paths to match your setup.

6. Use it

# List connections
mcpjungle invoke mm run '{}'

# PowerShell (Exchange)
mcpjungle invoke mm run '{"connection":"Contoso-GA","module":"exo","command":"Get-Mailbox -ResultSize 1"}'

# Graph API
mcpjungle invoke mm graph_request '{"connection":"Contoso-GA","endpoint":"/me"}'

# Power Automate (Flow API)
mcpjungle invoke mm graph_request '{"connection":"Contoso-GA","endpoint":"/providers/Microsoft.ProcessSimple/environments","resource":"flow"}'

Auth is automatic. If a connection isn't authenticated, the tool returns a device code:

DEVICE CODE: XXXXXXXX
Go to: https://microsoft.com/devicelogin

Complete the sign-in, then retry the command. No pre-auth step needed.

Architecture

┌─────────────────────────────────────────────────────────┐
│                    AI Assistant                          │
└─────────────────────┬───────────────────────────────────┘
                      │ MCP Protocol (stdio)
                      ▼
               ┌─────────────┐
               │  mm/server  │  Python MCP server
               │             │  - graph_request (MSAL → Graph API)
               │             │  - run (HTTP → session pool)
               └──────┬──────┘
                      │ HTTP :5200
                      ▼
          ┌───────────────────────┐
          │   session-pool/       │  Docker container(s)
          │   session_pool.py     │  - PowerShell processes per module
          │                       │  - Native device code auth
          │   Modules:            │  - Session persistence
          │   exo, pnp, azure,    │  - Command guardrails
          │   teams               │  - Comprehensive logging
          └───────────────────────┘
                      │
          ┌───────────┴───────────┐
          │ ~/.m365-connections   │  Connection registry (READ-ONLY)
          │ ~/.mm-graph-tokens/   │  Graph MSAL token cache
          │ ~/.m365-logs/         │  Persistent logs
          │ ~/.m365-state/        │  Session state persistence
          └───────────────────────┘

Tools

mm__run — PowerShell via Session Pool

Execute PowerShell commands through persistent Docker-hosted sessions.

Parameter

Description

connection

Connection name from registry

module

exo (Exchange), pnp (SharePoint), azure, teams

command

PowerShell command to execute

confirmed

Set true to bypass send guards (see Send Guards)

Omit all parameters to list available connections.

mm__graph_request — Microsoft Graph REST API

Direct HTTP requests to Microsoft Graph (or Flow API) via MSAL tokens.

Parameter

Description

connection

Connection name

endpoint

API path (e.g., /me/messages)

method

GET, POST, PATCH, PUT, DELETE (default: GET)

body

Request body for POST/PATCH/PUT

resource

graph (default) or flow for Power Automate

confirmed

Set true to bypass send guards (see Send Guards)

Send Guards

Email and Teams message sends are blocked by default. When an AI assistant tries to send an email or Teams message, MM intercepts the request and returns a formatted draft preview instead. The assistant must re-call with confirmed: true to actually send.

Guarded Graph endpoints:

  • POST .../sendMail, .../reply, .../replyAll, .../forward, .../send

  • POST /teams/{id}/channels/{id}/messages, /chats/{id}/messages

Guarded PowerShell commands:

  • Send-MailMessage, Send-MgUserMail

  • New-MgChatMessage, New-MgTeamChannelMessage, Submit-PnPTeamsChannelMessage

Disabling send guards:

Method

Scope

How

Per-connection

Single connection

Add "skipSendGuards": true to the connection in ~/.m365-connections.json

Global

All connections

Set env var MM_SEND_GUARDS=false

Per-connection overrides the global setting. Example:

{
  "connections": {
    "Contoso-Automation": {
      "appId": "...",
      "skipSendGuards": true,
      "description": "Automated sends, no confirmation needed"
    }
  }
}

Session Pool

The session pool manages PowerShell processes with native device code authentication.

Deployment Modes

Mode

File

Use Case

RAM

Unified

docker-compose.unified.yml

Dev, small servers

~2-4GB total

Isolated

docker-compose.isolated.yml

Production, multi-user

~512MB per connection

Features

  • Session persistence — Authenticated sessions survive container restarts. Session metadata saved to ~/.m365-state/, PowerShell token caches persisted via Docker volumes. Azure sessions restore from cached tokens; EXO/Teams require re-auth (in-process only).

  • Command guardrails — Blocks dangerous operations: Install-Module (container integrity), New-AzRoleAssignment (access escalation), raw OAuth requests, app registration modifications. Warned but allowed: Remove-Az*, mail forwarding rules.

  • Azure context isolation — In unified mode, Disable-AzContextAutosave + Select-AzContext by expectedEmail prevents cross-tenant context contamination when multiple Azure sessions share ~/.Azure.

  • Comprehensive logging — Dual output: stdout (docker logs) + persistent files (~/.m365-logs/). Every command's output content logged. AADSTS and auth error patterns flagged at WARNING level.

  • Keepalive — Background thread pings authenticated sessions every 5 minutes to prevent token expiry. Stale sessions (auth_pending > 15 min) automatically reaped.

  • Metrics/metrics endpoint with request counts, error rates, response times, session states.

Session Pool API

Endpoint

Method

Description

/health

GET

Health check

/status

GET

All session states

/connections

GET

List registry connections

/run

POST

Execute a command

/reset

POST

Reset a connection's sessions

/metrics

GET

Performance metrics

Host Directories

Path

Purpose

~/.m365-connections.json

Connection registry (read-only)

~/.m365-logs/

Persistent log files

~/.m365-state/

Session state for restart persistence

~/.mm-graph-tokens/

MSAL token cache for Graph API

Monitoring

# Container health
docker ps --format "{{.Names}}\t{{.Status}}" | grep m365

# Live logs
docker logs -f m365-pool

# Persistent logs (survive container restarts)
tail -f ~/.m365-logs/session-pool-unified.log

# Session status
curl http://localhost:5200/status | jq

# Metrics
curl http://localhost:5200/metrics | jq

History

This repo originally contained four separate MCP servers (graph, pnp, pwsh-manager, registry), consolidated in February 2026 into the single mm server. The old servers are preserved in _archived/ for reference.

License

MIT

Install Server
A
security – no known vulnerabilities
F
license - not found
A
quality - confirmed to work

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ForITLLC/forit-microsoft-graph'

If you have feedback or need assistance with the MCP directory API, please join our Discord server