Doramagic Project Pack · Human Manual

ms-365-admin-mcp-server

Related topics: System Architecture, Installation Guide, Configuration Reference

Project Overview

Related topics: System Architecture, Installation Guide, Configuration Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Risk Level Rubric

Continue reading this section for the full explanation and source context.

Section Critical Tools (Require Out-of-Band Sign-off)

Continue reading this section for the full explanation and source context.

Section 1. Client Credentials Flow (Service Principal)

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Installation Guide, Configuration Reference

Project Overview

Introduction

The ms-365-admin-mcp-server is a Model Context Protocol (MCP) server that exposes Microsoft 365 admin capabilities as MCP tools. Built with TypeScript and strict mode, it enables AI assistants like Claude to perform Microsoft 365 administrative operations through the Microsoft Graph API.

Sources: CONTRIBUTING.md

Purpose and Scope

The server acts as a bridge between AI assistants and Microsoft 365 admin functionality:

  • Tool Generation: Auto-generates 444+ MCP tools from the Microsoft Graph OpenAPI specification Sources: CHANGELOG.md
  • Security-First Design: Every write operation is classified with risk levels (low/medium/high/critical) Sources: CONTRIBUTING.md
  • Least Privilege: Tools declare minimum required Graph API permissions via appPermissions in endpoints.json Sources: CONTRIBUTING.md

Architecture Overview

graph TD
    subgraph "MCP Client (Claude Desktop/Code)"
        A[AI Assistant]
    end
    
    subgraph "ms-365-admin-mcp-server"
        B[index.ts - MCP Server]
        C[auth.ts - MSAL Authentication]
        D[cli.ts - CLI Parsing]
        E[endpoints.json - Tool Definitions]
        F[generated/ - Zod Client]
        G[cloud-config.ts - Endpoint Routing]
    end
    
    subgraph "Microsoft Graph API"
        H[Global Cloud]
        I[China 21Vianet]
    end
    
    A <--> B
    B <--> C
    B <--> D
    B <--> E
    B <--> F
    C <--> H
    C <--> I
    G --> H
    G --> I

Project Layout

Directory/FilePurpose
bin/Code-generation scripts (OpenAPI → Zod client)
src/auth.tsMSAL client credentials flow authentication
src/cli.tsCommander argv parsing for CLI arguments
src/cloud-config.tsGlobal vs China (21Vianet) endpoint routing
src/endpoints.jsonSource of truth for tool definitions
src/generated/Auto-generated Zod schemas from OpenAPI
src/index.tsMain MCP server entry point

Sources: CONTRIBUTING.md

Tool Categories

The server organizes its 444+ tools into distinct categories for easier discovery and management:

CategoryPatternDescription
identity`user\group\role\device\pim\guest\external`Users, groups, roles, devices, PIM, guests, external identities
exchange`exchange\mailbox\message`Message traces, mailboxes
intune`intune\managed-devic\compliance`Devices, compliance, configurations, Autopilot, apps, RBAC
governancerole-resource-namespaceAccess reviews, entitlement, lifecycle workflows, PIM for Groups/Roles
response`disable\revoke\block\reset\wipe`Incident response operations
ediscoveryediscoveryeDiscovery cases (Microsoft Purview)
cloudpc`cloud-pc\provisioning-polic`Cloud PC / Windows 365
callrecords`call-record\call-session\pstn`Teams call records
printprintUniversal Print
infoprotection`bitlocker\sensitivity-label`BitLocker, threat assessment, sensitivity labels
sharepointadminsharepointSharePoint tenant administration
retentionretentionRecords management

Sources: src/tool-categories.ts

Risk Classification

All non-GET operations must be classified with a risk level before execution. The server enforces this through src/risk-level.ts:

graph LR
    A[Tool Request] --> B{Method?}
    B -->|GET| C[Default: low]
    B -->|POST/PATCH/DELETE| D[Default: critical]
    E[Configured Risk] --> F[effectiveRiskLevel]
    C --> F
    D --> F
    F --> G{Allowed?}
    G -->|Yes| H[Execute]
    G -->|No| I[Block + Error]

Risk Level Rubric

LevelCriteriaExamples
lowRead-only queries, reports, trivial annotationsrun-hunting-query, add-security-alert-comment, Intune reports
mediumReversible mutation affecting single entityupdate-user, add-group-member, create-invitation
highBroad scope, credential change, or destructive+revoke-user-sessions, update-conditional-access-policy
criticalIrreversible or tenant-wide impactdelete-user, wipe-managed-device, delete-conditional-access-policy

Sources: src/risk-level.ts

Critical Tools (Require Out-of-Band Sign-off)

The following operations are blocked even with --allow-writes and require formal change requests:

  • delete-user, delete-group, delete-application
  • delete-conditional-access-policy
  • delete-managed-device, wipe-managed-device
  • add-directory-role-member (on privileged roles)

Sources: agent-skills/ms365-admin-mcp/references/tools-catalog.md

Authentication Flow

The server supports two authentication methods:

1. Client Credentials Flow (Service Principal)

For automated/headless scenarios:

// src/auth.ts - MSAL client credentials flow
const credential = new ClientCredentialCredential({
  clientId: process.env.MS365_ADMIN_MCP_CLIENT_ID,
  clientSecret: process.env.MS365_ADMIN_MCP_CLIENT_SECRET,
  tenantId: process.env.MS365_ADMIN_MCP_TENANT_ID,
});

2. Device Code Bootstrap (RFC 8628)

For Claude Desktop/Code integration where browser-based auth isn't available:

npx ms-365-admin-mcp-auth --server https://your-host.azurecontainerapps.io/mcp

Sources: src/auth-bootstrap.ts

Cloud Configuration

The server supports Microsoft Azure's global cloud and China (21Vianet) operated cloud:

// src/cloud-config.ts
export const CLOUD_CONFIG = {
  global: {
    authority: 'https://login.microsoftonline.com',
    graph: 'https://graph.microsoft.com',
  },
  china: {
    authority: 'https://login.partner.microsoftonline.cn',
    graph: 'https://microsoftgraph.chinacloudapi.cn',
  },
};

Sources: CONTRIBUTING.md

Development Setup

# Clone and install
git clone https://github.com/okapi-ca/ms-365-admin-mcp-server.git
cd ms-365-admin-mcp-server
npm install

# Generate client from Graph OpenAPI spec
npm run generate

# Build
npm run build

# Test
npm test

# Run MCP Inspector
npm run inspector

Sources: CONTRIBUTING.md

Tool Definition Schema

Each tool in endpoints.json follows this structure:

{
  "toolName": "list-users",
  "method": "GET",
  "path": "/v1.0/users",
  "appPermissions": ["User.Read.All"],
  "llmTip": "Returns a list of users in the organization",
  "riskLevel": "low"
}
FieldRequiredDescription
toolNameYesUnique identifier used by MCP clients
methodYesHTTP method (GET, POST, PATCH, DELETE)
pathYesGraph API endpoint path
appPermissionsYesMinimum required Graph API permissions
llmTipNoHint shown to the LLM in tool description
riskLevelNo*Risk classification (only required for non-GET)

Sources: CONTRIBUTING.md

Tool Execution Flow

sequenceDiagram
    participant Client
    participant Server as ms-365-admin-mcp-server
    participant Graph as Microsoft Graph API
    
    Client->>Server: list-users(...)
    Server->>Server: Check risk level
    Server->>Server: Validate auth token
    Server->>Graph: GET /v1.0/users
    Graph-->>Server: User list response
    Server-->>Client: Tool result

Package Information

The project is published to both npm and GitHub Container Registry:

RegistryPackage/Image
npm@okapi-ca/ms-365-admin-mcp-server
GHCRghcr.io/okapi-ca/ms-365-admin-mcp-server

Sources: CHANGELOG.md

Coding Standards

  • TypeScript Strict Mode: No any without justification Sources: CONTRIBUTING.md
  • No New Runtime Dependencies: Prefer standard library additions
  • Prettier + ESLint: Must pass (npm run format:check and npm run lint)
  • Comments Explain Why: Name things well instead of over-commenting

Version History

VersionToolsKey Changes
Latest444Security fixes, set-application-verified-publisher risk bump
v369369Cloud PC, Teams call records, Universal Print, Info Protection
v306306eDiscovery, Cloud PC, Intune, Identity Governance
v199199Elevated dismiss-risky-users to high risk
v175175Full security review, PIM, risk detections

Sources: CHANGELOG.md

Sources: CONTRIBUTING.md

Installation Guide

Related topics: Configuration Reference, Docker and Container Deployment

Section Related Pages

Continue reading this section for the full explanation and source context.

Section System Requirements

Continue reading this section for the full explanation and source context.

Section Azure AD Requirements

Continue reading this section for the full explanation and source context.

Section Pull from GHCR Registry

Continue reading this section for the full explanation and source context.

Related topics: Configuration Reference, Docker and Container Deployment

Installation Guide

This guide covers all supported methods for installing and configuring the ms-365-admin-mcp-server. The server exposes Microsoft 365 admin APIs as MCP tools, enabling AI assistants to perform administrative operations across Azure AD, Intune, Exchange, SharePoint, Teams, and other Microsoft 365 workloads.

Prerequisites

System Requirements

RequirementMinimumRecommended
Node.jsv20.xv22.x LTS
npmv10.xv10.x
Memory512 MB1 GB
Disk Space200 MB500 MB
OSWindows 10+, macOS 11+, LinuxWindows 11, macOS 14+, Ubuntu 22.04+

Azure AD Requirements

Before installation, you must have:

  • An Azure AD tenant (single-tenant required for client credentials flow)
  • An registered application with appropriate Graph API permissions
  • A valid client secret or certificate credential

Sources: docs/APP_REGISTRATION.md

Installation Methods

The server supports three installation methods:

graph TD
    A[Installation Methods] --> B[Docker Container]
    A --> C[Node.js Direct]
    A --> D[Claude Desktop Integration]
    
    B --> B1[GHCR Registry]
    B --> B2[Dockerfile Build]
    
    C --> C1[npm Global]
    C --> C2[Local Clone]
    
    D --> D1[Inspector Testing]
    D --> D2[Production Config]

Method 1: Docker Installation

Pull from GHCR Registry

The pre-built container image is published to GitHub Container Registry:

docker pull ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest

Run the Container

docker run -d \
  --name mcp-server \
  -p 8080:8080 \
  -e MS365_ADMIN_MCP_CLIENT_ID="your-client-id" \
  -e MS365_ADMIN_MCP_CLIENT_SECRET="your-client-secret" \
  -e MS365_ADMIN_MCP_TENANT_ID="your-tenant-id" \
  ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest

Docker Security Configuration

The Dockerfile implements several security controls:

FeatureImplementation
Non-root userContainer runs as node user (UID 1000)
Security headersX-Content-Type-Options, X-Frame-Options: DENY, CSP
Cache permissionsToken files stored with mode 0600
Network isolationSingle-tenant enforcement

Sources: SECURITY.md

Docker Bind Mounts for Persistent Cache

For production deployments requiring persistent authentication cache:

docker run -d \
  --name mcp-server \
  -p 8080:8080 \
  -v /path/to/cache:/home/node/.mcp-auth \
  -e MS365_ADMIN_MCP_CLIENT_ID="your-client-id" \
  -e MS365_ADMIN_MCP_CLIENT_SECRET="your-client-secret" \
  -e MS365_ADMIN_MCP_TENANT_ID="your-tenant-id" \
  ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest

The server honors the MCP_REMOTE_CONFIG_DIR environment variable, allowing Docker bind mounts and multi-user setups without patches.

Sources: CHANGELOG.md

Build from Dockerfile

For customization or air-gapped deployments:

git clone https://github.com/okapi-ca/ms-365-admin-mcp-server.git
cd ms-365-admin-mcp-server
docker build -t ms-365-admin-mcp-server:local .

Method 2: Node.js Installation

Option A: Install from npm Registry

npm install -g @okapi-ca/ms-365-admin-mcp-server

Option B: Local Development Setup

git clone https://github.com/okapi-ca/ms-365-admin-mcp-server.git
cd ms-365-admin-mcp-server
npm install

#### Build Steps

npm run generate    # Download Graph OpenAPI spec and generate client
npm run build

#### Verify Installation

npm test

Sources: CONTRIBUTING.md

Azure AD Application Registration

Required Permissions

The application requires Microsoft Graph API permissions. The following table summarizes permission scopes by category:

CategoryPermission TypeRequired Scopes
User ManagementApplicationUser.ReadWrite.All
Group ManagementApplicationGroup.ReadWrite.All
Device ManagementApplicationDeviceManagementManagedDevices.ReadWrite.All
Exchange AdminApplicationExchange.Admin
SharePointApplicationSharePoint.Admin
TeamsApplicationTeam.ReadWrite.All
SecurityApplicationSecurityEvents.ReadWrite.All

