MCP server for CIPP (CyberDrain Improved Partner Portal) — M365 multi-tenant management, users, security, and standards for MSPs
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
- !Licence file present but not machine-readable
claude mcp add cipp-mcp -- npx -y cipp-mcp{
"mcpServers": {
"cipp-mcp": {
"command": "npx",
"args": ["-y", "cipp-mcp"],
"env": {
"CIPP_BASE_URL": "<cipp_base_url>",
"CIPP_CLIENT_SECRET": "<cipp_client_secret>"
}
}
}
}CIPP_BASE_URLCIPP_CLIENT_SECRETMCP Servers overview
# CIPP MCP Server
MCP (Model Context Protocol) server for [CIPP](https://github.com/CyberDrain/CIPP) — the CyberDrain Improved Partner Portal. Provides AI assistants with structured access to CIPP's M365 multi-tenant management capabilities.
## Features
- **49 tools** across 12 categories
- Tenant, user, group, and mailbox management
- Mailbox and online-archive size reporting, per tenant or per user
- Per-user Entra ID sign-in logs (status, location, Conditional Access, MFA)
- Security: Conditional Access policies, named locations, Microsoft Secure Score
- Standards & compliance: BPA, domain health, drift detection
- License reporting (per-tenant and CSP-wide)
- Alerts, audit logs, and scheduled tasks
- GDAP role and invite management
- Stdio and HTTP transport modes
- MCP Gateway compatible
## Prerequisites
- Node.js 18+
- A running CIPP deployment
- CIPP API Key (generated from CIPP Settings → API Client Management)
## Installation
### Via npm (once published)
```sh
npx cipp-mcp
```
### From source
```sh
git clone https://github.com/WYRE-AI/cipp-mcp
cd cipp-mcp
npm install
npm run build
```
## Configuration
Set these environment variables (or copy `.env.example` to `.env`):
| Variable | Required | Description |
|---|---|---|
| `CIPP_BASE_URL` | Yes | Your CIPP **Azure Function App** URL (e.g. `https://cippXXXXX.azurewebsites.net`). **Do not use the SWA / frontend URL** — see [Finding your Function App URL](#finding-your-function-app-url). |
| `CIPP_API_KEY` | One of | Static Bearer token. Use this **or** the OAuth trio below. |
| `CIPP_TENANT_ID` | One of | Entra tenant ID that owns the CIPP API-client app registration. |
| `CIPP_CLIENT_ID` | One of | OAuth client ID issued by CIPP's API Client Management page. |
| `CIPP_CLIENT_SECRET` | One of | OAuth client secret paired with `CIPP_CLIENT_ID`. |
| `CIPP_TOKEN_SCOPE` | No | Override OAuth scope. Default: `api://<clientId>/.default`. An explicit value disables the legacy-scope fallback below. |
| `CIPP_TOKEN_SCOPE_FALLBACK` | No | When no explicit scope is set, retry a CIPP HTTP 401 once with the legacy `<clientId>/.default` scope and reuse whichever audience this client accepts. Default: `true`. `TOKEN_SCOPE_FALLBACK` is an alias. Gateway requests can send `x-token-scope-fallback`. |
| `CIPP_TOKEN_URL` | No | Override OAuth token endpoint (sovereign clouds only). |
| `MCP_TRANSPORT` | No | `stdio` (default) or `http` |
| `AUTH_MODE` | No | `env` (stdio and single-tenant HTTP) or `gateway`. Gateway mode requires CIPP credential headers on each `/mcp` request and does not fall back to `CIPP_*`. The container image and the Compose gateway service set `gateway`. |
| `CONDUIT_S2S_SECRET` | Yes for HTTP | Service-to-service secret shared with the gateway. HTTP logs an error and exits non-zero when this is empty, whitespace, or a known placeholder (`changeme`, `change-me`, `your-s2s-secret`, `your-secret`, `placeholder`, `secret`, `example`, `replace-me`, `replace-with-a-real-secret`, `s2s-secret`, or an unresolved `${...}` value). Compose will not start without it. Never commit a real value. |
| `MCP_ALLOW_INSECURE_DEV` | No | Set to exactly `1` only for local development to start HTTP without `CONDUIT_S2S_SECRET`. The process logs a warning, does not enforce `X-Gateway-S2S`, and listens on `127.0.0.1` only. A non-loopback `MCP_HTTP_HOST` is ignored and the override is logged. This flag does not bypass a known placeholder. |
| `MCP_HTTP_HOST` | No | Bind address when `MCP_TRANSPORT=http` and `CONDUIT_S2S_SECRET` is set. Defaults to `127.0.0.1` when unset. The container image sets `0.0.0.0`. |
| `MCP_HTTP_PORT` | No | Port for HTTP mode (default: 8080) |
| `LOG_LEVEL` | No | `error`, `warn`, `info` (default), or `debug` |
> [!IMPORTANT]
> `CIPP_BASE_URL` must be the **Azure Function App** URL — the CIPP-API backend,
> `https://<function-app-name>.azurewebsites.net` — **not** the Static Web App /
> custom-domain UI URL (e.g. `https://cipp.yourdomain.com`). The SWA's built-in
> auth intercepts bearer tokens and redirects them to its interactive login page,
> so every API call fails. Find the Function App (named like `cippXXXXX`) in your
> CIPP resource group in the Azure Portal.
`/health` stays unauthenticated and does not read credentials. The stdio transport does not use `CONDUIT_S2S_SECRET`.
### HTTP authentication
With `MCP_TRANSPORT=http` and `CONDUIT_S2S_SECRET` set, every `/mcp` request must include `X-Gateway-S2S`. The header value is `t=<unix seconds>,v1=<hex>`, where `v1` is the hex-encoded HMAC-SHA256 of the ASCII string `t=<unix seconds>` keyed with `CONDUIT_S2S_SECRET`. The timestamp must be within 300 seconds of the server clock. A missing or invalid header is HTTP 401, before CIPP credentials are read. The secret is never written to logs.
```
X-Gateway-S2S: t=1710000000,v1=<64 lowercase hex chars>
```
In `AUTH_MODE=gateway`, `/mcp` also requires `x-base-url` plus either `x-api-key` or all of `x-tenant-id`, `x-client-id`, and `x-client-secret` (`x-token-scope`, `x-token-url`, and `x-token-scope-fallback` are optional). Those headers are the only CIPP credential source for that request. A request missing them is HTTP 401 and does not use `CIPP_*` from the process environment.
`AUTH_MODE=env` still requires a valid `X-Gateway-S2S` header, then uses `CIPP_*` from the environment.
Local HTTP without a secret is development-only. It binds `127.0.0.1` even when `MCP_HTTP_HOST` is `0.0.0.0` or another non-loopback address:
```bash
MCP_TRANSPORT=http MCP_ALLOW_INSECURE_DEV=1 npm run dev
```
### Docker
The image listens on `0.0.0.0` inside the container (`MCP_HTTP_HOST`) and defaults to `AUTH_MODE=gateway`. Publish the port on loopback and pass the same S2S secret the gateway uses. In gateway mode, CIPP credentials arrive on each request as headers; they are not read from the environment.
```bash
docker build -t cipp-mcp .
docker run --rm \
-e CONDUIT_S2S_SECRET="$CONDUIT_S2S_SECRET" \
-p 127.0.0.1:8080:8080 \
cipp-mcp
```
Compose refuses to start when `CONDUIT_S2S_SECRET` is unset. The `cipp-mcp` service is gateway mode: it sets `AUTH_MODE=gateway`, publishes `127.0.0.1:8080:8080`, and does not set `CIPP_API_KEY`, `CIPP_CLIENT_ID`, `CIPP_CLIENT_SECRET`, `CIPP_TENANT_ID`, `CIPP_BASE_URL`, or `env_file`.
```bash
CONDUIT_S2S_SECRET="$CONDUIT_S2S_SECRET" docker compose up
```
Single-tenant HTTP (`AUTH_MODE=env`) still requires the S2S secret, then uses `CIPP_*`:
```bash
docker run --rm \
-e CONDUIT_S2S_SECRET="$CONDUIT_S2S_SECRET" \
-e AUTH_MODE=env \
-e CIPP_BASE_URL=https://cippXXXXX.azurewebsites.net \
-e CIPP_TENANT_ID=your-entra-tenant-id \
-e CIPP_CLIENT_ID=your-client-id \
-e CIPP_CLIENT_SECRET=your-client-secret \
-p 127.0.0.1:8080:8080 \
cipp-mcp
```
## Usage with Claude Desktop
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"cipp": {
"command": "node",
"args": ["/path/to/cipp-mcp/dist/entry.js"],
"env": {
"CIPP_BASE_URL": "https://cippXXXXX.azurewebsites.net",
"CIPP_TENANT_ID": "your-entra-tenant-id",
"CIPP_CLIENT_ID": "your-client-id",
"CIPP_CLIENT_SECRET": "your-client-secret"
}
}
}
}
```
> **Note:** `CIPP_BASE_URL` must be the Azure **Function App** URL (`.azurewebsites.net`), not
> the frontend SWA URL (`.azurestaticapps.net` or your custom domain). The SWA enforces
> browser-based auth and will redirect all API requests to a Microsoft login page.
## Tools
| Category | Tools |
|---|---|
| Tenants | list_tenants, get_tenant_details |
| Users | list_users, create_user, edit_user, disable_user, reset_password, reset_mfa, revoke_sessions, offboard_user, bec_check, list_mfa_users, list_user_devices, list_user_groups, list_user_signin_logs |
| Groups | list_groups, create_group |
| Mailboxes | list_mailboxes, list_mailbox_permissions, list_trusted_blocked_senders, list_mailbox_usage, get_mailbox_usage, set_out_of_office, set_email_forwarding |
| Security | list_conditional_access_policies, list_named_locations, get_secure_score, list_secure_score_controls |
| Applications | list_enterprise_apps |
| Standards | list_standards, run_standards_check, list_standard_templates, get_tenant_drift, get_tenant_alignment, create_standard_template, delete_standard_template, list_bpa, list_domain_health |
| Licenses | list_licenses, list_csp_licenses |
| Alerts | list_audit_logs, list_alert_queue |
| GDAP | list_gdap_roles, list_gdap_invites |
| Scheduler | list_scheduled_items, add_scheduled_item |
| Core | ping, get_version, list_logs |
### Editing a user right after creating it
`edit_user` first resolves the account's current UPN, because CIPP's
`Invoke-EditUser` rebuilds the UPN from `username` + `Domain` on every call and
editing without it would rename the account. Graph can lag a few seconds behind
a just-created account, so when that lookup finds nothing, answers HTTP 404, or
fails with a 5xx whose body is Graph's not-found (the `Request_ResourceNotFound`
code, or Graph's "Resource '<id>' does not exist or one of its queried
reference-property objects are not present" message), it is retried up to 4 attempts in total, waiting 1s, 3s and
6s (~10s). The decision uses the HTTP status, not message text; any other 4xx
(400, 401, 403) and other 5xx are not retried. If the user still isn't visible
the error says "Tried N times" and, when the last attempt got an HTTP error,
its status; wait a moment and retry.
### Mailbox and archive sizes
`list_mailbox_usage` reports every mailbox in a tenant — primary size, item
count, quota, percent of quota, and the same four figures for the online
archive — sorted largest first, with tenant-wide totals that cover every
mailbox even when only the top rows are returned.
**It requires CIPP's reporting database to have been synced for that tenant.**
This is not a design choice: `Invoke-ListMailboxes`' live Exchange query selects
no size fields at all, so the cache is the only tenant-wiWhat people ask about cipp-mcp
What is WYRE-AI/cipp-mcp?
+
WYRE-AI/cipp-mcp is mcp servers for the Claude AI ecosystem. MCP server for CIPP (CyberDrain Improved Partner Portal) — M365 multi-tenant management, users, security, and standards for MSPs It has 11 GitHub stars and its last recorded update is dated 2026-10-21.
How do I install cipp-mcp?
+
You can install cipp-mcp by cloning the repository (https://github.com/WYRE-AI/cipp-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is WYRE-AI/cipp-mcp safe to use?
+
Our security agent has analyzed WYRE-AI/cipp-mcp and assigned a Trust Score of 80/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains WYRE-AI/cipp-mcp?
+
WYRE-AI/cipp-mcp is maintained by WYRE-AI. The last recorded GitHub activity is dated 2026-10-21, with 4 open issues.
Are there alternatives to cipp-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy cipp-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/wyre-ai-cipp-mcp)<a href="https://claudewave.com/repo/wyre-ai-cipp-mcp"><img src="https://claudewave.com/api/badge/wyre-ai-cipp-mcp" alt="Featured on ClaudeWave: WYRE-AI/cipp-mcp" width="320" height="64" /></a>More MCP Servers
Reverse engineer anything with agents, from app behavior down to native binaries.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev