> This page is for Agent Handler.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.merge.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.merge.dev/_mcp/server.

# Enforce the endpoint through client policy

> How to push https://ah-api.merge.dev/mcp to every employee through Claude Code managed MCP, Codex managed configuration, and the admin consoles of Cursor, Windsurf, Copilot, and Gemini CLI, and what each client can enforce.

[Agent Handler for Employees](/merge-agent-handler/setup/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.

> **Check Default access before you push to everyone**
>
> 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](/merge-agent-handler/administer/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](/merge-agent-handler/build/skills/overview) 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.

| Client                                  |         Delivers the URL         | Blocks other servers | Where the policy lives                                                                      |
| --------------------------------------- | :------------------------------: | :------------------: | ------------------------------------------------------------------------------------------- |
| **Claude Code**                         |                Yes               |  Yes, automatically  | `managed-mcp.json` on the device, or managed settings                                       |
| **Codex** (CLI, IDE extension, desktop) |                Yes               |          Yes         | `/etc/codex/` files, the `com.openai.codex` managed preference, or ChatGPT workspace policy |
| **Gemini CLI**                          |                Yes               |          Yes         | Root-owned system `settings.json`                                                           |
| **Cursor**                              |                No                |          Yes         | Cursor Business or Enterprise dashboard                                                     |
| **Windsurf**                            |                No                |          Yes         | Windsurf Admin Portal                                                                       |
| **VS Code with Copilot**                |          Provision only          |        Partly        | Device policy plus GitHub organization policy                                               |
| **Claude apps** (web and desktop)       | No, employees connect themselves |          No          | claude.ai organization settings                                                             |

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.

> **Your MDM places the file, the client enforces it**
>
> 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`.

#### Write the file

**`managed-mcp.json`**

```json managed-mcp.json
{
  "mcpServers": {
    "agent-handler": {
      "type": "http",
      "url": "https://ah-api.merge.dev/mcp"
    }
  }
}
```

#### 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.

| Platform      | Path                                                       |
| ------------- | ---------------------------------------------------------- |
| macOS         | `/Library/Application Support/ClaudeCode/managed-mcp.json` |
| Linux and WSL | `/etc/claude-code/managed-mcp.json`                        |
| Windows       | `C:\Program Files\ClaudeCode\managed-mcp.json`             |

#### Confirm it took effect

On a test device, `claude mcp list` returns the Agent Handler endpoint alone, and adding anything else is refused:

```shell
claude mcp add --transport http test https://example.com/mcp
# Cannot add MCP server: enterprise MCP configuration is active and has exclusive control over MCP servers
```

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.

#### Have each employee sign in once

The endpoint arrives needing sign-in. The employee authenticates from the `/mcp` panel, or with `claude mcp login agent-handler`, and their Groups resolve from there.

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.

> **The file suppresses your claude.ai connectors too**
>
> `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](/merge-agent-handler/setup/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:

**`managed_config.toml`**

```toml managed_config.toml
[mcp_servers.agent_handler]
url = "https://ah-api.merge.dev/mcp"
auth = "oauth"
```

Then pin it as the only permitted server:

**`requirements.toml`**

```toml requirements.toml
[mcp_servers.agent_handler]
identity = { url = "https://ah-api.merge.dev/mcp" }
```

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](/merge-agent-handler/setup/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](/merge-agent-handler/setup/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](/merge-agent-handler/observe/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](/merge-agent-handler/build/cli/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:

1. **[Tool Call Logs](/merge-agent-handler/observe/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.
2. **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](/merge-agent-handler/administer/scim-provisioning)-synced directory and chase the difference.

The [Audit Trail](/merge-agent-handler/observe/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, `deniedMcpServers` merges 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.** `managedMcpServers` needs 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.json` on 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](/merge-agent-handler/administer/managing-tool-access).