Registration Steps

  1. Navigate to Azure Portal → Azure Active Directory → App registrations
  2. Select New registration
  3. Configure the application:
  • Name: ms-365-admin-mcp-server
  • Supported account types: Accounts in this organizational directory only
  • Redirect URI: Leave blank (not required for daemon apps)
  1. Navigate to Certificates & secretsNew client secret
  2. Copy and securely store the secret value (it cannot be retrieved later)
  3. Navigate to API permissionsAdd a permissionMicrosoft Graph
  4. Select Application permissions and add required scopes
  5. Click Grant admin consent

Sources: docs/APP_REGISTRATION.md

Configuration

Environment Variables

VariableRequiredDescription
MS365_ADMIN_MCP_CLIENT_IDYesAzure AD application (client) ID
MS365_ADMIN_MCP_CLIENT_SECRETYesClient secret value
MS365_ADMIN_MCP_TENANT_IDYesAzure AD tenant ID
MCP_REMOTE_CONFIG_DIRNoOverride cache directory path
CINoSet to true to disable clipboard operations
PORTNoHTTP server port (default: 8080)

Local .env File

Create a .env file in the project root for local development:

MS365_ADMIN_MCP_CLIENT_ID=your-client-id
MS365_ADMIN_MCP_CLIENT_SECRET=your-client-secret
MS365_ADMIN_MCP_TENANT_ID=your-tenant-id

Sources: CONTRIBUTING.md

Command-Line Options

node dist/index.js --help
OptionDescription
--client-id <id>Override MS365_ADMIN_MCP_CLIENT_ID
--client-secret <secret>Override MS365_ADMIN_MCP_CLIENT_SECRET
--tenant-id <id>Override MS365_ADMIN_MCP_TENANT_ID
--cache-dir <path>Override token cache directory
--allow-writesEnable write operations (default: read-only)
--list-toolsList available tools and exit
--preset <name>Enable preset category filters

Claude Desktop Integration

macOS Configuration

``bash ~/Library/Application Support/Claude/claude_desktop_config.json ``

  1. Locate the Claude Desktop configuration file:
  1. Add the MCP server configuration:
{
  "mcpServers": {
    "ms-365-admin": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "--env-file",
        "/absolute/path/to/.env",
        "-v",
        "/path/to/cache:/home/node/.mcp-auth",
        "ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest"
      ]
    }
  }
}

Sources: docs/SETUP_MACOS_EN.md

Windows Configuration

``powershell %APPDATA%\Claude\claude_desktop_config.json ``

  1. Locate the Claude Desktop configuration file:
  1. Add the MCP server configuration:
{
  "mcpServers": {
    "ms-365-admin": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "--env-file",
        "C:\\path\\to\\.env",
        "-v",
        "mcp-cache:C:\\Users\\ContainerAdministrator\\.mcp-auth",
        "ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest"
      ]
    }
  }
}

Sources: docs/SETUP_WINDOWS_EN.md

Interactive Testing with MCP Inspector

For testing the server configuration:

npm run inspector

Sources: CONTRIBUTING.md

Device Code Authentication (Optional)

For environments where browser-based authentication is unavailable, the server supports RFC 8628 device code flow:

npx ms-365-admin-mcp-auth \
  --server https://your-host.azurecontainerapps.io/mcp

The auth bootstrap tool:

  • Polls /token endpoint for authentication completion
  • Writes cache files (<hash>_client_info.json and <hash>_tokens.json) to ~/.mcp-auth/mcp-remote-<version>/
  • Uses mode 0600 for cache files (secure permissions)
  • Cache key = md5(serverUrl), matching mcp-remote's getServerUrlHash exactly
  • Supports best-effort clipboard copy (auto-disabled under CI=true or non-TTY)

Sources: src/auth-bootstrap.ts

Verifying Installation

List Available Tools

node dist/index.js --list-tools

This outputs all available MCP tools organized by category.

Test Authentication

curl http://localhost:8080/health

Expected response:

{"status": "ok", "authenticated": true}

Exit Codes

The server documents exit codes for Docker/CI wrappers:

CodeMeaning
0Success
1Usage error / invalid configuration
2Network error / Azure AD unreachable
3Access denied (insufficient permissions)
4Request timeout

Sources: CHANGELOG.md

Troubleshooting

Common Issues

IssueSolution
Tenant 'common' rejectedEnsure single-tenant registration; set MS365_ADMIN_MCP_TENANT_ID explicitly
Token cache not persistingUse -v flag to bind mount cache directory in Docker
Permission denied errorsVerify app registration has admin consent granted
Container exits immediatelyCheck logs with docker logs mcp-server; verify environment variables

Documentation References

  • Troubleshooting Guide — covers Server disconnected, Platform SSO symptoms, device_code flow walkthrough
  • SECURITY.md — security architecture and best practices

Next Steps

After successful installation:

  1. Review the Tool Catalog to understand available operations
  2. Configure appropriate risk levels for write operations
  3. Review use case patterns for Identity Management, Intune, and other workloads

Sources: docs/APP_REGISTRATION.md

Configuration Reference

Related topics: Project Overview, Installation Guide, HTTP Transport and Deployment

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Required Variables

Continue reading this section for the full explanation and source context.

Section Optional Variables

Continue reading this section for the full explanation and source context.

Section Risk Level Configuration

Continue reading this section for the full explanation and source context.

Related topics: Project Overview, Installation Guide, HTTP Transport and Deployment

Configuration Reference

Overview

The ms-365-admin-mcp-server provides a comprehensive configuration system that controls authentication, cloud endpoint selection, risk-based access control, and tool filtering. Configuration is driven through a combination of environment variables, CLI arguments, and JSON-based endpoint definitions.

The server implements a least-privilege security model where tools are classified by risk level, and the server operator can enforce a maximum permissible risk threshold to prevent accidental execution of destructive operations.

Configuration Architecture

graph TD
    A[Environment Variables] --> B[Secrets Module]
    A --> C[Cloud Config Module]
    D[CLI Arguments] --> E[CLI Parser]
    E --> F[Runtime Config]
    B --> F
    C --> F
    G[endpoints.json] --> H[Tool Registry]
    H --> I[Risk Level Classifier]
    I --> J[Access Control Filter]
    F --> J
    J --> K[MCP Tools]
    
    L[Auth Module] --> M[MSAL Token Cache]
    B --> L
    F --> L

Environment Variables

The server requires Azure AD application registration credentials. All environment variables use the MS365_ADMIN_MCP_ prefix.

Required Variables

VariableDescriptionRequired
MS365_ADMIN_MCP_CLIENT_IDAzure AD application (client) IDYes
MS365_ADMIN_MCP_CLIENT_SECRETClient secret for the applicationYes
MS365_ADMIN_MCP_TENANT_IDAzure AD tenant IDYes

Optional Variables

VariableDescriptionDefault
MS365_ADMIN_MCP_MAX_RISK_LEVELMaximum risk level permittedmedium
MS365_ADMIN_MCP_CLOUDTarget cloud: global or chinaglobal
MS365_ADMIN_MCP_PRESETComma-separated list of tool presetsall
MS365_ADMIN_MCP_PORTHTTP server port3000
MCP_REMOTE_CONFIG_DIRCustom cache directory for OAuth tokensPlatform default

Risk Level Configuration

Risk levels control which tools are exposed or executable. The server enforces a maximum risk level that acts as an access control gate.

Risk LevelRankDescription
low1Safe read-only operations
medium2Operations with moderate impact
high3Significant impact operations
critical4Irreversible or tenant-wide operations

The effective risk level for a tool is determined as follows (Sources: src/risk-level.ts:1-20):

export function effectiveRiskLevel(
  configuredRiskLevel: RiskLevel | undefined,
  method: string
): RiskLevel {
  if (configuredRiskLevel) return configuredRiskLevel;
  return method.toUpperCase() === 'GET' ? 'low' : 'critical';
}

Key rules:

  • If configuredRiskLevel is explicitly set, it is used directly
  • GET endpoints without explicit configuration default to low
  • Write endpoints without explicit configuration default to critical (fail-safe)
  • A tool is allowed if rank(effectiveRiskLevel) <= rank(maxRiskLevel)

Cloud Configuration

The server supports Microsoft 365 deployments in different sovereign clouds.

graph LR
    A[Config: cloud=global] --> B[login.microsoftonline.com]
    C[Config: cloud=china] --> D[login.partner.microsoftonline.cn]
    B --> E[Microsoft Graph Global]
    D --> F[Microsoft Graph China 21Vianet]

Supported Clouds

Cloud IdentifierAzure EnvironmentGraph Endpoint
globalMicrosoft Azurehttps://graph.microsoft.com
chinaAzure China 21Vianethttps://microsoftgraph.chinacloudapi.cn

The cloud configuration is loaded from environment variable MS365_ADMIN_MCP_CLOUD (Sources: src/cloud-config.ts) and determines which Microsoft Graph endpoint the server authenticates against.

CLI Arguments

The server accepts command-line arguments parsed by Commander.js (Sources: src/cli.ts)。

ArgumentShortDescriptionDefault
--max-risk-level-rMaximum risk level (low/medium/high/critical)medium
--preset-pTool preset filter (security, identity, etc.)all
--portHTTP server port3000
--list-toolsList available tools and exitfalse
--inspectorRun with MCP Inspectorfalse

Listing Tools with Presets

To validate preset patterns, run:

node dist/index.js --preset mypreset --list-tools

This validates that the preset regex matches tool names defined in endpoints.json.

Tool Presets

Tool presets filter the available tools based on regex patterns defined in src/tool-categories.ts (Sources: src/tool-categories.ts)。

Available Presets

Preset NamePattern MatchesDescription
securitysecurity, alert, incident, attack-simulation, threat-intelMicrosoft 365 Defender tools
auditaudit, sign-in, provisioning, directory, deletedAudit logs and sign-in activity
healthservice, health, issue, messageService health and Message Center
reportsreport, activity, usageUsage reports (Teams, Email, SharePoint)
identityuser, group, role, conditional, directory, device, pimEntra ID management
exchangeexchange, mailbox, message, mailExchange Online administration
intuneintune, managed, compliance, autopilot, mdm, mamIntune device management
governanceaccess-review, entitlement, lifecycle, terms-of-useIdentity Governance
compliancecompliance, license, secure-score, risk-detectionCompliance center tools
responsedisable-user, revoke, block, reset, dismiss, wipeIncident response operations
ediscoveryediscoveryMicrosoft Purview eDiscovery
cloudpccloud-pc, provisioning-policyWindows 365 Cloud PC
callrecordscall-record, call-session, pstn-callTeams call records
printprintUniversal Print
infoprotectionbitlocker, sensitivity, threat-assessmentInformation Protection
sharepointadminsharepoint, site-adminSharePoint admin center
retentionretention, recordsRecords management
teamsadminteam, teams-app, teams-policyTeams administration
all.*All available tools

Combining Presets

Multiple presets can be combined using the getCombinedPresetPattern function (Sources: src/tool-categories.ts:60-75):

export function getCombinedPresetPattern(presets: string[]): string {
  const patterns = presets.map((preset) => {
    const category = TOOL_CATEGORIES[preset];
    if (!category) {
      throw new Error(
        `Unknown preset: ${preset}. Available presets: ${Object.keys(TOOL_CATEGORIES).join(', ')}`
      );
    }
    return category.pattern.source;
  });
  return patterns.join('|');
}

Authentication Configuration

Authentication uses the MSAL (Microsoft Authentication Library) client credentials flow (Sources: src/auth.ts)。

Authentication Flow

sequenceDiagram
    participant Server
    participant MSAL
    participant Azure AD
    
    Server->>Azure AD: Request token with client credentials
    Azure AD-->>MSAL: Access token + refresh token
    MSAL-->>Server: Token cached
    Server->>Azure AD: Graph API calls with bearer token
    Azure AD-->>Server: Response

Token Cache Location

Tokens are cached in:

  • macOS/Linux: ~/.mcp-auth/mcp-remote-<version>/
  • Windows: %USERPROFILE%\.mcp-auth\mcp-remote-<version>\

Cache files are named <hash>_client_info.json and <hash>_tokens.json with mode 0600 permissions.

Remote Server Authentication

For remote HTTP server mode, device code authentication is supported (Sources: CONTRIBUTING.md):

  • Cache key = md5(serverUrl) to match mcp-remote's getServerUrlHash
  • Best-effort clipboard copy for device codes (auto-disabled under CI=true)
  • Configurable cache directory via --cache-dir or MCP_REMOTE_CONFIG_DIR

