Microsoft Entra SCIM 2.0 Provisioning API: user and group lifecycle, with a local mock.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent โ or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag โ we're steadily working through the catalog.
๐ก Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Model Context Protocol server for the Microsoft Entra SCIM 2.0 Provisioning API (GA April 2026). Exposes user and group lifecycle operations against https://graph.microsoft.com/rp/scim as MCP tools for agents like Claude.
get_service_provider_config, list_resource_types, list_schemas)Before this server can talk to your tenant, complete the one-time setup in the Microsoft docs:
User.ReadWrite.All, Group.ReadWrite.All (core lifecycle)CustomSecAttributeAssignment.ReadWrite.All, CustomSecAttributeDefinition.Read.All (CSA tools)User-LifeCycleInfo.ReadWrite.All (lifecycle tools)User-Mail.ReadWrite.All, User-Phone.ReadWrite.All, User.EnableDisableAccount.All (least-privilege alternatives)
Grant admin consent.Every SCIM API call is billed โ this server does not batch beyond what the API requires.
The package ships a local mock of the Entra SCIM API (entra-scim-mock-server) so you can drive every tool with zero Azure setup and zero API billing:
Then point the MCP server at it:
Mock flags: --port, --token, --seed <file.json>, --no-seed, --capture <file.jsonl> (log every request/response), --validator-compat (RFC-standard behavior for the Microsoft SCIM Validator โ see docs/scim-validator.md).
The server is a stdio MCP server, designed to be launched by your MCP client (Claude Desktop, Claude Code, etc.).
Required environment:
| Var | Required | Description |
|---|---|---|
ENTRA_TENANT_ID | yes | Directory (tenant) GUID |
ENTRA_CLIENT_ID | yes | App registration (client) GUID |
ENTRA_CLIENT_SECRET | one of | Client secret value (dev) |
ENTRA_CLIENT_CERT_PATH | one of | Path to a PEM containing the certificate and private key |
ENTRA_CLIENT_CERT_PASSWORD | optional | Password if the PEM is encrypted |
Set exactly one of ENTRA_CLIENT_SECRET or ENTRA_CLIENT_CERT_PATH.
| Var | Description |
|---|---|
ENTRA_SCIM_BASE_URL | Override the SCIM base URL (default https://graph.microsoft.com/rp/scim). Point it at the local mock. |
ENTRA_SCIM_STATIC_TOKEN | Use a fixed bearer token instead of Azure AD. Guardrails: requires ENTRA_SCIM_BASE_URL, refuses any *.microsoft.com / *.microsoft.us host, warns on non-loopback hosts, and cannot be combined with a real credential. Tenant/client IDs are not required in this mode. |
ENTRA_SCIM_DRY_RUN | Set to 1: tools run all client-side validation, then return the exact request that would have been sent instead of sending it. No token is acquired โ works with zero credential config. |
Dry-run results come back as a successful payload:
(DELETE carries no Accept header โ the API rejects a specific JSON media type there. Every other method sends Accept: application/json.)
Multi-request tools (e.g. add_group_members beyond 20 ids) surface only their first chunked request in dry-run.
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
For production, swap the secret for a certificate:
The Kind column is the tool's MCP annotations, which is what a client reads
when it decides whether a call needs your approval: read is readOnlyHint,
add is a write that only creates (destructiveHint: false), overwrite is a
write that discards or replaces state with no undo through this API
(destructiveHint: true).
| Tool | Kind | Purpose |
|---|---|---|
get_service_provider_config | read | One-shot capability discovery. Static per API version โ fetch once and reuse. |
list_resource_types | read | Enumerate SCIM resource types (User, Group). |
list_schemas | read | Enumerate SCIM schemas and Entra extensions, with each attribute's type, mutability and default-return. Check a patch path here before building it. |
list_users | read | List users; supports the API's restricted filter (eq/ew, and-only) and cursor pagination. Also how you resolve a userName to the object id every other user tool wants. |
get_user | read | Read a single user by id with optional attribute projection. Neither CSAs nor group membership are ever included. |
provision_user | add | Create a user with the required attribute set enforced (userName, password, displayName, name.givenName, name.familyName, mailNickname). |
update_user | overwrite | PATCH a user; blocks remove of mailNickname and enforces [type eq "work"] on address paths. |
deprovision_user | overwrite | DELETE a user. Soft-deleted for 30 days, restorable only via Graph; also strips every group membership. |
update_user_lifecycle | overwrite | Set lifecycle attrs (e.g. employeeLeaveDateTime) โ which Lifecycle Workflows can fire off. Requires User-LifeCycleInfo.ReadWrite.All. |
get_user_custom_security_attributes | read | Read a user's CSAs, projected by attribute set. attributeSets is required โ the API rejects the bare extension URN, and CSAs never come back from a plain get_user. |
update_user_custom_security_attributes | overwrite | PATCH CSAs on a user. remove, or replace with an empty array, deletes an assignment. |
list_groups | read | List groups with the API's restricted filter set. A members.value filter is the only way to read membership. |
get_group | read | Read a single group (members are NOT returned โ use list_groups with a members.value filter). |
create_group | add | POST a group. Sets mailEnabled, securityEnabled, mailNickname, description via the Entra extension. displayName is not unique. |
update_group | overwrite | PATCH group attributes only (membership ops are rejected here; type flags are fixed at creation). |
add_group_members | add | Add โฅ1 users to a group โ auto-chunks at 20 ids per PATCH (API cap), one Operation per PATCH. Idempotent. Each PATCH is atomic per RFC 7644, but a multi-chunk sequence is not: if a later chunk fails, this server (not the API) raises AddGroupMembersPartialFailure naming addedMemberIds / failedMemberIds / notAttemptedMemberIds, so a partial write is never silent. |
remove_group_member | overwrite | Remove a single user from a group (the API allows only one removal per PATCH, with no other ops). A 404 here usually means not a member, not no such group. |
delete_group | overwrite | DELETE a group. Unified groups are recoverable for 30 days via Graph; security groups are not. |
A model never reads this file, so everything it needs has to travel in the protocol. Three places carry it, and the split is deliberate:
provision_user that conflicts rather than merges.path example, because path syntax is the one thing here
that cannot be guessed: the API accepts a narrow subset of RFC 7644, and the
subset differs between ordinary attributes and CSAs.No reviews yet โ be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/microsoft-entra-scim)<a href="https://allmcps.com/mcp/microsoft-entra-scim"><img src="https://allmcps.com/api/badge/microsoft-entra-scim?style=directory" alt="Microsoft Entra SCIM on AllMCPs" /></a>