Tutorial7 min readMay 5, 2026

How to Secure an MCP Server

MCP servers run with whatever credentials you hand them. The default trust model is "the agent can do anything the server can do" — which means a misconfigured server is the difference between a useful assistant and an actively dangerous one. The seven habits below are the minimum baseline before letting an autonomous agent touch anything that matters.

Goal

A trust model the agent cannot escape

Time

~30 minutes for a full audit

Cadence

Every new MCP + 90-day rotation

The security baseline

1

Scope every credential to least privilege

Most MCP credentials are over-scoped on day one because the auth provider defaults to broad scopes. Cut every token to the narrowest scope that lets the workflow work — repo-only access for GitHub, read-only for databases, restricted keys for Stripe, single-channel for Slack. Re-issue the token whenever the scope shifts; never edit the scope of a long-lived credential.

2

Lock filesystem MCPs to explicit allowlists

The Filesystem MCP only reaches paths you pass on the command line. Pass a single project directory, never $HOME and never /. Reject symlinks pointing outside the allowlist by keeping the server's default symlink behaviour (it normalizes paths and rejects traversal). Every additional allowlisted path expands the blast radius — be deliberate.

// Good: scope to one project
"args": [
  "-y",
  "@modelcontextprotocol/server-filesystem",
  "/Users/you/code/this-one-project"
]

// Bad: agent can now read your dotfiles, password manager exports,
// SSH keys, and everything else under $HOME.
"args": [
  "-y",
  "@modelcontextprotocol/server-filesystem",
  "/Users/you"
]
3

Audit the tool list before trusting a server

Run any new MCP through the MCP Inspector and read every tool description. Many community MCPs include "exec" or "shell" tools that let the model run arbitrary commands — that is rarely what you actually want. If a server bundles a tool you do not need, prefer a more focused alternative or fork the server with the dangerous tool removed.

# List every tool a server exposes before installing
npx @modelcontextprotocol/inspector \
  npx -y @some-org/some-mcp

# In the Inspector UI: click "List Tools" and read each description.
# Look for: exec, shell, run, eval, os.* — these are write/exec capabilities.
4

Keep tokens out of committed files

Never hardcode a token in a config file that lives in Git. VS Code uses the inputs feature (password-type prompts stored in the OS keychain). Claude Code uses ${VAR_NAME} interpolation against the shell environment. Claude Desktop has no built-in secret store — keep claude_desktop_config.json out of dotfile repos that include real tokens, or use a per-machine secrets manager (1Password CLI, Vault) to inject values at launch.

5

Bound the prompt-injection blast radius

A web-search or web-scraping MCP can return content that contains injected instructions. The model may follow those instructions, especially if the surrounding tools have write capabilities. Mitigations: keep read-only and write tools in separate clients when possible; require human approval for anything irreversible (file deletion, transactions, message sends); never combine an internet-reading MCP with a credentialed-write MCP under an autonomous agent without an approval gate.

6

Rotate tokens on a schedule, not just on incident

Treat MCP credentials like any other long-lived API token: rotate every 90 days at most. Pick a rotation date, set a calendar reminder, and re-issue every token in your config on that date. Catching a leaked token six months after the leak does not help anyone.

7

Watch the running processes

Each MCP runs as its own child process. Periodically check what is actually launched: `ps aux | grep mcp` on macOS/Linux, Task Manager on Windows. Look for unfamiliar entries and confirm they map to MCPs you expect. A surprise process is the second-best signal of a compromised server (the first is the credential alert from your provider).

# macOS/Linux: list every MCP-ish process
ps aux | grep -iE "mcp|@modelcontextprotocol"

# Confirm each maps to an entry you remember adding.

Read-only by default, write only when proven

Every database, ticket-tracker, and write-capable MCP should start in read-only mode. Read-only mode gives the agent enough leverage to summarise, plan, and answer questions without ever being able to mutate state. Promote to read-write only after the workflow is reliable and you have an audit trail. Most teams never need write capabilities on most MCPs.

Pre-install checklist

A 60-second audit before adding any new MCP to a config. If a check fails, find an alternative or limit scope further.

MCP install audit
[ ] Maintainer is the underlying service OR a known/trusted org
[ ] Source repo has a recent commit (last 60 days)
[ ] Tool list inspected — no surprise exec/shell/eval tools
[ ] Token scoped to least privilege (re-issued, not edited)
[ ] Read-only mode enabled where the workflow allows it
[ ] Filesystem paths point to a single project, not $HOME
[ ] Token reference is via env / inputs / VAR — not hardcoded
[ ] Calendar reminder set for 90-day rotation

Common security mistakes

A community MCP requires "execute commands" scope

Pause and re-read the server's docs. "Execute commands" almost always means the server can run arbitrary shell on the host. Decide whether the use case is worth the risk; if not, find an alternative MCP or limit the server to a sandboxed user account.

You suspect a token was committed to Git

Rotate immediately, even if the repo is private. Once a token enters Git history, treat it as public — you cannot reliably scrub history across forks and CI caches. Issue a new token, update the config, and audit the provider's access logs for unexpected use.

You need to share a config without sharing the secret

Commit a redacted template (claude_desktop_config.example.json) with placeholder tokens, and an entry in the README explaining how to fill them in. Keep the real config out of Git via .gitignore. For team setups, look at 1Password CLI, Doppler, or Vault MCPs that fetch secrets at runtime instead of baking them into config.

FAQ

Should I worry about prompt injection in MCP outputs?

Yes — especially when an MCP returns content from outside your control (web search, scraped pages, third-party APIs). The model can follow injected instructions, particularly when an autonomous agent has both a web-reading MCP and a credentialed-write MCP active. The mitigation is process: separate read and write capabilities across clients, require human approval for irreversible actions.

Are official MCPs safer than community ones?

They are reviewed, but "safer" is a spectrum. Official MCPs published by the underlying service (GitHub, Stripe, Notion, Supabase) are the strongest baseline — they share an incentive with you to not break things. Community MCPs vary; treat the unverified ones the way you would treat any unsigned binary downloaded from the internet.

How do I tell if an MCP server has been compromised?

Three signals. (1) Unexpected processes — `ps aux | grep mcp` shows entries you do not recognize. (2) Unfamiliar API calls — your provider's access log shows requests you did not initiate. (3) Behaviour drift — the server starts asking for new scopes or returning unexpected outputs. Any of the three: rotate credentials and review the server source if you can.

Should I run MCP servers in a sandbox?

Worth considering for execute-capable servers (E2B, code-running MCPs, untrusted community servers). Tools like Docker, Firecracker microVMs, or a dedicated user account with restricted permissions all work. For typical read-mostly MCPs (Filesystem, GitHub, Postgres in read-only mode) the sandbox overhead usually outweighs the marginal safety gain — focus on credential scoping instead.

Next steps

Trust model is set. Browse security-focused MCPs that help an agent reason about credentials, secrets, and posture without granting write access.