Endpoint Configuration

The src/endpoints.json file is the source of truth for all tool definitions (Sources: src/endpoints.json)。

Endpoint Schema

Each endpoint definition includes:

FieldDescription
toolNameUnique identifier for the tool
methodHTTP method (GET, POST, PATCH, DELETE)
pathMicrosoft Graph API path
descriptionHuman-readable description
appPermissionsRequired Graph API permissions
riskLevelConfigured risk level (low/medium/high/critical)
categoryTool category for filtering

Risk Classification Examples

Critical-risk tools (Sources: agent-skills/ms365-admin-mcp/references/tools-catalog.md):

  • delete-user
  • delete-group
  • delete-conditional-access-policy
  • wipe-managed-device
  • delete-managed-device

High-risk tools:

  • revoke-user-sessions
  • confirm-compromised-users
  • create-conditional-access-policy
  • update-conditional-access-policy

Configuration Precedence

Configuration values are resolved in the following order (highest to lowest priority):

  1. CLI arguments (command-line overrides)
  2. Environment variables
  3. Default values
graph TD
    A[Config Sources] --> B[CLI Arguments]
    A --> C[Environment Variables]
    A --> D[Default Values]
    B --> E[Runtime Merged Config]
    C --> E
    D --> E
    E --> F[Server Initialization]

Example Configuration Files

Development .env File

Create a local .env file in the project root (Sources: CONTRIBUTING.md):

MS365_ADMIN_MCP_CLIENT_ID=your-app-client-id
MS365_ADMIN_MCP_CLIENT_SECRET=your-client-secret
MS365_ADMIN_MCP_TENANT_ID=your-tenant-id

Docker Configuration

For Docker deployments, use environment variables or bind-mounted configuration:

docker run \
  -e MS365_ADMIN_MCP_CLIENT_ID=... \
  -e MS365_ADMIN_MCP_CLIENT_SECRET=... \
  -e MS365_ADMIN_MCP_TENANT_ID=... \
  -e MS365_ADMIN_MCP_MAX_RISK_LEVEL=medium \
  -e MCP_REMOTE_CONFIG_DIR=/data/mcp-config \
  -v /path/to/config:/data/mcp-config \
  ghcr.io/okapi-ca/ms-365-admin-mcp-server

Exit Codes

The server uses specific exit codes for Docker and CI integration (Sources: CONTRIBUTING.md):

CodeMeaning
0Success
1Usage error / invalid configuration
2Network error
3Authentication denied
4Request timeout

Verification

Run the verification script to ensure configuration is valid:

npm run verify

This runs:

  • TypeScript compilation (npm run build)
  • Linting (npm run lint)
  • Formatting checks (npm run format:check)
  • Test suite (npm test)

Source: https://github.com/okapi-ca/ms-365-admin-mcp-server / Human Manual

System Architecture

Related topics: Project Overview, Code Generation Pipeline, Tool Categories and Presets

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Authentication Module (src/auth.ts)

Continue reading this section for the full explanation and source context.

Section Cloud Configuration (src/cloud-config.ts)

Continue reading this section for the full explanation and source context.

Section Tool Registry (src/endpoints.json)

Continue reading this section for the full explanation and source context.

Related topics: Project Overview, Code Generation Pipeline, Tool Categories and Presets

System Architecture

The ms-365-admin-mcp-server is a Model Context Protocol (MCP) server that exposes Microsoft 365 administrative operations as AI-consumable tools. It acts as a bridge between Large Language Models (LLMs) and the Microsoft Graph API, providing over 444 administrative endpoints organized into security-aware tool categories.

Overview

The server follows a layered architecture pattern with clear separation of concerns:

  1. Authentication Layer — MSAL-based OAuth2 client credentials flow
  2. Tool Registry — Declarative tool definitions from OpenAPI specs
  3. Risk Control Layer — Tool filtering based on configurable risk thresholds
  4. MCP Transport Layer — STDIO server or HTTP/SSE endpoint
  5. Graph API Client — Auto-generated TypeScript client from OpenAPI

Sources: CONTRIBUTING.md

Core Components

Authentication Module (`src/auth.ts`)

The server uses MSAL (Microsoft Authentication Library) with the client credentials flow for service-to-service authentication. This flow is suitable for daemon applications that operate without user interaction.

┌─────────────────────────────────────────────────────────────────┐
│                    Authentication Flow                          │
├─────────────────────────────────────────────────────────────────┤
│  1. Server starts → Initialize MSAL ConfidentialClientApplication │
│  2. Acquire token via client credentials (client_id + secret)     │
│  3. Token cached with expiration handling                         │
│  4. Graph API calls include Bearer token                          │
│  5. On 401 → Automatic token refresh                              │
└─────────────────────────────────────────────────────────────────┘

Configuration requires three environment variables:

VariableDescription
MS365_ADMIN_MCP_CLIENT_IDAzure AD application (client) ID
MS365_ADMIN_MCP_CLIENT_SECRETClient secret from certificate or app registration
MS365_ADMIN_MCP_TENANT_IDAzure AD tenant ID

Sources: CONTRIBUTING.md

Cloud Configuration (`src/cloud-config.ts`)

The server supports Microsoft Azure's global cloud as well as the China (21Vianet) operated cloud. Endpoint selection is configurable to support sovereign cloud deployments.

Cloud EnvironmentEndpoint Pattern
Globalgraph.microsoft.com
China (21Vianet)graph.microsoft.cn

Tool Registry (`src/endpoints.json`)

The endpoints.json file is the source of truth for all tool definitions. Each tool entry specifies:

{
  "toolName": {
    "method": "GET|POST|PATCH|PUT|DELETE",
    "path": "/v1.0/{resource}",
    "appPermissions": ["Permission.Read.All"],
    "llmTip": "Human-readable hint for the LLM",
    "riskLevel": "low|medium|high|critical"
  }
}

Sources: CONTRIBUTING.md

Risk Level System (`src/risk-level.ts`)

The server implements a risk-based access control system. Each non-GET operation must declare a risk level, and operators can configure a maximum allowed risk level.

export function effectiveRiskLevel(
  configuredRiskLevel: RiskLevel | undefined,
  method: string
): RiskLevel {
  if (configuredRiskLevel) return configuredRiskLevel;
  return method.toUpperCase() === 'GET' ? 'low' : 'critical';
}

Risk levels are enforced at runtime:

LevelCriteriaExamples
lowRead-only in effectlist-users, reports
mediumReversible mutationupdate-user, add-group-member
highBroad scope or credential changesrevoke-user-sessions, update-conditional-access-policy
criticalIrreversible or tenant-widedelete-user, wipe-managed-device

Sources: src/risk-level.ts, CONTRIBUTING.md

Tool Categories (`src/tool-categories.ts`)

Tools are organized into preset categories that map to regex patterns. Users can select specific categories to reduce the tool surface or enable focused administration.

export const TOOL_CATEGORIES: Record<string, ToolCategory> = {
  identity: {
    name: 'identity',
    pattern: /user|group|device|directory|role/i,
    description: 'Users, groups, roles, devices, PIM, guests, external identities',
  },
  compliance: {
    name: 'compliance',
    pattern: /license|secure-score|conditional-access|auth-methods/i,
    description: 'Licenses, Secure Score, Identity Protection, risk detections, CA policies',
  },
  // ... additional categories
};

Available presets include: identity, exchange, intune, governance, compliance, response, ediscovery, cloudpc, callrecords, print, infoprotection, sharepointadmin, retention, teamsadmin, reports, audit, and all.

Sources: src/tool-categories.ts

Server Architecture

STDIO Mode (MCP Standard)

In standard MCP mode, the server communicates over STDIO using JSON-RPC messages. This is the default mode for Claude Desktop and other MCP-compatible clients.

┌──────────────┐     STDIO (JSON-RPC)      ┌──────────────────────┐
│  MCP Client  │ ◄──────────────────────► │  ms-365-admin-mcp    │
│  (Claude)    │                           │  server              │
└──────────────┘                           └──────────────────────┘

HTTP Server Mode

The server can also run as an HTTP endpoint with Server-Sent Events (SSE) for streaming responses. This mode is suitable for remote deployments in containerized environments.

┌──────────────┐     HTTPS + SSE           ┌──────────────────────┐
│  HTTP Client │ ◄──────────────────────► │  ms-365-admin-mcp    │
│  (Remote)    │                           │  http-server         │
└──────────────┘                           └──────────────────────┘

The HTTP server supports two authentication mechanisms:

  1. OAuth2 Client Credentials — Direct token authentication
  2. Device Code Flow — Interactive authentication for CLI tools

Sources: CHANGELOG.md

Device Code Bootstrap (`src/auth-bootstrap.ts`)

For HTTP server deployments, the ms-365-admin-mcp-auth CLI tool implements RFC 8628 device code flow to pre-seed the mcp-remote token cache:

ms-365-admin-mcp-auth --server https://your-host.azurecontainerapps.io/mcp

This allows Claude Desktop/Code to skip the browser-based authentication flow when connecting to remote servers.

Key features:

  • Cache key = md5(serverUrl) for compatibility with mcp-remote
  • Token files stored in ~/.mcp-auth/mcp-remote-<version>/ with mode 0600
  • Best-effort clipboard copy (auto-disabled under CI=true)
  • Exit codes: 0 (ok), 1 (usage), 2 (network), 3 (denied), 4 (timeout)

Sources: src/auth-bootstrap.ts, CHANGELOG.md

Code Generation Pipeline

The server uses a code generation pipeline to transform the Microsoft Graph OpenAPI specification into type-safe TypeScript/Zod client code:

┌─────────────────┐     npm run generate      ┌─────────────────────┐
│  Graph OpenAPI  │ ───────────────────────► │  src/generated/      │
│  Specification  │                          │  (zod schemas +     │
│                 │                          │   typed clients)    │
└─────────────────┘                          └─────────────────────┘

The bin/ directory contains scripts that:

  1. Download the latest Graph API OpenAPI spec
  2. Parse and transform the specification
  3. Generate Zod validation schemas
  4. Create typed Graph API client methods

Sources: CONTRIBUTING.md

CLI Interface (`src/cli.ts`)

The server uses Commander.js for CLI argument parsing. Key commands:

CommandDescription
npm run inspectorStart MCP Inspector for interactive testing
--list-toolsDisplay all available tools matching current preset
--list-permissionsShow required Graph API permissions
--preset <name>Select tool category preset
--max-risk <level>Set maximum allowed risk level
--allow-writesEnable write operations (disabled by default)

Example usage:

# List tools in the identity preset
node dist/index.js --preset identity --list-tools

# Start with compliance tools and allow medium-risk operations
node dist/index.js --preset compliance --max-risk medium --allow-writes

Security Model

The server implements defense-in-depth through multiple layers:

1. Permission Layer

Every tool declares minimum required Graph API permissions (appPermissions). The server never requests overly broad permissions like .ReadWrite.All when .Read.All suffices.

2. Risk Classification

Write operations are classified into four risk levels. The --max-risk flag limits which operations can execute.

3. Explicit Write Confirmation

By default, write operations are disabled. The --allow-writes flag enables them, but high-risk operations still require explicit confirmation.

4. Audit Trail

All operations are logged with timestamps, tool names, and risk levels for security auditing.

Critical-risk tools require out-of-band sign-off and should not be executed through the chat interface without formal change request documentation:

ToolRisk Level
delete-usercritical
delete-groupcritical
delete-conditional-access-policycritical
delete-managed-devicecritical
wipe-managed-devicecritical

Sources: agent-skills/ms365-admin-mcp/references/tools-catalog.md

Development Workflow

Local Development Setup

git clone https://github.com/okapi-ca/ms-365-admin-mcp-server.git
cd ms-365-admin-mcp-server
npm install
npm run generate    # Download Graph OpenAPI spec and generate client
npm run build
npm test

Adding a New Tool

  1. Edit src/endpoints.json with the new endpoint definition
  2. Run npm run generate to regenerate the client
  3. Verify tool registration with --list-tools
  4. Add tests for non-trivial parameter handling
  5. Update README.md tool tables

Verification Commands

npm run format:check  # Prettier validation
npm run lint          # ESLint validation
npm test              # Run test suite
npm run verify        # All checks (format + lint + test)

Sources: CONTRIBUTING.md

Project Layout

