Skip to content

mcp · claude-code · revops · ai-governance · agencies

MCP Scopes Explained: Isolating Claude Connections Per Client

If you run an agency with duplicate client instances, your MCP config is probably leaking between them. A 90-second test that proves it, why the scope everyone reaches for is the wrong one, and the folder pattern that gives you a hard wall.

On this page
  1. Your Claude MCP config is probably leaking between clients
  2. What are the MCP scopes in Claude Code?
  3. Why duplicate instances make this worse than it looks
  4. Which scope actually isolates client data?
  5. How to set up one folder per client
  6. Three leaks local scope does not fix
  7. Does this work in Cowork or Claude Desktop?
  8. Where this approach runs out

I run an agency. Right now I am connected to five Attio instances, three HubSpots, six Google Analytics properties, and six Stripe accounts. One client is a private equity firm with a portfolio of companies, so the duplication compounds.

Load all of that at once and two things break.

First, the tools collide. You get six tools with the same name pointing at six different companies' revenue.

Second, and worse, the model picks one. Sometimes it picks right.

The failure I care about is not reading the wrong client's numbers and showing them to another client. That is bad. It is recoverable. The failure I care about is writing to the wrong client's CRM. There is no undo for that.

So I went looking for a hard wall. Here is what I found, including the part where the obvious answer turned out to be the wrong one.

Your Claude MCP config is probably leaking between clients.

Ninety seconds. Run this anywhere.

mkdir -p ~/scopetest && cd ~/scopetest

cat > .mcp.json <<'EOF'
{"mcpServers":{"parent-only-leak":{"type":"stdio","command":"echo","args":["leaked"]}}}
EOF

mkdir -p clientA && cd clientA
git init

cat > .mcp.json <<'EOF'
{"mcpServers":{"client-crm":{"type":"stdio","command":"echo","args":["correct"]}}}
EOF

claude mcp list

You are now inside a client folder that has its own .mcp.json and its own git repository. It should be sealed. Here is what came back on Claude Code v2.1.218:

client-crm: echo correct - Pending approval
parent-only-leak: echo leaked - Pending approval

The parent's server is loaded. Four things that test establishes:

-> .mcp.json files are inherited from parent directories. I confirmed it across two directory levels.

-> A .git in the client folder does not stop it. That folder was its own repository and inherited anyway.

-> On a name collision, the nearest definition wins. A crm in the client folder beats a crm in the parent.

-> Uniquely named parent servers silently join the set. This is the real danger. Not an override you would notice. A union you would not.

So project scope walls you off from sibling folders. It does not wall you off from anything above you. If your client folders sit under a shared parent that has any MCP config at all, every client inherits it.

What are the MCP scopes in Claude Code?

There are four layers that can put a tool in front of the model, not three. Ranked by blast radius, widest first.

Layer Stored in Loads in Inherits downward Safe for client credentials
claude.ai connectors Your Claude account Every folder, every surface Account-wide No
User scope ~/.claude.json Every project on that machine Machine-wide No
Project scope .mcp.json in the folder That folder and everything below it Yes No. It is built to be committed
Local scope ~/.claude.json, keyed to the exact path That one folder only No Yes

Precedence runs the opposite direction from blast radius. Local beats project, project beats user, user beats plugin servers, plugin beats claude.ai connectors. Narrowest wins.

That ordering is where agencies get burned. The widest layer sits at the bottom of the precedence list, so it never announces itself by overriding anything. It just quietly adds tools to every folder you open.

One thing that is easy to conflate: transport is a separate axis from scope. Whether a server runs as a local stdio process or a remote HTTP endpoint has nothing to do with which folders it loads in. Any transport can sit at any scope. I have pulled that apart in the full scope reference.

Why duplicate instances make this worse than it looks.

For one company with one Attio, none of this matters. Everything is loaded, everything is correct, and scope is a rounding error.

Run five Attios and it inverts.

The first problem is naming. Five servers exposing a search_records tool give the model five identical-looking doors into five different companies. You can namespace around it. attio_clienta_search_records and so on. That works until you have twenty servers and the names are doing the job a boundary should be doing.

The second problem is context. Every loaded server costs tokens. Tool search defers most of that now, so it is less brutal than it used to be, but twenty servers is still twenty servers. You are paying for nineteen clients' tools to sit in a room where you are working on one.

Both problems have the same fix, and it is not better naming.

Which scope actually isolates client data?

Local scope. It is also the default, which is why almost nobody configures it.

Same nested folder structure as before. This time the parent server is added at local scope instead of project scope:

cd ~/scopetest
claude mcp add --scope local parent-local -- echo local-parent

cd clientA
claude mcp list

Result:

No MCP servers configured.

Nothing crossed. Local scope is keyed to the exact project path inside ~/.claude.json, so it does not inherit in either direction.

Here is the inversion, and it is the whole post. The mechanism with a visible file you can drop in a client folder is the one that leaks. The mechanism that actually isolates is the invisible default you never touched.

