DEV Community

Rulestack
Rulestack

Posted on

MCP servers in Claude Code: the minimal setup, and when you should skip MCP entirely

Most MCP setup guides start with a wall of JSON. You don't need it. Claude Code can register an MCP server with one CLI command, and for a lot of teams the right number of MCP servers is zero — a shell command in a rules file does the same job with less context overhead. This is the minimal path, the config that actually gets written to disk, and the handful of failure modes that account for almost every "my server doesn't show up" thread.

The two-command happy path

For a local (stdio) server, this is the whole setup:

claude mcp add github -- npx -y @modelcontextprotocol/server-github
Enter fullscreen mode Exit fullscreen mode

Then inside a session:

/mcp
Enter fullscreen mode Exit fullscreen mode

/mcp shows every configured server, its connection state, and the tools it exposes. If your server is listed and connected, you're done. If it isn't, skip to the failure modes section — the cause is almost always one of four things.

The -- separator matters: everything after it is the command Claude Code runs to start the server process. Flags before it belong to claude mcp add itself.

Scopes: where the config actually lives

Every MCP server has a scope, and the scope decides which file it's written to and who else gets it. This is the part most people discover by accident when a server follows them into an unrelated project — or doesn't follow them into the one where they wanted it.

Scope Flag Written to Who sees it
local (default) your user config, keyed to the current project just you, just this project
project --scope project .mcp.json at the repo root everyone who clones the repo
user --scope user your user config, global just you, every project

Two practical rules fall out of this:

  • A server your whole team needs belongs in .mcp.json, committed like any other config file. Teammates get it on pull. Claude Code asks each person to approve a project's servers on first use (they're arbitrary executables from the internet's point of view), so nobody silently runs what you committed. If you decline the prompt and change your mind later, claude mcp reset-project-choices re-asks.
  • A server for your personal workflow belongs in user scope, not copy-pasted into every project's local scope. claude mcp add --scope user notion ... once, and it's everywhere.

.mcp.json is plain JSON and fine to edit by hand:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

That ${GITHUB_TOKEN} is not decoration — Claude Code expands environment variable references in .mcp.json (${VAR}, with ${VAR:-fallback} for defaults) at server start. This is how you commit a shared config without committing anyone's token: the file references the variable, each machine supplies its own value.

Remote servers

Servers that live behind a URL instead of a local process use a transport flag:

claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
Enter fullscreen mode Exit fullscreen mode

For services that need auth, run /mcp in a session and pick the server — Claude Code walks the OAuth flow in your browser and stores the token. No key ends up in a config file, which is exactly where keys shouldn't be.

Remote HTTP servers have one operational property worth internalizing: they fail with the network. If a provider's MCP endpoint is down, your session just loses those tools until it recovers. Design your rules so that nothing critical assumes an MCP tool is always present.

The four failure modes that actually happen

1. The command isn't on PATH where Claude Code runs. Your shell has nvm-managed node; the environment Claude Code launched from may not. If /mcp shows the server as failed and the log says command not found, use an absolute path to the binary (command: "/Users/you/.nvm/versions/node/v22.17.0/bin/npx") or a wrapper script that sources your environment first.

2. The env block is missing. A stdio server is a child process — it inherits nothing you didn't give it. If the server needs GITHUB_TOKEN and the env block doesn't pass it, the server usually starts fine and then every tool call fails with an auth error. The confusing symptom: connected server, broken tools.

3. The server is slow to start and gets killed. Claude Code enforces a startup timeout (configurable with the MCP_TIMEOUT environment variable). First-run npx downloads are the classic trigger: the download takes longer than the timeout, the server "fails", and the second attempt mysteriously works because the package is now cached. Warm the cache (npx -y <pkg> --help once) or raise the timeout.

4. It's a scope problem, not a server problem. The server works in the project where you added it and is "missing" everywhere else — because default scope is local. claude mcp list shows what's configured in the current context; if the server isn't in the list, it's not broken, it's just somewhere else.

Run claude --debug when none of the above fits — it logs each server's startup and the actual error instead of a silent absence.

Permissions: MCP tools are just tools

Every MCP tool gets a name of the form mcp__<server>__<tool>, and your permission rules treat it like any other tool. Two useful patterns:

{
  "permissions": {
    "allow": ["mcp__github__search_repositories"],
    "deny": ["mcp__github__delete_repository"]
  }
}
Enter fullscreen mode Exit fullscreen mode

mcp__github (no tool suffix) matches every tool the server exposes. One thing to know: MCP tool rules don't take argument patterns — you can allow or deny a tool, but not "this tool with these arguments". Scope your write-capable tokens accordingly: the permission system controls which tools run, the token controls what they can touch.

When you don't need MCP at all

Every connected server injects its tool definitions into context — that's capability you pay for in tokens on every request, whether or not the session uses it. Before adding a server, it's worth asking what the integration is actually for:

  • Wrapping a CLI you already have? Claude Code can run gh, aws, kubectl, psql through Bash directly. A line in your rules file ("use gh for GitHub operations") costs a few tokens once. An MCP server that duplicates a CLI costs schema tokens forever and adds a process to babysit.
  • One-off API calls? A documented curl pattern in a rules file is transparent, debuggable, and versioned with your repo.
  • Genuinely stateful integrations — OAuth-gated services with no usable CLI, streaming data sources, tools that need server-side session state — are what MCP is for. Sentry, Notion, browser control, internal platform APIs behind SSO: real use cases.

The heuristic that has held up: if you can express it as a command, write it as a rule; if it needs a connection, make it a server. Teams that follow it end up with one to three servers doing work nothing else can do, instead of eight servers reimplementing their shell.


Rulestack builds config packs for Claude Code, Cursor, and Codex — rules files, hooks, and permission setups tested against current tool behavior: https://rulestack.gumroad.com?ref=devto?ref=devto

Short, practical notes on AI coding agents, most days, on Bluesky: @ai-shop.bsky.social

Top comments (0)