# Ms 365 Mcp Server

> A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Office services through the Graph API

- **Type:** MCP server
- **Install:** `agentstack add mcp-softeria-ms-365-mcp-server`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Softeria](https://agentstack.voostack.com/s/softeria)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Softeria](https://github.com/Softeria)
- **Source:** https://github.com/Softeria/ms-365-mcp-server

## Install

```sh
agentstack add mcp-softeria-ms-365-mcp-server
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# ms-365-mcp-server

[](https://www.npmjs.com/package/@softeria/ms-365-mcp-server) [](https://github.com/softeria/ms-365-mcp-server/actions/workflows/build.yml) [](https://github.com/softeria/ms-365-mcp-server/blob/main/LICENSE)

Microsoft 365 MCP Server

A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Microsoft Office services through the Graph
API.

## Supported Clouds

This server supports multiple Microsoft cloud environments:

| Cloud                | Description                        | Auth Endpoint             | Graph API Endpoint              |
| -------------------- | ---------------------------------- | ------------------------- | ------------------------------- |
| **Global** (default) | International Microsoft 365        | login.microsoftonline.com | graph.microsoft.com             |
| **China** (21Vianet) | Microsoft 365 operated by 21Vianet | login.chinacloudapi.cn    | microsoftgraph.chinacloudapi.cn |

## Prerequisites

- Node.js >= 20 (recommended)
- Node.js 14+ may work with dependency warnings

## Features

- Authentication via Microsoft Authentication Library (MSAL)
- Comprehensive Microsoft 365 service integration
- Read-only mode support for safe operations
- Tool filtering for granular access control

## Output Format: JSON vs TOON

The server supports two output formats that can be configured globally:

### JSON Format (Default)

Standard JSON output with pretty-printing:

```json
{
  "value": [
    {
      "id": "1",
      "displayName": "Alice Johnson",
      "mail": "alice@example.com",
      "jobTitle": "Software Engineer"
    }
  ]
}
```

### (experimental) TOON Format

[Token-Oriented Object Notation](https://github.com/toon-format/toon) for efficient LLM token usage:

```
value[1]{id,displayName,mail,jobTitle}:
  "1",Alice Johnson,alice@example.com,Software Engineer
```

**Benefits:**

- 30-60% fewer tokens vs JSON
- Best for uniform array data (lists of emails, calendar events, files, etc.)
- Ideal for cost-sensitive applications at scale

**Usage:**
(experimental) Enable TOON format globally:

Via CLI flag:

```bash
npx @softeria/ms-365-mcp-server --toon
```

Via Claude Desktop configuration:

```json
{
  "mcpServers": {
    "ms365": {
      "command": "npx",
      "args": ["-y", "@softeria/ms-365-mcp-server", "--toon"]
    }
  }
}
```

Via environment variable:

```bash
MS365_MCP_OUTPUT_FORMAT=toon npx @softeria/ms-365-mcp-server
```

## Supported Services & Tools

The server provides 200+ tools covering most of the Microsoft Graph API surface. Each tool maps 1-to-1 to a Graph API endpoint and is defined declaratively in [`src/endpoints.json`](src/endpoints.json).

### Personal Account Tools (Available by default)

Email (Outlook), Calendar, OneDrive Files, Excel, OneNote, To Do Tasks, Planner, Contacts, User Profile, Search

### Organization Account Tools (Requires --org-mode flag)

Teams & Chats, Online Meetings, Transcripts & Recordings, Attendance Reports, SharePoint Sites & Lists, Shared Mailboxes & Calendars, User Management, Presence, Virtual Events

### Required Graph API Permissions

Permissions are requested dynamically based on which tools are enabled. Use `--list-permissions` to see the exact permissions for your configuration:

```bash
# Personal mode (default)
npx @softeria/ms-365-mcp-server --list-permissions

# Organization mode (includes Teams, SharePoint, etc.)
npx @softeria/ms-365-mcp-server --org-mode --list-permissions

# Filtered by preset
npx @softeria/ms-365-mcp-server --preset mail --list-permissions
```

This is useful for enterprise environments where Graph API permissions must be pre-approved and admin-consented before deploying a new version.

The `--list-permissions` JSON includes:

- `toolPermissions`: permissions implied by the tool surface before `--allowed-scopes` filtering
- `effectivePermissions`: permissions implied by the tools that remain enabled after `--allowed-scopes`
- `permissions`: legacy alias for `effectivePermissions`, kept for compatibility with existing scripts
- `allowedScopes`: the configured scope allowlist, when provided
- `disabledTools`: tools hidden because their required Graph scopes are not covered by `allowedScopes`
- `missingAllowedScopesForTools`: unique missing scopes across disabled tools
- `extraAllowedScopesNotUsedByTools`: allowed scopes that are not used by the current tool surface

### Allowed Scopes

By default, MSAL requests the scopes implied by the enabled tools, and the tool surface is controlled by `--enabled-tools`, `--preset`, `--org-mode`, and `--read-only`.

Enterprise and headless deployments can add a scope boundary with `--allowed-scopes` or `MS365_MCP_ALLOWED_SCOPES`. When configured, the server first computes the normal tool surface, then hides Graph tools whose required scopes are not covered by the allowlist. OAuth metadata and login flows request only the effective permissions for the tools that remain enabled.

```bash
npx @softeria/ms-365-mcp-server \
  --org-mode \
  --enabled-tools '^(list-mail-messages|get-mail-message|list-drives|get-drive-item|download-bytes)$' \
  --allowed-scopes 'User.Read Mail.Read Files.Read'
```

CLI value takes precedence over `MS365_MCP_ALLOWED_SCOPES`; if neither is set, the default tool-derived scope behavior is unchanged. Supplying an empty value fails at startup so deployments do not accidentally fall back to a wider tool surface.

Scope coverage is hierarchy-aware: for example, `Mail.ReadWrite` covers tools that require `Mail.Read`, and `Files.ReadWrite.All` covers tools that require `Files.Read`.

In HTTP mode, OAuth discovery advertises the effective filtered permissions so clients request the same consent surface. On-Behalf-Of mode (`--obo`) still advertises `api:///access_as_user` for protected-resource metadata; `--allowed-scopes` does not override OBO.

### Requesting extra scopes

`--allowed-scopes` only ever _narrows_ the token request. To request a Graph scope that no bundled tool needs — for example to drive an endpoint via `graph-batch` — use `--extra-scopes` (or `MS365_MCP_EXTRA_SCOPES`). These scopes are appended verbatim to the token request, on top of the tool-derived scopes.

```bash
npx @softeria/ms-365-mcp-server \
  --org-mode \
  --extra-scopes 'CopilotPackages.ReadWrite.All'
```

This is for use with your own Azure app registration (`MS365_MCP_CLIENT_ID` / `MS365_MCP_CLIENT_SECRET`): the default Softeria app only declares a lean, fixed permission set, so request additional scopes against an app you control (your tenant admin consents to them there). CLI value takes precedence over the env var; an empty value fails at startup.

## Organization/Work Mode

To access work/school features (Teams, SharePoint, etc.), enable organization mode using any of these flags:

```json
{
  "mcpServers": {
    "ms365": {
      "command": "npx",
      "args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
    }
  }
}
```

Organization mode must be enabled from the start to access work account features. Without this flag, only personal
account features (email, calendar, OneDrive, etc.) are available.

## Shared Mailbox Access

To access shared mailboxes, you need:

1. **Organization mode**: Shared mailbox tools require `--org-mode` flag (work/school accounts only)
2. **Delegated permissions**: `Mail.Read.Shared` or `Mail.Send.Shared` scopes
3. **Exchange permissions**: The signed-in user must have been granted access to the shared mailbox
4. **Usage**: Use the shared mailbox's email address as the `user-id` parameter in the shared mailbox tools

**Finding shared mailboxes**: Use the `list-users` tool to discover available users and shared mailboxes in your
organization.

Example: `list-shared-mailbox-messages` with `user-id` set to `shared-mailbox@company.com`

## Quick Start Example

Test login in Claude Desktop:

## Examples

## Integration

### Claude Desktop

To add this MCP server to Claude Desktop, edit the config file under Settings > Developer.

#### Personal Account (MSA)

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

#### Work/School Account (Global)

```json
{
  "mcpServers": {
    "ms365": {
      "command": "npx",
      "args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode"]
    }
  }
}
```

#### Work/School Account (China 21Vianet)

```json
{
  "mcpServers": {
    "ms365-china": {
      "command": "npx",
      "args": ["-y", "@softeria/ms-365-mcp-server", "--org-mode", "--cloud", "china"]
    }
  }
}
```

### Claude Code CLI

#### Personal Account (MSA)

```bash
claude mcp add ms365 -- npx -y @softeria/ms-365-mcp-server
```

#### Work/School Account (Global)

```bash
# macOS/Linux
claude mcp add ms365 -- npx -y @softeria/ms-365-mcp-server --org-mode

# Windows (use cmd /c wrapper)
claude mcp add ms365 -s user -- cmd /c "npx -y @softeria/ms-365-mcp-server --org-mode"
```

#### Work/School Account (China 21Vianet)

```bash
# macOS/Linux
claude mcp add ms365-china -- npx -y @softeria/ms-365-mcp-server --org-mode --cloud china

# Windows (use cmd /c wrapper)
claude mcp add ms365-china -s user -- cmd /c "npx -y @softeria/ms-365-mcp-server --org-mode --cloud china"
```

For other interfaces that support MCPs, please refer to their respective documentation for the correct
integration method.

### Open WebUI

Open WebUI supports MCP servers via HTTP transport with OAuth 2.1.

1. Start the server with HTTP mode:

   ```bash
   npx @softeria/ms-365-mcp-server --http
   ```

2. In Open WebUI, go to **Admin Settings → Tools** (`/admin/settings/tools`) → **Add Connection**:
   - **Type**: MCP Streamable HTTP
   - **URL**: Your MCP server URL with `/mcp` path
   - **Auth**: OAuth 2.1

3. Click **Register Client**.

> **Note**: Dynamic client registration is enabled by default in HTTP mode. Use `--no-dynamic-registration` to disable it. If using a custom Azure Entra app, the platform type for your redirect URI depends on whether the app has a client secret: with a secret use "Web", without one use "Mobile and desktop applications" (never "Single-page application").

**Quick test setup** using the default Azure app (ID `ms-365` and `localhost:8080` are pre-configured):

```bash
docker run -d -p 8080:8080 \
  -e WEBUI_AUTH=false \
  -e OPENAI_API_KEY \
  ghcr.io/open-webui/open-webui:main

npx @softeria/ms-365-mcp-server --http
```

Then add connection with URL `http://localhost:3000/mcp` and ID `ms-365`.

> **Running in Docker behind a reverse proxy?** Set `--public-url https://your-domain.com` so the OAuth authorize URL handed to the user's browser is reachable from outside the container network. See [docs/deployment.md](docs/deployment.md) for the full guide.

### Local Development

For local development or testing:

```bash
# From the project directory
claude mcp add ms -- npx tsx src/index.ts --org-mode
```

Or configure Claude Desktop manually:

```json
{
  "mcpServers": {
    "ms365": {
      "command": "node",
      "args": ["/absolute/path/to/ms-365-mcp-server/dist/index.js", "--org-mode"]
    }
  }
}
```

> **Note**: Run `npm run build` after code changes to update the `dist/` folder.

### Authentication

> ⚠️ You must authenticate before using tools.

The server supports three authentication methods:

#### 1. Device Code Flow (Default)

For interactive authentication via device code:

- **MCP client login**:
  - Call the `login` tool (auto-checks existing token)
  - If needed, get URL+code, visit in browser
  - Use `verify-login` tool to confirm
- **CLI login**:
  ```bash
  npx @softeria/ms-365-mcp-server --login
  ```
  Follow the URL and code prompt in the terminal.

Tokens are cached securely in your OS credential store (fallback to file).

#### 2. OAuth Authorization Code Flow (HTTP mode only)

When running with `--http`, the server **requires** OAuth authentication:

```bash
npx @softeria/ms-365-mcp-server --http 3000
```

This mode:

- Advertises OAuth capabilities to MCP clients
- Provides OAuth endpoints at `/auth/*` (authorize, token, metadata)
- **Requires** `Authorization: Bearer ` for all MCP requests
- Validates tokens with Microsoft Graph API
- **Disables** login/logout tools by default (use `--enable-auth-tools` to enable them)

MCP clients will automatically handle the OAuth flow when they see the advertised capabilities.

##### Setting up Azure AD for OAuth Testing

To use OAuth mode with custom Azure credentials (recommended for production), you'll need to set up an Azure AD app
registration:

1. **Create Azure AD App Registration**:

- Go to [Azure Portal](https://portal.azure.com)
- Navigate to Azure Active Directory → App registrations → New registration
- Set name: "MS365 MCP Server"

2. **Configure Redirect URIs**:

- **Configure the OAuth callback URI**: Go to your app registration and on the left side, go to Authentication.
- Under Platform configurations:
  - Click Add a platform (if you don’t already see one for "Mobile and desktop applications" / "Public client").
  - Choose Mobile and desktop applications or Public client/native (mobile & desktop) (label depends on portal version).

3. **Testing with MCP Inspector (`npm run inspector`)**:

- Go to your app registration and on the left side, go to Authentication.
- Under Platform configurations:
  - Click Add a platform (if you don’t already see one for "Web").
  - Choose Web.
  - Configure the following redirect URIs
    - `http://localhost:6274/oauth/callback`
    - `http://localhost:6274/oauth/callback/debug`
    - `http://localhost:3000/callback` (optional, for server callback)

4. **Get Credentials**:

- Copy the **Application (client) ID** from Overview page
- Go to Certificates & secrets → New client secret → Copy the secret value (optional for public apps)

5. **Configure Environment Variables**:
   Create a `.env` file in your project root:
   ```env
   MS365_MCP_CLIENT_ID=your-azure-ad-app-client-id-here
   MS365_MCP_CLIENT_SECRET=your-secret-here  # Optional for public apps
   MS365_MCP_TENANT_ID=common
   ```

With these configured, the server will use your custom Azure app instead of the built-in one.

#### 3. Bring Your Own Token (BYOT)

If you are running ms-365-mcp-server as part of a larger system that manages Microsoft OAuth tokens externally, you can
provide an access token directly to this MCP server:

```bash
MS365_MCP_OAUTH_TOKEN=your_oauth_token npx @softeria/ms-365-mcp-server
```

This method:

- Bypasses the interactive authentication flows
- Use your pre-existing OAuth token for Microsoft Graph API requests
- Does not handle token refresh (token lifecycle management is your responsibility)

> **Note**: HTTP mode requires authentication. For unauthenticated testing, use stdio mode with device code flow.
>
> **Authentication Tools**: In HTTP mode, login/logout tools are disabled by default since OAuth handles authentication.
> Use `--enable-auth-tools` if you need them available.

## Multi-Account Support

Use a single server instance to serve multiple Microsoft accounts. When more than one account is logged in, an `account` parameter is automatically injected into every tool, allowing you to specify which account to use per tool call.

**Login multiple accounts** (one-time per account):

```bash
# Login first account (device code flow)
npx @softeria/ms-365-mcp-server --login
# Follow the device code prompt, sign in as personal@outlook.com

# Login second account
npx @softeria/ms-365-mcp-server --login
# Follow the device code prompt, sign in as work@company.com
```

**List configured accounts:**

```bash
npx @softeria/ms-365-mcp-server --list-accounts
```

**Use in tool calls:** Pass `"account": "work@company.com"` in any tool request:

```json
{ "tool": "list-mail-messages", "arguments": { "account": "work@company.com" } }
```

**Behavior:**

- With a **single account** configured, it auto-selects (no `account` parameter needed).
- With **multiple accounts** and no `account` parameter, the server u

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Softeria](https://github.com/Softeria)
- **Source:** [Softeria/ms-365-mcp-server](https://github.com/Softeria/ms-365-mcp-server)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-softeria-ms-365-mcp-server
- Seller: https://agentstack.voostack.com/s/softeria
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
