# https://github.com/okapi-ca/ms-365-admin-mcp-server 项目说明书

生成时间：2026-05-15 11:16:11 UTC

## 目录

- [Project Overview](#overview)
- [Installation Guide](#installation)
- [Configuration Reference](#configuration)
- [System Architecture](#system-architecture)
- [Code Generation Pipeline](#code-generation)
- [Tool Categories and Presets](#tool-categories)
- [Security Model and Risk Classification](#security-model)
- [Azure Deployment Security](#azure-deployment-security)
- [HTTP Transport and Deployment](#http-deployment)
- [Docker and Container Deployment](#docker-deployment)

<a id='overview'></a>

## Project Overview

### 相关页面

相关主题：[System Architecture](#system-architecture), [Installation Guide](#installation), [Configuration Reference](#configuration)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/README.md)
- [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)
- [src/index.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/index.ts)
- [src/auth.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth.ts)
- [src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/tool-categories.ts)
- [src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)
- [CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)
</details>

# 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.

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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 资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)
- **Security-First Design**: Every write operation is classified with risk levels (low/medium/high/critical) 资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)
- **Least Privilege**: Tools declare minimum required Graph API permissions via `appPermissions` in `endpoints.json` 资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Architecture Overview

```mermaid
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/File | Purpose |
|----------------|---------|
| `bin/` | Code-generation scripts (OpenAPI → Zod client) |
| `src/auth.ts` | MSAL client credentials flow authentication |
| `src/cli.ts` | Commander argv parsing for CLI arguments |
| `src/cloud-config.ts` | Global vs China (21Vianet) endpoint routing |
| `src/endpoints.json` | Source of truth for tool definitions |
| `src/generated/` | Auto-generated Zod schemas from OpenAPI |
| `src/index.ts` | Main MCP server entry point |

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Tool Categories

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

| Category | Pattern | Description |
|----------|---------|-------------|
| `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 |
| `governance` | `role-resource-namespace` | Access reviews, entitlement, lifecycle workflows, PIM for Groups/Roles |
| `response` | `disable\|revoke\|block\|reset\|wipe` | Incident response operations |
| `ediscovery` | `ediscovery` | eDiscovery cases (Microsoft Purview) |
| `cloudpc` | `cloud-pc\|provisioning-polic` | Cloud PC / Windows 365 |
| `callrecords` | `call-record\|call-session\|pstn` | Teams call records |
| `print` | `print` | Universal Print |
| `infoprotection` | `bitlocker\|sensitivity-label` | BitLocker, threat assessment, sensitivity labels |
| `sharepointadmin` | `sharepoint` | SharePoint tenant administration |
| `retention` | `retention` | Records management |

资料来源：[src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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`:

```mermaid
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

| Level | Criteria | Examples |
|-------|----------|----------|
| `low` | Read-only queries, reports, trivial annotations | `run-hunting-query`, `add-security-alert-comment`, Intune reports |
| `medium` | Reversible mutation affecting single entity | `update-user`, `add-group-member`, `create-invitation` |
| `high` | Broad scope, credential change, or destructive+ | `revoke-user-sessions`, `update-conditional-access-policy` |
| `critical` | Irreversible or tenant-wide impact | `delete-user`, `wipe-managed-device`, `delete-conditional-access-policy` |

资料来源：[src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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)

资料来源：[agent-skills/ms365-admin-mcp/references/tools-catalog.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

```typescript
// 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:

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

资料来源：[src/auth-bootstrap.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth-bootstrap.ts)

## Cloud Configuration

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

```typescript
// 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',
  },
};
```

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Development Setup

```bash
# 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
```

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Tool Definition Schema

Each tool in `endpoints.json` follows this structure:

```json
{
  "toolName": "list-users",
  "method": "GET",
  "path": "/v1.0/users",
  "appPermissions": ["User.Read.All"],
  "llmTip": "Returns a list of users in the organization",
  "riskLevel": "low"
}
```

| Field | Required | Description |
|-------|----------|-------------|
| `toolName` | Yes | Unique identifier used by MCP clients |
| `method` | Yes | HTTP method (GET, POST, PATCH, DELETE) |
| `path` | Yes | Graph API endpoint path |
| `appPermissions` | Yes | Minimum required Graph API permissions |
| `llmTip` | No | Hint shown to the LLM in tool description |
| `riskLevel` | No* | Risk classification (only required for non-GET) |

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Tool Execution Flow

```mermaid
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:

| Registry | Package/Image |
|----------|---------------|
| npm | `@okapi-ca/ms-365-admin-mcp-server` |
| GHCR | `ghcr.io/okapi-ca/ms-365-admin-mcp-server` |

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Coding Standards

- **TypeScript Strict Mode**: No `any` without justification 资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

| Version | Tools | Key Changes |
|---------|-------|-------------|
| Latest | 444 | Security fixes, `set-application-verified-publisher` risk bump |
| v369 | 369 | Cloud PC, Teams call records, Universal Print, Info Protection |
| v306 | 306 | eDiscovery, Cloud PC, Intune, Identity Governance |
| v199 | 199 | Elevated `dismiss-risky-users` to high risk |
| v175 | 175 | Full security review, PIM, risk detections |

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

---

<a id='installation'></a>

## Installation Guide

### 相关页面

相关主题：[Configuration Reference](#configuration), [Docker and Container Deployment](#docker-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [Dockerfile](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/Dockerfile)
- [docs/APP_REGISTRATION.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/APP_REGISTRATION.md)
- [docs/SETUP_MACOS_EN.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SETUP_MACOS_EN.md)
- [docs/SETUP_WINDOWS_EN.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SETUP_WINDOWS_EN.md)
</details>

# 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

| Requirement | Minimum | Recommended |
|-------------|---------|-------------|
| Node.js | v20.x | v22.x LTS |
| npm | v10.x | v10.x |
| Memory | 512 MB | 1 GB |
| Disk Space | 200 MB | 500 MB |
| OS | Windows 10+, macOS 11+, Linux | Windows 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

资料来源：[docs/APP_REGISTRATION.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/APP_REGISTRATION.md)

## Installation Methods

The server supports three installation methods:

```mermaid
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:

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

### Run the Container

```bash
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:

| Feature | Implementation |
|---------|----------------|
| Non-root user | Container runs as `node` user (UID 1000) |
| Security headers | X-Content-Type-Options, X-Frame-Options: DENY, CSP |
| Cache permissions | Token files stored with mode 0600 |
| Network isolation | Single-tenant enforcement |

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)

### Docker Bind Mounts for Persistent Cache

For production deployments requiring persistent authentication cache:

```bash
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.

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Build from Dockerfile

For customization or air-gapped deployments:

```bash
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

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

### Option B: Local Development Setup

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

#### Build Steps

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

#### Verify Installation

```bash
npm test
```

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Azure AD Application Registration

### Required Permissions

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

| Category | Permission Type | Required Scopes |
|----------|----------------|-----------------|
| User Management | Application | User.ReadWrite.All |
| Group Management | Application | Group.ReadWrite.All |
| Device Management | Application | DeviceManagementManagedDevices.ReadWrite.All |
| Exchange Admin | Application | Exchange.Admin |
| SharePoint | Application | SharePoint.Admin |
| Teams | Application | Team.ReadWrite.All |
| Security | Application | SecurityEvents.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)
4. Navigate to **Certificates & secrets** → **New client secret**
5. Copy and securely store the secret value (it cannot be retrieved later)
6. Navigate to **API permissions** → **Add a permission** → **Microsoft Graph**
7. Select **Application permissions** and add required scopes
8. Click **Grant admin consent**

资料来源：[docs/APP_REGISTRATION.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/APP_REGISTRATION.md)

## Configuration

### Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `MS365_ADMIN_MCP_CLIENT_ID` | Yes | Azure AD application (client) ID |
| `MS365_ADMIN_MCP_CLIENT_SECRET` | Yes | Client secret value |
| `MS365_ADMIN_MCP_TENANT_ID` | Yes | Azure AD tenant ID |
| `MCP_REMOTE_CONFIG_DIR` | No | Override cache directory path |
| `CI` | No | Set to `true` to disable clipboard operations |
| `PORT` | No | HTTP server port (default: 8080) |

### Local .env File

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

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

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

### Command-Line Options

```bash
node dist/index.js --help
```

| Option | Description |
|--------|-------------|
| `--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-writes` | Enable write operations (default: read-only) |
| `--list-tools` | List available tools and exit |
| `--preset <name>` | Enable preset category filters |

## Claude Desktop Integration

### macOS Configuration

1. Locate the Claude Desktop configuration file:
   ```bash
   ~/Library/Application Support/Claude/claude_desktop_config.json
   ```

2. Add the MCP server configuration:

```json
{
  "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"
      ]
    }
  }
}
```

资料来源：[docs/SETUP_MACOS_EN.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SETUP_MACOS_EN.md)

### Windows Configuration

1. Locate the Claude Desktop configuration file:
   ```powershell
   %APPDATA%\Claude\claude_desktop_config.json
   ```

2. Add the MCP server configuration:

```json
{
  "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"
      ]
    }
  }
}
```

资料来源：[docs/SETUP_WINDOWS_EN.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SETUP_WINDOWS_EN.md)

### Interactive Testing with MCP Inspector

For testing the server configuration:

```bash
npm run inspector
```

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Device Code Authentication (Optional)

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

```bash
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)

资料来源：[src/auth-bootstrap.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth-bootstrap.ts)

## Verifying Installation

### List Available Tools

```bash
node dist/index.js --list-tools
```

This outputs all available MCP tools organized by category.

### Test Authentication

```bash
curl http://localhost:8080/health
```

Expected response:
```json
{"status": "ok", "authenticated": true}
```

## Exit Codes

The server documents exit codes for Docker/CI wrappers:

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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Troubleshooting

### Common Issues

| Issue | Solution |
|-------|----------|
| `Tenant 'common' rejected` | Ensure single-tenant registration; set `MS365_ADMIN_MCP_TENANT_ID` explicitly |
| Token cache not persisting | Use `-v` flag to bind mount cache directory in Docker |
| Permission denied errors | Verify app registration has admin consent granted |
| Container exits immediately | Check logs with `docker logs mcp-server`; verify environment variables |

### Documentation References

- [Troubleshooting Guide](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/TROUBLESHOOTING.md) — covers Server disconnected, Platform SSO symptoms, device_code flow walkthrough
- [SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md) — security architecture and best practices

## Next Steps

After successful installation:

1. Review the [Tool Catalog](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/tools-catalog.md) to understand available operations
2. Configure appropriate [risk levels](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/tools-catalog.md) for write operations
3. Review use case patterns for [Identity Management](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/usecase-identity.md), [Intune](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/usecase-intune.md), and other workloads

---

<a id='configuration'></a>

## Configuration Reference

### 相关页面

相关主题：[Project Overview](#overview), [Installation Guide](#installation), [HTTP Transport and Deployment](#http-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/cli.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/cli.ts)
- [src/cloud-config.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/cloud-config.ts)
- [src/secrets.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/secrets.ts)
- [src/auth.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth.ts)
- [src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)
- [src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/tool-categories.ts)
- [src/endpoints.json](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/endpoints.json)
- [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)
</details>

# 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

```mermaid
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

| Variable | Description | Required |
|----------|-------------|----------|
| `MS365_ADMIN_MCP_CLIENT_ID` | Azure AD application (client) ID | Yes |
| `MS365_ADMIN_MCP_CLIENT_SECRET` | Client secret for the application | Yes |
| `MS365_ADMIN_MCP_TENANT_ID` | Azure AD tenant ID | Yes |

### Optional Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `MS365_ADMIN_MCP_MAX_RISK_LEVEL` | Maximum risk level permitted | `medium` |
| `MS365_ADMIN_MCP_CLOUD` | Target cloud: `global` or `china` | `global` |
| `MS365_ADMIN_MCP_PRESET` | Comma-separated list of tool presets | `all` |
| `MS365_ADMIN_MCP_PORT` | HTTP server port | `3000` |
| `MCP_REMOTE_CONFIG_DIR` | Custom cache directory for OAuth tokens | Platform 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 Level | Rank | Description |
|------------|------|-------------|
| `low` | 1 | Safe read-only operations |
| `medium` | 2 | Operations with moderate impact |
| `high` | 3 | Significant impact operations |
| `critical` | 4 | Irreversible or tenant-wide operations |

The effective risk level for a tool is determined as follows (资料来源：[src/risk-level.ts:1-20]())：

```typescript
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.

```mermaid
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 Identifier | Azure Environment | Graph Endpoint |
|-----------------|-------------------|----------------|
| `global` | Microsoft Azure | `https://graph.microsoft.com` |
| `china` | Azure China 21Vianet | `https://microsoftgraph.chinacloudapi.cn` |

The cloud configuration is loaded from environment variable `MS365_ADMIN_MCP_CLOUD` (资料来源：[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 (资料来源：[src/cli.ts]())。

| Argument | Short | Description | Default |
|----------|-------|-------------|---------|
| `--max-risk-level` | `-r` | Maximum risk level (low/medium/high/critical) | `medium` |
| `--preset` | `-p` | Tool preset filter (security, identity, etc.) | `all` |
| `--port` | | HTTP server port | `3000` |
| `--list-tools` | | List available tools and exit | `false` |
| `--inspector` | | Run with MCP Inspector | `false` |

### Listing Tools with Presets

To validate preset patterns, run:

```bash
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` (资料来源：[src/tool-categories.ts]())。

### Available Presets

| Preset Name | Pattern Matches | Description |
|-------------|-----------------|-------------|
| `security` | security, alert, incident, attack-simulation, threat-intel | Microsoft 365 Defender tools |
| `audit` | audit, sign-in, provisioning, directory, deleted | Audit logs and sign-in activity |
| `health` | service, health, issue, message | Service health and Message Center |
| `reports` | report, activity, usage | Usage reports (Teams, Email, SharePoint) |
| `identity` | user, group, role, conditional, directory, device, pim | Entra ID management |
| `exchange` | exchange, mailbox, message, mail | Exchange Online administration |
| `intune` | intune, managed, compliance, autopilot, mdm, mam | Intune device management |
| `governance` | access-review, entitlement, lifecycle, terms-of-use | Identity Governance |
| `compliance` | compliance, license, secure-score, risk-detection | Compliance center tools |
| `response` | disable-user, revoke, block, reset, dismiss, wipe | Incident response operations |
| `ediscovery` | ediscovery | Microsoft Purview eDiscovery |
| `cloudpc` | cloud-pc, provisioning-policy | Windows 365 Cloud PC |
| `callrecords` | call-record, call-session, pstn-call | Teams call records |
| `print` | print | Universal Print |
| `infoprotection` | bitlocker, sensitivity, threat-assessment | Information Protection |
| `sharepointadmin` | sharepoint, site-admin | SharePoint admin center |
| `retention` | retention, records | Records management |
| `teamsadmin` | team, teams-app, teams-policy | Teams administration |
| `all` | .* | All available tools |

### Combining Presets

Multiple presets can be combined using the `getCombinedPresetPattern` function (资料来源：[src/tool-categories.ts:60-75]())：

```typescript
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 (资料来源：[src/auth.ts]())。

### Authentication Flow

```mermaid
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 (资料来源：[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 (资料来源：[src/endpoints.json]())。

### Endpoint Schema

Each endpoint definition includes:

| Field | Description |
|-------|-------------|
| `toolName` | Unique identifier for the tool |
| `method` | HTTP method (GET, POST, PATCH, DELETE) |
| `path` | Microsoft Graph API path |
| `description` | Human-readable description |
| `appPermissions` | Required Graph API permissions |
| `riskLevel` | Configured risk level (low/medium/high/critical) |
| `category` | Tool category for filtering |

### Risk Classification Examples

Critical-risk tools (资料来源：[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

```mermaid
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 (资料来源：[CONTRIBUTING.md]())：

```bash
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:

```bash
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 (资料来源：[CONTRIBUTING.md]())：

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Usage error / invalid configuration |
| 2 | Network error |
| 3 | Authentication denied |
| 4 | Request timeout |

## Verification

Run the verification script to ensure configuration is valid:

```bash
npm run verify
```

This runs:
- TypeScript compilation (`npm run build`)
- Linting (`npm run lint`)
- Formatting checks (`npm run format:check`)
- Test suite (`npm test`)

---

<a id='system-architecture'></a>

## System Architecture

### 相关页面

相关主题：[Project Overview](#overview), [Code Generation Pipeline](#code-generation), [Tool Categories and Presets](#tool-categories)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [docs/ARCHITECTURE.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/ARCHITECTURE.md)
- [src/server.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/server.ts)
- [src/http-server.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/http-server.ts)
- [src/graph-client.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/graph-client.ts)
- [src/auth.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth.ts)
</details>

# 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

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

| Variable | Description |
|----------|-------------|
| `MS365_ADMIN_MCP_CLIENT_ID` | Azure AD application (client) ID |
| `MS365_ADMIN_MCP_CLIENT_SECRET` | Client secret from certificate or app registration |
| `MS365_ADMIN_MCP_TENANT_ID` | Azure AD tenant ID |

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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 Environment | Endpoint Pattern |
|-------------------|------------------|
| Global | `graph.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:

```json
{
  "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"
  }
}
```

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

```typescript
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:

| Level | Criteria | Examples |
|-------|----------|----------|
| `low` | Read-only in effect | `list-users`, reports |
| `medium` | Reversible mutation | `update-user`, `add-group-member` |
| `high` | Broad scope or credential changes | `revoke-user-sessions`, `update-conditional-access-policy` |
| `critical` | Irreversible or tenant-wide | `delete-user`, `wipe-managed-device` |

资料来源：[src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts), [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

```typescript
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`.

资料来源：[src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

```bash
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)

资料来源：[src/auth-bootstrap.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth-bootstrap.ts), [CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## CLI Interface (`src/cli.ts`)

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

| Command | Description |
|---------|-------------|
| `npm run inspector` | Start MCP Inspector for interactive testing |
| `--list-tools` | Display all available tools matching current preset |
| `--list-permissions` | Show required Graph API permissions |
| `--preset <name>` | Select tool category preset |
| `--max-risk <level>` | Set maximum allowed risk level |
| `--allow-writes` | Enable write operations (disabled by default) |

Example usage:
```bash
# 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:

| Tool | Risk Level |
|------|------------|
| `delete-user` | critical |
| `delete-group` | critical |
| `delete-conditional-access-policy` | critical |
| `delete-managed-device` | critical |
| `wipe-managed-device` | critical |

资料来源：[agent-skills/ms365-admin-mcp/references/tools-catalog.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/tools-catalog.md)

## Development Workflow

### Local Development Setup

```bash
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

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

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

```bash
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`:

```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

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

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

---

<a id='code-generation'></a>

## Code Generation Pipeline

### 相关页面

相关主题：[System Architecture](#system-architecture), [Tool Categories and Presets](#tool-categories)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [bin/generate-graph-client.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/generate-graph-client.mjs)
- [bin/modules/generate-mcp-tools.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/modules/generate-mcp-tools.mjs)
- [bin/modules/simplified-openapi.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/modules/simplified-openapi.mjs)
- [bin/modules/extract-descriptions.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/modules/extract-descriptions.mjs)
- [bin/modules/download-openapi.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/modules/download-openapi.mjs)
- [src/generated/endpoint-types.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/generated/endpoint-types.ts)
- [src/graph-tools.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/graph-tools.ts)
- [src/endpoints.json](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/endpoints.json)
</details>

# 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.

**资料来源:** [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Architecture Overview

```mermaid
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.

| Parameter | Type | Description |
|-----------|------|-------------|
| `outputPath` | `string` | Local path to save the downloaded OpenAPI spec |
| `version` | `string` | API 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

**资料来源:** [bin/modules/download-openapi.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:**

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

**资料来源:** [bin/modules/simplified-openapi.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:**

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

**资料来源:** [bin/modules/extract-descriptions.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:**

```mermaid
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:**

| Field | Source | Description |
|-------|--------|-------------|
| `toolName` | operationId → kebab-case | Unique tool identifier |
| `pathPattern` | OpenAPI path | API endpoint path |
| `method` | HTTP method | GET, POST, PUT, PATCH, DELETE |
| `appPermissions` | securitySchemes | Required Graph API permissions |
| `llmTip` | description | Optional hint for LLM context |
| `riskLevel` | Manual annotation | low/medium/high/critical |

**资料来源:** [bin/modules/generate-mcp-tools.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/modules/generate-mcp-tools.mjs), [src/endpoints.json](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/endpoints.json)

### 5. Graph Client Generator

**File:** `bin/generate-graph-client.mjs`

Orchestrates the entire pipeline and generates TypeScript source files.

**Generated artifacts:**

| File | Purpose |
|------|---------|
| `src/generated/endpoint-types.ts` | TypeScript interfaces for all endpoints |
| `src/generated/schemas.ts` | Zod validation schemas |
| `src/generated/descriptions.ts` | Tool descriptions and documentation |

**资料来源:** [bin/generate-graph-client.mjs](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/bin/generate-graph-client.mjs)

## Generated Output Files

### endpoint-types.ts

Auto-generated TypeScript types derived from OpenAPI schemas.

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

**资料来源:** [src/generated/endpoint-types.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/generated/endpoint-types.ts)

### endpoints.json

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

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

**资料来源:** [src/endpoints.json](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/endpoints.json)

## Tool Registration Flow

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

```mermaid
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:**

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

**资料来源:** [src/graph-tools.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/graph-tools.ts), [src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)

## Execution Workflow

### Standard Generation

```bash
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

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

**资料来源:** [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Configuration

### Risk Level Annotations

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

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

**Risk classification rubric:**

| Level | Criteria | Example Tools |
|-------|----------|---------------|
| `low` | Read-only queries, reports | `list-users`, `get-user` |
| `medium` | Reversible single-entity mutation | `update-user`, `add-group-member` |
| `high` | Significant impact, credential changes | `revoke-user-sessions`, `update-ca-policy` |
| `critical` | Irreversible or tenant-wide | `delete-user`, `wipe-managed-device` |

**资料来源:** [CONTRIBUTING.md:50-62](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

### Permission Mapping

Application permissions are declared per tool in `endpoints.json`:

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

**资料来源:** [agent-skills/ms365-admin-mcp/references/graph-permissions.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/graph-permissions.md)

## Adding New Tools

### Workflow

```mermaid
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](https://github.com/microsoftgraph/msgraph-metadata).

### Step 2: Register in endpoints.json

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

### Step 3: Regenerate Code

```bash
npm run generate
```

### Step 4: Verify Registration

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

**资料来源:** [CONTRIBUTING.md:30-45](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

## Verification and Testing

### List Tools

Display all registered tools:

```bash
node dist/index.js --list-tools
```

### List Permissions

Display required Graph API permissions:

```bash
node dist/index.js --list-permissions
```

### Preset Filtering

List tools by preset category:

```bash
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`

**资料来源:** [src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/tool-categories.ts)

## Summary

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

| Capability | Description |
|------------|-------------|
| **Automation** | Eliminates manual TypeScript/Zod schema writing |
| **Consistency** | Uniform tool naming and structure |
| **Type Safety** | End-to-end TypeScript typing from OpenAPI to server |
| **Extensibility** | Easy addition of new Graph API endpoints |
| **Documentation** | Auto-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.

---

<a id='tool-categories'></a>

## Tool Categories and Presets

### 相关页面

相关主题：[System Architecture](#system-architecture), [Security Model and Risk Classification](#security-model)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/tool-categories.ts)
- [src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)
- [src/endpoints.json](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/endpoints.json)
</details>

# 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

资料来源：[src/tool-categories.ts:1-1]()

## Architecture

```mermaid
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

| Component | File | Responsibility |
|-----------|------|----------------|
| ToolCategory interface | `src/tool-categories.ts` | Defines the category schema |
| TOOL_CATEGORIES registry | `src/tool-categories.ts` | Maps category names to regex patterns |
| effectiveRiskLevel() | `src/risk-level.ts` | Resolves risk level per tool |
| isToolAllowed() | `src/risk-level.ts` | Checks if tool passes max risk threshold |

资料来源：[src/tool-categories.ts:1-15]()

## ToolCategory Interface

```typescript
export interface ToolCategory {
  name: string;
  pattern: RegExp;
  description: string;
}
```

| Field | Type | Purpose |
|-------|------|---------|
| `name` | `string` | Unique identifier for the category |
| `pattern` | `RegExp` | Regex pattern tested against tool names |
| `description` | `string` | Human-readable description for documentation |

资料来源：[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`.

资料来源：[src/tool-categories.ts:7-40]()

### Available Categories

| Preset | Pattern Scope | Description |
|--------|---------------|-------------|
| `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) |
| `identity` | Complex pattern (users, groups, roles, conditional access, PIM, devices, etc.) | Identity and access management (Entra ID users, groups, roles, devices, PIM, guest users, external identities) |

资料来源：[src/tool-categories.ts:7-40]()

## Risk Level System

### Effective Risk Level Resolution

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

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

| Scenario | Result |
|----------|--------|
| `configuredRiskLevel` is set | Returns configured value |
| Method is GET (case-insensitive) | Returns `low` |
| Method is POST/PUT/DELETE, no config | Returns `critical` (fail-safe default) |

资料来源：[src/risk-level.ts:10-18]()

### Risk Level Hierarchy

| Level | Criteria | Example Tools |
|-------|----------|---------------|
| `low` | Read-only operations | `list-users`, `get-security-alert` |
| `medium` | Reversible mutations on single entities | `update-user`, `add-group-member` |
| `high` | Significant impact, credential changes, or destructive operations | `revoke-user-sessions`, `update-conditional-access-policy` |
| `critical` | Irreversible or tenant-wide impact | `delete-user`, `wipe-managed-device`, `delete-conditional-access-policy` |

资料来源：[CONTRIBUTING.md:1-20]()

### Tool Permission Check

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

```typescript
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`.

资料来源：[src/risk-level.ts:20-25]()

## Category Matching Flow

```mermaid
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:

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

资料来源：[CONTRIBUTING.md:25-35]()

### Step 2: Validate the Pattern

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

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

资料来源：[CONTRIBUTING.md:37-38]()

## Tool Definition Schema

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

```json
{
  "toolName": {
    "method": "GET|POST|PUT|DELETE",
    "appPermissions": ["Permission.Read.All"],
    "llmTip": "Optional hint for LLM",
    "riskLevel": "low|medium|high|critical"  // only for non-GET
  }
}
```

| Field | Required | Description |
|-------|----------|-------------|
| `method` | Yes | HTTP method for the Graph API call |
| `appPermissions` | Yes | Minimum Graph API permissions |
| `llmTip` | No | Hint displayed to LLM in tool description |
| `riskLevel` | For non-GET | Risk classification per the rubric |

资料来源：[CONTRIBUTING.md:55-65]()

## Preset Index

| Preset | Use Case File | Primary Tools |
|--------|---------------|---------------|
| `security` | `usecase-security.md` | Alerts, incidents, attack simulations, threat intel |
| `audit` | `usecase-audit.md` | Directory audits, sign-ins, provisioning logs |
| `health` | `usecase-health.md` | Service health, Message Center |
| `reports` | `usecase-reports.md` | Teams, Email, SharePoint, OneDrive usage |
| `identity` | `usecase-identity.md` | Users, groups, roles, devices, PIM |
| `exchange` | `usecase-exchange.md` | Message traces, mailboxes |
| `intune` | `usecase-intune.md` | Device management, compliance, configurations |
| `governance` | `usecase-governance.md` | Access reviews, entitlement, lifecycle |
| `compliance` | `usecase-compliance.md` | Licenses, Secure Score, Identity Protection |
| `response` | `usecase-response.md` | Incident response operations |
| `ediscovery` | `usecase-ediscovery.md` | eDiscovery cases (Purview) |
| `cloudpc` | `usecase-cloudpc.md` | Cloud PC / Windows 365 |
| `callrecords` | `usecase-callrecords.md` | Teams call records |
| `print` | `usecase-print.md` | Universal Print |
| `infoprotection` | `usecase-infoprotection.md` | BitLocker, sensitivity labels |
| `sharepointadmin` | `usecase-sharepointadmin.md` | SharePoint tenant administration |
| `retention` | `usecase-retention.md` | Records management |

资料来源：[agent-skills/ms365-admin-mcp/references/tools-catalog.md:1-50]()

## Verification Commands

After adding a new preset, verify registration:

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

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

资料来源：[CONTRIBUTING.md:66-72]()

## Integration with MCP Server

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

```mermaid
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

---

<a id='security-model'></a>

## Security Model and Risk Classification

### 相关页面

相关主题：[Tool Categories and Presets](#tool-categories), [Azure Deployment Security](#azure-deployment-security)

<details>
<summary>Relevant Source Files</summary>

以下源码文件用于生成本页说明：

- [docs/RISK_MODEL.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/RISK_MODEL.md)
- [src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)
- [SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)
- [docs/SECURITY_REVIEW_2026-04-20.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SECURITY_REVIEW_2026-04-20.md)
- [docs/SECURITY_REVIEW_2026-04-25.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SECURITY_REVIEW_2026-04-25.md)
- [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)
- [agent-skills/ms365-admin-mcp/references/tools-catalog.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/tools-catalog.md)
</details>

# 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

资料来源：[docs/RISK_MODEL.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

| Level | Criteria | Example Operations |
|-------|----------|-------------------|
| `low` | Read-only operations, reports, POST-only queries, or trivial annotations | `run-hunting-query`, `add-security-alert-comment`, listing operations |
| `medium` | Reversible mutations affecting a single entity | `update-user`, `add-group-member`, `create-invitation` |
| `high` | Significant impact: broad scope, credential change, or destructive | `revoke-user-sessions`, `update-conditional-access-policy`, `confirm-compromised-users` |
| `critical` | Irreversible or tenant-wide impact | `delete-user`, `wipe-managed-device`, `delete-conditional-access-policy` |

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

### Risk Level Rank

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

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

资料来源：[src/risk-level.ts:1-5](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)

## Risk Classification Algorithm

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

```typescript
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

资料来源：[src/risk-level.ts:17-25](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)

## Access Control Function

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

```typescript
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.

资料来源：[src/risk-level.ts:27-32](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)

## 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`.

资料来源：[docs/RISK_MODEL.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/RISK_MODEL.md)

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

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

| Cap Value | Effect |
|-----------|--------|
| `--max-risk-level low` | Only read operations (`low`) are exposed |
| `--max-risk-level medium` | Adds medium-risk mutations; hides high/critical tools |
| `--max-risk-level high` | Adds high-risk operations; critical tools hidden |
| `--max-risk-level critical` | All 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

资料来源：[docs/SECURITY_REVIEW_2026-04-20.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

资料来源：[docs/SECURITY_REVIEW_2026-04-20.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

资料来源：[docs/SECURITY_REVIEW_2026-04-20.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SECURITY_REVIEW_2026-04-20.md)

### SEC-G03 — Sensitive Read Annotations

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

| Category | Count | Risk Levels |
|----------|-------|-------------|
| BitLocker recovery keys | 1 | `high` |
| LAPS passwords | 1 | `high` |
| eDiscovery cases/custodians/searches | 4 | `high` |
| Subject rights requests | 1 | `high` |
| Auth methods | 3 | `medium` |
| Sign-ins | 2 | `medium` |
| Risk detections | 2 | `medium` |
| Message traces | 2 | `medium` |
| Federated credentials | 2 | `medium` |

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

资料来源：[docs/SECURITY_REVIEW_2026-04-20.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

| Tool | Impact |
|------|--------|
| `delete-user` | Permanently removes user from tenant |
| `delete-group` | Removes group and all memberships |
| `add-directory-role-member` | Grants permanent privileged role |
| `disable-user-account` | On privileged/break-glass accounts |

### Compliance & Security

| Tool | Impact |
|------|--------|
| `delete-conditional-access-policy` | Removes tenant-wide access controls |
| `delete-ediscovery-case` | Permanently removes legal hold case |
| `wipe-managed-device` | Remote wipe of enrolled device |
| `clean-windows-device` | Removes device from Intune |

资料来源：[agent-skills/ms365-admin-mcp/references/tools-catalog.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

| Tool | Risk | Requirement |
|------|------|-------------|
| `revoke-user-sessions` | high | Confirm before executing |
| `confirm-compromised-users` | high | Confirm per case |
| `confirm-safe-users` | high | Confirm per case |
| `dismiss-risky-users` | high | Confirm per case |
| `change-user-password` | high | Confirm with operator |
| `update-device` | high | Confirm with operator |

资料来源：[agent-skills/ms365-admin-mcp/references/usecase-compliance.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/agent-skills/ms365-admin-mcp/references/usecase-compliance.md)

## Security Architecture Flow

```mermaid
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:

```mermaid
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.

```typescript
// 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
};
```

资料来源：[src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/tool-categories.ts)

## Verification Commands

Verify tool registration and permissions:

```bash
# 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
```

资料来源：[docs/RISK_MODEL.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/RISK_MODEL.md)

## Security Review Process

All security-relevant changes undergo review per documented processes:

| Review Date | Scope |
|-------------|-------|
| 2026-04-20 | Initial security review — SEC-G01, SEC-G02, SEC-G03 implementation |
| 2026-04-25 | Follow-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

资料来源：[docs/SECURITY_REVIEW_2026-04-20.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/SECURITY_REVIEW_2026-04-20.md)  
资料来源：[docs/SECURITY_REVIEW_2026-04-25.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

| Module | Purpose |
|--------|---------|
| `src/risk-level.ts` | Risk level computation and comparison |
| `src/user-token-authorization.ts` | User token validation |
| `src/jwks-stale-cache.ts` | JWKS caching for token validation |
| `src/upstream-error.ts` | Graph API error handling |
| `src/untrusted-envelope.ts` | Nonce envelope wrapping |

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

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)

---

<a id='azure-deployment-security'></a>

## Azure Deployment Security

### 相关页面

相关主题：[Security Model and Risk Classification](#security-model), [HTTP Transport and Deployment](#http-deployment), [Docker and Container Deployment](#docker-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [docs/AZURE_DEPLOYMENT_SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/AZURE_DEPLOYMENT_SECURITY.md)
- [infra/main.bicep](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/infra/main.bicep)
- [infra/parameters.example.jsonc](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/infra/parameters.example.jsonc)
- [docs/CYSEC-1420/graph-permissions-baseline.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/CYSEC-1420/graph-permissions-baseline.md)
- [docs/CYSEC-1420/network-design-gate.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/CYSEC-1420/network-design-gate.md)
- [SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)
- [CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)
</details>

# 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

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

```mermaid
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:

| Endpoint | Purpose | Sovereign Equivalent |
|----------|---------|----------------------|
| `login.microsoftonline.com` | Microsoft Entra authentication | `login.partner.microsoftonline.cn` |
| `graph.microsoft.com` | Microsoft Graph API | `microsoftgraph.chinacloudapi.cn` |

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md) | [docs/CYSEC-1420/network-design-gate.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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)

```bash
# 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
```

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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 Name | Description | Required |
|-------------|-------------|----------|
| `MS365_ADMIN_MCP_CLIENT_ID` | Entra application client ID | Yes |
| `MS365_ADMIN_MCP_CLIENT_SECRET` | Client secret (if not using cert) | Conditional |
| `MS365_ADMIN_MCP_KEYVAULT_URL` | Key Vault base URL | Yes |
| `AZURE_STORAGE_ACCOUNT_NAME` | Table storage for OAuth state | OAuth mode only |
| `AZURE_STORAGE_TABLE_NAME` | Table name for PKCE state | OAuth mode only |

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)

### Certificate Authentication

The deployment **prefers** certificate-based authentication over client secrets:

```mermaid
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

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)

### Secret Rotation Policy

| Credential Type | Rotation Interval |
|----------------|-------------------|
| Client Secrets | 90 days |
| Certificates | Per certificate validity period |
| Federated Credentials | No 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

```mermaid
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
```

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### OAuth Storage

OAuth mode requires Azure Table Storage for PKCE state management:

| Component | Configuration |
|-----------|--------------|
| Storage Account | Standard_LRS, TLS 1.2, OAuth-only authentication |
| Table Name | `oauthstate` (configurable) |
| Access | Managed Identity with Storage Table Data Contributor role |
| PKCE Lifetime | 10 minutes |

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Graph API Permissions

### Least Privilege Model

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

资料来源：[docs/CYSEC-1420/graph-permissions-baseline.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/CYSEC-1420/graph-permissions-baseline.md)

### Application Permission Categories

| Category | Permission Type | Example Operations |
|----------|----------------|-------------------|
| Directory | Read.All | list-users, list-groups |
| Device Management | ReadWrite.All | update-device, wipe-managed |
| Policy | ReadWrite.All | create-conditional-access-policy |
| Security | Read.All / ReadWrite.All | list-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
```

资料来源：[agent-skills/ms365-admin-mcp/references/graph-permissions.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

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

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

```
Original: "Authenticated user alice@example.com"
Redacted: "Authenticated user sha256:1a2b3c4d5e6f..."
```

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)

### Audit Trail

Enable verbose logging for complete audit trails:

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

The following audit operations are available via the MCP tools:

| Tool | Purpose |
|------|---------|
| `list-directory-audits` | Directory sign-in and activity logs |
| `list-intune-audit-events` | Intune device management events |
| `list-sign-ins` | Conditional Access and sign-in logs |

### Log Storage Configuration

The Winston logger uses a configurable log directory:

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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Bicep Infrastructure Deployment

### Deployment Architecture

```mermaid
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

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `allowedClients` | array | Yes | List of Entra app IDs permitted to connect |
| `tags` | object | Yes | Tags propagated to all resources |
| `acrLoginServer` | string | Yes | Azure Container Registry login server |
| `location` | string | Yes | Azure region |
| `environmentName` | string | Yes | Deployment environment |
| `maxReplicas` | int | No | Maximum container replicas (default: 1) |

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Storage Account Configuration

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

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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Private Container Registry

The deployment supports pulling images from private Azure Container Registry:

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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

## Related Documentation

- [SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md) — Core security practices
- [docs/APP_REGISTRATION.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/APP_REGISTRATION.md) — Application registration guide
- [docs/CYSEC-1420/](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/docs/CYSEC-1420/) — Security compliance documentation

---

<a id='http-deployment'></a>

## HTTP Transport and Deployment

### 相关页面

相关主题：[Docker and Container Deployment](#docker-deployment), [Azure Deployment Security](#azure-deployment-security), [Configuration Reference](#configuration)

<details>
<summary>Relevant Source Files</summary>

以下源码文件用于生成本页说明：

- [CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)
- [SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)
- [CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)
- [src/auth-bootstrap.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/auth-bootstrap.ts)
- [src/tool-categories.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/tool-categories.ts)
- [src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)
</details>

# 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 Mode | Use Case | Authentication |
|---------------|----------|----------------|
| stdio | Local Claude Desktop integration | Direct client credentials |
| StreamableHTTP | Claude.ai Web, Claude Desktop remote | OAuth 2.0 + PKCE proxy |
| Remote HTTP | Containerized deployments (Azure Container Apps) | Device code bootstrap |

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## HTTP Server Architecture

### Core Components

The HTTP transport is implemented across several interconnected modules:

| Module | Responsibility |
|--------|----------------|
| `http-server.ts` | Main HTTP server, routing, middleware, security headers |
| `oauth-proxy.ts` | OAuth 2.0 discovery, PKCE proxy, Entra ID integration |
| `token-validator.ts` | JWT validation, tenant verification, scope enforcement |
| `auth-bootstrap.ts` | RFC 8628 device_code flow for remote authentication |

资料来源：[CONTRIBUTING.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CONTRIBUTING.md)

### Request Flow

```mermaid
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

| Endpoint | Purpose |
|----------|---------|
| `GET /.well-known/oauth-authorization-server` | OAuth 2.0 authorization server metadata |
| `GET /.well-known/oauth-protected-resource` | Protected resource metadata for client discovery |
| `GET /.well-known/microsoft-hosted-userpolicy` | Microsoft-hosted user policy information |

资料来源：[CHANGELOG.md:73-75](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Authentication Headers

The server implements proper WWW-Authenticate header responses:

| Scenario | Header Response |
|----------|-----------------|
| Missing token | `WWW-Authenticate: Bearer resource_metadata="..."` |
| Invalid token | `WWW-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`.

资料来源：[CHANGELOG.md:81-85](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Required Configuration

When running in OAuth mode, deployments must specify:

```bash
--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.

资料来源：[CHANGELOG.md:34-37](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## 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

```mermaid
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

```bash
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)
```

资料来源：[src/auth-bootstrap.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

资料来源：[CHANGELOG.md:56-58](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Usage error |
| 2 | Network failure |
| 3 | Access denied |
| 4 | Timeout |

These exit codes facilitate Docker and CI wrapper scripting.

资料来源：[CHANGELOG.md:63-65](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Security Configuration

### Security Headers

All HTTP responses include the following security headers:

| Header | Value | Purpose |
|--------|-------|---------|
| `X-Content-Type-Options` | `nosniff` | Prevent MIME type sniffing |
| `X-Frame-Options` | `DENY` | Prevent clickjacking |
| `Cache-Control` | `no-store` | Prevent sensitive data caching |
| Content-Security-Policy | `default-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.

资料来源：[CHANGELOG.md:88-91](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Request Validation

| Validation Type | Implementation |
|-----------------|----------------|
| Body size limit | 100 KB maximum |
| Path traversal | Parameters checked for `../`, `/`, `\`, `?`, `#`, `&` |
| ReDoS protection | `--enabled-tools` regex capped at 500 characters |

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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 Level | Description | Enforcement |
|------------|-------------|-------------|
| `low` | Read-only operations, reports | Allowed by default |
| `medium` | Reversible mutations, single entity | Requires `--allow-writes` |
| `high` | Significant impact, credential changes | Requires explicit cap |
| `critical` | Irreversible or tenant-wide | Requires `--allow-critical` |

资料来源：[src/risk-level.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/risk-level.ts)

## Deployment Patterns

### Local Deployment (Stdio)

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

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

### Remote HTTP Deployment (Container Apps)

```bash
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

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

## Command Line Options

### Transport Options

| Option | Description | Default |
|--------|-------------|---------|
| `--oauth-mode` | Enable OAuth 2.0 proxy | Disabled |
| `--public-url` | Public URL for OAuth callbacks | Required in OAuth mode |
| `--required-user-scopes` | Scopes required in user tokens | Empty (any scope) |
| `--allow-any-tenant-user` | Allow users from any tenant | Disabled |
| `--cache-dir` | Override token cache directory | `~/.mcp-auth/mcp-remote-<ver>` |

### Security Options

| Option | Description | Default |
|--------|-------------|---------|
| `--allow-writes` | Allow write operations up to medium risk | Disabled |
| `--allow-critical` | Allow critical write operations | Disabled |
| `--max-risk-level` | Maximum allowed risk level | `medium` |

### Other Options

| Option | Description | Default |
|--------|-------------|---------|
| `--enabled-tools` | Regex pattern to limit available tools | All tools |
| `--preset` | Enable a tool category preset | None |
| `--list-tools` | List available tools and exit | - |
| `--list-permissions` | List required permissions and exit | - |

## Troubleshooting

### Common Issues

| Symptom | Cause | Solution |
|---------|-------|----------|
| `Server disconnected` | Network connectivity or proxy issue | Check `docs/TROUBLESHOOTING.md` |
| Platform SSO errors | Conditional Access policy blocking | Review device_code flow documentation |
| `ERR_ERL_UNEXPECTED_X_FORWARDED_FOR` | Rate limiter not trusting proxy | Ensure `--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

- [Authentication and Authorization](src/auth.ts)
- [Token Validation](src/token-validator.ts)
- [Risk Model](docs/RISK_MODEL.md)
- [Troubleshooting Guide](docs/TROUBLESHOOTING.md)

---

<a id='docker-deployment'></a>

## Docker and Container Deployment

### 相关页面

相关主题：[HTTP Transport and Deployment](#http-deployment), [Azure Deployment Security](#azure-deployment-security), [Installation Guide](#installation)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [Dockerfile](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/Dockerfile)
- [.dockerignore](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/.dockerignore)
- [src/storage/index.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/storage/index.ts)
- [src/storage/oauth-storage.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/storage/oauth-storage.ts)
- [src/storage/memory-storage.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/storage/memory-storage.ts)
- [src/storage/table-storage.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/storage/table-storage.ts)
</details>

# 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:

| Mode | Transport | Use Case |
|------|-----------|----------|
| **stdio** | Standard I/O | Local development, MCP Inspector, direct client integration |
| **HTTP** | HTTP/SSE | Production deployments, remote client access, enterprise integration |

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

```dockerfile
# 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"]
```

资料来源：[Dockerfile](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/SECURITY.md)

### Build Arguments and Environment Variables

| Variable | Purpose | Required |
|----------|---------|----------|
| `MS365_ADMIN_MCP_CLIENT_ID` | Azure AD application client ID | Yes |
| `MS365_ADMIN_MCP_CLIENT_SECRET` | Application secret | Yes |
| `MS365_ADMIN_MCP_TENANT_ID` | Azure AD tenant identifier | Yes |
| `NODE_ENV` | Runtime environment (`production`) | Recommended |
| `MS365_ADMIN_MCP_LOG_DIR` | Log output directory | Optional |

## 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.

```mermaid
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]
```

资料来源：[src/storage/index.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/src/storage/index.ts)

### Storage Backend Selection

| Backend | Use Case | Persistence | Multi-instance |
|---------|----------|-------------|----------------|
| **Memory** | Local dev, single-use | ❌ Lost on restart | ❌ Not supported |
| **File-based** | Single instance, Docker with volumes | ✅ Survives restart | ❌ Not recommended |
| **Azure Table** | Production multi-instance | ✅ Distributed | ✅ Recommended |

资料来源：[src/storage/oauth-storage.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

| File | Purpose | Permissions |
|------|---------|-------------|
| `<hash>_client_info.json` | Client registration metadata | 0600 |
| `<hash>_tokens.json` | OAuth 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.

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

```typescript
// 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>;
}
```

资料来源：[src/storage/table-storage.ts](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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.

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Recommended Volume Structure

```yaml
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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Log Directory Configuration

| Environment | Default Path | Notes |
|-------------|--------------|-------|
| Bicep/Azure | `/tmp/ms365-admin-mcp/logs` | Avoids home directory issues |
| Standard | `~/.ms365-admin-mcp/logs` | User's home directory |
| Custom | Set via `MS365_ADMIN_MCP_LOG_DIR` | Override default |

## Azure Deployment (Bicep)

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

### Required Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `allowedClients` | array | Required; HTTP mode refuses to start without it |
| `tags` | object | Propagated to every resource; required by org-level policies |
| `acrLoginServer` | string | Azure Container Registry login server |
| `location` | string | Azure region |

> `allowedClients` Bicep parameter (required; HTTP mode refuses to start without it)

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Container Registry Integration

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

```bicep
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
  }
}
```

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Exit Codes

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

| Code | Meaning | Use Case |
|------|---------|----------|
| 0 | Success | Normal operation, clean shutdown |
| 1 | Usage error | Invalid arguments, missing required parameters |
| 2 | Network error | Azure AD connectivity failure |
| 3 | Access denied | Authentication/authorization failure |
| 4 | Timeout | Request timeout during Graph API calls |

> Documented exit codes (0 ok, 1 usage, 2 network, 3 denied, 4 timeout) for Docker / CI wrappers.

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## HTTP Server Configuration

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

### Security Headers

| Header | Value | Purpose |
|--------|-------|---------|
| `X-Content-Type-Options` | `nosniff` | Prevent MIME type sniffing |
| `X-Frame-Options` | `DENY` | Prevent clickjacking |
| `Cache-Control` | `no-store` | Prevent sensitive data caching |
| CSP | `default-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

资料来源：[SECURITY.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/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:

```typescript
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.

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

### Environment Detection

| Variable | Detection | Behavior |
|----------|-----------|----------|
| `CI=true` | CI pipeline | Disable clipboard |
| `non-TTY` | Background process | Disable clipboard |
| `CI=undefined` + TTY | Interactive shell | Enable clipboard |

## Troubleshooting

### Common Deployment Issues

| Issue | Cause | Resolution |
|-------|-------|------------|
| `EACCES` on logs | Home directory inaccessible | Set `MS365_ADMIN_MCP_LOG_DIR=/tmp/...` |
| Authentication failures | Missing `allowedClients` | Configure Bicep parameter |
| Token loss on restart | Memory storage selected | Use file or table storage backend |
| Slow cold starts | Large image size | Use multi-stage build, `--only=production` |

### Docker Bind Mount Patterns

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

```bash
# 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

资料来源：[CHANGELOG.md](https://github.com/okapi-ca/ms-365-admin-mcp-server/blob/main/CHANGELOG.md)

## Development with Docker

### Building Locally

```bash
# 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

```bash
# 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

- [Architecture Documentation](./ARCHITECTURE.md)
- [Security Model](./SECURITY.md)
- [HTTP Deployment](./HTTP_DEPLOYMENT.md)
- [Troubleshooting Guide](./TROUBLESHOOTING.md)

---

---

## Doramagic 踩坑日志

项目：okapi-ca/ms-365-admin-mcp-server

摘要：发现 9 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。

## 1. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：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. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | last_activity_observed missing

## 3. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | no_demo; severity=medium

## 4. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | no_demo; severity=medium

## 5. 安全/权限坑 · 来源证据：SEC-003: uuid <14.0.0 transitive vulnerabilities via @azure/msal-node

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：SEC-003: uuid <14.0.0 transitive vulnerabilities via @azure/msal-node
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_103cf7f40efc40e99adfa2eb14d9717e | https://github.com/okapi-ca/ms-365-admin-mcp-server/issues/70 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 6. 安全/权限坑 · 来源证据：SEC-004: UPN persisted in logs without redaction option (PII / GDPR exposure)

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：SEC-004: UPN persisted in logs without redaction option (PII / GDPR exposure)
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_6ede43fd3f7247e0981524934656dbeb | https://github.com/okapi-ca/ms-365-admin-mcp-server/issues/71 | 来源类型 github_issue 暴露的待验证使用条件。

## 7. 安全/权限坑 · 来源证据：SEC-005: Express body parser runs before authentication and rate limiting

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：SEC-005: Express body parser runs before authentication and rate limiting
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_e53044f4bde148d7882ccf83273f1e22 | https://github.com/okapi-ca/ms-365-admin-mcp-server/issues/72 | 来源类型 github_issue 暴露的待验证使用条件。

## 8. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | issue_or_pr_quality=unknown

## 9. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | github_repo:1210842314 | https://github.com/okapi-ca/ms-365-admin-mcp-server | release_recency=unknown

<!-- canonical_name: okapi-ca/ms-365-admin-mcp-server; human_manual_source: deepwiki_human_wiki -->
