Skip to content

All posts

AI

MCP security checklist for enterprises

Ritesh Patel

AI: MCP security checklist for enterprises

An MCP security checklist for enterprises confirms five things: which servers an agent can load, which server identities are allowed, which tokens and scopes a server holds, which tools need a person’s approval, and whether each call is logged. Each item has one owner, either the client policy or the MCP server.

Who enforces each control

Each checklist area has a primary owner, shown below. The items that follow say what to check in each.

Checklist area Owner Items
Server approval and identity Managed settings and your approved list 1 to 7
Token audience and scopes Authorization server and MCP server 8 to 10
Per-tool rules and prompts Client permission rules 11 to 12
Server controls and call record MCP server and client telemetry 16 to 18

The checklist

Work through these in order. Each item says what to verify, so an engineer can confirm it on a managed machine without relying on a vendor claim.

Inventory and approval

  1. Inventory every server a session can load. Reviewing a project’s .mcp.json is not enough. Claude Code’s security page notes that servers at other scopes, claude.ai connectors and plugins also add servers. The post on finding MCP servers covers searching codebases and clusters for the ones you missed.
  2. Don’t let a repository approve its own servers. A cloned repository can’t approve its own servers. The MCP docs say that enableAllProjectMcpServers or enabledMcpjsonServers committed to .claude/settings.json is ignored in an untrusted folder. Confirm that each developer has accepted the workspace trust dialog before you rely on project approvals.
  3. Write the approved list with exact values. For each server, record the owner, the purpose, the exact URL or the command with its arguments, and the tools it exposes. A name in a list is not enough, as the next section shows.
  4. Decide who may add servers, and write it down. Whether developers can add their own servers is a policy choice. Managed settings enforce it, and the per-tool and allowlist post walks through the file formats. Make the decision before rollout so the approved list and the policy agree.

Server identity and transport

  1. Allow by URL or command, never by name. A name is a label each user assigns, not a control. The allowlist post covers the URL and command match rules.
  2. Check the port and scheme in each URL pattern. A * in the hostname matches every port, so the allowlist post is the place to check the pattern before you approve a server.
  3. Mind the env block. Command entries do not compare it, so define a server in managed-mcp.json if you must control its environment values. The allowlist post lists the other match gaps.

Authentication and tokens

  1. Require PKCE with S256 on remote OAuth servers. The MCP authorization specification says clients MUST use the S256 code challenge method when technically capable. It also says clients MUST refuse to proceed if the authorization server metadata lacks code_challenge_methods_supported. All authorization server endpoints MUST be served over HTTPS.
  2. Pin the scopes. Set oauth.scopes to the subset your security team approved. The docs say it takes precedence over scopes the server advertises, so a server that advertises more gets only what you pin.
{
  "mcpServers": {
    "slack": {
      "type": "http",
      "url": "https://mcp.slack.com/mcp",
      "oauth": {
        "scopes": "channels:read chat:write search:read"
      }
    }
  }
}

If a tool call returns 403 insufficient_scope, the docs say the call fails and the server shows as needing sign-in. A new scope is granted only after you add it to the pinned list and authenticate again. 10. Check that servers accept only their own tokens. The authorization specification says an MCP server MUST accept only tokens issued specifically for itself, MUST reject tokens that do not name it in the audience, and MUST NOT pass through the token it received from the client. Test this with a token issued for another resource. The call should be refused.

Tool-level control

  1. Block unreviewed MCP tools, and keep the block narrow enough to allow reviewed ones. In Claude Code a deny rule is checked before any allow rule, whatever the rule’s specificity. A blanket deny of mcp__* therefore cannot be reopened by adding allow rules beneath it. Narrow it to the servers or tools you have not approved, then add allow rules for the named tools you have reviewed. The tool-level authorization post covers rule syntax and the order in which rules are checked.
{
  "permissions": {
    "deny": [
      "mcp__*"
    ]
  }
}
  1. Mark consent tools in the server. If you build a server, a tool whose prompt is itself the consent step can be marked so that Claude Code prompts on every call. The docs say this applies even in acceptEdits, auto and bypassPermissions modes, and that allow rules don’t skip the prompt. Use it only for tools where auto-approval would mean no person agreed.
{
  "name": "grant_access",
  "description": "Requests access to a protected resource",
  "_meta": {
    "anthropic/requiresUserInteraction": true
  }
}

