12 KiB
MCP Configuration Reference
Complete schema and technical reference for MCP server configuration in Claude Code plugins.
Configuration Schema
Stdio Server Configuration
{
command: string // Required: Executable path or command name
args?: string[] // Optional: Command-line arguments
env?: Record<string, string> // Optional: Environment variables
}
Field Details:
-
command: The executable to run. Can be:- System command:
"node","python","npx" - Absolute path:
"/usr/local/bin/my-server" - Plugin-relative:
"${CLAUDE_PLUGIN_ROOT}/servers/my-server"
- System command:
-
args: Array of arguments passed to the command- Order matters
- Supports variable expansion:
["--config", "${CONFIG_PATH}"]
-
env: Environment variables for the process- Inherits user's environment by default
- Additional vars override/extend inherited ones
- Supports variable expansion:
{"KEY": "${USER_KEY}"}
Example:
{
"my-server": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/dist/server.js", "--port", "8080"],
"env": {
"NODE_ENV": "production",
"LOG_LEVEL": "${LOG_LEVEL:-info}"
}
}
}
HTTP Server Configuration
{
type: "http" // Required: Transport type
url: string // Required: HTTP(S) endpoint URL
headers?: Record<string, string> // Optional: HTTP headers
}
Field Details:
-
type: Must be"http"for HTTP transport -
url: The MCP endpoint URL- Must be valid HTTP(S) URL
- Supports variable expansion:
"${API_BASE_URL}/mcp" - Should end in
/mcpby convention
-
headers: HTTP headers sent with requests- Common uses: Authentication, API keys, custom metadata
- Supports variable expansion:
{"Authorization": "Bearer ${TOKEN}"}
Example:
{
"api-server": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${API_TOKEN}",
"X-Client-Version": "1.0.0",
"Accept": "application/json"
}
}
}
SSE Server Configuration (Deprecated)
{
type: "sse" // Required: Transport type
url: string // Required: SSE endpoint URL
headers?: Record<string, string> // Optional: HTTP headers
}
Note: SSE transport is deprecated. Use HTTP transport instead when available.
Field Details:
type: Must be"sse"for Server-Sent Events transporturl: The SSE endpoint URLheaders: HTTP headers (same as HTTP transport)
Example:
{
"legacy-server": {
"type": "sse",
"url": "https://api.example.com/sse",
"headers": {
"X-API-Key": "${API_KEY}"
}
}
}
Environment Variable Expansion
Syntax
| Pattern | Behavior | Example |
|---|---|---|
${VAR} |
Required variable (error if not set) | ${API_KEY} |
${VAR:-default} |
Optional with fallback value | ${PORT:-8080} |
${CLAUDE_PLUGIN_ROOT} |
Plugin directory path (special) | ${CLAUDE_PLUGIN_ROOT}/bin |
Expansion Locations
Environment variables can be expanded in:
-
Stdio servers:
commandfieldargsarray elementsenvobject values
-
HTTP/SSE servers:
urlfieldheadersobject values
Special Variables
${CLAUDE_PLUGIN_ROOT}
- Type: Plugin-specific
- Value: Absolute path to plugin directory
- Use case: Reference bundled servers, configs, assets
- Example:
"${CLAUDE_PLUGIN_ROOT}/servers/db-server"
User Environment Variables
All variables from user's shell environment are available:
{
"env": {
"PATH": "${PATH}", // User's PATH
"HOME": "${HOME}", // User's home directory
"DATABASE_URL": "${DATABASE_URL}" // Custom user variable
}
}
Expansion Examples
Basic expansion:
{
"url": "${API_BASE_URL}/mcp"
}
With API_BASE_URL=https://api.example.com, becomes:
https://api.example.com/mcp
Default values:
{
"env": {
"LOG_LEVEL": "${LOG_LEVEL:-info}",
"PORT": "${PORT:-3000}"
}
}
Without environment variables set, becomes:
{
"env": {
"LOG_LEVEL": "info",
"PORT": "3000"
}
}
Plugin-relative paths:
{
"command": "${CLAUDE_PLUGIN_ROOT}/bin/server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"]
}
With plugin at /home/user/.claude/plugins/my-plugin, becomes:
command: /home/user/.claude/plugins/my-plugin/bin/server
args: ["--config", "/home/user/.claude/plugins/my-plugin/config.json"]
Configuration Files
.mcp.json (Recommended)
Location: Plugin root directory
Structure:
{
"mcpServers": {
"server-name-1": { /* config */ },
"server-name-2": { /* config */ }
}
}
Advantages:
- Separates concerns (MCP config separate from plugin metadata)
- Easier to maintain complex configurations
- Can be shared/reused across plugins
- Better for multiple MCP servers
Example:
{
"mcpServers": {
"database": {
"command": "npx",
"args": ["-y", "@bytebase/dbhub", "--dsn", "${DATABASE_URL}"]
},
"api": {
"type": "http",
"url": "${API_BASE_URL}/mcp"
}
}
}
plugin.json (Inline)
Location: .claude-plugin/plugin.json
Structure:
{
"name": "my-plugin",
"version": "1.0.0",
"mcpServers": {
"server-name": { /* config */ }
}
}
Advantages:
- Single file for simple plugins
- All configuration in one place
- No additional files needed
Example:
{
"name": "simple-plugin",
"version": "1.0.0",
"description": "A simple plugin with one MCP server",
"mcpServers": {
"api": {
"type": "http",
"url": "https://api.example.com/mcp"
}
}
}
Choosing Between .mcp.json and inline:
- Use
.mcp.jsonfor 2+ servers or complex configs - Use inline for single simple server
- Both methods are functionally identical
Server Lifecycle
1. Plugin Enable
- Plugin is enabled via
/plugin enable - MCP servers are registered with Claude Code
- No servers start yet
2. Claude Code Start
- Claude Code reads enabled plugins
- MCP servers start automatically
- Stdio servers: Process spawned
- HTTP/SSE servers: Connection established
3. Server Ready
- Server responds to initialization
- Tools/resources/prompts registered
- Available via
/mcpcommand
4. Plugin Update
- Configuration changes detected
- Requires Claude Code restart to apply
- Old servers stop, new ones start on restart
5. Plugin Disable
- Plugin disabled via
/plugin disable - MCP servers stop automatically
- Resources cleaned up
Platform-Specific Considerations
Windows
npx Wrapper Required:
{
"command": "cmd",
"args": ["/c", "npx", "-y", "package-name"]
}
Path Separators:
- Windows: Use forward slashes
/in JSON - Variable expansion handles platform differences
- Example:
"${CLAUDE_PLUGIN_ROOT}/bin/server"works on all platforms
Environment Variables:
{
"env": {
"USERPROFILE": "${USERPROFILE}", // Windows home directory
"APPDATA": "${APPDATA}" // Windows app data
}
}
macOS/Linux
Standard Commands:
{
"command": "npx",
"args": ["-y", "package-name"]
}
Executable Permissions:
- Bundled executables must have execute permissions
- Set in version control:
git update-index --chmod=+x server.sh - Or in plugin distribution:
chmod +x ${CLAUDE_PLUGIN_ROOT}/bin/*
Validation and Errors
Common Validation Errors
Invalid JSON:
Error: Failed to parse .mcp.json
Solution: Validate JSON syntax with jq or JSON validator
Missing Required Fields:
Error: Missing required field 'command' in stdio server config
Error: Missing required field 'url' in http server config
Solution: Add required fields per schema above
Invalid Variable Expansion:
Error: Environment variable 'API_KEY' is required but not set
Solution: Set required environment variable or provide default value
Invalid URL:
Error: Invalid URL in http server config
Solution: Ensure URL is valid HTTP(S) format
Runtime Errors
Server Won't Start:
- Check command path exists and is executable
- Verify all required environment variables are set
- Check server logs for startup errors
Connection Failed (HTTP/SSE):
- Verify URL is accessible
- Check network/firewall settings
- Confirm authentication headers are correct
Server Not Found:
- Ensure plugin is enabled
- Restart Claude Code after config changes
- Check
/mcpoutput for registered servers
Performance Considerations
Stdio Servers
Process Overhead:
- Each stdio server is a separate process
- Consider resource usage for multiple servers
- Use HTTP servers for remote services
Startup Time:
- Servers start on Claude Code launch
- Slow-starting servers delay tool availability
- Consider lazy initialization for heavy servers
HTTP/SSE Servers
Network Latency:
- Remote servers add network latency
- Use connection pooling where possible
- Consider caching for read-heavy operations
Rate Limiting:
- Respect API rate limits
- Implement backoff strategies
- Cache responses when appropriate
Security Best Practices
Credential Management
✅ Do:
- Store credentials in environment variables
- Use
${VAR}expansion in configs - Document required variables in README
- Use secure storage for sensitive values
❌ Don't:
- Hardcode credentials in JSON
- Commit credentials to version control
- Share credentials in plugin distributions
- Log credential values
Network Security
HTTPS Only:
{
"type": "http",
"url": "https://api.example.com/mcp" // ✅ HTTPS
}
Avoid HTTP:
{
"type": "http",
"url": "http://api.example.com/mcp" // ❌ Insecure
}
Certificate Validation:
- HTTPS certificates are validated by default
- Don't disable certificate validation
- Use valid, trusted certificates
Process Security
Least Privilege:
- Stdio servers run with user's permissions
- Don't require elevated privileges
- Validate all inputs from MCP protocol
Sandboxing:
- Stdio servers are not sandboxed
- Be cautious with user input
- Validate/sanitize all data
Debugging
Enable Debug Logging
Set environment variables before starting Claude Code:
export DEBUG=mcp:*
export MCP_LOG_LEVEL=debug
claude
Check Server Status
Within Claude Code:
/mcp
Shows:
- Registered servers
- Connection status
- Available tools/resources
Test Server Manually
Stdio Server:
# Test command directly
node ${CLAUDE_PLUGIN_ROOT}/servers/my-server.js
# With environment
API_KEY=test node servers/my-server.js
HTTP Server:
# Test endpoint
curl -H "Authorization: Bearer ${API_TOKEN}" \
https://api.example.com/mcp
Common Debug Scenarios
Server Not Appearing:
- Check plugin is enabled:
/plugin list - Verify config syntax:
cat .mcp.json | jq . - Restart Claude Code
- Check for error messages on startup
Server Starts But No Tools:
- Check server logs for initialization errors
- Verify server implements MCP protocol correctly
- Test server manually outside Claude Code
- Check server responds to
tools/listrequest
Environment Variables Not Expanding:
- Verify syntax:
${VAR}not$VAR - Check variable is set:
echo $VAR - Restart Claude Code after setting variables
- Check for typos in variable names