> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lumos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Governance: Deploying to Your Fleet

> Deploy MCP Governance across your organization with Jamf, Intune or Kandji.

This guide explains how to deploy MCP Governance across your organization with your MDM, so every device reports and enforces without anyone having to touch a laptop.

# Deploy MCP Governance across your fleet

MCP Governance records and controls every MCP tool call your employees' AI agents make. This guide is how you get it onto a whole company rather than one machine at a time.

<Note>
  **Looking for the Lumos MCP servers?**

  This page is about governing the MCP servers *your employees' agents* call. If you are trying to connect an AI client *to Lumos*, see the [Lumos User MCP Server](/docs/mcp) or the [Lumos Admin MCP Server](/docs/lumos-admin-mcp).
</Note>

<Info>
  **Early access.** The MDM steps below are written from the product's design and have not yet been verified end to end. Lumos is looking for design partners to run the first rollouts. Talk to your Lumos contact before scoping this to a large fleet.
</Info>

## Pick your path first

There are two ways to install MCP Governance. Your choice determines whether your policies can be trusted.

| | Per-user install | MDM deployment |
| - | - | - |
| How it goes on | Each person runs one command from the install page | Your MDM enrolls every device once |
| Who has to act | Every employee | One admin |
| Identity | Self-reported by the agent's local config | Bound to your IdP user id at enrollment |
| Coverage reporting | None — "never installed" and "installed" look the same | The Devices tab shows every machine's state |
| Use it for | A pilot, up to \~25 people | Everything else |

**Per-user install is a pilot tool.** The install page issues an enrollment token scoped to that one person, and they run the command themselves. Two consequences: the email the agent reports comes from a file in that person's own home directory, which they can edit, and the person who installed the hooks can remove them.

That is fine for a proof of concept, where the point is to see what your agents are doing. It is not a basis for a policy that says *this person may not call that tool*. If you intend to block anything, deploy by MDM.

The rest of this guide assumes MDM.

## Before you begin

You need:

* A Lumos account with Organization Admin, and MCP Governance enabled on your domain.

* Jamf, Intune or Kandji, with the authority to scope a script and a configuration profile to your fleet.

* Claude Code or Codex on the target machines.

* A device inventory export from your MDM as CSV, carrying at minimum each device's serial and its owner's Okta user id or Entra object id.

## How it works

Your MDM does two things: it runs a one-time enrollment script on each device, and it pushes a hook config for each AI agent in use. Nothing from Lumos is installed — the script writes a single device token, and the hook is a `curl` invocation.

From then on, every MCP tool call on that device is checked against your policies before it runs and logged after it runs, attributed to the person your inventory names for that machine.

Devices move through three states, visible on the Devices tab:

* **Pending** — the device is in your uploaded inventory but the enrollment script has not run on it yet.
* **Enrolled** — the script has run, the device holds a token, and its tool calls are being attributed to its owner.
* **Refused** — a machine tried to enroll with a serial that is not in your inventory.

**Refused is a feature, not just an error.** A refused attempt still appears on the Devices tab, which means you find out that someone is running an agent on a machine you were not governing. Review refused rows as part of your rollout: move the ones you recognise to Pending and they become eligible to enroll, and treat the ones you don't recognise as something to investigate.

<Warning>
  **Read this before you touch the Claude console.**

  If your organization uses server-managed settings in the Claude console (Admin Settings → Claude Code → Managed settings), do not paste the hook config into the console until every device is enrolled. Console settings reach every Claude Code install in the organization at once, and a machine that has no device token yet will have all of its tool calls denied.

  The safe order is: enroll the fleet first, confirm the Devices tab, then change the console.
</Warning>

## 1. Import your device inventory

Export your device list from your MDM as CSV and upload it in Lumos at **MCP tool usage → Devices → Import**.

| Column | Required | What it does |
| - | - | - |
| `serial` | Yes | What the device proves at enrollment. |
| `stable_identifier` | Yes, unless `email` is set | The owner's Okta user id or Entra object id. Tool calls are attributed to this person. When blank, Lumos looks it up from `email`. |
| `udid` | No | Your MDM's own device id. |
| `email` | No | Shown next to the device. Used to look up the owner when `stable_identifier` is blank. |
| `hostname` | No | The machine's name, shown beside its serial. Lumos also accepts `Computer Name`, `Device name`, or `name` as the header, so a Jamf or Intune export uploads as downloaded. |

Header names are case-insensitive and order does not matter. Lumos previews the import before writing anything.