ms-365-admin-mcp-server/
├── bin/                    # Code-generation scripts (OpenAPI → zod client)
├── src/
│   ├── auth.ts             # MSAL client credentials flow
│   ├── auth-bootstrap.ts   # Device code bootstrap CLI
│   ├── cli.ts              # Commander argv parsing
│   ├── cloud-config.ts     # Global vs China (21Vianet) endpoints
│   ├── endpoints.json      # Source of truth for tool definitions
│   ├── generated/          # Auto-generated zod schemas and clients
│   ├── graph-client.ts     # Graph API client wrapper
│   ├── http-server.ts      # HTTP/SSE server implementation
│   ├── risk-level.ts       # Risk classification logic
│   ├── server.ts           # MCP STDIO server implementation
│   └── tool-categories.ts  # Tool category presets
├── docs/                   # Documentation
├── agent-skills/           # Claude Code skill definitions
└── README.md

Deployment Options

Docker Container

The server is published to GitHub Container Registry:

docker run -p 8080:8080 \
  -e MS365_ADMIN_MCP_CLIENT_ID=... \
  -e MS365_ADMIN_MCP_CLIENT_SECRET=... \
  -e MS365_ADMIN_MCP_TENANT_ID=... \
  ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest

Claude Desktop Integration

For local development, add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "ms-365-admin": {
      "command": "npx",
      "args": ["-y", "@okapi-ca/ms-365-admin-mcp-server"],
      "env": {
        "MS365_ADMIN_MCP_CLIENT_ID": "...",
        "MS365_ADMIN_MCP_CLIENT_SECRET": "...",
        "MS365_ADMIN_MCP_TENANT_ID": "..."
      }
    }
  }
}

Claude Code Skill Installation

cp -r agent-skills/ms365-admin-mcp ~/.claude/skills/

The skill auto-loads when the conversation matches its description field.

Sources: CONTRIBUTING.md

Code Generation Pipeline

Related topics: System Architecture, Tool Categories and Presets

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 1. OpenAPI Download Module

Continue reading this section for the full explanation and source context.

Section 2. Simplified OpenAPI Processor

Continue reading this section for the full explanation and source context.

Section 3. Description Extractor

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Tool Categories and Presets

Code Generation Pipeline

Overview

The Code Generation Pipeline is an automated build process that transforms the Microsoft Graph OpenAPI specification into a fully-typed MCP (Model Context Protocol) server implementation. This pipeline generates TypeScript/Zod schemas, endpoint types, and tool definitions, enabling type-safe interactions with over 500 Microsoft Graph API endpoints.

Sources: CONTRIBUTING.md

Architecture Overview

graph TD
    A[Microsoft Graph OpenAPI Spec] --> B[download-openapi.mjs]
    B --> C[simplified-openapi.mjs]
    C --> D[extract-descriptions.mjs]
    D --> E[generate-mcp-tools.mjs]
    E --> F[generate-graph-client.mjs]
    F --> G[src/generated/]
    G --> H[endpoint-types.ts]
    G --> I[schemas.ts]
    G --> J[descriptions.ts]
    G --> K[endpoints.json]
    K --> L[graph-tools.ts]
    L --> M[MCP Server]

Pipeline Components

1. OpenAPI Download Module

File: bin/modules/download-openapi.mjs

Downloads the Microsoft Graph OpenAPI specification from the official Microsoft Graph metadata repository.

ParameterTypeDescription
outputPathstringLocal path to save the downloaded OpenAPI spec
versionstringAPI version to download (default: v1.0)

Key behaviors:

  • Fetches OpenAPI spec from https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/openapi/v1.0/openapi.yaml
  • Handles network errors with retry logic
  • Validates downloaded file structure

Sources: bin/modules/download-openapi.mjs

2. Simplified OpenAPI Processor

File: bin/modules/simplified-openapi.mjs

Transforms the raw OpenAPI specification into a simplified intermediate format optimized for code generation.

Transformation rules:

  • Flattens nested schema references
  • Resolves $ref pointers
  • Extracts path parameters, query parameters, and request body schemas
  • Normalizes response schemas

Output structure:

interface SimplifiedEndpoint {
  path: string;
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
  operationId: string;
  summary?: string;
  parameters: Parameter[];
  requestBody?: RequestBody;
  responses: Record<string, Response>;
  security?: SecurityRequirement[];
}

Sources: bin/modules/simplified-openapi.mjs

3. Description Extractor

File: bin/modules/extract-descriptions.mjs

Extracts human-readable descriptions from OpenAPI operations for use in tool documentation and LLM prompts.

Extraction sources (priority order):

  1. operation.description - Primary description
  2. operation.summary - Fallback summary
  3. Parameter descriptions from schema

Generated output:

interface ToolDescription {
  operationId: string;
  description: string;
  parameterDescriptions: Record<string, string>;
  deprecationNotice?: string;
}

Sources: bin/modules/extract-descriptions.mjs

4. MCP Tools Generator

File: bin/modules/generate-mcp-tools.mjs

Generates MCP tool definitions from the processed OpenAPI specification.

Generation process:

graph LR
    A[OpenAPI Operations] --> B[Parse endpoint config]
    B --> C[Generate tool name]
    C --> D[Create Zod schema]
    D --> E[Extract risk level]
    E --> F[Write to endpoints.json]

Tool naming convention:

  • Operation IDs are converted to kebab-case
  • Prefixes are preserved for categorization (e.g., list-, get-, create-, update-, delete-)

Generated metadata per tool:

FieldSourceDescription
toolNameoperationId → kebab-caseUnique tool identifier
pathPatternOpenAPI pathAPI endpoint path
methodHTTP methodGET, POST, PUT, PATCH, DELETE
appPermissionssecuritySchemesRequired Graph API permissions
llmTipdescriptionOptional hint for LLM context
riskLevelManual annotationlow/medium/high/critical

Sources: bin/modules/generate-mcp-tools.mjs, src/endpoints.json

5. Graph Client Generator

File: bin/generate-graph-client.mjs

Orchestrates the entire pipeline and generates TypeScript source files.

Generated artifacts:

FilePurpose
src/generated/endpoint-types.tsTypeScript interfaces for all endpoints
src/generated/schemas.tsZod validation schemas
src/generated/descriptions.tsTool descriptions and documentation

Sources: bin/generate-graph-client.mjs

Generated Output Files

endpoint-types.ts

Auto-generated TypeScript types derived from OpenAPI schemas.

// Auto-generated - DO NOT EDIT
export interface ListUsersResponse {
  '@odata.context'?: string;
  value: User[];
}

Sources: src/generated/endpoint-types.ts

endpoints.json

The source of truth for all tool definitions, serving as the configuration manifest for tool registration.

{
  "toolName": "list-users",
  "pathPattern": "/users",
  "method": "GET",
  "appPermissions": ["User.Read.All"],
  "llmTip": "List all users in the organization",
  "riskLevel": "low"
}

Sources: src/endpoints.json

Tool Registration Flow

After code generation, the pipeline integrates with the MCP server through graph-tools.ts:

graph TD
    A[endpoints.json] --> B[loadEndpoints]
    B --> C[For each endpoint]
    C --> D[Create Zod param schema]
    D --> E[Generate tool description]
    E --> F[Calculate risk level]
    F --> G[server.tool registration]
    G --> H[MCP Server runtime]

Risk level calculation logic:

function effectiveRiskLevel(configuredRiskLevel, method) {
  if (configuredRiskLevel) return configuredRiskLevel;
  return method.toUpperCase() === 'GET' ? 'low' : 'critical';
}

Sources: src/graph-tools.ts, src/risk-level.ts

Execution Workflow

Standard Generation

npm run generate

This command:

  1. Downloads the latest Graph OpenAPI spec
  2. Simplifies and normalizes the spec
  3. Extracts descriptions
  4. Generates MCP tool definitions
  5. Outputs TypeScript types and schemas

Full Build Pipeline

npm run generate    # Download and generate code
npm run build       # Compile TypeScript
npm test            # Run verification tests
npm run verify      # lint + format + test

Sources: CONTRIBUTING.md

Configuration

Risk Level Annotations

Tools requiring special risk classification must be annotated in endpoints.json:

{
  "toolName": "delete-user",
  "riskLevel": "critical"
}

Risk classification rubric:

LevelCriteriaExample Tools
lowRead-only queries, reportslist-users, get-user
mediumReversible single-entity mutationupdate-user, add-group-member
highSignificant impact, credential changesrevoke-user-sessions, update-ca-policy
criticalIrreversible or tenant-widedelete-user, wipe-managed-device

Sources: CONTRIBUTING.md:50-62

Permission Mapping

Application permissions are declared per tool in endpoints.json:

{
  "toolName": "list-sign-ins",
  "appPermissions": ["AuditLog.Read.All"]
}

Sources: agent-skills/ms365-admin-mcp/references/graph-permissions.md

Adding New Tools

Workflow

graph TD
    A[Find Graph API endpoint] --> B[Add to endpoints.json]
    B --> C[Run npm run generate]
    C --> D[Verify tool registration]
    D --> E[Add tests if needed]
    E --> F[Update documentation]

Step 1: Identify the Endpoint

Locate the desired operation in the Microsoft Graph OpenAPI spec.

Step 2: Register in endpoints.json

{
  "toolName": "list-something",
  "pathPattern": "/something",
  "method": "GET",
  "appPermissions": ["Something.Read.All"],
  "llmTip": "Optional hint shown to the LLM",
  "riskLevel": "low"
}

Step 3: Regenerate Code

npm run generate

Step 4: Verify Registration

node dist/index.js --list-tools | grep list-something
node dist/index.js --list-permissions | grep Something

Sources: CONTRIBUTING.md:30-45

Verification and Testing

List Tools

Display all registered tools:

node dist/index.js --list-tools

List Permissions

Display required Graph API permissions:

node dist/index.js --list-permissions

Preset Filtering

List tools by preset category:

node dist/index.js --preset security --list-tools
node dist/index.js --preset identity --list-tools

Available presets: security, audit, health, reports, identity, exchange, intune, governance, compliance, response, ediscovery, cloudpc, callrecords, print, infoprotection, sharepointadmin, retention, teamsadmin, all

Sources: src/tool-categories.ts

Summary

The Code Generation Pipeline is the backbone of the ms-365-admin-mcp-server, enabling:

CapabilityDescription
AutomationEliminates manual TypeScript/Zod schema writing
ConsistencyUniform tool naming and structure
Type SafetyEnd-to-end TypeScript typing from OpenAPI to server
ExtensibilityEasy addition of new Graph API endpoints
DocumentationAuto-generated descriptions and permission lists

By maintaining endpoints.json as the single source of truth and running npm run generate, developers can keep the MCP server synchronized with the evolving Microsoft Graph API surface.

Source: https://github.com/okapi-ca/ms-365-admin-mcp-server / Human Manual

Tool Categories and Presets

Related topics: System Architecture, Security Model and Risk Classification

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Core Components

Continue reading this section for the full explanation and source context.

Section Available Categories

Continue reading this section for the full explanation and source context.

Section Effective Risk Level Resolution

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Security Model and Risk Classification

Tool Categories and Presets

Overview

Tool Categories and Presets provide a logical grouping mechanism for the 515 tools exposed by the ms-365-admin-mcp-server. Categories use regex patterns to match tool names against predefined groups, enabling bulk operations, risk assessment, and organized documentation across different Microsoft 365 admin domains.

The system serves two primary purposes:

  • Organization: Grouping related tools by functional domain (security, identity, compliance, etc.)
  • Risk governance: Applying consistent risk levels and access controls across tool groupings

Sources: src/tool-categories.ts:1-1

Architecture

graph TD
    A[endpoints.json] --> B[Tool Definitions]
    B --> C{regex pattern matching}
    D[tool-categories.ts] --> C
    C --> E[ToolCategory Assignment]
    E --> F[Risk Level Resolution]
    G[risk-level.ts] --> F
    F --> H[MCP Server Response]
    
    I[riskLevel from config] --> F
    J[HTTP Method GET/POST/PUT/DELETE] --> G

Core Components

ComponentFileResponsibility
ToolCategory interfacesrc/tool-categories.tsDefines the category schema
TOOL_CATEGORIES registrysrc/tool-categories.tsMaps category names to regex patterns
effectiveRiskLevel()src/risk-level.tsResolves risk level per tool
isToolAllowed()src/risk-level.tsChecks if tool passes max risk threshold

Sources: src/tool-categories.ts:1-15

ToolCategory Interface

export interface ToolCategory {
  name: string;
  pattern: RegExp;
  description: string;
}
FieldTypePurpose
namestringUnique identifier for the category
patternRegExpRegex pattern tested against tool names
descriptionstringHuman-readable description for documentation

Sources: src/tool-categories.ts:1-5

Category Registry

The TOOL_CATEGORIES record contains all predefined categories. Each category uses a case-insensitive regex pattern to match tool names defined in endpoints.json.

Sources: src/tool-categories.ts:7-40

Available Categories

