All articles
Dev ToolsBy Petru Popa · 6 min read

The Client List Is the Policy

GitHub shipped two enterprise control planes in two days. Read the reference pages before you count on either.

On 6 August GitHub made MCP allowlists generally available in enterprise managed settings. Enterprise owners set allowedMcpServers and deniedMcpServers in copilot/managed-settings.json, kept in the source organization's .github-private repository on the default branch. Entries match a server by serverUrl for remote HTTP and SSE endpoints, with wildcard support; by serverCommand for local stdio servers, on exact command; or by serverName, which the announcement calls a user-assigned convenience label. Three clients are named as enforcing it: the GitHub Copilot app, Copilot CLI, and VS Code. The announcement adds that policies fail closed, so a malformed or unverifiable configuration is blocked rather than allowed.

A day later GitHub opened a second enterprise surface. Enterprise owners can now install public GitHub Apps built outside their enterprise, and any user or organization can now create an app that requests enterprise permissions.

Two days, two control planes. Then read the reference pages underneath.

Two mechanisms, one missing surface

GitHub ships two ways to restrict MCP servers, and its own documentation ranks them. The concepts page presents the managed settings file as the recommended route — generally available, matching on name, URL, or stdio commands — against a custom registry that is in public preview, matches on name or ID only, and can be bypassed by users editing configuration files. The registry reference page is blunter about itself: it flags the private registry as not the recommended method, notes that strict enforcement preventing installation of non-registry servers is not yet available, and describes managed settings as the stricter URL-based enforcement that users cannot override locally.

So use managed settings. The documentation settles that much. What it does not settle is coverage — and on coverage the two mechanisms have the same shape.

The registry reference publishes a support table with a version floor per client: Copilot CLI 1.0.11, Eclipse 4.38, JetBrains 1.5.64, Visual Studio 18.4.0, VS Code 1.109.3, Xcode 0.47.0. The same table marks the Copilot cloud agent as supporting neither registry display nor allowlist enforcement. The managed settings path has a shorter list rather than a longer one: the announcement names the GitHub Copilot app, Copilot CLI, and VS Code, and the concepts page says client support is limited to what the managed settings documentation covers, with an expansion promised but not dated.

Set the two lists side by side and the same surface is absent from both. The cloud agent is marked unsupported on the registry table and is not among the three clients named for managed settings — and it is the execution path with nobody at the keyboard, where an allowlist does work no human review is also doing.

The changelog's fail-closed line needs reading against that. It covers a configuration that is malformed or unverifiable; it says nothing about a client that never consults the configuration at all. Only the first failure mode leaves a trace in a policy audit.

The mechanics make it structural rather than an oversight to wait out. The Model Context Protocol specification revision dated 2025-06-18 defines two standard transports, and in the stdio transport the client launches the server as a subprocess and speaks JSON-RPC over its stdin and stdout. There is no broker in that picture. Whatever decides a local server is permitted has to be the process that spawns it, which is why every one of these controls is a property of the client rather than of the account. That page attaches explicit security requirements to Streamable HTTP — validate the Origin header, bind to localhost, authenticate connections — and states no comparable requirement for a stdio subprocess.

The second surface has no event stream

GitHub's docs say an enterprise installation grants only the enterprise-level permissions the app requested and reaches no organization or repository data without a separate installation on each organization. That sounds narrow until you read what the enterprise level covers: creating organizations in the enterprise, installing applications across organizations, managing SCIM provisioning, user management, and custom repository properties. It is not a read-only administrative scope. It is the permission to decide what else gets installed.

The same page states that webhooks are unsupported for enterprise installations, that API support is still incomplete, and that the capability is in public preview. So the surface with the authority to install other apps across your organizations emits no events. There is nothing to subscribe to, which makes detection somebody opening a settings page on a schedule. That page also covers GitHub Enterprise Cloud only; the same article path under the Enterprise Server documentation set returns a 404.

This is the shape described in why enterprise AI does not ship: the model is not the constraint, the last mile is. A control whose real coverage is a list of client names spread across every laptop in the company is a change-management project wearing a policy's clothes.

What to do this quarter

  1. Write the policy in managed-settings.json, not the registry. GitHub's own reference marks the private registry as not the recommended method and bypassable by editing configuration files, and calls managed settings the stricter enforcement users cannot override locally.
  2. Inventory your clients against the three named for managed settings — the Copilot app, Copilot CLI, VS Code. Anything else your developers use sits outside the policy until GitHub documents otherwise.
  3. If you use the registry, treat its table as the coverage limit. Copilot CLI 1.0.11, Eclipse 4.38, JetBrains 1.5.64, Visual Studio 18.4.0, VS Code 1.109.3, Xcode 0.47.0. Report the share of developers below those versions.
  4. Gate the Copilot cloud agent somewhere else. It is marked unsupported on the registry table and absent from the managed settings list, so whatever you rely on for the unattended path cannot be either of these.
  5. Prefer serverUrl and serverCommand matchers over serverName. The announcement calls the name a convenience label.
  6. Put enterprise app installations on a review calendar. With no webhooks, a recurring manual check is the detection mechanism.

What would show this wrong

The claim is that the binding constraint on both MCP controls is which client is doing the executing, not what the policy file says, and that the gap sits precisely where execution is unattended. Two things would falsify it. The cloud agent appearing in either mechanism's documented coverage would close the unattended gap outright. Documented server-side enforcement — a refusal at the API that does not depend on which build a developer installed — would make the policy file the real boundary and retire the whole client inventory. Until one of those appears, the honest inventory is a list of client names, and a calendar reminder.

Ready to start?

Turn this into a plan for your team.

One week, fixed fee: a working session with your team, a prioritized use-case backlog, and an ROI model for the opportunities worth chasing.

Book an AI Opportunity Sprint