Safeguard
AI Security

MCP Server Permissions: A Practical Checklist for Reducin...

A practical checklist for scoping MCP server permissions, denying risky defaults, and limiting the blast radius when an AI agent's tool access is exploited.

Aman Khan
AppSec Engineer
8 min read

Most MCP servers ship with default configurations that grant far more access than any single task requires — a filesystem connector that can read your entire home directory to fetch one config file, a database server plugin with write access when only SELECT queries are ever issued, a shell-exec tool that can run arbitrary commands because nobody scoped it down. When an AI agent is compromised through a prompt injection, a malicious tool description, or a poisoned response, the damage it can do is bounded by exactly one thing: the permissions the MCP server was granted. That's the blast radius.

This checklist walks through the concrete permission decisions that determine whether a compromised MCP integration costs you a single file or your entire production environment. It's written for teams already running MCP servers in CI, IDEs, or agent orchestration pipelines who need to harden them before the next incident report has their name in it.

What Permissions Does a Typical MCP Server Actually Request?

Most MCP servers request broader filesystem, network, and process permissions than their stated function needs, and almost nobody audits the gap. Take the widely used filesystem MCP server: its default configuration in early 2025 releases mounted an entire directory tree (often a user's home directory or an entire repo checkout) with read-write access, even when the connected agent's task was "summarize these three markdown files." The GitHub MCP server, similarly, is commonly configured with a personal access token scoped to repo (full read/write across every repository the token owner can touch) rather than a fine-grained token scoped to the one repository the agent needs.

The pattern repeats across categories: database MCP servers connecting with an app's primary credentials instead of a read-only replica user; Slack MCP integrations authorized with chat:write and channels:read across the entire workspace instead of a single channel; cloud provider MCP servers (AWS, GCP) attached to IAM roles with AdministratorAccess because that was the fastest way to get a demo working on a Tuesday afternoon. Each of these is a permission grant made for convenience during setup that nobody revisited before the server went into a workflow that an LLM — not a human — now drives autonomously.

Why Does Over-Provisioning an MCP Server Matter More Than It Would for a Normal Service?

It matters more because the entity deciding which permissions to exercise is a language model reacting to text, not a human following a runbook. A traditional service account with excess permissions is a static risk — it sits there until a human or a scripted attack chain deliberately misuses it. An MCP server's permissions, by contrast, are exercised dynamically based on what the connected LLM decides to do in response to whatever content it just ingested: a webpage, a PR description, a support ticket, an email. Anthropic's own MCP documentation and multiple 2024-2025 disclosures on prompt injection (including the "tool poisoning" pattern documented by Invariant Labs in April 2025) demonstrated that a malicious tool description or injected instruction can redirect an agent's actions without any human in the loop noticing until after the fact.

This is why the same over-provisioned AdministratorAccess role that might sit unused for years on a human's IAM identity becomes an active liability the moment it's attached to an MCP server: the agent doesn't need to be socially engineered, phished, or bribed. It just needs to read one poisoned document, one malicious npm package's postinstall script description, or one crafted GitHub issue, and the permissions do the rest — instantly, silently, and at machine speed.

Which Permissions Should Be Denied by Default?

Write, delete, and execute permissions should be denied by default for any MCP server whose task is fundamentally read-oriented. If an MCP server exists to answer questions about your codebase, summarize documents, or search logs, it needs read access and nothing else — no git push, no DROP TABLE, no rm -rf, no shell execution tool bolted on "just in case it's useful later." In practice this means:

  • Filesystem MCP servers should be scoped to specific directories (not / or ~), and mounted read-only unless a specific, named workflow requires writes.
  • Database MCP servers should connect through a dedicated read-only role, never the application's primary credential, and never a superuser or db_owner grant.
  • Git/GitHub MCP servers should use fine-grained personal access tokens scoped to one repository and a minimal permission set (contents: read, pull requests: read) rather than classic tokens with full repo scope.
  • Any MCP server offering a generic "run command" or "execute code" tool should be treated as equivalent to root access and isolated in its own sandboxed environment, never run alongside servers holding credentials to production systems.

A useful test: if you can't articulate, in one sentence, why this specific MCP server needs write or execute access for its stated purpose, deny it and see what actually breaks.

How Do You Scope Credentials So a Compromised Server Can't Move Laterally?

You scope credentials by giving each MCP server its own narrowly-bound identity instead of reusing a shared service account across servers or environments. Credential reuse is the single biggest amplifier of blast radius: if your Slack MCP server, your GitHub MCP server, and your internal database MCP server all authenticate using the same cloud service account or the same vault-issued token, compromising the weakest of the three (often the one with the least security attention, like a hobbyist-maintained community MCP server) hands the attacker the keys to all three.

Concretely, this means one credential per MCP server, per environment, with an expiry. A GitHub token used by an MCP server in a CI pipeline should not be the same token a developer's local IDE agent uses — different blast radii, different lifetimes, different revocation paths. Cloud IAM roles attached to MCP servers should follow the same least-privilege boundary as any other workload identity: a role that can read from one specific S3 bucket, not s3:* on the whole account. And every credential should have a rotation and expiry policy short enough that a token leaked in a log file or a misconfigured MCP server's debug output has a limited shelf life — 90 days is a reasonable ceiling for anything touching production, and secrets used by MCP servers with internet-facing inputs (i.e., anything that reads untrusted text) deserve tighter windows still.

How Should You Monitor MCP Servers Once They're Deployed?

You should monitor MCP servers by logging every tool call with its full argument payload and alerting on any call that falls outside the server's expected permission envelope, not just on outright failures. Because the entity invoking tools is a model rather than a deterministic script, "normal" behavior has more variance than a typical service — which is exactly why baseline deviation matters more, not less. A filesystem MCP server that suddenly starts reading files outside its configured directory scope, a database MCP server issuing a DELETE when it's only ever issued SELECT, or a GitHub MCP server opening pull requests against a repository it's never touched before are all signals worth an automatic alert, not a quarterly log review.

Practical monitoring for MCP deployments should include: structured audit logs of every tool invocation (tool name, arguments, calling agent/session, timestamp); anomaly detection tuned to each server's declared permission scope rather than generic thresholds; and a kill switch that can revoke an MCP server's credentials or disable the server entirely within minutes of a suspicious pattern, not after the next deploy cycle. Teams that treat MCP servers like any other third-party dependency — scanned once at onboarding and then forgotten — are the ones that find out about a compromise from a customer, not from their own logging.

What Does a Practical MCP Hardening Checklist Look Like?

A practical checklist has five items, and all five map directly to the sections above: inventory every MCP server in use and document what permissions it actually holds versus what it needs; deny write, delete, and execute by default and require an explicit, documented exception for each one granted; issue a unique, narrowly-scoped credential per server per environment with an expiry under 90 days; log every tool call and alert on deviation from the server's declared scope; and review the full list on a fixed cadence (quarterly at minimum) rather than only when onboarding a new server. Teams that skip the recurring review are the ones who, a year later, discover three MCP servers still holding AdministratorAccess grants issued for a demo that shipped to production and was never revisited.

How Safeguard Helps

Safeguard gives security and platform teams visibility into exactly this gap: what MCP servers are running across your environments, what permissions and credentials each one actually holds, and where that scope has drifted from what the server's function requires. Instead of manually auditing IAM roles, API tokens, and filesystem mounts server by server, Safeguard continuously inventories MCP integrations across your CI pipelines, IDEs, and agent infrastructure, flags over-provisioned grants (like a read-only tool holding write scope, or a credential shared across multiple servers), and surfaces anomalous tool-call patterns that fall outside a server's expected permission envelope. For teams shipping AI agents into production, that means the blast radius of any single compromised MCP server is something you've measured and bounded in advance — not something you discover after the fact.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.