Re-importing updates each listed serial's owner, `udid`, `email`, and name. A blank `udid` or `email` cell clears that value, but a blank name never does. An owner an admin assigned by hand is kept. A **Retired** device whose serial is in the file returns to **Pending**, so leave retired machines out of the file. A **Refused** serial that is now in the file also becomes **Pending** and can enroll. Other statuses, and each device's token and timestamps, stay as they are.

A name from the file wins over the name the machine reports when it enrolls. A blank name cell never erases a name Lumos already has, so a file without names leaves existing names in place. On macOS, the enrollment script reports the machine's Computer Name (the name your MDM shows) rather than its DNS hostname.

Every device you upload lands as **Pending**. Scope the import to the machines you intend to govern: a serial that is not in the inventory cannot enroll.

## 2. Create an enrollment token

In Lumos, go to **Settings → API Tokens → Add** and choose **MCP Enrollment Token**. Name it after the rollout, pick a lifetime, and copy the `lmcpe_` value — it is shown once.

Only a Lumos admin can create one. A single token enrolls as many devices as you need, but only serials that are already in your inventory.

<Tip>
  On Jamf the token goes in the policy rather than the script. On Intune and Kandji it has to sit in the script body, so pick the shortest lifetime that covers your rollout window and delete the script afterwards.
</Tip>

## 3. Push the enrollment script

The script runs once per device, as root. It writes the device token to `/Library/Lumos/device-token` and nothing else.

<Tabs>
  <Tab title="Jamf">
    Go to **Settings → Computer Management → Scripts** and create a script:

    ```shell theme={null}
    #!/bin/sh
    curl -fsSL https://mcp-governance.lumos.com/enroll.sh | sudo LUMOS_ENROLL_TOKEN="$4" sh
    ```

    Then create a **Policy** that runs it:

    * **Scope:** the smart group covering your fleet — not a static list, or new hires will silently miss enrollment.
    * **Parameter 4:** the `lmcpe_` token. Keeping it in the policy rather than the script means the token is not sitting in your script library.
    * **Trigger:** recurring check-in, plus enrollment complete so new machines pick it up automatically.
    * **Execution frequency:** once per computer.
  </Tab>

  <Tab title="Intune">
    Go to **Devices → Scripts → Add → macOS**, with the token inline:

    ```shell theme={null}
    #!/bin/sh
    curl -fsSL https://mcp-governance.lumos.com/enroll.sh | sudo LUMOS_ENROLL_TOKEN="lmcpe_..." sh
    ```

    * **Run as signed-in user:** No.
    * **Script frequency:** once is enough; the script is safe to re-run.
    * **Assignment:** the group covering your fleet, so new machines pick it up on enrollment.

    **Delete the script once the rollout is complete.** Anyone who can read your Intune script library can read the token until you do.
  </Tab>

  <Tab title="Kandji">
    Go to **Library → Add New → Custom Script**, with the token inline:

    ```shell theme={null}
    #!/bin/sh
    curl -fsSL https://mcp-governance.lumos.com/enroll.sh | sudo LUMOS_ENROLL_TOKEN="lmcpe_..." sh
    ```

    * **Execution frequency:** run once per device. The script is safe to re-run if you need to.
    * **Blueprint:** assign to the blueprints covering your fleet, so newly enrolled Macs pick it up automatically.

    **Delete the Library item once the rollout is complete**, and mint a fresh token if you need to enroll more devices later.
  </Tab>
</Tabs>

## 4. Push the hook config

Download the config for each agent in use and push it as managed settings. Do not edit the command inside it.

| Agent | Config URL | Destination |
| - | - | - |
| Claude Code | `https://mcp-governance.lumos.com/hooks/claude_code/config` | `/Library/Application Support/ClaudeCode/managed-settings.json` |
| Codex | `https://mcp-governance.lumos.com/hooks/codex/config` | `hooks.json` in the `managed_dir` named by `requirements.toml`, with `allow_managed_hooks_only = true` |

Append `?capture=none` to the URL if tool arguments must never leave the device. Policies that match on tool input will then never match.

<Tabs>
  <Tab title="Jamf">
    Push it as a configuration profile scoped to the same smart group as the enrollment policy.
  </Tab>

  <Tab title="Intune">
    Push it as a custom `.mobileconfig` profile, assigned to the same group as the enrollment script.
  </Tab>

  <Tab title="Kandji">
    Push it as a Custom Profile, assigned to the same blueprints as the enrollment script.
  </Tab>
