← All posts
·12 min read

Claude Code MCP Setup: Connect Tools Without the Bloat

Claude CodeMCPConfigurationTools
Claude Code MCP setup: connect tools without the bloat

Why MCP without rules turns into context bloat

The Model Context Protocol is the standard that lets Claude Code talk to external systems through a uniform interface. An MCP server exposes a set of tools, a database query tool, a GitHub API wrapper, a browser automation driver, and Claude Code can call them the same way it calls a built-in tool. The appeal is obvious. Instead of asking Claude to shell out to a CLI and parse the output, you give it a typed tool that returns structured data. The risk is just as obvious once you have lived with it: every server you enable pays a tax, and the tax is paid in the one resource a session cannot get back, which is context.

A Claude Code session with a dozen MCP servers enabled loads every tool definition from every server into the system prompt before the first message. Each tool carries a name, a description, and a full JSON schema for its parameters. A server with twenty tools can consume several thousand tokens of context that Claude reads on every turn whether it uses the server or not. Enable fifteen servers and a meaningful fraction of the window is gone before you have asked a question. The session that started sharp degrades faster, forgets earlier instructions sooner, and re-reads its own output more often, all because the config enabled tools the task never needed.

This guide covers the MCP setup that keeps Claude Code connected to the systems a task actually touches without drowning the context window: the .mcp.json structure and where it lives, the three config scopes and who inherits each, authentication that keeps secrets out of the repository, the context-cost math that decides what to enable, and the discipline of disabling idle servers. For the broader resource the whole window depends on, Claude Code context window management covers how a session spends and recovers its budget. For the servers that ship with the most leverage, Claude Code MCP servers covers the catalog worth knowing.

The .mcp.json structure

Claude Code reads MCP server definitions from a .mcp.json file. The shape is a single mcpServers object keyed by server name, and each entry declares how to launch the server and what environment it needs.

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PAT}"
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL}"
      }
    }
  }
}

Each server has a command and args that tell Claude Code how to start the process, and an env block that passes the credentials and configuration the server needs. The ${VAR} syntax reads from the environment rather than hardcoding a value, which is the single most important habit in this file. A token written literally into .mcp.json and committed to a repository is a leaked credential, and the leak is permanent because Git history keeps it even after you delete the line.

Servers can also connect over HTTP rather than launching a local process, which is how hosted MCP servers and remote integrations work.

{
  "mcpServers": {
    "linear": {
      "type": "http",
      "url": "https://mcp.linear.app/sse",
      "headers": {
        "Authorization": "Bearer ${LINEAR_API_KEY}"
      }
    }
  }
}

The type: "http" entry points Claude Code at a remote endpoint and passes auth in the headers. The same secret-handling rule applies: the bearer token reads from the environment, never the literal value, so the config file carries no credential of its own.

The MCP CLAUDE.md template

The CLAUDE.md at your project root is read at the start of every Claude Code session. For a project that uses MCP it needs to declare which servers exist, what each is for, the context-cost policy, the secret-handling rule, and the hard rules that stop Claude from wiring servers it does not need or leaking tokens into the repo.

# MCP rules

## Servers in use
- github: PRs, issues, commits (HTTP, token from env)
- postgres: read-only queries against the dev database
- playwright: browser automation for E2E debugging only

## Config scope
- Project servers live in .mcp.json, committed, NO secrets inline
- Personal servers live in user scope, never committed
- Secrets ALWAYS read from env with ${VAR}, never literal values

## Context cost (MANDATORY)
- Every enabled server adds tool definitions to the system prompt
- Enable ONLY servers the current task needs
- Disable idle servers with `claude mcp disable <name>`
- A server with many tools is a context cost even when unused

## Adding a server
- Confirm the task cannot be done with a built-in tool first
- Document the server's purpose in this file before enabling it
- Prefer a narrow, single-purpose server over a broad one

## Hard rules
- NEVER write a literal token or secret into .mcp.json
- NEVER commit a .mcp.json that contains a credential
- NEVER enable a server "just in case" it might be useful
- NEVER leave a one-off server enabled after the task is done
- ALWAYS read secrets from environment variables
- ALWAYS check the built-in tools before reaching for an MCP server

Three of these rules carry most of the weight.

