m365-governed-mcp
# m365-governed-mcp
A **governance-first** [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for **Microsoft 365 and SharePoint**.
It lets an AI assistant reach enterprise content through a **governed adapter** instead of a brittle, over-permissioned integration. The core principle: **the AI only ever sees what the signed-in person is allowed to see.**
> **Status: v0.5.0.** Delegated **`search`**, **`get_list_items`**, and **`get_file`** tools that read your Microsoft 365 content **as the signed-in user**, so results are security-trimmed by construction. Sign-in **opens your browser automatically** (device-code fallback). `about` and `governance_model` describe the server.
## Why a governed MCP server?
Most "M365 MCP" servers use **app-only** permissions, so the AI can read anything in the tenant and quietly overshare. This server is built the other way around:
- **Delegated authentication** — it calls Microsoft Graph *as the user*, so results are security-trimmed by construction.
- **Least privilege** — read-oriented scopes by default; writes are explicit and confirmable.
- **Auditable** — every tool call is logged (who, what, when).
- **Oversharing- and sensitivity-aware** — flags broadly shared or labeled items instead of hiding the risk.
- **Local by default** — runs on the user's machine over stdio; **no hosted service, so credentials and data never leave the device.**
## Prerequisites
**On your machine**
- **Node.js 18+** (provides `npx`, which runs the server on demand — no clone or build needed).
- **An MCP client that supports local (stdio) servers** — e.g. **Claude Code** or an IDE MCP client. Note: the current **Claude Desktop (Fable) build only accepts remote *URL* connectors**, so it can't host this local server yet; use Claude Code for now.
**In your Microsoft 365 tenant — one Azure AD app registration**
The tools sign you in and call Microsoft Graph **as you**, so you need a public-client app registration in your tenant (one-time, ~3 minutes). Do it with the [setup script](#quick-setup-script) below, or by hand:
1. **Entra admin center → App registrations → New registration.** Name it e.g. `m365-governed-mcp`. Supported account types: *Accounts in this organizational directory only*. Register.
2. Copy the **Application (client) ID** and **Directory (tenant) ID** from the Overview page.
3. **API permissions → Add a permission → Microsoft Graph → Delegated** → add `Sites.Read.All` and `Files.Read.All`. Grant admin consent if your tenant requires it.
4. **Authentication → Allow public client flows → Yes.** (Enables the device-code fallback.)
5. **Authentication → Add a platform → Mobile and desktop applications → redirect URI `http://localhost`.** (Enables the interactive browser sign-in.) Save.
No client secret or certificate — it's a public client using delegated permissions.
### Quick setup script
Instead of the manual steps, run [`scripts/New-M365GovernedMcpApp.ps1`](scripts/New-M365GovernedMcpApp.ps1) (needs the `Microsoft.Graph` PowerShell module; sign in as an admin). It creates the app registration with all the settings above, grants admin consent, and prints your `TENANT_ID` and `CLIENT_ID` plus a ready-to-paste config block:
```powershell
Install-Module Microsoft.Graph -Scope CurrentUser # if not already installed
./scripts/New-M365GovernedMcpApp.ps1
```
## Install
No install needed — your MCP client runs it on demand with `npx`. Provide your `TENANT_ID` and `CLIENT_ID` in the `env` block.
### Claude Code (recommended)
```bash
claude mcp add m365-governed -e TENANT_ID=<your-tenant-id> -e CLIENT_ID=<your-app-client-id> -- npx -y @gvijaikumar9/m365-governed-mcp
```
Or add it to a project `.mcp.json`:
```json
{
"mcpServers": {
"m365-governed": {
"command": "npx",
"args": ["-y", "@gvijaikumar9/m365-governed-mcp"],
"env": { "TENANT_ID": "<your-tenant-id>", "CLIENT_ID": "<your-app-client-id>" }
}
}
}
```
### Claude Desktop
> Local (stdio) servers work in Claude Desktop builds that read `claude_desktop_config.json`. The newest **Fable** build accepts only remote URL connectors — if you're on that build, use Claude Code instead.
Add to `claude_desktop_config.json` (Windows: `%APPDATA%\Claude\`, macOS: `~/Library/Application Support/Claude/`):
```json
{
"mcpServers": {
"m365-governed": {
"command": "npx",
"args": ["-y", "@gvijaikumar9/m365-governed-mcp"],
"env": {
"TENANT_ID": "<your-tenant-id>",
"CLIENT_ID": "<your-app-client-id>"
}
}
}
}
```
Restart Claude Desktop, then ask it to search your content. On first use it **opens your browser to sign in** — after that you're signed in for the session. (If a browser can't be opened, it falls back to a device-code link.)
## Tools (v0.5.0)
| Tool | Description |
|------|-------------|
| `search` | Search your M365 files and list items **as the signed-in user** (security-trimmed). Args: `query` (required), `size` (1-25, default 10). |
| `get_list_items` | Read items from a named SharePoint list **as the signed-in user** (security-trimmed). Args: `site` (site URL, required), `list` (display name, required), `top` (1-100, default 20). |
| `get_file` | Read a document's content **as the signed-in user** (security-trimmed). Text for text-based files; metadata only for Office/binary. Args: `url` (file URL, required), `max_chars` (default 20000). |
| `about` | Purpose, version, status, and how the server runs. |
| `governance_model` | The delegated-auth, least-privilege, audited, sensitivity-aware design. |
## Roadmap
- **v0.3** ✅ — interactive browser sign-in (smoother than device code), with device-code fallback.
- **v0.4** ✅ — `get_list_items` (read a named SharePoint list) + a one-command app-registration setup script.
- **v0.5** ✅ — `get_file` (read a document's content).
- **Next** — persistent token cache; oversharing and sensitivity-label flags on results; a local audit log; more tools (`list_sites`, `list_files`).
## License
[MIT](LICENSE) © Vijay Kumar Gilakattula
TDQS
Scored across 3 tools
The three tools serve clearly separate purposes: search performs content lookup, about provides server metadata, and governance_model explains design philosophy. No overlap exists between them.
Naming is inconsistent: 'search' is a terse verb, 'about' is a generic noun, and 'governance_model' is a compound noun with an underscore. No clear pattern or verb_noun convention emerges.
With only three tools, the set is lean but not unreasonably thin for a search-centric server. The 'about' and 'governance_model' tools are meta but serve onboarding and trust purposes, making the count feel purposeful albeit limited.
The domain appears to be Microsoft 365 content search, but the surface is severely limited—no ability to retrieve actual file items, list data, or perform any CRUD. Even basic 'get item' or 'list sites' operations are absent, forcing agents to rely solely on vague search results.