</Tabs>

Users see a one-time approval dialog for the hooks the next time their agent starts.

## 5. Verify

A device is done when its row on the Devices tab reads **Enrolled** and its tool calls appear on MCP tool usage under the right person.

Compare your MDM's own success count against the enrolled count in Lumos — a smart group in Jamf, the script success count in Intune, the Library item status in Kandji. Investigate anything that stays **Pending**: that means the script has not run on that device yet, so start with the scope and your MDM's run log.

## The rollout, in four stages

Enrollment is the mechanical part. Getting from "installed" to "enforcing" without breaking anyone's work is the part worth pacing.

<Steps>
  <Step title="Pilot (about a week)">
    **Do:** 5 to 10 devices, chosen from people who use agents heavily. Enroll them through the MDM path, not the install page, so you are testing what you will actually run.

    **Don't:** write any policies.

    **Move on when:** every pilot device reads **Enrolled**, tool calls are appearing under the right person, and you recognise the MCP servers showing up in Inventory.
  </Step>

  <Step title="Fleet enrollment (one to two weeks)">
    **Do:** import the full device inventory, mint an enrollment token, scope the enrollment script and the hook config to the whole fleet.

    **Don't:** write any policies yet. Nothing blocks at this stage, by design — you are buying coverage, not control.

    **Move on when:** the Devices tab shows the enrolled count matching your fleet, every **Refused** row has been reviewed — moved to Pending if you recognise it, investigated if you don't — and no row has been **Pending** for more than a few days.
  </Step>

  <Step title="Observe (at least two weeks)">
    **Do:** read the events. Which MCP servers are in use, by whom, and which tools. Mark servers **Approved** or leave them **Needs Review** in Inventory. Write your *allow* policies now — they change nothing on their own, and writing them against real observed usage is how you avoid blocking work you didn't know existed.

    **Don't:** write deny policies.

    **Move on when:** every MCP server your people actually use has been reviewed and given a status, and you can name the handful of tool calls you intend to stop.
  </Step>

  <Step title="Enforce">
    **Do:** add deny policies, narrowest first — a specific tool on a specific server, or a specific group. Watch the events for a week before widening. A blocked call fails with the policy name in the message, so the employee knows why and who to ask.

    **Don't:** open with an org-wide default-deny. Start with the calls you can justify blocking to the person they affect.

    **Done when:** your deny policies hold, the blocks you see are the ones you intended, and support volume has settled.
  </Step>
</Steps>

## Keeping it running

* **New hires.** A new device appears in your MDM, flows into the Lumos inventory, and the enrollment policy runs on it. Check the policy is scoped to a dynamic group rather than a static list of machines.
* **Token expiry.** Enrollment tokens have a lifetime. Devices already enrolled keep working when a token expires; new devices stop enrolling. Diarise the expiry.
* **Re-imaged or replaced machines.** Re-running the enrollment script re-enrolls the device with a fresh token.
* **Lost, stolen or offboarded machines.** Revoke the device on the Devices tab. Revocation is per device and takes effect immediately: that machine's token stops working and nothing else in your fleet is affected. Make this a step in your existing lost-device and offboarding runbooks.

## Troubleshooting

### A device shows Refused

A machine presented a serial that is not in your inventory. Add the serial to your CSV and re-import, or move the row to Pending from the Devices tab, and it becomes eligible to enroll.

### A row stays Pending

The enrollment script has not run on that device yet. Check your MDM policy scope and its run log.

### An Enrolled device has a rising refusal count

A second device is presenting that serial, or the script ran twice. Revoke the device, then let the script re-run.

### The enrollment token has a rising refusal count

Devices outside your inventory are presenting it. Check your MDM scope, and revoke and re-mint the token if it has leaked.

### The script logs "the enrollment token is unknown, expired or revoked"

The token is dead. Create a new one and update your MDM policy.

### A device shows Enrolled but no tool calls appear

Claude Code is ignoring the hook config your MDM pushed, because your organization has server-managed settings in the Claude console. Run `/status` in Claude Code — the file is listed under "Skipped sources". Apply one of the console fixes, then restart Claude Code.

### An agent's tool calls are all denied

The device is revoked, or its token file was deleted. Re-run the enrollment script; it enrolls the device with a fresh token.

## Security review

Your security team will want to know what is captured, where it goes, and what this does and does not stop. That is on its own page: [MCP Governance: Security & Privacy](/docs/mcp-governance-security).
