mcp-management
MCP Server Management
Expert knowledge for managing Model Context Protocol (MCP) servers on a project-by-project basis, with support for runtime management, OAuth remote servers, and dynamic server discovery.
When to Use This Skill
| Use this skill when... | Use configure-mcp instead when... |
|---|---|
| Understanding MCP architecture and concepts | Setting up .mcp.json for a new project |
| Managing servers at runtime (enable/disable) | Installing new servers interactively |
| Setting up OAuth remote MCP servers | Running compliance checks on MCP configuration |
| Troubleshooting connection failures | Adding specific servers from the registry |
Implementing list_changed dynamic discovery |
Generating project standards reports |
MCP Architecture Overview
MCP connects Claude Code to external tools and data sources via two transport types:
| Transport | Usage | Auth | Configuration |
|---|---|---|---|
| Stdio (local) | Command-based servers via npx, bunx, uvx, go run |
None needed | .mcp.json |
| HTTP+SSE (remote) | URL-based servers hosted externally | OAuth 2.1 | .mcp.json with url field |
Local Server (Stdio)
{
"mcpServers": {
"context7": {
"command": "bunx",
"args": ["-y", "@upstash/context7-mcp"]
}
}
}
Remote Server (HTTP+SSE with OAuth)
{
"mcpServers": {
"my-remote-server": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${MY_API_TOKEN}"
}
}
}
}
Runtime Server Management
/mcp Commands (Claude Code 2.1.50+)
Use these slash commands to manage servers without editing configuration files:
| Command | Description |
|---|---|
/mcp |
List all configured MCP servers and their connection status |
/mcp enable <server> |
Enable a server for the current session |
/mcp disable <server> |
Disable a server for the current session (session-scoped only) |
Note: Enable/disable are session-scoped. Edit .mcp.json for permanent changes.
Check Server Status
# List configured servers
jq -r '.mcpServers | keys[]' .mcp.json
# Verify server config
jq '.mcpServers.context7' .mcp.json
OAuth Support for Remote MCP Servers
Claude Code 2.1.50+ includes improved OAuth handling for remote MCP servers:
OAuth Flow Overview
Remote MCP servers using HTTP+SSE transport use OAuth 2.1:
- Claude Code discovers OAuth metadata from
/.well-known/oauth-authorization-server - Discovery metadata is cached to avoid repeated HTTP round-trips on session start
- User authorizes in the browser; token is stored and reused across sessions
- If additional permissions are needed mid-session, step-up auth is triggered
Step-Up Auth
Step-up auth occurs when a tool requires elevated permissions not granted in the initial OAuth flow:
- Server signals that additional scope is required
- Claude Code prompts the user to re-authorize with the expanded scope
- After re-authorization, the original tool call is retried automatically
OAuth Discovery Caching
Metadata from /.well-known/oauth-authorization-server is cached per server URL. If a remote server changes its OAuth configuration, force a refresh by:
- Using
/mcp disable <server>then/mcp enable <server>in the session - Or restarting Claude Code to clear the cache
Remote Server Configuration
{
"mcpServers": {
"my-service": {
"url": "https://api.example.com/mcp/sse",
"headers": {
"Authorization": "Bearer ${MY_SERVICE_TOKEN}"
}
}
}
}
Use ${VAR_NAME} syntax for environment variable references — never hardcode tokens.
Dynamic Tool Discovery (list_changed)
MCP servers that support the list_changed capability can update their tool list dynamically without requiring a session restart.
How It Works
- Server declares
{"tools": {"listChanged": true}}in its capabilities response - When the server's tool set changes, it sends
notifications/tools/list_changed - Claude Code refreshes its tool list from that server automatically
- New tools become available immediately in the current session
Practical Implications
- No session restart required when a server adds or removes tools dynamically
- Useful for servers that expose project-context-specific tools
- For
resources/list_changedandprompts/list_changed— same pattern applies
Checking Capabilities
The capabilities are declared by the server during initialization. Claude Code subscribes automatically when the server declares support. No client-side configuration is required.
Troubleshooting
Server Won't Connect
# Verify server command is available
which bunx # or npx, uvx, go
# Test server manually
bunx -y @upstash/context7-mcp # Should start without error
# Validate JSON syntax
jq empty .mcp.json && echo "JSON is valid" || echo "JSON syntax error"
Missing Environment Variables
# List all env vars referenced in .mcp.json
jq -r '.mcpServers[] | .env // {} | to_entries[] | "\(.key)=\(.value)"' .mcp.json
# Check which are set
jq -r '.mcpServers[] | .env // {} | keys[]' .mcp.json | while read var; do
clean_var=$(echo "$var" | sed 's/\${//;s/}//')
[ -z "${!clean_var}" ] && echo "MISSING: $clean_var" || echo "SET: $clean_var"
done
OAuth Remote Server Issues
| Symptom | Likely Cause | Action |
|---|---|---|
| Authorization prompt repeats | Token not persisted | Check token storage permissions |
| Step-up auth loop | Scope mismatch | Revoke and re-authorize |
| Discovery fails | Server down or URL wrong | Verify server URL and connectivity |
| Cache stale | Server changed OAuth config | Disable/enable server to refresh |
SDK MCP Server Race Condition (2.1.49/2.1.50)
When using claude-agent-sdk 0.1.39 with MCP servers, a known race condition in SDK-based MCP servers causes CLIConnectionError: ProcessTransport is not ready for writing. Workaround: use pre-computed context or static stdio servers instead of SDK MCP servers.
Configuration Patterns
Project-Scoped (Recommended)
Store in .mcp.json at project root. Add to .gitignore for personal configs or track for team configs.
{
"mcpServers": {
"context7": {
"command": "bunx",
"args": ["-y", "@upstash/context7-mcp"]
},
"sequential-thinking": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]
}
}
}
User-Scoped (Personal)
For servers you want available everywhere, add to ~/.claude/settings.json:
{
"mcpServers": {
"my-personal-tool": {
"command": "npx",
"args": ["-y", "my-personal-mcp"]
}
}
}
Plugin-Scoped
Plugins can declare MCP servers in plugin.json:
{
"mcpServers": {
"plugin-api": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/api-server",
"args": ["--port", "8080"]
}
}
}
Or via external file: "mcpServers": "./.mcp.json"
Agentic Optimizations
| Context | Command |
|---|---|
| Quick status check | jq -c '.mcpServers | keys' .mcp.json 2>/dev/null |
| Validate JSON | jq empty .mcp.json 2>&1 |
| List env vars needed | jq -r '.mcpServers[] | .env // {} | keys[]' .mcp.json 2>/dev/null | sort -u |
| Check specific server | jq -e '.mcpServers.context7' .mcp.json >/dev/null 2>&1 && echo "installed" |
| Find servers in plugin | find . -name '.mcp.json' -maxdepth 2 |
Quick Reference
Server Types by Transport
| Type | When to Use | Example |
|---|---|---|
command (stdio) |
Local tools, no auth needed | bunx, npx, uvx, go run |
url (HTTP+SSE) |
Remote hosted servers, OAuth needed | https://... |
Key Files
| File | Purpose |
|---|---|
.mcp.json |
Project-level MCP server config (team-shareable) |
~/.claude/settings.json |
User-level MCP server config (personal) |
plugin.json |
Plugin-level MCP server declarations |