Human in the loop

  1. Put a person in front of sensitive calls. The tools specification says there SHOULD always be a human in the loop with the ability to deny tool invocations. Applications SHOULD make clear which tools are exposed to the model, show a visible indicator when a tool runs, and show tool inputs to the user before calling the server.
  2. Treat tool annotations as untrusted. The specification says clients MUST consider tool annotations to be untrusted unless they come from trusted servers. Do not write allow rules from annotations alone. Read them as information about a tool, then decide the rule yourself.
  3. Re-review when the tool list changes. A server that declares the listChanged capability SHOULD send a notification when its tools change. Treat each notification as a change that needs review, because a new tool can widen what an agent may do without any change on your side.
{
  "jsonrpc": "2.0",
  "method": "notifications/tools/list_changed"
}

Server-side controls

  1. Check the server’s own controls. The tools specification requires servers to validate inputs, enforce access control, rate limit and sanitize outputs. Write the access check per tool, not only per server. The tool-level authorization post maps which checks sit with the server.
  2. Set timeouts and validate results. The Claude Code MCP docs say the per-server timeout is a hard wall-clock limit for each tool call, and progress notifications do not extend it. The idle window defaults to five minutes for HTTP, SSE and WebSocket servers. The tools specification says clients SHOULD validate tool results before passing them to the model and SHOULD implement timeouts.

Logging and rollout

  1. Log every call, including denials. The tools specification says clients SHOULD log tool usage for audit purposes. The audit post covers the OpenTelemetry setup. The Claude Code monitoring docs describe OTEL_LOG_TOOL_DETAILS, which is off by default. Set it to 1 to add MCP server and tool names and tool input to tool events.
  2. Tell users before a block lands. The managed MCP docs say a server that becomes blocked by policy disappears from /mcp and claude mcp list with no signal that policy is the reason. Name the blocked servers to affected users when you roll out a new restriction.

Gaps the docs leave open

  • Upgrades can start servers without notice. The allowlist post covers the gap where an upgrade starts loading a server that an allowlist was blocking.
  • Reviewing one file is not an inventory. Project files, user settings, plugins and connectors each add servers, so the approved list must cover all of them.
  • The specification leaves the access design open. It requires servers to implement access controls but does not say how. Your per-tool design is yours to write and test.

Sources checked on 2026-11-13: the MCP tools specification and authorization specification, and the Claude Code permissions, MCP, managed MCP, monitoring and security docs.

Next steps

Start with the inventory and the approved list, then set identity and scope rules, then turn on logging. For the individual controls, read how to restrict which MCP servers Claude Code can use, how to set tool-level authorization and how to audit MCP tool calls. The pillar page for this topic is MCP security. If your sign-in runs through an identity provider, read cross-app access for MCP for how the client and the provider share it.

Frequently asked questions

What should an enterprise check before it approves an MCP server?

Confirm who publishes the server and which tools it exposes, and record the exact URL or command you approve. Check which credentials it needs and whether it uses OAuth with scopes you can pin. Then add an allowlist entry and name an owner. A display name is not enough, because any user can label a server with any name.

Does the MCP specification require servers to enforce access control?

Yes. The tools specification says servers MUST validate all tool inputs, implement proper access controls, rate limit tool invocations and sanitize tool outputs. Clients should prompt for sensitive operations and log tool usage. Those server duties sit alongside client-side checks, not in place of them.

Can an MCP server pass a client's OAuth token on to another API?

No. The MCP authorization specification says an MCP server MUST NOT pass through the token it received from the MCP client. It must accept only tokens issued for itself. If it calls an upstream API, that API issues a separate token. Clients must send the resource parameter from RFC 8707 so tokens are bound to the server they are meant for.

Does a repository's .mcp.json show every MCP server a session can load?

No. Claude Code's security docs say servers at other scopes, claude.ai connectors and plugins also add servers, so a file review misses them. A cloned repository also cannot approve its own servers. Project approvals count only after the developer accepts the workspace trust dialog, so confirm trust before you rely on them.

Ritesh Patel, Founder & VP Product, Nirmata

Ritesh Patel is a founder of Nirmata and leads its products. He writes about governing AI coding agents, MCP security and Kubernetes policy as code.

LinkedIn

Govern AI agents with AIControlsControl what AI agents do, and prove it.
ShareXLinkedIn

Stay up-to-date with the latest in AI, governance, and infrastructure

Subscribe to our free monthly newsletter to get industry news, DevOps tips, and articles right to your inbox on Kyverno, containerization, Kubernetes deployment & management and more.