PresetPattern ScopeDescription
security`security\alert\incident\attack-simulation\threat-intel`Security alerts, incidents, attack simulations, and threat intelligence (Microsoft 365 Defender)
audit`audit\sign-in\provisioning\directory\deleted-user\deleted-group`Audit logs, deleted items (directory audits, sign-ins, provisioning)
health`service\health\issue\message`Service health and Message Center announcements
reports`report\activity\usage`Usage reports (Teams, Email, Active Users, SharePoint, OneDrive, Mailbox, M365 Apps)
identityComplex pattern (users, groups, roles, conditional access, PIM, devices, etc.)Identity and access management (Entra ID users, groups, roles, devices, PIM, guest users, external identities)

Sources: src/tool-categories.ts:7-40

Risk Level System

Effective Risk Level Resolution

The effectiveRiskLevel() function determines the actual risk level for any tool:

export function effectiveRiskLevel(
  configuredRiskLevel: RiskLevel | undefined,
  method: string
): RiskLevel {
  if (configuredRiskLevel) return configuredRiskLevel;
  return method.toUpperCase() === 'GET' ? 'low' : 'critical';
}
ScenarioResult
configuredRiskLevel is setReturns configured value
Method is GET (case-insensitive)Returns low
Method is POST/PUT/DELETE, no configReturns critical (fail-safe default)

Sources: src/risk-level.ts:10-18

Risk Level Hierarchy

LevelCriteriaExample Tools
lowRead-only operationslist-users, get-security-alert
mediumReversible mutations on single entitiesupdate-user, add-group-member
highSignificant impact, credential changes, or destructive operationsrevoke-user-sessions, update-conditional-access-policy
criticalIrreversible or tenant-wide impactdelete-user, wipe-managed-device, delete-conditional-access-policy

Sources: CONTRIBUTING.md:1-20

Tool Permission Check

The isToolAllowed() function compares the tool's effective risk against the server's configured maximum:

export function isToolAllowed(
  configuredRiskLevel: RiskLevel | undefined,
  method: string,
  maxRiskLevel: RiskLevel
): boolean {
  return rank(effectiveRiskLevel(configuredRiskLevel, method)) <= rank(maxRiskLevel);
}

The rank() function (implied internal) orders risk levels: low < medium < high < critical.

Sources: src/risk-level.ts:20-25

Category Matching Flow

graph LR
    A[Tool Name] --> B{Iterate TOOL_CATEGORIES}
    B -->|match found| C[Assign Category]
    B -->|no match| D[Uncategorized]
    
    E[Tool Method] --> F[effectiveRiskLevel]
    F --> G{Method == GET?}
    G -->|Yes| H[risk = low]
    G -->|No| I{configuredRiskLevel?}
    I -->|Yes| J[risk = configured]
    I -->|No| K[risk = critical]

Adding a New Preset

Step 1: Edit tool-categories.ts

Add a new entry to the TOOL_CATEGORIES object:

export const TOOL_CATEGORIES: Record<string, ToolCategory> = {
  mypreset: {
    name: 'mypreset',
    pattern: /pattern-matching-tool-names/i,
    description: 'Short human-readable description',
  },
  // ...existing categories
};

Sources: CONTRIBUTING.md:25-35

Step 2: Validate the Pattern

node dist/index.js --preset mypreset --list-tools

This command tests the regex against all tools in endpoints.json and lists matches.

Sources: CONTRIBUTING.md:37-38

Tool Definition Schema

Tools are defined in endpoints.json with the following structure:

{
  "toolName": {
    "method": "GET|POST|PUT|DELETE",
    "appPermissions": ["Permission.Read.All"],
    "llmTip": "Optional hint for LLM",
    "riskLevel": "low|medium|high|critical"  // only for non-GET
  }
}
FieldRequiredDescription
methodYesHTTP method for the Graph API call
appPermissionsYesMinimum Graph API permissions
llmTipNoHint displayed to LLM in tool description
riskLevelFor non-GETRisk classification per the rubric

Sources: CONTRIBUTING.md:55-65

Preset Index

PresetUse Case FilePrimary Tools
securityusecase-security.mdAlerts, incidents, attack simulations, threat intel
auditusecase-audit.mdDirectory audits, sign-ins, provisioning logs
healthusecase-health.mdService health, Message Center
reportsusecase-reports.mdTeams, Email, SharePoint, OneDrive usage
identityusecase-identity.mdUsers, groups, roles, devices, PIM
exchangeusecase-exchange.mdMessage traces, mailboxes
intuneusecase-intune.mdDevice management, compliance, configurations
governanceusecase-governance.mdAccess reviews, entitlement, lifecycle
complianceusecase-compliance.mdLicenses, Secure Score, Identity Protection
responseusecase-response.mdIncident response operations
ediscoveryusecase-ediscovery.mdeDiscovery cases (Purview)
cloudpcusecase-cloudpc.mdCloud PC / Windows 365
callrecordsusecase-callrecords.mdTeams call records
printusecase-print.mdUniversal Print
infoprotectionusecase-infoprotection.mdBitLocker, sensitivity labels
sharepointadminusecase-sharepointadmin.mdSharePoint tenant administration
retentionusecase-retention.mdRecords management

Sources: agent-skills/ms365-admin-mcp/references/tools-catalog.md:1-50

Verification Commands

After adding a new preset, verify registration:

# List tools matching the preset
node dist/index.js --list-tools | grep <pattern>

# Check required permissions
node dist/index.js --list-permissions | grep <Permission>

Sources: CONTRIBUTING.md:66-72

Integration with MCP Server

The tool categories system integrates with the MCP server's execution pipeline:

sequenceDiagram
    participant Client
    participant MCPServer
    participant RiskChecker
    participant GraphAPI
    
    Client->>MCPServer: call_tool(toolName, params)
    MCPServer->>MCPServer: Match toolName against TOOL_CATEGORIES
    MCPServer->>RiskChecker: effectiveRiskLevel(configured, method)
    RiskChecker-->>MCPServer: resolvedRiskLevel
    MCPServer->>RiskChecker: isToolAllowed(resolvedRiskLevel, maxRiskLevel)
    RiskChecker-->>MCPServer: allowed: boolean
    
    alt allowed == false
        MCPServer-->>Client: Error: Tool exceeds max risk level
    else allowed == true
        MCPServer->>GraphAPI: Execute request
        GraphAPI-->>MCPServer: Response
        MCPServer-->>Client: Tool result
    end

Sources: src/tool-categories.ts:1-1

Security Model and Risk Classification

Related topics: Tool Categories and Presets, Azure Deployment Security

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Risk Level Rank

Continue reading this section for the full explanation and source context.

Section --allow-writes

Continue reading this section for the full explanation and source context.

Section --max-risk-level <level

Continue reading this section for the full explanation and source context.

Related topics: Tool Categories and Presets, Azure Deployment Security

Security Model and Risk Classification

Overview

The ms-365-admin-mcp-server implements a defense-in-depth security model centered on risk classification for all Graph API operations. Every tool exposed by the server is classified according to its potential impact, and the server enforces configurable risk caps to prevent accidental execution of destructive or high-impact operations.

The security model serves two primary purposes:

  1. Operational Safety — Prevent unintended destructive operations (deletes, wipes, credential changes) from executing without explicit confirmation
  2. Prompt Injection Defense — Protect against malicious data injected through Microsoft Graph responses into the LLM context window

Sources: docs/RISK_MODEL.md

Risk Level Taxonomy

The server defines four risk levels in ascending order of severity. Each level corresponds to a specific operational threshold and requires explicit user action to execute.

LevelCriteriaExample Operations
lowRead-only operations, reports, POST-only queries, or trivial annotationsrun-hunting-query, add-security-alert-comment, listing operations
mediumReversible mutations affecting a single entityupdate-user, add-group-member, create-invitation
highSignificant impact: broad scope, credential change, or destructiverevoke-user-sessions, update-conditional-access-policy, confirm-compromised-users
criticalIrreversible or tenant-wide impactdelete-user, wipe-managed-device, delete-conditional-access-policy

Sources: CONTRIBUTING.md

Risk Level Rank

Risk levels are ranked numerically for comparison purposes. Higher numbers indicate greater severity.

const RISK_RANK: Record<RiskLevel, number> = {
  low: 0,
  medium: 1,
  high: 2,
  critical: 3,
};

Sources: src/risk-level.ts:1-5

Risk Classification Algorithm

The effective risk level for any tool is determined by a deterministic algorithm that combines explicit configuration with method-based defaults.

export function effectiveRiskLevel(
  configuredRiskLevel: RiskLevel | undefined,
  method: string
): RiskLevel {
  if (configuredRiskLevel) return configuredRiskLevel;
  return method.toUpperCase() === 'GET' ? 'low' : 'critical';
}

Decision Logic:

  1. If configuredRiskLevel is explicitly set in endpoints.json, use it
  2. For GET requests without explicit configuration, default to low (safe reads)
  3. For non-GET requests (write operations) without explicit configuration, default to critical — this is a fail-safe design that prevents silently exposing unannotated write endpoints

Sources: src/risk-level.ts:17-25

Access Control Function

The isToolAllowed function determines whether a tool at a given risk level is permitted given a maximum risk cap.

export function isToolAllowed(
  configuredRiskLevel: RiskLevel | undefined,
  method: string,
  maxRiskLevel: RiskLevel
): boolean {
  return rank(effectiveRiskLevel(configuredRiskLevel, method)) <= rank(maxRiskLevel);
}

A tool is allowed when its effective risk level rank is less than or equal to the configured maximum risk level.

Sources: src/risk-level.ts:27-32

Server Configuration Flags

`--allow-writes`

By default, the server operates in read-only mode. The --allow-writes flag must be explicitly passed to enable any write operations, regardless of their risk level.

This flag is a prerequisite for risk-based filtering — even if --max-risk-level medium is set, no writes execute without --allow-writes.

Sources: docs/RISK_MODEL.md

`--max-risk-level <level>`

Caps the maximum risk level of tools registered at startup. Implies --allow-writes.

Cap ValueEffect
--max-risk-level lowOnly read operations (low) are exposed
--max-risk-level mediumAdds medium-risk mutations; hides high/critical tools
--max-risk-level highAdds high-risk operations; critical tools hidden
--max-risk-level criticalAll tools exposed (default with --allow-writes)

When --max-risk-level medium is used:

  • BitLocker recovery keys (high read) are hidden
  • LAPS passwords (high read) are hidden
  • 15 additional medium-risk reads are filtered

Sources: docs/SECURITY_REVIEW_2026-04-20.md

Security Controls (SEC-G Series)

SEC-G01 — Risk Level Cap

The --max-risk-level CLI flag caps the risk level of registered tools. Implies --allow-writes. Unannotated writes default to critical (fail-safe).

This control ensures that sensitive endpoints cannot be invoked even if an attacker somehow manipulates the tool invocation, because the server never registers them.

Sources: docs/SECURITY_REVIEW_2026-04-20.md

SEC-G02 — Nonce-Enveloped Responses

Every successful Microsoft Graph tool response is wrapped in a nonce-delimited envelope with an untrusted-data preamble before reaching the LLM:

<graph_response_NN>
[UNTRUSTED DATA - VERIFY BEFORE USE]
<nonce>base64_encoded_random_bytes</nonce>
<content>actual_response</content>
</graph_response_NN>
  • Per-call crypto.randomBytes(8) nonce prevents envelope escape
  • Defends against prompt injection through user-controlled Graph fields:
  • displayName
  • mail subject
  • Chat body
  • Site title
  • OAuth app name
  • Any other user-facing field

Sources: docs/SECURITY_REVIEW_2026-04-20.md

SEC-G03 — Sensitive Read Annotations

22 sensitive-read GET operations are annotated with explicit risk levels:

CategoryCountRisk Levels
BitLocker recovery keys1high
LAPS passwords1high
eDiscovery cases/custodians/searches4high
Subject rights requests1high
Auth methods3medium
Sign-ins2medium
Risk detections2medium
Message traces2medium
Federated credentials2medium

These annotations feed SEC-G01: --max-risk-level medium automatically hides the high-level sensitive reads.

Sources: docs/SECURITY_REVIEW_2026-04-20.md

Critical Operations by Category

Critical-level operations require out-of-band sign-off and should never be executed based solely on chat confirmation.

Identity

ToolImpact
delete-userPermanently removes user from tenant
delete-groupRemoves group and all memberships
add-directory-role-memberGrants permanent privileged role
disable-user-accountOn privileged/break-glass accounts

Compliance & Security

ToolImpact
delete-conditional-access-policyRemoves tenant-wide access controls
delete-ediscovery-casePermanently removes legal hold case
wipe-managed-deviceRemote wipe of enrolled device
clean-windows-deviceRemoves device from Intune

Sources: agent-skills/ms365-admin-mcp/references/tools-catalog.md

