Where to configure it
Admins edit the policy under Settings → Tool governance → Enforce. Editing requires the Manage org settings capability. The Enforce editor has four groups — Allowed remote MCP URLs, Allowed local (STDIO) packages, Allowed built-in MCP servers, and Blocked built-in tools. The page saves Protect denylists and Enforce settings together; unchanged groups are preserved exactly as fetched.All source rules are fail-closed: anything Enforce cannot positively match to a Runlayer-managed source, an allowlist entry, or a permitted built-in is blocked. Widening what runs always means adding an allowlist entry, never removing a block.
Allowed remote MCP URLs
Enforce blocks remote (HTTP/S) MCP servers that do not point at your Runlayer instance. Add allowed remote MCP URLs to permit specific external endpoints. You can configure up to 50 entries. Each entry is a base URL. A tool call’s MCP URL is allowed when:- The scheme, host, and port match the entry (default ports
443/80for HTTPS / HTTP are treated the same as omitting the port). - If the entry has no path (or only
/), any path on that origin is allowed. - If the entry includes a path (for example
https://partner.example.com/mcp), the MCP URL’s path must match that prefix with a path boundary —/mcpand/mcp/streammatch;/mcpbackupdoes not.
Allowed local (STDIO) packages
Enforce also blocks local (stdio) MCP servers — those launched by a command such asnpx ... or uvx ... — unless the launched package is on your stdio package allowlist. This lets you permit specific published MCP packages without permitting arbitrary local command execution. The editor accepts up to 100 entries.
Local commands are trivially spoofable, so Enforce never allowlists a raw command string. Instead it extracts a canonical package identity from the command and matches that against the list. A command that does not resolve to a launcher-backed package identity is denied.
Package identity
Each entry is a canonical package identity: an ecosystem (npm or PyPI), a name, and an optional version pin.
- Ecosystem + name must match. Names are normalized before comparison (see Name normalization).
- Version is optional. An entry with no version matches any version; an entry pinned to a version matches only that version. A versionless launch command can never satisfy a pinned entry.
Recognized launchers
Only ecosystem launchers resolve to a package identity. Every other program — including raw binary paths (/usr/local/bin/server), interpreters (node build/index.js, python -m server), and unknown launchers — has no package identity and is blocked.
Other package runners —
pnpm dlx, bunx, yarn dlx — and container launchers like docker run are not recognized, so servers launched through them cannot be allowlisted and are always blocked in Enforce. Relaunch the server through npx or uvx (or run it as a Runlayer-managed server) to allow it.Which argument is the package
Enforce matches the package the launcher actually installs and runs — normally the first argument after the launcher’s own flags. If an explicit package flag is present (npx --package foo bar, uvx --from foo bar), that flag’s value is the package. Commands Enforce cannot resolve to a single package are blocked (see Always blocked).
Version pinning
Leave the version blank on an entry to allow any version.
Name normalization
Names are normalized so stored entries match what the parser produces at hook time:- npm — lowercased. The leading
@of a scoped name is part of the name, not a version separator. - PyPI — PEP 503 canonical form: lowercased, with runs of
-,_, and.collapsed to a single-. Somcp_server_fetch,MCP.Server.Fetch, andmcp-server-fetchare all the same package.
Always blocked
These never resolve to a single package identity and are always denied, regardless of the allowlist:- Arbitrary-command launchers —
npx --call/-crun an arbitrary command string, not a package. - Unrecognized launcher flags before the command — Enforce cannot safely tell which argument is the package, so it fails closed. Put npm config in
.npmrcor environment variables rather than inline flags. - Shell injection — commands with hidden shell operators, subshells, or injection patterns.
- Unparseable or empty commands.
Worked examples
What name-based allowlisting covers
The allowlist identifies packages by name and, optionally, version. It does not verify package contents, so continue using your existing dependency and supply-chain controls alongside Enforce.Promote a discovered package (one-click)
When Detect discovers a local stdio MCP whose command resolves to a package identity, you can Add to allowlist in one click from the sighting’s detail drawer — Enforce appends the parsed identity to the stdio allowlist. This requires the Manage org settings capability. The same one-click Add to allowlist action is available for discovered remote MCP URLs.Blocked built-in tools
Beyond MCP sources, Enforce can deny built-in client tools by behavior type. Toggle a type on to block every built-in tool of that type across supported clients:
These are behavior-level switches — each blocks a whole category of built-in tool. There is no per-path or per-command rule layer; for content-based decisions on the calls that remain allowed, use your scanner configuration.
Types you do not toggle on are allowed by default, and a built-in tool whose name does not map to one of these governed types is also allowed by default — it is not covered by this control, though scanner decisions still apply to it.
This is part of local tool lifecycle enforcement, so it requires Full session scanning APIs and the target Hook client enabled under Settings → Agent session monitoring. Shadow MCP source blocking (the remote-URL, stdio, and built-in dimensions) stays active without full session scanning. See Enforcement paths.
Built-in MCP servers
Some clients ship non-configurable, built-in MCP servers that never appear in any config file — for example GitHub Copilot CLI’sgithub-mcp-server, playwright, fetch, time, and computer-use. The client resolves these internally, so the hook identifies them by (client, built-in server name) rather than by URL or command.
Enforce ships a safe default allowlist of well-known built-ins per client, so these keep working out of the box:
In the Allowed built-in MCP servers group:
- Keep Use Runlayer safe defaults on (the default) to trust the built-ins above.
- Turn it off to define a custom list — seeded from the defaults so you can prune or extend it — that replaces the defaults entirely. Each row is a
(client, built-in server name)pair. - Clear the custom list to block all built-in MCP servers.
Claude.ai account connectors are allowed through. A connector the user has attached to their Claude account on claude.ai has no URL or local command on the device — Claude Code reports it by connector source and name. Enforce allows these connector calls rather than blocking them; govern them through your Claude.ai workspace controls.
Related Resources
Protect policy
Configure allow-unless-denied MCP source governance for Protect
Enforce
How Enforce intercepts calls, deployment, and troubleshooting
Detect
Discover shadow servers and promote them to the allowlist
Policies
Configure access control policies for managed MCPs
Deploy AI Watch
Install the package and turn on Enforce