On this page
MCP Config File: Where It Lives and How to Scan It for Risky Servers (Nov 2026)

Your MCP config file lists every server your agent can start and what each one gets. Scan it in two passes. First read it by hand for five risks: unpinned versions, tokens in env, servers that shell out, plain-HTTP remotes and broad access. Then grade every server in it with one prompt.

The two passes catch different things. The hand check covers how you set servers up. The grade covers the servers themselves. Neither one replaces the other.

Where each client keeps its MCP config file

Client MCP config file Servers are under
Claude Desktop macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
mcpServers
Claude Code ~/.claude.json (user scope, and local scope under projects)
.mcp.json in the project (project scope, often committed)
mcpServers
Cursor ~/.cursor/mcp.json (all projects)
.cursor/mcp.json (one project)
mcpServers
VS Code User: mcp.json in your profile folder (%APPDATA%\Code\User\ on Windows, ~/Library/Application Support/Code/User/ on macOS, ~/.config/Code/User/ on Linux)
Workspace: .vscode/mcp.json
Older setups: "mcp" in settings.json
servers
Windsurf ~/.codeium/windsurf/mcp_config.json mcpServers (remotes use serverUrl)
Gemini CLI ~/.gemini/settings.json (user)
.gemini/settings.json (project)
mcpServers (HTTP remotes use httpUrl)
Codex ~/.codex/config.toml [mcp_servers.<name>] tables

Two quick ways to see what's loaded without opening files: claude mcp list in Claude Code, and the MCP: List Servers command in VS Code.

A project file like .mcp.json, .cursor/mcp.json or .vscode/mcp.json is easy to commit by accident. Anyone who clones the repo gets it, tokens and all. Check those first.

What one entry looks like

Every client uses the same two shapes. A local server is a command your machine runs:

"filesystem": {
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"],
  "env": {}
}

A remote server is a URL your client connects to:

"sentry": {
  "url": "https://mcp.sentry.dev/mcp",
  "headers": {}
}

A local entry runs code on your machine with your user's rights. A remote entry sends your prompts and tool calls to someone else's server. Read each one with that in mind.

Read it by hand: five things to look for

Here is a config with most of the problems in it. We use it again below.

{
  "mcpServers": {
    "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/"] },
    "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"],
                "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_EXAMPLE_NOT_REAL" } },
    "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] },
    "deploy-helper": { "command": "bash", "args": ["-c", "curl -fsSL https://example.com/install.sh | sh && deploy-mcp"] },
    "analytics": { "url": "http://mcp.example-analytics.com/mcp?token=abc123" },
    "sentry": { "url": "https://mcp.sentry.dev/mcp" }
  }
}

1. Unpinned versions

npx -y some-package with no version, or @latest, runs whatever version npx resolves when the client starts. That's usually the newest one. A bad release, or a rug pull, reaches you without you choosing it.

  • Spot it: npx args with a bare package name or @latest, uvx with a bare name, Docker images with no tag or :latest.
  • Fix it: pin the version you tested: some-package@1.4.2, uvx some-package@1.4.2, or an image tag or digest.

In the example, server-filesystem, server-github and context7-mcp@latest are all unpinned.

2. Tokens in env, args or URLs

A token pasted into env sits in plain text in that file. So does one in an argument or a URL query string, like ?token=abc123 in the example.

  • Spot it: values that look like keys (ghp_, sk-, xoxb-, long random strings) in env, args, headers or url.
  • Fix it: keep the value out of the file. Use your client's variable syntax or an input prompt, and give the token the fewest scopes that work. The steps for each client are in how to keep API keys out of your MCP config.

If the file was ever committed, the token is in your git history. Rotate it.

3. Servers that shell out

Some entries don't start a server package at all. They start a shell.

  • Spot it: bash -c, sh -c, cmd /c, powershell -Command, curl ... | sh, or uvx --from git+https://... pointing at a branch.
  • Why it matters: the command can change every time the script it downloads changes, and nobody can grade it. deploy-helper in the example pipes a remote script into sh on every start.
  • Fix it: install a named, pinned package instead, or read the script and keep a local copy you control.

Servers whose job is to run shell commands (terminal or "desktop control" servers) are a different case. They do exactly what they say. Keep approval on for every command they run.

4. Plain-HTTP remotes

A remote at http:// (not https://) sends your prompts, tool results and any token in clear text. analytics in the example does both.

  • Spot it: url, serverUrl or httpUrl starting with http://, unless it's http://localhost or 127.0.0.1 on your own machine.
  • Fix it: use the https:// address. If the server doesn't have one, don't use it with a real token.

5. Broad access

  • Spot it: a filesystem server given / or your whole home folder (the example gives it /), Docker with -v /:/host or --privileged, a database URL for production, a token with every scope.
  • Fix it: give each server only the folder, database or scopes it needs for the job.

While you're there, check for packages their authors have given up on. In npm, npm view @modelcontextprotocol/server-github deprecated prints "Archived and unmaintained; no security guarantees." That's the old GitHub server in the example. The current one is GitHub's own GitHub MCP server.

Scan your MCP config: grade every server in one prompt

The hand check tells you how you run each server. It can't tell you whether the server itself has a login, gets updates, or has known CVEs. That's what a grade is for.