High-Risk Operations

High-risk operations require explicit confirmation and dry-run before execution.

Confirmation Required

ToolRiskRequirement
revoke-user-sessionshighConfirm before executing
confirm-compromised-usershighConfirm per case
confirm-safe-usershighConfirm per case
dismiss-risky-usershighConfirm per case
change-user-passwordhighConfirm with operator
update-devicehighConfirm with operator

Sources: agent-skills/ms365-admin-mcp/references/usecase-compliance.md

Security Architecture Flow

graph TD
    A[Tool Invocation Request] --> B{--allow-writes enabled?}
    B -->|No| C[Reject All Writes]
    B -->|Yes| D[Check effectiveRiskLevel]
    D --> E{Lookup configuredRiskLevel<br/>in endpoints.json}
    E -->|Found| F[Use Configured Level]
    E -->|Not Found| G{Method = GET?}
    G -->|Yes| H[Default: low]
    G -->|No| I[Default: critical<br/>FAIL-SAFE]
    F --> J[Calculate rank<br/>effectiveRiskLevel]
    H --> J
    I --> J
    J --> K{rank ≤ maxRiskLevel?}
    K -->|Yes| L[Execute Tool]
    K -->|No| M[Block Tool<br/>Not Registered]
    L --> N[Graph API Call]
    N --> O[Wrap in Nonce Envelope<br/>SEC-G02]
    O --> P[Return to LLM]

Risk Level Inheritance

The risk classification follows a hierarchical inheritance model:

graph LR
    A[endpoints.json] --> B[Tool Registration]
    B --> C{--max-risk-level}
    C --> D[Tool Availability]
    
    E[GET Methods] --> F[Default: low<br/>unless overridden]
    G[Write Methods] --> H[Default: critical<br/>fail-safe]

Tool Categories and Risk Patterns

The server organizes tools into presets based on name patterns, each with distinct risk profiles.

// From src/tool-categories.ts
const PATTERNS = {
  security: /alert|incident|attack/i,
  audit: /audit|sign-in|provisioning|deleted/i,
  health: /serviceHealth|messageCenter/i,
  response: /disable-user|revoke|block|reset|confirm|dismiss/i,
  // ... more categories
};

Sources: src/tool-categories.ts

Verification Commands

Verify tool registration and permissions:

# List all registered tools
node dist/index.js --list-tools

# List required Graph permissions
node dist/index.js --list-permissions

# Verify a specific preset
node dist/index.js --preset security --list-tools

# Verify specific risk level tools
node dist/index.js --max-risk-level medium --list-tools

Sources: docs/RISK_MODEL.md

Security Review Process

All security-relevant changes undergo review per documented processes:

Review DateScope
2026-04-20Initial security review — SEC-G01, SEC-G02, SEC-G03 implementation
2026-04-25Follow-up review — permission scope reductions, dismiss-risky-users elevation

The review identified and addressed:

  • Over-privileged permission scopes reduced to least-privilege
  • dismiss-risky-users elevated from medium to high
  • Query string sanitization to prevent secret leakage
  • Dead dependency removal

Sources: docs/SECURITY_REVIEW_2026-04-20.md Sources: docs/SECURITY_REVIEW_2026-04-25.md

Best Practices for Operators

  1. Start with --max-risk-level medium — Only escalate when high-risk tools are required
  2. Dry-run before high/critical operations — Always read the target object first
  3. Out-of-band confirmation for critical — Use ticketing systems for delete/wipe operations
  4. Review permissions quarterly — Run --list-permissions to audit required scopes
  5. Never run without understanding — Each references/usecase-*.md file documents tool risk levels before use

Module Dependencies

The security model is implemented in pure, testable modules:

ModulePurpose
src/risk-level.tsRisk level computation and comparison
src/user-token-authorization.tsUser token validation
src/jwks-stale-cache.tsJWKS caching for token validation
src/upstream-error.tsGraph API error handling
src/untrusted-envelope.tsNonce envelope wrapping

All modules have unit test coverage (51 tests covering all security-critical paths).

Sources: SECURITY.md

Sources: docs/RISK_MODEL.md

Azure Deployment Security

Related topics: Security Model and Risk Classification, HTTP Transport and Deployment, Docker and Container Deployment

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Defense in Depth

Continue reading this section for the full explanation and source context.

Section Private Endpoint Configuration

Continue reading this section for the full explanation and source context.

Section Required Egress Endpoints

Continue reading this section for the full explanation and source context.

Related topics: Security Model and Risk Classification, HTTP Transport and Deployment, Docker and Container Deployment

Azure Deployment Security

Overview

The ms-365-admin-mcp-server provides a comprehensive Azure deployment security model designed to protect Microsoft 365 administrative operations. This documentation covers the security controls, network architecture, secret management, and compliance considerations for deploying the server in Azure Container Apps.

Core Security Principles

Defense in Depth

The security architecture implements multiple layers of protection:

  1. Network Isolation — Private networking with VNet integration and egress restrictions
  2. Secret Management — Azure Key Vault for all sensitive credentials
  3. Authentication — Microsoft Identity (MSAL) with client credentials flow
  4. Authorization — Role-based access with MCP permission scopes
  5. Audit — Comprehensive logging with PII redaction capabilities
  6. Certificate Authentication — Preference for certificates over client secrets

Sources: SECURITY.md

Network Architecture

Private Endpoint Configuration

The deployment uses private networking to restrict communication paths. All egress traffic is routed through Azure Firewall or Network Security Groups (NSGs) to enforce granular control.

graph TD
    subgraph "Azure Cloud"
        subgraph "Virtual Network"
            CA["Container Apps<br/>Environment"]
            VNET["VNet Integration"]
        end
        subgraph " egress"
            FW["Azure Firewall"]
            PE["Private Endpoint<br/>Key Vault"]
        end
    end
    
    subgraph "Microsoft Services"
        AAD["Microsoft Identity<br/>login.microsoftonline.com"]
        GRAPH["Microsoft Graph<br/>graph.microsoft.com"]
    end
    
    CA --> VNET
    VNET --> FW
    FW --> AAD
    FW --> GRAPH
    CA --> PE
    PE --> KV["Key Vault"]
    
    style CA fill:#e1eff6
    style FW fill:#fff3cd
    style KV fill:#d4edda

Required Egress Endpoints

The server requires outbound access to the following Microsoft endpoints:

EndpointPurposeSovereign Equivalent
login.microsoftonline.comMicrosoft Entra authenticationlogin.partner.microsoftonline.cn
graph.microsoft.comMicrosoft Graph APImicrosoftgraph.chinacloudapi.cn

Sources: SECURITY.md | docs/CYSEC-1420/network-design-gate.md

HTTP Mode Security

When exposing the server via HTTP transport, strict controls apply:

  • Never expose on 0.0.0.0 without a reverse proxy enforcing TLS
  • Always pass --allowed-clients with the minimum set of Entra app IDs
  • Use --allow-any-tenant-user only when explicitly intended (defaults to deny)
# Example secure HTTP startup
node dist/index.js \
  --transport streamable-http \
  --allowed-clients "app-id-1,app-id-2" \
  --public-url https://mcp.example.com \
  --log-redact-upn

Sources: SECURITY.md

Secret Management

Azure Key Vault Integration

All sensitive credentials must be stored in Azure Key Vault rather than environment files or source control.

Secret NameDescriptionRequired
MS365_ADMIN_MCP_CLIENT_IDEntra application client IDYes
MS365_ADMIN_MCP_CLIENT_SECRETClient secret (if not using cert)Conditional
MS365_ADMIN_MCP_KEYVAULT_URLKey Vault base URLYes
AZURE_STORAGE_ACCOUNT_NAMETable storage for OAuth stateOAuth mode only
AZURE_STORAGE_TABLE_NAMETable name for PKCE stateOAuth mode only

Sources: SECURITY.md

Certificate Authentication

The deployment prefers certificate-based authentication over client secrets:

graph LR
    A["Key Vault<br/>Certificate"] --> B["Managed Identity"]
    B --> C["Container Apps<br/>Environment"]
    C --> D["Microsoft Graph<br/>API"]

Benefits of certificate authentication:

  • No secret rotation required (certificate validity managed separately)
  • Federated credentials eliminate client secret storage entirely
  • Workload identity federation supported for GitHub Actions deployments

Sources: SECURITY.md

Secret Rotation Policy

Credential TypeRotation Interval
Client Secrets90 days
CertificatesPer certificate validity period
Federated CredentialsNo rotation required

Identity and Access Management

Authentication Modes

The server supports two authentication modes:

  1. Application Credentials (Default) — Client ID + Secret/Certificate
  2. OAuth Mode — Full OAuth 2.0 authorization code flow with PKCE
graph TD
    subgraph "OAuth Mode Flow"
        U["User/Browser"] --> |"1. GET /authorize"| MCP["MCP Server"]
        MCP --> |"2. Redirect to Entra"| AAD["Microsoft Entra"]
        U --> |"3. User Authentication"| AAD
        AAD --> |"4. Auth Code + PKCE"| MCP
        MCP --> |"5. Token Request"| AAD
        AAD --> |"6. Access Token"| MCP
    end

Sources: CHANGELOG.md

OAuth Storage

OAuth mode requires Azure Table Storage for PKCE state management:

ComponentConfiguration
Storage AccountStandard_LRS, TLS 1.2, OAuth-only authentication
Table Nameoauthstate (configurable)
AccessManaged Identity with Storage Table Data Contributor role
PKCE Lifetime10 minutes

Sources: CHANGELOG.md

Graph API Permissions

Least Privilege Model

The deployment follows a least-privilege approach with application permissions scoped to required operations only.

Sources: docs/CYSEC-1420/graph-permissions-baseline.md

Application Permission Categories

CategoryPermission TypeExample Operations
DirectoryRead.Alllist-users, list-groups
Device ManagementReadWrite.Allupdate-device, wipe-managed
PolicyReadWrite.Allcreate-conditional-access-policy
SecurityRead.All / ReadWrite.Alllist-risky-users, confirm-compromised

Required Read Permissions (Default)

Directory.Read.All
Group.Read.All
User.Read.All
Device.Read.All
DeviceManagementRBAC.Read.All
Policy.Read.All
AuditLog.Read.All

Sources: agent-skills/ms365-admin-mcp/references/graph-permissions.md

Logging and Monitoring

PII-Aware Logging

The server provides built-in PII redaction for logs forwarded to SIEM systems:

node dist/index.js --log-redact-upn

This flag replaces UPN values in log lines with deterministic SHA-256 prefixes:

Original: "Authenticated user [email protected]"
Redacted: "Authenticated user sha256:1a2b3c4d5e6f..."

Sources: SECURITY.md

Audit Trail

Enable verbose logging for complete audit trails:

node dist/index.js -v  # Enable verbose logging

The following audit operations are available via the MCP tools:

ToolPurpose
list-directory-auditsDirectory sign-in and activity logs
list-intune-audit-eventsIntune device management events
list-sign-insConditional Access and sign-in logs

Log Storage Configuration

The Winston logger uses a configurable log directory:

export MS365_ADMIN_MCP_LOG_DIR=/var/log/ms365-admin-mcp

Sources: CHANGELOG.md

Bicep Infrastructure Deployment

Deployment Architecture

graph TD
    subgraph "Resource Group"
        subgraph "Networking"
            VNET["Virtual Network"]
            SUBNET["Subnet"]
            FW["Azure Firewall"]
        end
        subgraph "Compute"
            ACA["Container Apps<br/>Environment"]
            APP["MCP Server<br/>Container"]
        end
        subgraph "Data"
            KV["Key Vault"]
            SA["Storage Account"]
            TBL["Table Storage"]
        end
        subgraph "Identity"
            UAMI["User-Assigned<br/>Managed Identity"]
        end
    end
    
    APP --> SUBNET
    APP --> KV
    APP --> SA
    APP --> UAMI
    UAMI --> KV
    UAMI --> SA
    FW --> VNET
    
    style APP fill:#e1eff6
    style KV fill:#d4edda
    style FW fill:#fff3cd

Required Bicep Parameters

ParameterTypeRequiredDescription
allowedClientsarrayYesList of Entra app IDs permitted to connect
tagsobjectYesTags propagated to all resources
acrLoginServerstringYesAzure Container Registry login server
locationstringYesAzure region
environmentNamestringYesDeployment environment
maxReplicasintNoMaximum container replicas (default: 1)

Sources: CHANGELOG.md

Storage Account Configuration

The Bicep template provisions a secure storage account for OAuth PKCE state:

{
  "sku": {
    "name": "Standard_LRS"
  },
  "properties": {
    "minimumTlsVersion": "TLS1_2",
    "allowSharedKeyAccess": false,
    "defaultToOAuthAuthentication": true
  }
}

