GitHub has made Model Context Protocol (MCP) server allow and deny lists generally available in Copilot enterprise managed settings. An organization can now restrict the tools that development agents connect to by matching a remote server URL, the exact command for a local server or, with important caveats, its declared name.

The feature addresses a concrete problem. An MCP server can give an agent access to a repository, database, browser, incident ticket or local terminal. Without central policy, each developer can add a different connector with its own dependencies, permissions and authentication. An allowlist reduces that surface, but it does not replace capability review, execution isolation, secret management or supply-chain controls.

The short answer

QuestionAnswer
What can an enterprise control?Remote MCP servers by URL, local servers by command and arguments, and optionally a server name.
Where does the rule apply?GitHub Copilot app, Copilot CLI and Visual Studio Code according to the current documentation.
Does an empty allowlist block everything?An empty allowedMcpServers blocks added servers except Copilot's built-in default servers.
What if a server matches both lists?Deny always wins over allow.
Can multiple policy layers combine?Yes. Every allow layer must accept the server, while deny entries accumulate.
Is an allowlist enough to secure MCP?No. Teams must still assess exposed tools, identities, secrets, network access, sandboxing and the software supply chain.

How the two lists work

allowedMcpServers defines the servers users may add. If the setting is omitted, servers remain allowed unless a deny rule applies. When entries are present, only matching servers pass. An empty array blocks all user-added servers except first-party default servers built into Copilot.

deniedMcpServers is an unconditional prohibition. A server matching a denied entry remains blocked even when it also matches an allowed entry. This precedence prevents a broad rule such as an approved domain from accidentally restoring an explicitly prohibited URL.

When several managed-setting sources are active, allow rules form an intersection: every layer must permit the server. Deny rules behave as a union. A prohibition at one level cannot be canceled by a more permissive configuration elsewhere. GitHub also documents fail-closed behavior for malformed or unverifiable matching conditions.

A configuration example

Managed settings can be stored in copilot/managed-settings.json in the source organization's dedicated .github-private repository. The following deliberately restrictive example must be adapted:

{
  "allowedMcpServers": [
    { "serverUrl": "https://mcp.example.com/*" },
    {
      "serverCommand": [
        "npx",
        "-y",
        "@company/mcp-server@1.4.2"
      ]
    }
  ],
  "deniedMcpServers": [
    { "serverUrl": "https://*.unapproved.example/*" }
  ],
  "sandbox": {
    "enabled": true,
    "allowBypass": false,
    "sandboxMcpServers": true
  }
}

Each list object must use one matcher type. A local command includes the executable and every argument in exact order. Changing an option or version therefore changes the compared identity. The example pins the package instead of using @latest, so a new release is not automatically executed under an existing approval.

The sandbox block illustrates a complementary defense, not a requirement for MCP matching. Confirm the keys supported by the clients and plans in use. Test the complete policy in a pilot before broad deployment.

Identifying a remote server correctly

For a remote server, serverUrl supports wildcard patterns. GitHub canonicalizes URLs before comparison, including case, internationalized domains, default ports, fragments, trailing dots and some percent-encoded host octets. This reduces bypasses that rely on two spellings of the same destination.

An overly broad wildcard remains risky. Approving an entire shared domain can include a service created later or owned by another team. Prefer a dedicated hostname and path, document the owner, and examine redirect, DNS and corporate-proxy behavior.

The URL is not the entire application identity. The same endpoint can change code, tenant or permissions without changing its address. Vendor review, authentication, logs, data retention and change management must accompany the matcher.

Local commands require dependency governance

A local MCP server is commonly started through npx, uvx, a binary or a container. serverCommand exactly compares the command and its arguments, without wildcard expansion. That precision can block an unexpected variant, but it does not make the executed content immutable.

A command that downloads the latest package on every start lets the supply chain change behind a stable rule. Pin a version and, where supported, a digest or checksum. An internal mirror, dependency scanning and a promotion process add assurance for tools that can reach source code or a terminal.

Working directory, environment variables and process credentials also matter. Two launches with the same command line can have different authority on different machines. Connect MCP policy to endpoint management, shell profiles and service identities.

Why serverName is not a security boundary

GitHub supports name matching for deployment convenience, but its documentation warns that users control and can change this name. An unapproved server could reuse the label of an approved connector.

Names are useful for display or migration, not trust identity. A security rule should prefer the canonical URL of a remote service or the exact local command. Organizations already matching names should plan replacements and look for misleading duplicates.

Where to deploy managed settings

GitHub documents several levels with MDM, server, file and user precedence. Centrally served settings fit consistent, auditable administration. MDM is appropriate when device groups require different policies or a restriction must remain present even when a remote service is unavailable.

File settings help with development containers, Codespaces or environments where server management is unavailable. Documented paths are /Library/Application Support/GitHubCopilot/managed-settings.json on macOS, %ProgramFiles%\GitHubCopilot\managed-settings.json on Windows and /etc/github-copilot/managed-settings.json on Linux.

GitHub says server settings refresh about hourly; restart or reauthentication can force retrieval. If fetching fails with no cached copy, those settings may be unavailable. A restriction that must always apply therefore deserves a managed local layer in addition to server delivery.

Gaps the list does not close

Announced coverage includes the Copilot app, Copilot CLI and Visual Studio Code. Other MCP clients, standalone scripts and unmanaged AI tools are not automatically governed by this policy. Software inventory and installation controls remain necessary if the goal is enterprise-wide MCP governance.

First-party servers built into Copilot are exempt from deny lists according to GitHub's reference. Administrators need to understand their capabilities and the Copilot policies around them instead of assuming an empty array disables them.

MCP sandboxing concerns local execution inside Copilot CLI's isolated environment. It does not place a remote server in a local sandbox. Relevant controls for remote services include OAuth scopes, service accounts, network segmentation, API limits and server-side auditing.

Finally, approving a server does not approve every one of its tools for every repository. A connector may expose both read-only search and destructive actions. When capabilities cannot be separated, approval must consider the server's maximum authority.

A ten-step rollout

  1. inventory current MCP clients, servers, owners and users;
  2. classify the data, tools and actions each server can access;
  3. remove connectors without an owner or demonstrated use;
  4. pin local packages and define an update path;
  5. create precise URL or command matchers, never name alone;
  6. add explicit denials for known unwanted domains and commands;
  7. combine lists with sandboxing, permissions, network controls and least-privilege identities;
  8. test allowed, denied, malformed and unavailable cases in every client;
  9. pilot with a small group before organization-wide deployment;
  10. log exceptions, set expiration dates and review the list regularly.

Emergency overrides should be rare, temporary and attributable. A useful exception request records the server, business need, affected data, owner, duration and removal plan. A list that only grows eventually becomes a catalogue of old decisions.

A governance building block, not a guarantee

Managed MCP lists give security teams a control that was missing when connectors were mainly configured workstation by workstation. Their cumulative behavior and deny precedence support least privilege, while exact command matching can reduce unexpected variants.

The result still depends on everything around the list. An approved server can be compromised, overprivileged or updated unsafely. The goal is not merely a valid JSON file, but a small set of identified, reviewed, isolated and observable connectors. Under those conditions, MCP becomes a managed capability instead of another implicit access path for every agent.