# Minerva MCP — Microsoft 365 & Azure [Health: Active]

**Category:** 💬 Communication  
**Repository:** https://github.com/HoussemMak/minerva-mcp  
**GitHub Stars:** 0  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/minerva-mcp-microsoft-365-azure

## Description
Microsoft 365 & Azure admin: Graph, ARM, and the PowerShell cmdlets Graph does not expose.

## Tools
Capabilities this server exposes over MCP:

- **microsoft_graph_call** — Any Microsoft Graph call (v1.0 or beta)
- **azure_arm_call** — Any Azure Resource Manager call
- **microsoft_search** — Unified Microsoft Search
- **get_tenant_context** — Organisation, licences, Secure Score
- **generate_security_report** — Tenant security posture
- **execute_exchange_online** — Exchange Online cmdlets
- **execute_pnp_sharepoint** — PnP PowerShell (SharePoint) cmdlets
- **execute_teams_admin** — Teams Admin cmdlets
- **execute_purview_compliance** — Purview / compliance cmdlets

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "minerva-mcp-microsoft-365-azure": {
    "command": "npx",
    "args": ["-y","minerva-mcp","--stdio"]
  }
}
```

## Documentation & README

# Minerva MCP

**Microsoft 365 and Azure administration for AI assistants — including the parts Microsoft Graph cannot reach.**

[![CI](https://github.com/HoussemMak/minerva-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/HoussemMak/minerva-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![MCP 2026-07-28](https://img.shields.io/badge/MCP-2026--07--28-6b46c1.svg)](https://modelcontextprotocol.io/specification/2026-07-28)

An [MCP](https://modelcontextprotocol.io) server that lets Claude, Copilot, VS Code
or any MCP client query and administer a Microsoft 365 tenant in plain language.

---

## Why another Microsoft 365 MCP server?

There are already good ones, and this is not trying to replace them.

| | [Lokka](https://github.com/merill/lokka) | [ms-365-mcp-server](https://github.com/softeria/ms-365-mcp-server) | **Minerva MCP** |
|---|:---:|:---:|:---:|
| Microsoft Graph | ✅ | ✅ 300+ tools | ✅ generic call |
| Azure Resource Manager | ✅ | — | ✅ |
| **Exchange Online cmdlets** | — | — | ✅ |
| **SharePoint / PnP cmdlets** | — | — | ✅ |
| **Teams Admin cmdlets** | — | — | ✅ |
| **Purview / compliance cmdlets** | — | — | ✅ |
| Risk classification per action | — | — | ✅ |
| Human approval before writes | — | read-only switch | ✅ native to the protocol |
| MCP 2026-07-28 (stateless) | — | — | ✅ |

**If you only need Graph, use Lokka or ms-365-mcp-server.** They are excellent,
more mature, and more widely used. Lokka in particular is written by a Microsoft
Entra product manager.

Reach for this one when you hit the wall everyone hits eventually: **a large part
of Microsoft 365 administration has no Graph API.** Mailbox permissions,
transport rules, message trace, retention policies, sensitivity labels, Teams
calling policies, SharePoint term stores, tenant-wide Exchange settings — those
live in PowerShell and nowhere else. This server exposes them, with a
risk classification and a confirmation step in front of anything that writes.

---

## How it fits together

```mermaid
flowchart LR
    A["AI client<br/>Claude · VS Code · Copilot Studio"]
    B["minerva-mcp"]
    C{"Risk<br/>classifier"}
    D["Human<br/>confirmation"]
    G["Microsoft Graph<br/>Azure ARM · Search"]
    P["PowerShell 7<br/>Exchange · PnP · Teams · Purview"]
    M["Microsoft<br/>authorizes the token"]

    A -->|"stdio or HTTP"| B
    B --> C
    C -->|"read"| G
    C -->|"write"| D
    D -->|"signed mandate"| G
    D -->|"signed mandate"| P
    C -->|"read"| P
    G --> M
    P --> M