Sources: CHANGELOG.md

Private Container Registry

The deployment supports pulling images from private Azure Container Registry:

registries: {
  loginServer: acrLoginServer
  identity: uamiResourceId
  passwordSecretRef: ''
}

Sources: CHANGELOG.md

Deployment Checklist

Pre-Deployment Security Review

  • [ ] Store all secrets in Azure Key Vault
  • [ ] Configure allowed clients (minimum Entra app IDs)
  • [ ] Enable PII redaction for log forwarding
  • [ ] Configure network segmentation with allowed egress endpoints
  • [ ] Apply Conditional Access to service principal (geofencing, sign-in risk)
  • [ ] Review and minimize Graph API permissions

Deployment Validation

  • [ ] Verify HTTP mode not exposed on 0.0.0.0
  • [ ] Confirm managed identity access to Key Vault
  • [ ] Test OAuth PKCE flow with Table Storage
  • [ ] Validate verbose logging output
  • [ ] Verify allowed clients can connect

Post-Deployment Monitoring

  • [ ] Monitor list-sign-ins for anomalies on service principal
  • [ ] Enable directory audit log forwarding to SIEM
  • [ ] Set up alerts for critical tool invocations
  • [ ] Review access reviews for application owners

Migration Guide

From Version 0.1.0 to 0.2.x

  1. Required: Add --allowed-clients parameter (HTTP mode refuses startup without it)
  2. Required for OAuth mode: Add --public-url if behind reverse proxy
  3. Review: Check --allow-any-tenant-user if relying on implicit behavior
  4. Optional: Update Bicep to add Storage Account for OAuth PKCE bridge

Sources: CHANGELOG.md

Scaling Considerations

  • Single replica is the default
  • For multi-replica deployments, externalize PKCE storage first
  • Run az deployment group create with updated Bicep for Storage Account provisioning

Sources: SECURITY.md

HTTP Transport and Deployment

Related topics: Docker and Container Deployment, Azure Deployment Security, Configuration Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Transport Modes

Continue reading this section for the full explanation and source context.

Section Core Components

Continue reading this section for the full explanation and source context.

Section Request Flow

Continue reading this section for the full explanation and source context.

Related topics: Docker and Container Deployment, Azure Deployment Security, Configuration Reference

HTTP Transport and Deployment

The ms-365-admin-mcp-server supports multiple transport mechanisms for exposing Microsoft 365 administration capabilities to MCP clients. The HTTP transport layer forms the foundation for remote deployments, OAuth-based authentication flows, and secure communication between clients and the server.

Overview

The server implements a flexible HTTP transport architecture that supports both local stdio connections and remote HTTP-based deployments. This dual-mode design enables the server to operate as a local desktop companion (via Claude Desktop) or as a scalable cloud-hosted service accessible to multiple users simultaneously.

Transport Modes

Transport ModeUse CaseAuthentication
stdioLocal Claude Desktop integrationDirect client credentials
StreamableHTTPClaude.ai Web, Claude Desktop remoteOAuth 2.0 + PKCE proxy
Remote HTTPContainerized deployments (Azure Container Apps)Device code bootstrap

Sources: CHANGELOG.md

HTTP Server Architecture

Core Components

The HTTP transport is implemented across several interconnected modules:

ModuleResponsibility
http-server.tsMain HTTP server, routing, middleware, security headers
oauth-proxy.tsOAuth 2.0 discovery, PKCE proxy, Entra ID integration
token-validator.tsJWT validation, tenant verification, scope enforcement
auth-bootstrap.tsRFC 8628 device_code flow for remote authentication

Sources: CONTRIBUTING.md

Request Flow

graph TD
    A[MCP Client] --> B[HTTP Server<br/>src/http-server.ts]
    B --> C{Auth Mode}
    C -->|OAuth| D[OAuth Proxy<br/>src/oauth-proxy.ts]
    C -->|Device Code| E[Auth Bootstrap<br/>src/auth-bootstrap.ts]
    C -->|Client Creds| F[Direct Auth]
    D --> G[Token Validator<br/>src/token-validator.ts]
    E --> G
    F --> G
    G --> H{Valid Token?}
    H -->|Yes| I[Tool Executor]
    H -->|No| J[401/403 Response]
    I --> K[Microsoft Graph API]

OAuth 2.0 Proxy Mode

The --oauth-mode flag enables Entra-backed OAuth 2.0 + PKCE proxy endpoints, allowing Claude Desktop, Claude Code, and Claude.ai Web to authenticate users through Microsoft Entra ID without client-side configuration beyond the server URL.

Discovery Endpoints

EndpointPurpose
GET /.well-known/oauth-authorization-serverOAuth 2.0 authorization server metadata
GET /.well-known/oauth-protected-resourceProtected resource metadata for client discovery
GET /.well-known/microsoft-hosted-userpolicyMicrosoft-hosted user policy information

Sources: CHANGELOG.md:73-75

Authentication Headers

The server implements proper WWW-Authenticate header responses:

ScenarioHeader Response
Missing tokenWWW-Authenticate: Bearer resource_metadata="..."
Invalid tokenWWW-Authenticate: Bearer resource_metadata="...", error="invalid_token"

Without these headers, Claude clients could not discover the protected-resource metadata and would surface Authorization with the MCP server failed before ever reaching /authorize.

Sources: CHANGELOG.md:81-85

Required Configuration

When running in OAuth mode, deployments must specify:

--oauth-mode
--public-url https://<fqdn>  # Required when behind a reverse proxy
--required-user-scopes <scopes>  # If callers request a specific scope

Deployments relying on the implicit "any authenticated user" behavior must add --allow-any-tenant-user to their startup command.

Sources: CHANGELOG.md:34-37

Remote HTTP Server with Device Code Authentication

The ms-365-admin-mcp-auth bootstrap tool implements RFC 8628 device_code flow to pre-seed the mcp-remote token cache, allowing Claude Desktop/Code to skip the browser flow for remote MCP servers.

Authentication Flow

sequenceDiagram
    participant Client as Claude Desktop/Code
    participant Auth as ms-365-admin-mcp-auth
    participant Server as MCP Server (Remote)
    participant Entra as Microsoft Entra ID

    Client->>Auth: ms-365-admin-mcp-auth --server <url>
    Auth->>Entra: POST /devicecode
    Entra-->>Auth: device_code, verification_uri
    Auth->>Client: Display verification URL
    loop Poll until authenticated
        Auth->>Entra: POST /token (device_code)
        Entra-->>Auth: pending | success
    end
    Auth->>Server: Cached tokens stored locally
    Client->>Server: MCP requests (uses cached tokens)

Command Line Interface

ms-365-admin-mcp-auth [options]

Required Options:
  -s, --server <url>    MCP server URL (with or without /mcp suffix)

Options:
  --scope <scope>       Override OAuth scope (defaults to server metadata)
  --cache-dir <path>    Override cache directory
  --timeout <minutes>   Authentication timeout (default: 8 minutes)

Sources: src/auth-bootstrap.ts

Token Cache Location

Tokens are cached at:

~/.mcp-auth/mcp-remote-<version>/
├── <hash>_client_info.json
└── <hash>_tokens.json

The cache key is computed as md5(serverUrl), matching mcp-remote's getServerUrlHash function exactly. File permissions are set to mode 0600 for security.

Sources: CHANGELOG.md:56-58

Exit Codes

CodeMeaning
0Success
1Usage error
2Network failure
3Access denied
4Timeout

These exit codes facilitate Docker and CI wrapper scripting.

Sources: CHANGELOG.md:63-65

Security Configuration

Security Headers

All HTTP responses include the following security headers:

HeaderValuePurpose
X-Content-Type-OptionsnosniffPrevent MIME type sniffing
X-Frame-OptionsDENYPrevent clickjacking
Cache-Controlno-storePrevent sensitive data caching
Content-Security-Policydefault-src 'none'Restrict resource loading

Rate Limiting

The Express server is configured with trust proxy set to 1 to properly handle X-Forwarded-For headers from Azure Container Apps or reverse proxies. This prevents the express-rate-limit validator from incorrectly blocking requests due to unexpected forwarded headers.

Sources: CHANGELOG.md:88-91

Request Validation

Validation TypeImplementation
Body size limit100 KB maximum
Path traversalParameters checked for ../, /, \, ?, #, &
ReDoS protection--enabled-tools regex capped at 500 characters

Sources: SECURITY.md

Token Validation

The token validator enforces:

  1. Tenant isolation: Tenant common is rejected; single-tenant mode required for client credentials
  2. Scope verification: Tokens must include required user scopes
  3. Audience validation: Token audience must match server configuration
  4. Error logging: Failed validations log aud, tid, and upn for debugging

Risk Classification for Write Operations

The HTTP transport integrates with the risk-level system to enforce write operation restrictions:

Risk LevelDescriptionEnforcement
lowRead-only operations, reportsAllowed by default
mediumReversible mutations, single entityRequires --allow-writes
highSignificant impact, credential changesRequires explicit cap
criticalIrreversible or tenant-wideRequires --allow-critical

Sources: src/risk-level.ts

Deployment Patterns

Local Deployment (Stdio)

For local use with Claude Desktop, the server operates in stdio mode:

{
  "mcpServers": {
    "ms-365-admin": {
      "command": "npx",
      "args": ["-y", "@okapi-ca/ms-365-admin-mcp-server"]
    }
  }
}

Remote HTTP Deployment (Container Apps)

docker run -d \
  --name mcp-server \
  -e MS365_ADMIN_MCP_CLIENT_ID=<client-id> \
  -e MS365_ADMIN_MCP_CLIENT_SECRET=<secret> \
  -e MS365_ADMIN_MCP_TENANT_ID=<tenant-id> \
  -p 3000:3000 \
  ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest

OAuth-Enabled Deployment

npm start -- \
  --oauth-mode \
  --public-url https://mcp.contoso.com/mcp \
  --allow-any-tenant-user \
  --max-risk-level medium

Command Line Options

Transport Options

OptionDescriptionDefault
--oauth-modeEnable OAuth 2.0 proxyDisabled
--public-urlPublic URL for OAuth callbacksRequired in OAuth mode
--required-user-scopesScopes required in user tokensEmpty (any scope)
--allow-any-tenant-userAllow users from any tenantDisabled
--cache-dirOverride token cache directory~/.mcp-auth/mcp-remote-<ver>

Security Options

OptionDescriptionDefault
--allow-writesAllow write operations up to medium riskDisabled
--allow-criticalAllow critical write operationsDisabled
--max-risk-levelMaximum allowed risk levelmedium

Other Options

OptionDescriptionDefault
--enabled-toolsRegex pattern to limit available toolsAll tools
--presetEnable a tool category presetNone
--list-toolsList available tools and exit-
--list-permissionsList required permissions and exit-

Troubleshooting

Common Issues

SymptomCauseSolution
Server disconnectedNetwork connectivity or proxy issueCheck docs/TROUBLESHOOTING.md
Platform SSO errorsConditional Access policy blockingReview device_code flow documentation
ERR_ERL_UNEXPECTED_X_FORWARDED_FORRate limiter not trusting proxyEnsure --public-url is set behind reverse proxy

Debugging Steps

  1. Verify --public-url is set correctly when behind a reverse proxy
  2. Check that Entra app registration exposes the access_as_user scope
  3. Confirm --required-user-scopes matches the scopes your callers request
  4. Review logs for token validation failures (includes aud, tid, upn)

See Also

Sources: CHANGELOG.md

Docker and Container Deployment

Related topics: HTTP Transport and Deployment, Azure Deployment Security, Installation Guide

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Deployment Modes

Continue reading this section for the full explanation and source context.

Section Base Image and Runtime

Continue reading this section for the full explanation and source context.

Section Security Configuration

Continue reading this section for the full explanation and source context.

Related topics: HTTP Transport and Deployment, Azure Deployment Security, Installation Guide

Docker and Container Deployment

This page documents the Docker and container deployment architecture for the Microsoft 365 Admin MCP Server. The server is published to both npm as @okapi-ca/ms-365-admin-mcp-server and to GitHub Container Registry (GHCR) as ghcr.io/okapi-ca/ms-365-admin-mcp-server, enabling flexible deployment options for enterprise environments.

Overview

The MCP server supports containerized deployment through Docker, which is essential for production environments requiring isolation, scalability, and consistent runtime behavior. Container deployment enables integration with enterprise systems including Azure Container Instances, Azure Kubernetes Service, and on-premises Docker infrastructure.

Deployment Modes

The server operates in two primary modes:

ModeTransportUse Case
stdioStandard I/OLocal development, MCP Inspector, direct client integration
HTTPHTTP/SSEProduction deployments, remote client access, enterprise integration

