How to secure your MCP setup
Everything here can be done in an afternoon. None of it requires a security background, a budget, or a new toolchain.
Ordered roughly by how much risk each item removes per unit of effort.
1. Get the secrets out of the config files
This is the single highest-value change and it takes ten minutes.
Every MCP client substitutes environment variables in the config. Claude Desktop uses ${VAR}. VS Code and Cursor use ${env:VAR}. Your config should therefore contain the name of a secret and never the secret itself.
Move the real values into your shell profile, and understand the trade-off you are making: a shell profile is readable by anything running as you, which is more than a config file is. It is still the right default, because the config file is the one you paste into chats.
Note that process.env.NAME does not work. MCP clients substitute variables themselves; they do not evaluate JavaScript. The string is passed through literally and your server receives the wrong value.
2. Make the safe path the easy path
The reason credentials end up pasted into forums is that redaction is an extra step taken while frustrated. Remove the step.
- Keep a committed
config.example.jsonwith placeholder values and every field your setup uses. - Keep the real one in
config.json, gitignored, outside any directory you push from. - Point teammates at the example file when they ask how your setup works.
3. Split tokens per agent
If one credential can reach everything, one successful injection reaches everything.
Give each agent only the credentials its own job needs. The coding agent gets a repo-scoped GitHub token and nothing else. The research agent gets a search key. The support agent gets a ticketing token with a read scope it actually uses.
This is uncomfortable to set up the first time and trivial after, because you end up writing a short list of what each agent is for.
4. Scope the filesystem to a directory, not a disk
A path of / or ~ makes every SSH key, every .env, and every credential store on the machine reachable through the agent.
Give it one working directory:
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./workspace"]
One directory means that even a fully successful injection has a small ceiling.
5. Remove the guardrail-removing flags
--dangerously-skip-permissions, --allow-all-tools, --no-sandbox exist to make an agent easier to run. They remove the last check between a prompt and your filesystem, which is exactly the check prompt injection needs you to have removed.
If you added one to make something work, the underlying problem is usually a permission prompt that appeared at an inconvenient moment. Grant the specific capability the task needs instead.
6. Keep local servers local
When an MCP server runs on your machine, bind it to 127.0.0.1, not 0.0.0.0. The difference is between “reachable from this machine” and “reachable from the network you are on”, which includes every coffee-shop and hotel network you connect from.
If you need remote access, terminate TLS somewhere you control and tunnel — do not expose the raw port and hope.
7. Pin every installer
npx -y some-package resolves to whatever the registry serves at the moment it runs. Pin it:
"args": ["-y", "@modelcontextprotocol/server-github@0.6.2"]
Upgrades then become a decision rather than a surprise. Given that the same argument vector often carries your credentials, the package you run is part of your trust boundary.
8. Scan git history once
Even if you have been careful since the last incident, your history is the accumulated evidence. One pass over it tells you whether step 2 is already working.
# if you have trufflehog or gitleaks installed
gitleaks detect --source . --redact
# or, for the obvious cases, over the whole history:
git log -p --all | grep -nE '(gh[pousr]_[A-Za-z0-9]{36}|sk-[A-Za-z0-9]{32,}|AKIA[0-9A-Z]{16})'
Any hit is a credential to rotate, not a line to delete.
9. Re-run the scanner after every change
The config is the thing you edit most often, so it is the thing most likely to drift back. Paste it into the scanner whenever you add a server or change an auth setup. It takes a second, and it costs nothing because it runs on your machine.
What this does not cover
Prompt injection. There is no configuration that makes an agent safe from untrusted instructions, and anyone selling you one is selling a feeling. What the steps above do is bound the damage when injection succeeds — which is the only thing that has ever been in your control anyway.