Skip to content

Managing MCP server configuration across coding agents

Each coding harness reads MCP servers from its own file: Claude Code from .mcp.json, Cursor from .cursor/mcp.json, OpenCode from opencode.json, and the shared Open Agents layout from .agents/mcp.json. The same server needs one hand edit per file, and the harness does not report a typo in any of them. Since Tuff 0.1.8 an MCP server is a capability: the declaration lives in one place, and Tuff generates the config entries.

This walkthrough uses the everything server from the built-in catalog. It is the reference server the MCP project publishes for exercising the protocol, and it needs no API key. You need tuff and Node’s npx on your PATH.

Terminal window
mkdir mcp-demo && cd mcp-demo
tuff init
tuff add mcp everything -a claude -a cursor -a open-agents
installed everything (claude) -> .claude/mcp-servers/everything/server.toml
installed everything (cursor) -> .cursor/mcp-servers/everything/server.toml
installed everything (open-agents) -> .agents/mcp-servers/everything/server.toml
registered MCP server everything (claude) -> .mcp.json
registered MCP server everything (cursor) -> .cursor/mcp.json
registered MCP server everything (open-agents) -> .agents/mcp.json
installed everything from the built-in catalog (catalog 1.0.0)

Tuff writes two files per harness. The config entry is the file the harness reads:

.mcp.json
{
"mcpServers": {
"everything": {
"args": [
"-y",
"@modelcontextprotocol/server-everything"
],
"command": "npx"
}
}
}

The tracked record is the declaration Tuff hashes. tuff check and tuff diff use it in the same way as for a skill:

.claude/mcp-servers/everything/server.toml
id = "everything"
version = "1.0.0"
type = "mcp-server"
description = "Reference server exercising the full MCP surface: tools, resources, and prompts. Needs no API key, which makes it a good first target for tuff mcp doctor."
[server]
transport = "stdio"
command = "npx"
args = [
"-y",
"@modelcontextprotocol/server-everything",
]
[server.env]
[server.metadata]
tools_summary = "echo, add, longRunningOperation, sampleLLM, getTinyImage"

Each catalog entry is a launch declaration checked against the vendor’s README. The catalog holds no server code: npx, uvx, or docker fetches the server when the harness starts it.

Terminal window
tuff list
┌───────────────────┬────────────┬─────────┬─────────┬─────────────┬─────────┬──────────────────────────────────┐
│ ID │ TYPE │ VERSION │ SCOPE │ AGENT │ STATUS │ PATH │
├───────────────────┼────────────┼─────────┼─────────┼─────────────┼─────────┼──────────────────────────────────┤
│ everything │ mcp-server │ 1.0.0 │ project │ claude │ ✓ clean │ .claude/mcp-servers/everything │
│ everything │ mcp-server │ 1.0.0 │ project │ cursor │ ✓ clean │ .cursor/mcp-servers/everything │
│ everything │ mcp-server │ 1.0.0 │ project │ open-agents │ ✓ clean │ .agents/mcp-servers/everything │
│ tuff-capabilities │ skill │ 1.0.0 │ project │ open-agents │ ✓ clean │ .agents/skills/tuff-capabilities │
│ tuff-cli-guide │ skill │ 0.1.0 │ project │ open-agents │ ✓ clean │ .agents/skills/tuff-cli-guide │
└───────────────────┴────────────┴─────────┴─────────┴─────────────┴─────────┴──────────────────────────────────┘

tuff list shows one everything row per harness, because each harness has its own copy of the entry. tuff init installed the tuff-cli-guide skill, and the tuff-capabilities skill is described in the last section.

tuff mcp doctor starts each installed server, completes the MCP initialize handshake, and requests its tool list:

Terminal window
tuff mcp doctor
┌────────────┬───────────┬─────────────────────────────┬────────┬────────────┐
│ ID │ TRANSPORT │ HARNESSES │ STATUS │ DETAIL │
├────────────┼───────────┼─────────────────────────────┼────────┼────────────┤
│ everything │ stdio │ claude, cursor, open-agents │ ✓ ok │ 13 tool(s) │
└────────────┴───────────┴─────────────────────────────┴────────┴────────────┘

The server reported 13 tools. With the npm package already cached, the check took about half a second. Doctor prints one row per server, because every harness launches the same process. It exits non-zero when a server is unhealthy, so it can run in CI next to tuff check.

Add "--verbose" to the args in .mcp.json. Every managed entry has a baseline hash, so tuff check reports the change:

Terminal window
tuff check
✗ everything mcp-server claude modified (.mcp.json#everything)
✓ everything mcp-server cursor ok
✓ everything mcp-server open-agents ok
✓ tuff-capabilities skill open-agents ok
✓ tuff-cli-guide skill open-agents ok

The failing row names the file and the entry. tuff update restores the entry, and without --force it refuses to overwrite a local change:

Terminal window
tuff update everything -a claude
error: 'everything' has local changes
hint: run 'tuff diff everything' first, or use --force to reload from the catalog
Terminal window
tuff update everything -a claude --force
tuff check
installed everything (claude) -> .claude/mcp-servers/everything/server.toml
registered MCP server everything (claude) -> .mcp.json
✓ everything mcp-server claude ok
✓ everything mcp-server cursor ok
✓ everything mcp-server open-agents ok
✓ tuff-capabilities skill open-agents ok
✓ tuff-cli-guide skill open-agents ok

tuff check and tuff update leave servers added by hand next to Tuff’s unchanged.

A manifest names the environment variable that holds a token, and Tuff does not store the token. The catalog entry for GitHub’s server uses GITHUB_PERSONAL_ACCESS_TOKEN:

Terminal window
tuff add mcp github -a claude
tuff mcp doctor
installed github (claude) -> .claude/mcp-servers/github/server.toml
registered MCP server github (claude) -> .mcp.json
note: 'github' reads a variable from the environment; export GITHUB_PERSONAL_ACCESS_TOKEN before starting the harness
installed github from the built-in catalog (catalog 1.0.0)
┌────────────┬───────────┬─────────────────────────────┬───────────────┬─────────────────────────────────────┐
│ ID │ TRANSPORT │ HARNESSES │ STATUS │ DETAIL │
├────────────┼───────────┼─────────────────────────────┼───────────────┼─────────────────────────────────────┤
│ everything │ stdio │ claude, cursor, open-agents │ ✓ ok │ 13 tool(s) │
│ github │ stdio │ claude │ ? missing env │ export GITHUB_PERSONAL_ACCESS_TOKEN │
└────────────┴───────────┴─────────────────────────────┴───────────────┴─────────────────────────────────────┘

Doctor checks the environment before starting a server, so the GitHub server was not started. In an interactive terminal, tuff add also asks whether the token is stored under a different variable name.

Terminal window
tuff delete everything -a claude -a cursor -a open-agents
tuff delete github -a claude
deleted 'everything' from project scope
deleted 'github' from project scope

tuff delete removes the config entries and the tracked records, and leaves the mcpServers object in each file.

Tuff regenerates a tuff-capabilities skill in .agents/skills/ when capabilities change. It lists every installed server with its description, transport, and tool summary, and tells the agent that the servers are already loaded by the harness.

  • The MCP Servers reference covers the manifest, the full catalog, and the safety rules.
  • tuff add mcp also accepts a directory or a git URL for a server the catalog does not include.
  • A server you ship yourself is an MCP-native tool: Tuff copies its code and registers it.