Sources: CHANGELOG.md

Docker Configuration

Base Image and Runtime

The Dockerfile configures a Node.js runtime environment optimized for the MCP server's requirements. The image uses a multi-stage build approach to minimize the final image size while ensuring all dependencies are properly installed.

# Reference: Dockerfile structure from repository conventions
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
CMD ["node", "dist/index.js"]

Sources: Dockerfile

Security Configuration

The container runs as a non-root user to comply with security best practices and enterprise compliance requirements. This prevents privilege escalation attacks and limits the blast radius of potential container compromises.

Non-root Docker user
- Security headers: X-Content-Type-Options, X-Frame-Options: DENY, Cache-Control: no-store, CSP default-src 'none'
- Body size limit: 100 KB

Sources: SECURITY.md

Build Arguments and Environment Variables

VariablePurposeRequired
MS365_ADMIN_MCP_CLIENT_IDAzure AD application client IDYes
MS365_ADMIN_MCP_CLIENT_SECRETApplication secretYes
MS365_ADMIN_MCP_TENANT_IDAzure AD tenant identifierYes
NODE_ENVRuntime environment (production)Recommended
MS365_ADMIN_MCP_LOG_DIRLog output directoryOptional

Persistent Storage Architecture

The server requires persistent storage for OAuth tokens and authentication state. The storage implementation supports multiple backends to accommodate different deployment scenarios.

graph TD
    A[MCP Server] --> B[Storage Abstraction Layer]
    B --> C[Memory Storage]
    B --> D[File-based Storage]
    B --> E[Azure Table Storage]
    
    D --> F[~/.mcp-auth/]
    E --> G[Azure Table]
    
    C -->|Ephemeral| H[Pod/Container Restart]
    D -->|Persistent| I[Volume Mount]
    E -->|Distributed| J[Multi-instance]

Sources: src/storage/index.ts

Storage Backend Selection

BackendUse CasePersistenceMulti-instance
MemoryLocal dev, single-use❌ Lost on restart❌ Not supported
File-basedSingle instance, Docker with volumes✅ Survives restart❌ Not recommended
Azure TableProduction multi-instance✅ Distributed✅ Recommended

Sources: src/storage/oauth-storage.ts

File-based Storage Details

When using file-based storage, the server creates a directory structure under ~/.mcp-auth/mcp-remote-<version>/ with the following files:

FilePurposePermissions
<hash>_client_info.jsonClient registration metadata0600
<hash>_tokens.jsonOAuth tokens (access, refresh)0600

The cache key uses md5(serverUrl) matching mcp-remote's getServerUrlHash implementation exactly, ensuring compatibility with existing tooling.

Cache key = md5(serverUrl), matching mcp-remote's getServerUrlHash exactly; a regression test locks the hash against the known production URL.

Sources: CHANGELOG.md

Azure Table Storage Backend

For production deployments requiring high availability and horizontal scaling, the server supports Azure Table Storage as a distributed state backend:

// Storage interface contract
export interface OAuthStorage {
  getClientInfo(serverUrl: string): Promise<ClientInfo | null>;
  saveClientInfo(serverUrl: string, info: ClientInfo): Promise<void>;
  getTokens(serverUrl: string): Promise<Tokens | null>;
  saveTokens(serverUrl: string, tokens: Tokens): Promise<void>;
  deleteTokens(serverUrl: string): Promise<void>;
}

Sources: src/storage/table-storage.ts

Volume Mounts and Configuration

Host Path Bindings

For Docker deployments, the server honors the --cache-dir CLI flag and MCP_REMOTE_CONFIG_DIR environment variable to enable custom storage locations. This is essential for:

  • Docker bind mounts: Map host directories to container paths
  • Multi-user setups: Shared configuration directories
  • Persistent logs: Surviving container recreation
--cache-dir + MCP_REMOTE_CONFIG_DIR env var honoured, so Docker bind mounts and multi-user setups work without patches.

Sources: CHANGELOG.md

version: '3.8'
services:
  mcp-server:
    image: ghcr.io/okapi-ca/ms-365-admin-mcp-server:latest
    volumes:
      - ./config:/config:ro        # Application configuration
      - mcp-auth:/root/.mcp-auth  # Persistent OAuth state
      - mcp-logs:/root/.ms365-admin-mcp/logs  # Application logs
    environment:
      - MS365_ADMIN_MCP_CLIENT_ID=${CLIENT_ID}
      - MS365_ADMIN_MCP_CLIENT_SECRET=${CLIENT_SECRET}
      - MS365_ADMIN_MCP_TENANT_ID=${TENANT_ID}
      - MCP_REMOTE_CONFIG_DIR=/config

volumes:
  mcp-auth:
  mcp-logs:

Logging Configuration

The Winston logger default behavior was updated to support containerized environments where the standard home directory may not be accessible:

Winston logger now uses MS365_ADMIN_MCP_LOG_DIR=/tmp/... by default in the Bicep template, avoiding EACCES against /nonexistent/.ms365-admin-mcp/logs when the image runs as a rootless user without a home directory

Sources: CHANGELOG.md

Log Directory Configuration

EnvironmentDefault PathNotes
Bicep/Azure/tmp/ms365-admin-mcp/logsAvoids home directory issues
Standard~/.ms365-admin-mcp/logsUser's home directory
CustomSet via MS365_ADMIN_MCP_LOG_DIROverride default

Azure Deployment (Bicep)

For Azure-native deployments, the project includes Bicep templates supporting:

Required Parameters

ParameterTypeDescription
allowedClientsarrayRequired; HTTP mode refuses to start without it
tagsobjectPropagated to every resource; required by org-level policies
acrLoginServerstringAzure Container Registry login server
locationstringAzure region
allowedClients Bicep parameter (required; HTTP mode refuses to start without it)

Sources: CHANGELOG.md

Container Registry Integration

The Bicep template configures Azure Container Registry pull access using a User-Assigned Managed Identity (UAMI):

resource acr 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
  name: acrLoginServer
}

resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'mcp-server-uami'
}

resource acrPullRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(acr.id, uami.id, 'acrpull')
  scope: acr
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
    principalId: uami.properties.principalId
  }
}

Sources: CHANGELOG.md

Exit Codes

The server defines specific exit codes for container orchestration and CI/CD integration:

CodeMeaningUse Case
0SuccessNormal operation, clean shutdown
1Usage errorInvalid arguments, missing required parameters
2Network errorAzure AD connectivity failure
3Access deniedAuthentication/authorization failure
4TimeoutRequest timeout during Graph API calls
Documented exit codes (0 ok, 1 usage, 2 network, 3 denied, 4 timeout) for Docker / CI wrappers.

Sources: CHANGELOG.md

HTTP Server Configuration

When deployed in HTTP mode, the server exposes an HTTP endpoint with specific security configurations:

Security Headers

HeaderValuePurpose
X-Content-Type-OptionsnosniffPrevent MIME type sniffing
X-Frame-OptionsDENYPrevent clickjacking
Cache-Controlno-storePrevent sensitive data caching
CSPdefault-src 'none'Content Security Policy

Request Validation

  • Body size limit: 100 KB maximum
  • Path parameter validation: Rejects traversal patterns (../, /, \, ?, #, &) for skipEncoding parameters
  • ReDoS protection: --enabled-tools regex capped at 500 characters
Path parameter validation against traversal (../, /, \, ?, #, &) for skipEncoding params

Sources: SECURITY.md

CI/CD Integration

Best-Effort Clipboard

The server includes clipboard functionality for copying authentication codes during device code flow. This behavior is automatically disabled in CI environments:

const clipboard = process.env.CI !== 'true' && process.stdout.isTTY
  ? platformClipboard()
  : null;
Best-effort clipboard copy (pbcopy / clip / wl-copy / xclip), auto-disabled under CI=true or non-TTY.

Sources: CHANGELOG.md

Environment Detection

VariableDetectionBehavior
CI=trueCI pipelineDisable clipboard
non-TTYBackground processDisable clipboard
CI=undefined + TTYInteractive shellEnable clipboard

Troubleshooting

Common Deployment Issues

IssueCauseResolution
EACCES on logsHome directory inaccessibleSet MS365_ADMIN_MCP_LOG_DIR=/tmp/...
Authentication failuresMissing allowedClientsConfigure Bicep parameter
Token loss on restartMemory storage selectedUse file or table storage backend
Slow cold startsLarge image sizeUse multi-stage build, --only=production

Docker Bind Mount Patterns

For Persistent storage, use named volumes or host bind mounts:

# Named volumes (recommended)
docker run -v mcp-auth:/root/.mcp-auth ghcr.io/okapi-ca/ms-365-admin-mcp-server

# Host bind mount
docker run -v /data/mcp-config:/root/.mcp-auth ghcr.io/okapi-ca/ms-365-admin-mcp-server
docs/TROUBLESHOOTING.md — full section covering Docker bind-mount patterns, Conditional Access caveat

Sources: CHANGELOG.md

Development with Docker

Building Locally

# Clone repository
git clone https://github.com/okapi-ca/ms-365-admin-mcp-server.git
cd ms-365-admin-mcp-server

# Install dependencies
npm install

# Generate client from OpenAPI spec
npm run generate

# Build TypeScript
npm run build

# Build Docker image
docker build -t ms-365-admin-mcp-server:latest .

Running with Docker Compose

# Create .env file
cat > .env << EOF
MS365_ADMIN_MCP_CLIENT_ID=your-client-id
MS365_ADMIN_MCP_CLIENT_SECRET=your-client-secret
MS365_ADMIN_MCP_TENANT_ID=your-tenant-id
EOF

# Start server
docker-compose up -d

# View logs
docker-compose logs -f

See Also

Sources: CHANGELOG.md

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

medium README/documentation is current enough for a first validation pass.

The project should not be treated as fully validated until this signal is reviewed.

medium Maintainer activity is unknown

Users cannot judge support quality until recent activity, releases, and issue response are checked.

medium no_demo

The project may affect permissions, credentials, data exposure, or host boundaries.

medium no_demo

The project may affect permissions, credentials, data exposure, or host boundaries.

Doramagic Pitfall Log

Doramagic extracted 9 source-linked risk signals. Review them before installing or handing real data to the project.

1. Capability assumption: README/documentation is current enough for a first validation pass.

  • Severity: medium
  • Finding: README/documentation is current enough for a first validation pass.
  • User impact: The project should not be treated as fully validated until this signal is reviewed.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: capability.assumptions | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | README/documentation is current enough for a first validation pass.

2. Maintenance risk: Maintainer activity is unknown

  • Severity: medium
  • Finding: Maintenance risk is backed by a source signal: Maintainer activity is unknown. Treat it as a review item until the current version is checked.
  • User impact: Users cannot judge support quality until recent activity, releases, and issue response are checked.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: evidence.maintainer_signals | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | last_activity_observed missing

3. Security or permission risk: no_demo

  • Severity: medium
  • Finding: no_demo
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: downstream_validation.risk_items | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | no_demo; severity=medium

4. Security or permission risk: no_demo

  • Severity: medium
  • Finding: no_demo
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: risks.scoring_risks | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | no_demo; severity=medium

5. Security or permission risk: SEC-003: uuid <14.0.0 transitive vulnerabilities via @azure/msal-node

  • Severity: medium
  • Finding: Security or permission risk is backed by a source signal: SEC-003: uuid <14.0.0 transitive vulnerabilities via @azure/msal-node. Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/okapi-ca/ms-365-admin-mcp-server/issues/70

6. Security or permission risk: SEC-004: UPN persisted in logs without redaction option (PII / GDPR exposure)

  • Severity: medium
  • Finding: Security or permission risk is backed by a source signal: SEC-004: UPN persisted in logs without redaction option (PII / GDPR exposure). Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/okapi-ca/ms-365-admin-mcp-server/issues/71

7. Security or permission risk: SEC-005: Express body parser runs before authentication and rate limiting

  • Severity: medium
  • Finding: Security or permission risk is backed by a source signal: SEC-005: Express body parser runs before authentication and rate limiting. Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/okapi-ca/ms-365-admin-mcp-server/issues/72

8. Maintenance risk: issue_or_pr_quality=unknown

  • Severity: low
  • Finding: issue_or_pr_quality=unknown。
  • User impact: Users cannot judge support quality until recent activity, releases, and issue response are checked.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: evidence.maintainer_signals | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | issue_or_pr_quality=unknown

9. Maintenance risk: release_recency=unknown

  • Severity: low
  • Finding: release_recency=unknown。
  • User impact: Users cannot judge support quality until recent activity, releases, and issue response are checked.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: evidence.maintainer_signals | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | release_recency=unknown

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 4

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using ms-365-admin-mcp-server with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence