ForIT Microsoft Graph
This lean MCP server provides direct Microsoft Graph API access with multi-tenant account management, designed to minimize context bloat while enabling comprehensive Microsoft 365 integration.
Core Capabilities:
Multi-tenant authentication - Log in to multiple Microsoft 365 accounts simultaneously using device code flow, ideal for headless/SSH environments
Universal Graph API access - Execute any Graph API request through a single
graph-requesttool supporting all HTTP methods (GET, POST, PUT, PATCH, DELETE), custom headers, and request bodiesCross-tenant querying - Target specific accounts via
accountIdparameter to query different tenants in the same conversation without switchingFull Microsoft 365 coverage - Access all services including Outlook, Calendar, OneDrive, Users, Groups, Teams, and SharePoint
Advanced OData queries - Use
$select,$filter,$top,$orderby,$expand,$count, and$searchfor precise data retrievalAPI version control - Choose between stable (v1.0) and preview (beta) endpoints
Account lifecycle management - List, select, verify status, and remove cached accounts
Context-efficient design - Only 7 tools (~1KB context) replace 30-40 specialized tools (~12KB), reducing AI model overhead
PnP CLI complement - Works alongside PnP CLI for specialized SharePoint, Teams, and Power Platform operations
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ForIT Microsoft Graphshow my upcoming calendar events for this week"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 ( |
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 |
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)
Name it something like
MM-CLI(or whatever you want)Set Supported account types to "Accounts in this organizational directory only"
Leave Redirect URI blank (device code flow doesn't need one)
Click Register
Copy the Application (client) ID — this is your
appIdCopy the Directory (tenant) ID — this is your
tenantIdGo to API permissions > Add a permission > Microsoft Graph > Delegated permissions and add:
Permission | For |
| Email (read, send, manage) |
| Calendar operations |
| OneDrive / SharePoint files |
| SharePoint sites |
| Basic profile |
| Look up other users |
| Contacts |
| To Do / Planner tasks |
| OneNote |
| Teams chat |
| Teams team info |
| Teams channels |
| Send Teams messages |
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 interactivelySee 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-GAThis 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 |
| Yes | Application (client) ID from your app registration |
| Yes | Domain ( |
| Yes | Directory (tenant) ID GUID |
| Recommended | Expected sign-in email — MM warns if you auth as the wrong account |
| Yes | Human-readable label |
| Yes | Which MCP servers can use this connection ( |
| No | Set |
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 # Delete3. Install Python dependencies
cd mm
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt4. 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 -dVerify it's running:
curl http://localhost:5200/health | jq5. 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.jsonThe 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/deviceloginComplete 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 name from registry |
|
|
| PowerShell command to execute |
| Set |
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 name |
| API path (e.g., |
|
|
| Request body for POST/PATCH/PUT |
|
|
| Set |
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,.../sendPOST /teams/{id}/channels/{id}/messages,/chats/{id}/messages
Guarded PowerShell commands:
Send-MailMessage,Send-MgUserMailNew-MgChatMessage,New-MgTeamChannelMessage,Submit-PnPTeamsChannelMessage
Disabling send guards:
Method | Scope | How |
Per-connection | Single connection | Add |
Global | All connections | Set env var |
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 |
| Dev, small servers | ~2-4GB total |
Isolated |
| 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-AzContextby 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 —
/metricsendpoint with request counts, error rates, response times, session states.
Session Pool API
Endpoint | Method | Description |
| GET | Health check |
| GET | All session states |
| GET | List registry connections |
| POST | Execute a command |
| POST | Reset a connection's sessions |
| GET | Performance metrics |
Host Directories
Path | Purpose |
| Connection registry (read-only) |
| Persistent log files |
| Session state for restart persistence |
| 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 | jqHistory
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
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