The secret-handling rule prevents the most expensive mistake. A literal token in a committed .mcp.json is exposed to everyone with repo access and stays in history forever. The rule forces every credential through ${VAR}, so the file is safe to commit and the secret lives only in the environment.

The context-cost rule is the one teams discover too late. Claude Code does not warn you that fifteen enabled servers are eating the window. It simply gets worse at long sessions. The rule makes the cost explicit and ties it to a habit: enable what the task needs, disable the rest. This is the same discipline that Claude Code cost optimization applies to spend, because context and cost move together.

The built-in-first rule stops a common over-engineering reflex. Claude will reach for an MCP server to do something a single Bash call already handles, adding a dependency and a context cost for no gain. The rule forces the question every time: can a built-in tool do this? If yes, the server is not worth the tax.

Config scopes: local, project, user

Claude Code resolves MCP config from three scopes, and knowing which is which prevents the confusion where a server works for you but not a teammate, or a credential ends up somewhere it should not.

Project scope is the .mcp.json at the repository root. It is committed, shared with everyone who clones the repo, and meant for servers the whole team uses. Because it is committed, it must never contain a literal secret. This is where the GitHub server, the project database server, and any team-wide integration belong, all reading their credentials from the environment.

User scope is config stored in your Claude Code user settings, outside any repository. It applies across every project you open and is never committed. This is where personal servers belong: a notes server you use everywhere, a personal API key you do not want in any repo, a tool that is yours rather than the team's.

Local scope is project-specific config that stays on your machine and is not committed, typically in a local settings file. It is the right place for a server you want in this project but not in the shared config, for example a debugging server you are trialling before proposing it to the team.

The CLI manages these explicitly, so you do not have to hand-edit files to get the scope right.

# Add a server to project scope (committed .mcp.json)
claude mcp add github --scope project

# Add a server to user scope (applies everywhere, never committed)
claude mcp add my-notes --scope user

# List configured servers and their scope
claude mcp list

# Disable an idle server to reclaim context
claude mcp disable playwright

The --scope flag decides who inherits the server. The disable command is the one to remember, because it is how you reclaim the context a server costs without deleting its config. A server you disable today and re-enable next week keeps its definition; it just stops loading its tools into the window in the meantime.

Authentication without leaking credentials

MCP servers need credentials, and the only safe place for a credential is the environment. The pattern is a .env file that is git-ignored, exported into the shell Claude Code runs in, and referenced by ${VAR} in the config.

# .env (git-ignored, never committed)
GITHUB_PAT=ghp_xxxxxxxxxxxxxxxxxxxx
DATABASE_URL=postgresql://localhost:5432/dev
LINEAR_API_KEY=lin_api_xxxxxxxxxxxx
# .gitignore (confirm .env is listed)
.env
.env.local

With the secrets in a git-ignored .env, the .mcp.json references them by name and carries nothing sensitive. The first thing to verify on any project is that .env is actually in .gitignore, because a single accidental commit of that file is a credential rotation event for every key it holds.

For HTTP servers that use OAuth rather than a static token, Claude Code handles the auth flow interactively the first time you connect, storing the resulting token in its own credential store rather than in any file you manage. The principle is identical: the token never lands in a committed file.

When a server fails to start, the cause is almost always a missing or misnamed environment variable. The ${VAR} resolved to empty, the server launched without its credential, and it errored on the first call. Checking that the variable is exported in the shell Claude Code inherited fixes the common case.

The context-cost math that decides what to enable

The decision to enable a server is a context-budget decision, and treating it as one changes how the file looks. Each server you enable loads its full tool surface into the system prompt. A focused server with three or four tools costs little. A broad server that exposes thirty tools, each with a detailed schema, costs a great deal, and you pay it on every turn for the whole session whether or not Claude calls a single one of those tools.

The practical rule is to match enabled servers to the session's actual work. A session that is debugging a database issue needs the database server and nothing else. A session reviewing a pull request needs the GitHub server. A session doing both might warrant both, but a session that has fifteen servers enabled out of habit is spending its window on tools it will never touch in this task.