And it dissolves the naming problem instead of managing it. If only one Attio is ever loaded in a folder, there is nothing to collide with. You do not need attio_clienta_search_records. You need search_records and a wall.

How to set up one folder per client.

Flat. Not nested under a shared parent with config in it.

~/clients/
  acme/
    CLAUDE.md
  northwind/
    CLAUDE.md
  portfolio-co-1/
    CLAUDE.md

For each client, from inside that folder:

cd ~/clients/acme
claude mcp add --scope local attio -- npx -y attio-mcp-server
claude mcp add --scope local stripe --transport http https://mcp.stripe.com

No --scope flag also works, since local is the default. I write it out anyway so the intent is legible to whoever reads the setup next.

Verify before you trust it:

cd ~/clients/northwind && claude mcp list

If you see Acme's servers there, stop and fix it before you do any work.

The client's CLAUDE.md carries the context that should never travel: which instance is which, what the naming conventions are, what is off limits. Same wall, applied to instructions instead of tools.

Three leaks local scope does not fix.

Do the folder setup and stop there and you are still exposed.

-> User scope. Anything you added with --scope user is live in every client folder. Audit it with claude mcp list from a folder that should be empty. If anything shows up, that is your leak.

-> claude.ai connectors. Anything connected in your Claude account flows into Claude Code automatically. It sits last in precedence, so it never overrides anything and never announces itself. Check /mcp inside a session, not just the CLI.

-> Secrets in a committed .mcp.json. If you do use project scope for anything, the env block goes into git history. Use ${VAR} expansion and keep the values in your shell.

Does this work in Cowork or Claude Desktop?

No, and this is the part I could not find a straight answer to anywhere.

Cowork and Claude Desktop do not read a per-folder .mcp.json. Anthropic's documentation is direct about the reason: remote connectors are configured and brokered through your Claude account, and the connection originates from Anthropic's servers rather than your machine. Local MCP servers configured in Claude Desktop through claude_desktop_config.json are a separate mechanism that does use your local network, but those are not available in Cowork or claude.ai.

Which means connector scoping on those surfaces is account-level. Per-conversation toggles exist. Per-folder walls do not.

Claude Code is currently the only surface where directory-scoped MCP config is real. If per-client isolation is a hard requirement, that is where the client work has to happen.

Where this approach runs out.

Everything above is manual, per-machine, and held together by discipline. It does not survive a second operator. It does not survive a laptop swap. Nothing audits it, so the first time it fails you will find out from a client.

That is a governance problem, not a config problem, and past a handful of clients it stops being solvable with files. If you are at that point and want to talk it through, book a chat.

Run the test first though. Ninety seconds, and you will know which side of this you are on.

- Jaron

Frequently asked questions

What are the MCP scopes in Claude Code?

Claude Code has three configuration scopes plus a fourth account-level layer. Local scope is stored in ~/.claude.json keyed to the exact project path and loads only in that one folder. Project scope lives in a .mcp.json file at the folder root, is designed to be committed to version control, and loads in that folder and every folder below it. User scope is stored in ~/.claude.json and loads in every project on that machine. Separately, connectors added to your claude.ai account flow into Claude Code automatically. Precedence runs local, then project, then user, then plugin servers, then claude.ai connectors.

Does .mcp.json inherit from parent directories?

Yes. Tested on Claude Code v2.1.218, a client folder with its own .mcp.json and its own git repository still loads MCP servers defined in a parent directory's .mcp.json, confirmed across two directory levels. On a name collision the nearest definition wins, but uniquely named parent servers are silently added to the set. A .git directory in the child does not stop inheritance.

Which MCP scope isolates client data properly?

Local scope. It is keyed to the exact project path inside ~/.claude.json and does not inherit in either direction, so a server added at local scope in a parent folder does not appear in subfolders. Project scope isolates you from sibling folders but not from ancestor folders. Local scope is also the default when you run claude mcp add without a scope flag.

Can I scope MCP connections per folder in Claude Cowork or Claude Desktop?

No. Cowork and Claude Desktop do not read a per-folder .mcp.json. Remote connectors are configured and brokered through your Claude account and the connection originates from Anthropic's servers rather than your machine, so scoping there is account-level with per-conversation toggles. Local MCP servers configured in claude_desktop_config.json are a separate mechanism and are not available in Cowork or claude.ai. Claude Code is currently the only surface with real directory-scoped MCP configuration.

How do I stop MCP tool name collisions across multiple client instances?

Scope each client's servers to that client's folder with local scope rather than namespacing the tool names. If only one CRM instance is ever loaded in a given folder there is nothing to collide with, so the model cannot pick the wrong instance. Namespacing tool names manages the symptom and stops scaling once you have many servers loaded at once.

How do I check whether my MCP config is leaking between clients?

Open a terminal in a client folder that should have no shared tooling and run claude mcp list. Anything that appears which you did not add in that folder is a leak, coming from user scope, a parent directory's .mcp.json, or a claude.ai connector. Also run /mcp inside a session, because account-level connectors do not always surface in the CLI output.