Our TrustedMCP MCP server has a check_config tool for this. (We built it, so weigh that.) Add it, then ask:

Check the MCP servers in my config.

Run with npx, it finds the Claude Desktop, Claude Code, Cursor, VS Code and Windsurf files above on its own. For Gemini CLI or another client with an mcpServers JSON file, give it the path. For Codex, ask about each server by name. The hosted version can't see your files, so paste the config into the chat.

Here is the real output for the example config, from the live API on 2026-11-12:

Checked 6 MCP servers in 1 config: 3 graded (A 2, D 1), 0 only in the official registry, 3 not found.

### pasted config
- **filesystem**: grade **D**, Filesystem MCP Server. Fix first: No login: keep it local and never expose it on a network. Better graded in its category: Appwrite MCP Server (A), Buildkite MCP Server (A), Sentry MCP Server (A). https://trustedmcp.io/servers/filesystem-mcp-server
- **github**: not found (npm:@modelcontextprotocol/server-github). Review it yourself.
- **context7**: grade **A**, Context7 MCP. Fix first: Login is optional: turn it on. https://trustedmcp.io/servers/context7-mcp
- **deploy-helper**: runs `bash` with a local file or a name we can't match, so it can't be looked up. Review it yourself.
- **analytics**: not found (remote:mcp.example-analytics.com/mcp). Review it yourself.
- **sentry**: grade **A**, Sentry MCP Server. All four checks at full marks. https://trustedmcp.io/servers/sentry-mcp

To ask for a grade: https://trustedmcp.io/submit

Notice what it didn't flag. The grade for Context7 is A, but the config still runs @latest. The analytics URL shows up without http:// or the token, because check_config sends only names, package names, image names and URLs without query strings. Your tokens never leave your machine with the npx version, and that also means the tool can't warn you about them. That's why you do both passes.

What to do with each result

A or B. Good starting point. Still fix anything from the hand check: pin it, move tokens out, narrow its access. The "Fix first" line names the one thing that cost it the most points.

C or D. Read the "Fix first" line and the listing. A low grade often comes from something you can work around, like no login on a server you only run over stdio on your own machine. Then decide:

  • Keep it, limited. Local only, the narrowest folder or token, approval on for every tool call.
  • Swap it. The "better graded" names are in the same category, but they don't always do the same job. Check that one fits before you swap.
  • Remove it. If you haven't used it this month, take it out. Every server in the file is something your agent can start.

Not found or "only in the official registry". We have no grade for it. That's not a bad sign on its own, but you have to do the checking:

  1. Find the repo and see who maintains it, when it last changed and whether issues get answers.
  2. Run npm view <package> deprecated (or check PyPI) for an abandoned package.
  3. Ask registry_lookup about it. It shows the official MCP Registry entry and any reported security issues.
  4. Ask us to grade it. We add the ones people use.

Local scripts (node /path/to/server.js, python my_server.py) can't be graded by anyone but you. Read the code, or keep it on a machine with nothing to lose.

For the full before-you-install checklist, see are MCP servers safe?.

When to scan again

  • After you add or update a server.
  • When a big MCP CVE is in the news. Our monthly security roundup lists them.
  • Once a month anyway. Grades change when servers ship new versions or new CVEs land.

Frequently asked questions

Where is the MCP config file in Claude Code?

User-scope and local-scope servers are in ~/.claude.json. Project-scope servers are in .mcp.json at the project root, which is often committed to git. Run claude mcp list to see all of them.

Where is claude_desktop_config.json?

On macOS, ~/Library/Application Support/Claude/claude_desktop_config.json. On Windows, %APPDATA%\Claude\claude_desktop_config.json. In Claude Desktop, Settings, Developer, Edit Config opens it.

Is there a tool that scans my MCP config automatically?

Our check_config tool grades every server in it (we built it, so weigh that). Other tools check different things, like tool descriptions for prompt injection. MCP security tools compares what each kind checks and misses. None of them replaces reading the file once yourself.

Does check_config send my tokens anywhere?

Not with the npx version. It reads the file on your machine and sends only server names, package names, image names and server URLs without query strings. Env values, headers, tokens and file paths stay local. With the hosted version you paste the file, so the whole text is sent over HTTPS. We read only those same fields from it.

What is the best MCP server scanner?

It depends on what you want checked, and none of them checks everything. Scanners like Snyk Agent Scan and Cisco MCP Scanner start your servers and read their tool descriptions. A grade lookup like our check_config (we built it, so weigh that) grades each server in your file from public signals without running it. MCP security tools compares what each kind checks and misses.

How do I check an MCP server before I add it to my config?

Look it up first: the MCP registry check guide shows how to confirm it in the official MCP Registry and read any reported issues. Then read its entry by hand for the five risks above, and ask for its grade with check_config.

Is an unpinned npx server dangerous?

It's a risk, not a flaw. You run whatever the author published last, without choosing to. Most releases are fine. Pinning means a bad one can't reach you until you decide to update.

What does "not found" mean in the results?

We don't have a grade for that server, or the entry doesn't name a package, image or URL we can match. Review it yourself, check the official MCP Registry with registry_lookup, or ask us to grade it.