Security Policies
6 min read
Security policies allow you to define rules that MCP packages must satisfy before they are allowed to execute. The MCP Client evaluates policies before launching any MCP server process. If a package violates any policy, execution is blocked with a clear error message.
How Policies Work
When you run mcp run, the client follows this enforcement sequence:
1. Resolve package from registry
2. Download and validate SHA-256 digest
3. Read manifest metadata (cert_level, origin, permissions)
4. ── POLICY EVALUATION ──
a. Check cert_level >= min_cert_level
b. Check origin in allowed_origins
c. Filter environment variables (allowed_env / blocked_env)
d. Check subprocess permissions
5. Launch MCP server in sandbox (only if all policies pass)
If any policy check fails at step 4, the process stops immediately. No code from the MCP server is executed.
Policy Evaluation Output
When a policy blocks execution, you see a clear explanation:
Policy violation: certification level too low
Package: acme/[email protected]
Cert Level: 1 (Static Verified)
Required: 2 (Security Certified)
Execution blocked. To override, use --min-cert-level 1
With --dry-run, you can test policy evaluation without executing:
mcp run acme/[email protected] --dry-run
Policy evaluation for acme/[email protected]:
Cert Level: 2 >= 2 (required) PASS
Origin: Verified in [Official, Verified] PASS
Environment: 3 of 15 variables allowed PASS
Subprocess: denied (manifest does not request) PASS
All policies passed. Package would execute.
Certification Level Policy
The certification level policy sets the minimum security analysis depth required for a package to run.
Configuration
# ~/.mcp/config.yaml
policy:
min_cert_level: 2
Or via environment variable:
export MCP_MIN_CERT_LEVEL=2
Or per-run:
mcp run acme/[email protected] --min-cert-level 2
Level Descriptions
| Level | Name | Score Required | What It Guarantees |
|---|---|---|---|
| 0 | Integrity Verified | Any | SHA-256 digest and manifest schema validated |
| 1 | Static Verified | >= 60 | Basic static analysis passed |
| 2 | Security Certified | >= 80 | Full security analysis including all 14 vulnerability classes |
| 3 | Runtime Certified | >= 90 | Dynamic runtime analysis (future capability) |
Recommendations by Use Case
| Use Case | Recommended Level | Rationale |
|---|---|---|
| Personal development | 0 | Maximum flexibility, accept any package |
| Team development | 1 | Ensure basic analysis has run |
| Staging/QA | 2 | Require full security analysis |
| Production | 2 or 3 | Only certified packages in production workloads |
| Regulated environments | 3 | Maximum assurance with runtime verification |
Origin Policy
The origin policy restricts which publisher types are allowed to run. This prevents untrusted community packages from executing in environments that require verified publishers.
Configuration
# ~/.mcp/config.yaml
policy:
allowed_origins:
- "Official"
- "Verified"
Or via environment variable:
export MCP_ALLOWED_ORIGINS="Official,Verified"
Or per-run:
mcp run acme/[email protected] --allowed-origins Official,Verified
Origin Types
| Origin | Description | Trust Level |
|---|---|---|
| Official | Published and maintained by the MCP Hub team | Highest |
| Verified | Publisher identity has been verified through a validation process | High |
| Community | Published by any registered user, no identity guarantees | Variable |
Typical Configurations
Restrictive (enterprise/production):
policy:
allowed_origins:
- "Official"
- "Verified"
Moderate (team development):
policy:
allowed_origins:
- "Official"
- "Verified"
- "Community"
This is the default configuration, allowing all origin types.
Maximum restriction (high-security):
policy:
allowed_origins:
- "Official"
Only packages maintained by the MCP Hub team are permitted.
Environment Variable Filtering
The environment variable policy controls which environment variables from the host system are passed into MCP server processes. This prevents accidental exposure of secrets, API keys, and credentials.
Configuration
# ~/.mcp/config.yaml
policy:
# Variables matching these patterns ARE passed to the MCP server.
allowed_env:
- "PATH"
- "HOME"
- "LANG"
- "LC_*"
- "TZ"
- "MY_APP_*"
# Variables matching these patterns are NEVER passed, even if
# they match an allowed_env pattern. Blocked takes precedence.
blocked_env:
- "AWS_*"
- "GITHUB_TOKEN"
- "MCP_REGISTRY_TOKEN"
- "*_SECRET*"
- "*_PASSWORD*"
- "*_KEY*"
- "*_CREDENTIAL*"
Pattern Matching
Environment variable patterns support glob-style matching:
| Pattern | Matches |
|---|---|
PATH | Exactly PATH |
LC_* | LC_ALL, LC_CTYPE, LC_MESSAGES, etc. |
*_SECRET* | DB_SECRET, MY_SECRET_KEY, API_SECRET_TOKEN |
AWS_* | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION |
Precedence Rules
- Blocked patterns always win. If a variable matches both
allowed_envandblocked_env, it is blocked. - Explicit
--envflags bypass filtering. When you pass--env KEY=VALUEon the command line, that variable is always included regardless of filtering rules. This is intentional: explicit is always allowed.
Example
Given:
allowed_env: ["PATH", "HOME", "MY_*"]
blocked_env: ["*_SECRET*"]
| Variable | Result | Reason |
|---|---|---|
PATH | Passed | Matches allowed_env |
HOME | Passed | Matches allowed_env |
MY_APP_URL | Passed | Matches MY_* |
MY_SECRET_KEY | Blocked | Matches *_SECRET* (blocked wins) |
AWS_ACCESS_KEY_ID | Blocked | Does not match any allowed_env pattern |
Subprocess Control
The subprocess policy determines whether MCP servers can spawn child processes. This is a defense-in-depth measure that limits what a compromised MCP server can do.
Configuration
# ~/.mcp/config.yaml
policy:
allow_subprocess: false
How It Works
- When
allow_subprocessisfalse(the default), the MCP server process cannot fork or exec child processes. On Linux, this is enforced via seccomp filters. - When
allow_subprocessistrue, subprocesses are permitted but still subject to the same resource limits (PIDs, memory, CPU) as the parent process. - The MCP server manifest can declare subprocess permissions. If the manifest requests subprocess access and the policy denies it, execution is blocked.
Platform Support
| Platform | Subprocess Enforcement |
|---|---|
| Linux | seccomp (kernel-level, mandatory) |
| macOS | Limited (process monitoring, best-effort) |
| Windows | Not available |
Subprocess control is only fully enforced on Linux via seccomp filters. On macOS and Windows, a determined MCP server can bypass subprocess restrictions.
Combining Policies
Policies are evaluated independently, and all must pass for execution to proceed. Here is an example of a strict enterprise configuration:
# ~/.mcp/config.yaml
policy:
# Only Security Certified or higher
min_cert_level: 2
# Only verified publishers
allowed_origins:
- "Official"
- "Verified"
# Minimal environment exposure
allowed_env:
- "PATH"
- "HOME"
- "LANG"
blocked_env:
- "*_SECRET*"
- "*_PASSWORD*"
- "*_KEY*"
- "*_TOKEN*"
- "AWS_*"
- "AZURE_*"
- "GCP_*"
# No subprocesses
allow_subprocess: false
Enterprise Policy Distribution
For organizations using MCP Hub Enterprise, policies can be centrally managed and distributed to all team members.
How Enterprise Policies Work
- Organization admins define governance policies in the MCP Hub dashboard under Settings > Policies.
- Policies are published to the registry as metadata alongside the organization’s configuration.
- MCP Client checks for organization policies when authenticating. If an organization policy exists, it is merged with the local configuration.
- Organization policies take precedence over local configuration. An individual user cannot lower the minimum cert level below what the organization requires.
Enterprise Policy Merge Rules
| Setting | Merge Behavior |
|---|---|
min_cert_level | Maximum wins. If org requires 2 and user sets 1, effective level is 2. |
allowed_origins | Intersection. If org allows [Official, Verified] and user allows [Verified, Community], effective set is [Verified]. |
allowed_env | Intersection. Only variables allowed by both org and user are passed. |
blocked_env | Union. Variables blocked by either org or user are blocked. |
allow_subprocess | Most restrictive wins. If either org or user denies, subprocesses are denied. |
Example: Enterprise Override
Organization policy (set in MCP Hub dashboard):
min_cert_level: 2
allowed_origins: ["Official", "Verified"]
blocked_env: ["AWS_*", "AZURE_*", "GCP_*"]
allow_subprocess: false
User’s local config:
min_cert_level: 0
allowed_origins: ["Official", "Verified", "Community"]
allow_subprocess: true
Effective policy after merge:
min_cert_level: 2 # Org wins (maximum)
allowed_origins: ["Official", "Verified"] # Intersection
blocked_env: ["AWS_*", "AZURE_*", "GCP_*"] # Union
allow_subprocess: false # Org wins (most restrictive)
Enforcement by Download
Enterprise organizations with dedicated subdomains (acme.registry.mcp-hub.io) can enforce policies at the network level. By routing all MCP client traffic through the corporate subdomain, the registry itself rejects resolve/download requests for packages that violate organizational policies. This provides enforcement even if the local client configuration is modified.
Auditing Policy Decisions
All policy evaluations are recorded in the audit log when auditing is enabled:
{
"timestamp": "2025-01-15T10:30:00Z",
"event": "policy_evaluation",
"package": "acme/[email protected]",
"result": "pass",
"checks": {
"cert_level": {"required": 2, "actual": 2, "result": "pass"},
"origin": {"allowed": ["Official", "Verified"], "actual": "Verified", "result": "pass"},
"env_filtered": {"allowed": 3, "blocked": 12, "total": 15},
"subprocess": {"allowed": false, "requested": false, "result": "pass"}
}
}
Policy violations are logged with result: "blocked":
{
"timestamp": "2025-01-15T10:31:00Z",
"event": "policy_evaluation",
"package": "acme/[email protected]",
"result": "blocked",
"violation": "cert_level",
"checks": {
"cert_level": {"required": 2, "actual": 1, "result": "fail"}
}
}