·10 min read

How to Share MCP Servers Across Your Engineering Team

Stop MCP config drift. Learn how to share MCP servers across your team with version-controlled .mcp.json, safe secrets, and server allowlists.

The fastest way to share MCP servers across an engineering team is to stop treating MCP configuration as personal machine state. Check a project-scoped .mcp.json into version control, reference secrets through environment variables instead of hardcoding them, prefer centralized remote servers over per-developer local processes, and enforce an allowlist so only approved servers run against your codebase.

That one paragraph is the whole playbook. The rest of this guide walks through each step with working configs, because the details — where each tool reads its config, how secrets leak, when a centralized MCP server beats a local one — are where most team MCP setups fall apart.

The team MCP problem: config drift and snowflake setups

MCP servers are how agents like Claude Code, Cursor, and Windsurf reach your actual infrastructure: databases, issue trackers, CI, internal APIs. They are also, in most teams, configured entirely by hand on each laptop.

The result is a familiar failure mode:

  • Config drift. One developer runs the GitHub MCP server pinned to a specific version; another runs latest with different flags. The same prompt produces different tool behavior on different machines.
  • Snowflake setups. The senior engineer who set up the Postgres MCP server six months ago has a working config nobody else can reproduce. When their laptop dies, so does the setup.
  • Silent security gaps. Someone pastes a production API key directly into a JSON config that later gets committed, screenshotted, or synced to a personal dotfiles repo.
  • Onboarding tax. Every new hire spends an afternoon reverse-engineering which servers the team actually uses, with which credentials, at which versions.

MCP servers for teams need the same discipline as any other shared dependency: declared in the repo, reviewed in PRs, reproducible on any machine. Here is how to get there.

Step 1: Share MCP servers through version control

MCP config version control starts with a simple decision: the project — not the developer — owns the server list.

1. Create a project-scoped .mcp.json

Claude Code reads a .mcp.json file at the repository root and treats it as project-scoped configuration, shared by everyone who clones the repo:

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

Note the ${GITHUB_TOKEN} syntax — Claude Code expands environment variables inside .mcp.json, which is what makes the file safe to commit (more on that in step 2).

2. Commit it and review changes like code

git add .mcp.json
git commit -m "chore: add shared MCP server config"

From now on, adding or changing an MCP server is a pull request. That gets you review, history, blame, and rollback for free. Someone wants to add a new server? They open a PR and the team sees exactly what command runs and what credentials it needs.

3. Mirror the config for other tools

Each tool reads project-level MCP config from its own location:

ToolProject config location
Claude Code.mcp.json (repo root)
Cursor.cursor/mcp.json
VS Code / GitHub Copilot.vscode/mcp.json
Windsurfglobal mcp_config.json (no per-repo file)

The JSON shape is nearly identical across tools, so most teams keep one canonical config and copy or generate the variants. If your team is split across editors, our guide to MCP in Claude Code covers the Claude-specific scopes (local, project, user) in more depth.

Step 2: Secrets management that doesn't leak keys

The number one rule: the committed config declares which secrets a server needs, never their values.

1. Reference variables, don't inline them

Bad — this ends up in git history forever:

{
  "env": {
    "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_a1b2c3..."
  }
}

Good — the config is inert without the developer's own environment:

{
  "env": {
    "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
  }
}

2. Document required variables in an example file

Commit a .env.example next to the config so nobody has to guess:

# .env.example — copy to .env and fill in (never commit .env)
GITHUB_TOKEN=            # GitHub PAT, repo scope only
DATABASE_URL_READONLY=   # read-only replica, NOT the primary

3. Scope every credential down

Each developer supplies their own token, scoped to the minimum the server needs: a read-only database role, a repo-scoped PAT, a sandbox API key. If a laptop is compromised, you revoke one person's credentials — not a shared team key. Shared static keys pasted into group chats are how MCP setups end up in incident reports; our MCP security best practices guide covers the full threat model, including tool poisoning and prompt injection via server responses.

VS Code's .vscode/mcp.json goes a step further with an inputs block that prompts each developer for secrets on first use and stores them outside the repo — worth using if your team lives in Copilot.

Step 3: Centralized MCP server vs. per-dev local servers

Every server in your config runs in one of two ways, and the choice matters more for teams than for individuals:

Local (stdio)Centralized remote (HTTP)
Runs whereEach developer's machineOne shared endpoint
Version consistencyDrifts per machineEveryone hits the same version
CredentialsPer-dev env varsOAuth per user, enforced server-side
Access controlWhatever the token allowsCentrally scoped and revocable
Best forFilesystem, local builds, offline workDatabases, internal APIs, SaaS integrations

A centralized MCP server flips the trust model in your favor. Instead of forty laptops each holding a database credential, one audited endpoint holds it, and developers authenticate to the endpoint via OAuth. Config-wise, remote servers are also simpler to share — there is nothing to install:

