Enforce the endpoint through client policy
Agent Handler for Employees ends by sharing a URL and trusting people to paste it, which leaves two things open: employees who never get around to it look identical to employees you never reached, and nothing stops someone connecting an ungoverned MCP server beside yours.
Both close in the AI client rather than in Agent Handler. Most clients now ship an enterprise policy layer: a root-owned file or an admin console fixing which MCP servers load, which employees cannot override. Point it at https://ah-api.merge.dev/mcp and the connection arrives on first launch with no step for the employee, and on the strongest clients nothing else arrives with it. Read this once SCIM is syncing and Group access is mapped, since it changes how the URL reaches people, not what they can do with it.
What enforcement does and does not change
Your identity provider decides who exists, Agent Handler decides what each person can call from the tool access you assigned under Manage access → Group access, and the client policy layer decides only whether their AI client connects to you at all.
That separation is what makes a fixed deployment safe. Two employees who receive a byte-identical config file get different tools, because the endpoint answers according to their Groups rather than according to the file. You push the same door to everyone, not the same access.
Each employee still authenticates once, completing SSO through your identity provider and seeing the same consent screen listing what their Groups grant. No client here supports pre-seeding a token, which is the right outcome: a shared token would hand everyone one person’s access instead of their own.
Force-installing reaches employees who are synced but not yet in a mapped Group, and they fall back to Default access. If you left that empty, their AI client connects successfully and shows no tools, which reads to them as broken software rather than as pending configuration. Set Default access, or expect the support tickets. See Managing tool access.
Skills ride the same connection. The client reaches list_skills and retrieve_skill alongside the tool calls once skill retrieval is enabled for your organization, so one push delivers skills too, with nothing copied to the machine and nothing to sync.
How much each client will enforce
Two capabilities matter and get conflated. Delivering the URL to everyone is one. Stopping an employee adding an ungoverned server beside it is the other, and it decides whether the access you mapped is the whole picture.
Start with Claude Code and Codex. They cover most of the work employees bring to an AI client, and each does both jobs through one mechanism.
Every device-side mechanism here is a file or a managed preference, so your MDM’s only job is putting it there. The client reads its own policy continuously and refuses what the policy excludes, so there is no remediation loop and no drift window to size.
Clients that deploy a fixed set
Claude Code
Deploy a managed-mcp.json and Claude Code loads the servers in that file and nothing else. Employees cannot add, modify, or use another server, including one from a project .mcp.json, one a plugin supplies, or one passed with --mcp-config.
Deploy it to the fixed path for each platform
The file has to be root-owned. It is a standalone file rather than a setting, so it cannot travel through server-managed settings.
Confirm it took effect
On a test device, claude mcp list returns the Agent Handler endpoint alone, and adding anything else is refused:
The URL does not have to be real, since the policy check rejects the command before contacting anything. If the employee’s own servers still appear, the file is not being read: check the path and the ownership.
Two softer variants. To let employees keep the servers they add and receive yours as well, list the endpoint under managedMcpServers in a managed settings source instead of deploying the file, which needs Claude Code v2.1.259 or later. To publish an approved catalog rather than a fixed set, set allowedMcpServers with allowManagedMcpServersOnly: true. Without that second key, allowlists merge across every settings scope including the employee’s own ~/.claude/settings.json, so they can widen what you permitted.
managed-mcp.json also hides the claude.ai connectors Claude Code fetches for itself, including any you configured for the organization. If you added Agent Handler as an organization connector as well, following Agent Handler for Employees, set "allowAllClaudeAiMcps": true in a managed settings source so both load. Claude Code honors that key only from admin-controlled tiers, so employees cannot re-enable what exclusive control suppressed.
Codex
Codex splits its policy layer in two, and the split is the point: managed_config.toml sets defaults an employee can change at runtime, and requirements.toml sets constraints they cannot. Use both.
Install the endpoint as a default:
Then pin it as the only permitted server:
Identity matches on URL rather than on the name you gave the server, which is what makes the allowlist worth having: a server renamed to resemble yours does not pass. An mcp_servers table that is present but empty disables MCP altogether.
Both files live at /etc/codex/ on macOS and Linux, and at ~/.codex/ on Windows. On macOS you can deliver them as a managed preference on the com.openai.codex domain instead, with each file base64-encoded into config_toml_base64 and requirements_toml_base64. On a ChatGPT enterprise workspace you can attach the same policy in the cloud, which reaches anyone who signs in to that workspace without touching their machine.
Gemini CLI
A root-owned system settings.json supplies mcpServers employees cannot override, and mcp.allowed restricts what else may load.
Clients that can only block
These cannot install the URL for an employee, so employees still connect it themselves following Agent Handler for Employees. Use the policy layer to keep anything ungoverned from sitting beside it.
Cursor. The Enterprise dashboard allowlists MCP servers by URL pattern, so permitting the Agent Handler endpoint blocks the rest. Allowlisting alone tends to disappoint, because Agent still prefers integrations it already has over a tool surface it has to discover. Add a team rule pointing it at Agent Handler for the systems you granted. The local permissions.json is subordinate to the dashboard, and Cursor documents it as not a security boundary.
Windsurf. The Admin Portal allowlists server IDs by regex, where one entry for the Agent Handler endpoint excludes every other server.
VS Code with Copilot. Provision the endpoint with a user or workspace mcp.json, then enforce with the ChatMCP=registry device policy plus GitHub’s registry-only organization policy. GitHub documents that name matching here is bypassable by editing config, so treat this as provisioning with a filter rather than exclusive control. ChatMCP=none is the hard stop.
Clients with no MCP policy layer
Claude apps (web and desktop). An Owner adds Agent Handler once as an organization custom connector and each employee connects it themselves, which is the flow already covered in Agent Handler for Employees. Claude’s custom connectors authorize per person by design, so this makes your tools available to everyone and mandatory for nobody.
This is usually the largest non-technical population in a company, and it is the honest gap in this path. Govern it on the Agent Handler side instead: keep Group access tight, set Default access deliberately, and read Tool Call Logs to see who actually connected rather than assuming the announcement reached them.
CLI-based tools. Where a policy layer is missing or an employee works across several machines, the Merge CLI is the lighter answer. They run merge login against the same identity provider flow and merge setup claude-code, and their access resolves from their Groups exactly as it does over MCP.
Verify that tools are reaching people
A config that deployed and a tool surface that got used are different things, and your MDM cannot tell them apart. Check both:
- Tool Call Logs. Every call an employee’s client made, with who ran it and whether it succeeded. This is the evidence the endpoint is connected and working, and it needs nothing on the device.
- Employees with no calls at all. A client that received your config and never signed in looks exactly like a machine you never reached. Compare the employees in the logs against your SCIM-synced directory and chase the difference.
The Audit Trail is the third signal and the most useful. Denied calls land there as access requests, so a run of the same tool from one Group means the rollout worked and that Group’s access is too narrow. Widen it in Manage access → Group access rather than granting people one at a time.
Run all three against a canary group of five to ten machines before widening. A config that landed on the fleet and produced calls from six people has landed and is being ignored.
Limits worth stating up front
Tell your security team these before they find them:
- The client layer is client-side. An employee with local admin can edit a file, run an older binary, or set an environment variable that dodges policy. Anthropic’s own documentation calls server-managed settings a client-side control rather than a security boundary. You get compliance by default, and drift that is visible and reversible.
- An employee’s own denylist still applies to your server. In Claude Code,
deniedMcpServersmerges from their settings, so someone can block a managed server for themselves. They cannot put a different one in its place. - Version floors fail quietly.
managedMcpServersneeds Claude Code v2.1.259 or later, and Codex managed configuration needs a recent build. Older installs ignore policy rather than erroring, so confirm versions on the canary group. - Cloud sessions are weaker everywhere. A
managed-mcp.jsonon a workstation does not reach a cloud session, and Copilot’s cloud coding agent ignores registry policy. Those need the vendor’s own cloud policy tier. - Network egress rules cannot see a local server. Egress filtering catches direct-to-server MCP traffic but never a server running on the machine, so client policy is the only layer that covers those.
- The layer that cannot be bypassed from the device is Agent Handler. An unmanaged config cannot authenticate through your identity provider, resolve a Group, or reach a Connector’s stored credentials. Deprovision someone and their tokens are revoked whatever their laptop still has on it, which is the difference between losing enforcement and losing control.
Next
Set what employees can reach once the endpoint lands, in Managing tool access.