```

Reads go straight through. Writes stop at a classifier, come back to you as an
`input_required` describing the action and its consequences, and only run once
you confirm. Microsoft still has the final word: the server forwards a token, it
never grants access.

## Install

Nothing to clone. Add it to your client and sign in on first use.

### Claude Desktop

`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "minerva": {
      "command": "npx",
      "args": ["-y", "minerva-mcp", "--stdio"]
    }
  }
}
```

### VS Code

`.vscode/mcp.json`:

```json
{
  "servers": {
    "minerva": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "minerva-mcp", "--stdio"]
    }
  }
}
```

More, including read-only and app-only setups, in [`examples/`](examples/).

On the first tool call the server prints a device-code prompt **on stderr**:
open the link, enter the code, done. No app registration needed to try it — it
uses the public Microsoft Graph PowerShell client by default.

**Requirements:** Node.js 20+. For the PowerShell tools, [PowerShell 7+](https://aka.ms/powershell)
and the modules you intend to use (`ExchangeOnlineManagement`, `PnP.PowerShell`,
`MicrosoftTeams`).

---

## What you can ask

> *"Which mailboxes have full access delegated to someone outside their department?"*
> → `execute_exchange_online` with `Get-MailboxPermission`, no Graph equivalent exists.

> *"Show me every conditional access policy that does not require MFA, and our Secure Score."*
> → `generate_security_report` + `microsoft_graph_call`.

> *"Create a shared mailbox for invoicing and give the finance team access."*
> → classified as a write: the server describes the action and its consequences,
> and waits for your confirmation before doing anything.

---

## Tools

| Tool | What it does | Graph equivalent? |
|---|---|:---:|
| `microsoft_graph_call` | Any Microsoft Graph call (v1.0 or beta) | — |
| `azure_arm_call` | Any Azure Resource Manager call | — |
| `microsoft_search` | Unified Microsoft Search | — |
| `get_tenant_context` | Organisation, licences, Secure Score | — |
| `generate_security_report` | Tenant security posture | — |
| `execute_exchange_online` | Exchange Online cmdlets | ❌ none |
| `execute_pnp_sharepoint` | PnP PowerShell (SharePoint) cmdlets | ❌ none |
| `execute_teams_admin` | Teams Admin cmdlets | ❌ none |
| `execute_purview_compliance` | Purview / compliance cmdlets | ❌ none |

Restrict the surface with `--tools=microsoft_graph_call,get_tenant_context`, or
forbid every write with `--read-only`.

---

## Approval, and why it is not optional

A model reads untrusted content — an email subject, a site name, a document —
and decides which tool to call. Prompt injection is not hypothetical, and the
tools here can delete mailboxes.

So writes do not simply execute. Every action is classified `auto`, `confirmed`
or `critical` from the HTTP verb and path (or the PowerShell verb). Anything
above `auto` makes the server answer `input_required` under
[MCP's Multi Round-Trip Requests](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr):
your client shows what is about to happen and its consequences, you confirm, and
only then does it run.

The confirmation is a signed mandate (HMAC) bound to the caller, the method, and
a digest of the arguments, valid five minutes. A mandate obtained to delete
`/users/1` cannot be replayed on `/users/999`, and cannot be presented by anyone
else.

If your client does not support elicitation, nothing is silently executed: the
server returns an error saying the action needs confirmation.

---

## Options

Every flag has an environment variable equivalent.

### Transport

| Flag | Env | Default | |
|---|---|---|---|
| `--stdio` | `MINERVA_TRANSPORT=stdio` | HTTP | JSON-RPC over stdin/stdout |
| `--port=<n>` | `MCP_SERVER_PORT` | `3001` | HTTP listen port |

In stdio mode **all logs go to stderr** — stdout belongs to the protocol.

### Authentication

| Flag | Env | |
|---|---|---|
| `--auth=<mode>` | `MINERVA_AUTH_MODE` | `bearer`, `device-code`, `client-secret` |
| `--tenant=<id>` | `MINERVA_TENANT_ID`, `AZURE_TENANT_ID` | Entra tenant |
| `--client-id=<id>` | `MINERVA_CLIENT_ID`, `AZURE_CLIENT_ID` | Application |
| `--client-secret=<s>` | `AZURE_CLIENT_SECRET` | App-only secret |

Defaults: `bearer` over HTTP (the caller supplies the token), `device-code` over
stdio, `client-secret` as soon as a secret is present. Each resource gets its own
token: Graph, ARM, Exchange, Purview, SharePoint and Teams do not share an
audience.

### Scope

| Flag | Env | |
|---|---|---|
| `--read-only` | `MINERVA_READ_ONLY` | Refuse every write |
| `--tools=<a,b,c>` | `MINERVA_TOOLS` | Register only these tools |
| `--ps=<mode>` | `MINERVA_PS_EXECUTOR` | `auto`, `redis`, `local`, `none` |
| `--sharepoint-url=<url>` | `MINERVA_SHAREPOINT_URL` | Required by the PnP tool locally |
| `--allowed-origins=<a,b>` | `MINERVA_ALLOWED_ORIGINS` | Browser origins allowed on `/mcp` |
| `--redis-url=<url>` | `REDIS_URL` | Queue for an external PowerShell runner |
| — | `MINERVA_MRTR_SECRET` | Signing key for approval mandates |
| — | `MINERVA_PWSH_PATH` | Path to `pwsh` |
| — | `MINERVA_REQUIRE_VERIFIED_TOKENS` | Refuse tokens whose signature cannot be verified |

`--read-only` reuses the same risk classifier as the approval gate, so it covers
PowerShell cmdlets too, not just HTTP verbs.

---

## Protocol support

Speaks **MCP 2026-07-28**, and still serves handshake-era clients until
**2027-07-28**.

| | |
|---|---|
| Stateless core (per-request `_meta`, no `initialize`, no `Mcp-Session-Id`) | ✅ |
| `server/discover` | ✅ |
| Multi Round-Trip Requests (`input_required`) | ✅ — this is the approval mechanism |
| `MCP-Protocol-Version` / `Mcp-Method` / `Mcp-Name` headers, base64 sentinel | ✅ validated against the body |
| `ttlMs` / `cacheScope` on lists | ✅ always `private` |
| Version negotiation (`-32022` listing supported versions) | ✅ |
| `Origin` validation (anti DNS-rebinding) | ✅ |
| GET/DELETE on the MCP endpoint | ✅ `405`, removed by this revision |
| Handshake era (`initialize`) | ✅ until 2027-07-28 |

One endpoint serves both generations; the request body decides which. Both read
the **same tool registry**, and a test compares them against a frozen contract so
they cannot drift.

---

## Security

Read [SECURITY.md](SECURITY.md) before deploying. The three things that matter:

1. **This server grants nothing.** It forwards a Microsoft token; Microsoft
   authorizes. A restricted token gives a restricted server.
2. **Graph tokens cannot be verified by a third party** — they carry a `nonce`
   header that only Graph can check. Their `tid`/`oid` claims are therefore
   self-reported. The server validates them structurally, flags them
   `verified: false`, and binds approval mandates to a **fingerprint of the token
   itself** rather than to the claims alone. A token that *should* have verified
   and did not is rejected.
3. **Local PowerShell mode isolates nothing.** Cmdlets run with the current
   user's rights. Do not expose it to a caller you do not trust.

Cmdlet names and parameters never reach the script as code: they travel through
environment variables, the name is validated against a strict `Verb-Noun`
pattern, and the call goes through `Get-Command` plus the call operator.

Report a vulnerability privately — see [SECURITY.md](SECURITY.md).

---

## What this does not do

- **No process isolation** in local mode.
- **No multi-tenant brokering** — one server, one identity.
- **No signed audit ledger.** Audit events are JSON on stderr, not a signed,
  offline-verifiable record.

Those three belong to [Minerva-IA](https://github.com/HoussemMak), the commercial
platform this server was extracted from. Everything in this repository works
without it.

---

## Development

```bash
npm install
npm run dev:stdio     # stdio, hot reload
npm run verify        # typecheck + tests + secret scan
npm run build && node scripts/smoke-stdio.mjs
```

Tests need no credentials and touch no network.

Pull requests are closed until 2027-07-31 — see [CONTRIBUTING.md](CONTRIBUTING.md)
for why, and for what is welcome in the meantime (bug reports very much are).

## Licence

MIT — see [LICENSE](LICENSE).