{
  "mcpServers": {
    "internal-api": {
      "type": "http",
      "url": "https://mcp.internal.example.com/mcp"
    }
  }
}

The practical split most teams land on: remote for anything touching shared infrastructure, local stdio only for servers that genuinely need the developer's machine (filesystem access, local test runners). This is also the model localskills uses for its own MCP server — agents search and install skills over MCP with OAuth and scoped access, so there is no shared key to distribute and nothing for a new developer to run locally.

Step 4: One-command team MCP setup for new engineers

With the config in the repo and secrets externalized, onboarding collapses to: clone, set env vars, approve the servers. Make even that scriptable.

1. Add a setup script

#!/usr/bin/env bash
# scripts/setup-mcp.sh
set -euo pipefail

if [ ! -f .env ]; then
  cp .env.example .env
  echo "Created .env — fill in your tokens, then re-run."
  exit 1
fi

echo "MCP config is in .mcp.json (Claude Code) and .cursor/mcp.json (Cursor)."
echo "Your editor will prompt you to approve the project servers on first launch."

New engineer, day one: bash scripts/setup-mcp.sh, fill in two tokens, done. Both Claude Code and Cursor prompt for explicit approval before running project-declared servers, so committing the config never silently executes anything on a teammate's machine.

2. Package the whole playbook as an installable skill

Config files tell tools what to run; they don't teach agents or humans when and how to use those servers. That knowledge — "use postgres-readonly for schema questions, never write via MCP, prefer the GitHub server over shelling out to gh" — belongs in a skill.

On localskills.sh, a skill is a versioned package with a root SKILL.md that can bundle supporting files — docs, scripts, and config templates — up to 100 MB per version. Publish your team's MCP conventions once, then every engineer installs them into whichever tools they use:

npm install -g @localskills/cli
localskills login
localskills install acme/mcp-conventions --target claude cursor windsurf

One published skill, written out in each tool's native format — .claude/skills/ for Claude Code, .cursor/rules for Cursor, .windsurf/rules/ for Windsurf. When the conventions change, you publish a new version and the team pulls the update instead of re-circulating a wiki page. It is the same shared-standards workflow teams already use for coding rules, applied to MCP.

Step 5: Governance — allowlists and approved servers

Sharing is only half of team MCP setup; the other half is deciding what doesn't run.

1. Allowlist project servers explicitly

In Claude Code, a checked-in .claude/settings.json can pin exactly which .mcp.json servers are approved:

{
  "enabledMcpjsonServers": ["github", "postgres-readonly"],
  "disabledMcpjsonServers": ["experimental-scraper"]
}

Now a drive-by PR that adds a server to .mcp.json does nothing until the allowlist changes too — a second, very visible diff for reviewers.

2. Enforce at the organization level

For settings developers shouldn't be able to override, Claude Code supports managed settings deployed by IT, which can restrict MCP usage machine-wide. See our managed settings guide for the full deployment story.

3. Maintain an approved-server registry

Keep a short, reviewed list of servers your org trusts — package name, pinned version, required scopes, owner. Vet anything new before it lands in any repo's config: MCP servers execute with your credentials, and an unvetted server is arbitrary code with database access. Treat additions to the registry with the same seriousness as adding a production dependency.

FAQ: how teams share MCP servers

Should I commit .mcp.json to git?

Yes — that's what project scope is for. Commit the server list with environment-variable references for anything sensitive, add .env to .gitignore, and let each tool's approval prompt act as the final consent gate on every machine.

How do I share MCP servers without sharing API keys?

Declare secrets as ${VAR} references in the committed config and have each developer supply their own scoped credential via a local .env file or shell profile. For shared infrastructure, prefer a centralized remote server with per-user OAuth so no static key exists to leak in the first place.

What's the difference between a local and a remote MCP server?

A local server is a process (usually npx ...) each developer runs on their own machine over stdio; a remote server is a shared HTTP endpoint everyone connects to. Teams generally centralize servers that touch shared systems and keep only machine-specific servers local.

How do I stop teammates from adding unapproved MCP servers?

Use an explicit allowlist (enabledMcpjsonServers in Claude Code) checked into the repo so new servers require a reviewed settings change, and enforce org-wide restrictions through managed settings where you need a hard guarantee.

Can one MCP config work across Claude Code, Cursor, and Windsurf?

The JSON shape is close enough that one canonical server list can generate all the variants, but each tool reads from a different path — .mcp.json, .cursor/mcp.json, .vscode/mcp.json. Keep one source of truth in the repo and mirror it; document the mapping in a shared skill so nobody has to rediscover it.


Ready to give your team one source of truth for agent setup? Create a free localskills.sh account and publish your MCP conventions as a versioned, installable skill.

npm install -g @localskills/cli
localskills login
localskills publish