Some setups use a token-optimizer layer that lazy-loads tool definitions only when a server is first called rather than at startup, which softens the cost for servers you keep configured but rarely use. Where that is available it is worth using, but it does not remove the underlying principle. The leanest session is the one with the fewest tools competing for attention, and a focused tool surface produces sharper reasoning than a sprawling one. This is the same trade-off that governs Claude Code subagents: a narrow surface outperforms a broad one because attention is finite.

Verifying a server works

Before you rely on a server in a real task, confirm it starts, authenticates, and exposes the tools you expect. The CLI gives you a direct way to check.

# Confirm the server is configured and shows as connected
claude mcp list

# Inspect what tools a server exposes
claude mcp get github

The list command shows each configured server and whether Claude Code could connect to it. A server that shows as failed almost always has a credential or command problem, the wrong package name in args, a missing environment variable, a token without the right scope. The get command shows the tool surface, which is how you confirm the server exposes what you need and, just as usefully, see how many tools it brings so you can judge its context cost before enabling it for a long session.

A quick connection test inside a throwaway session is the final check. Ask Claude to perform one read-only operation through the server, listing repositories, running a trivial query, and confirm it returns real data. If the operation succeeds, the wiring is correct and the credential is valid.

Common Claude Code mistakes with MCP

Six patterns Claude generates incorrectly without CLAUDE.md constraints.

1. A literal token written into .mcp.json

Claude generates: an env block with the actual secret value inline.

Correct pattern: ${VAR} reading from a git-ignored environment file, never the literal value.

2. Enabling a server a built-in tool already covers

Claude generates: an MCP server to run a command a single Bash call handles.

Correct pattern: check the built-in tools first; only add a server when no built-in does the job.

3. Wrong scope for the server

Claude generates: a personal credential added to the committed project .mcp.json.

Correct pattern: personal servers in user scope, team servers in project scope with secrets from env.

4. Idle servers left enabled

Claude generates: every server from every past task still loaded into the window.

Correct pattern: claude mcp disable <name> for anything the current task does not need.

5. No .gitignore entry for the secrets file

Claude generates: a .env with real keys and no confirmation it is ignored.

Correct pattern: verify .env is in .gitignore before any key goes in it.

6. A broad server chosen over a narrow one

Claude generates: a single sprawling server with thirty tools for a task that needs three.

Correct pattern: prefer a focused single-purpose server to keep the tool surface and context cost small.

Add each pattern to CLAUDE.md with the corrected form. Combined with CLAUDE.md examples for the general structure, the result is MCP config Claude gets right the first time.

Keeping the config lean over time

MCP config rots the same way a dependency list does. A server added for one task stays enabled long after the task is done. A credential added to the environment outlives the integration that needed it. Left alone, the .mcp.json accumulates servers nobody remembers enabling, each quietly taxing the context window of every session.

The maintenance habit is periodic pruning. Once in a while, read the .mcp.json and the output of claude mcp list, and for each server ask whether the project still uses it. A server that no current workflow touches should be disabled or removed, and its credential pulled from the environment if nothing else needs it. The same claude mcp disable command that reclaims context for a single session is the tool for keeping the standing config lean. This is the configuration equivalent of the dependency hygiene that Claude Code permissions brings to what Claude is allowed to run.

Building an MCP setup that connects without bloating

The MCP CLAUDE.md in this guide produces a setup where servers read their credentials from the environment and never leak into the repo, project and personal config live in the right scope, only the servers a task needs are enabled, idle servers are disabled to reclaim context, and a built-in tool is preferred whenever it does the job. The result is a session connected to exactly the systems it touches, with a context window spent on the work rather than on tools it will never call.

The principle is the same as any Claude Code configuration. MCP without rules accumulates servers, leaks secrets, and quietly burns the context window on unused tool definitions. The CLAUDE.md is what keeps the config lean, the secrets safe, and the window spent where it matters.

For the resource every MCP decision draws down, Claude Code context window management covers how a session budgets and recovers context. For the spend side of the same trade-off, Claude Code cost optimization covers how to keep token usage efficient. For the catalog of servers worth knowing, Claude Code MCP servers covers the integrations with the most leverage.

Get Claudify. Wire Claude Code to the tools it needs and none of the ones it does not.

More like this

Ready to upgrade your Claude Code setup?

Get Claudify
Featured on Dofollow.Tools AI Toolz Dir Claudify - Featured on Startup Fame