MCP (Model Context Protocol) is the standard that lets Claude Code and Claude Desktop talk to external tools, databases, browsers, and APIs. The protocol is good. The config files are where teams trip.
In the last quarter I have reviewed 12 Claude Code setups across engineering teams. Eight had broken or insecure .mcp.json files. Five could not name what one of their MCP servers actually did. Three had production database credentials checked into version control.
This is the field guide. It also pairs with the MCP Server Config Builder, which encodes the safe defaults below into a guided form.
What MCP is, in one paragraph
An MCP server is a process Claude Code launches (stdio) or connects to (http/sse). The server exposes tools, resources, and prompts. The agent gets to use them as if they were native. A filesystem server lets the agent read files. A github server lets it open issues. A postgres server lets it query your database. You can write your own in 50 lines of TypeScript or Python.
The 12-minute first server
If you have never run an MCP server, do this:
- Open your
.claude.json(user-level) or create a.mcp.jsonin a repo (project-level). - Add this:
{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "${REPO_ROOT}"]
}
}
}
- Start a new Claude Code session in that repo.
- Ask the agent to list the files in the repo. It will use the new server.
Done. You have your first MCP server.
The three configs that brick setups
1. Servers with credentials in plaintext
I have seen .mcp.json files committed to public repositories with GITHUB_PERSONAL_ACCESS_TOKEN in plaintext. I have seen Postgres connection strings with production passwords. I have seen Vault tokens.
The fix is to reference environment variables, not embed secrets:
{
"mcpServers": {
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" }
}
}
}
Load the real value from your shell, a .env, or a vault. Never the JSON.
2. Servers nobody owns
The audit pattern: a server in .mcp.json that nobody on the team can describe. It was added by someone who has since left. It is still loaded every session. It has permissions nobody reviewed.
The fix is a quarterly MCP review. Three columns: server name, business case, owner. If a row has no owner, delete it by Friday.
3. Stdio commands that pull arbitrary npm packages
npx -y @some-org/cool-mcp-server runs whatever is in the latest version of that package. If the upstream maintainer's account is compromised, your laptop runs the attacker's code with whatever permissions you handed the server.
The fix is to pin versions and review what you install:
{
"args": ["-y", "@modelcontextprotocol/server-github@0.6.2"]
}
For anything internal-only, build the server yourself and publish to your private registry.
Stdio vs http vs sse
- stdio: process running locally, started by the client. Best for filesystem access, local databases, anything that should not leave the machine.
- http: remote server you connect to. Best for shared infrastructure: a team-wide Postgres MCP, a hosted browser automation server.
- sse: server-sent events over http. Best for long-running operations where the server pushes incremental updates.
For most teams, stdio is right for 80 percent of servers. http for the 20 percent that need to be shared.
What the audit-grade config looks like
A real one of mine, anonymized:
{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem@0.5.1", "${REPO_ROOT}"]
},
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github@0.6.2"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GH_REPO_SCOPE_TOKEN}" }
},
"internal-search": {
"type": "http",
"url": "https://mcp.internal.example.com/search"
}
}
}
Three servers. Pinned versions. No secrets in the file. Every server has a justifiable business case.
Receipts
- 12 audits in 90 days.
- 8 of 12 had broken or insecure
.mcp.jsonfiles. - 5 of 12 had servers nobody on the team could describe.
- 3 of 12 had production credentials in the config.
- Median MCP-related cleanup time per repo: 45 minutes.
If you want a clean starting point, the config builder outputs valid JSON in about three minutes. If you want your real config audited, that is the engagement.