Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Guides creation of high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK). Covers tool design, authentication, Docker deployment, and evaluation creation. NOT when consuming existing MCP servers (use the server directly).
.claude/skills/aiskillstore-building-mcp-servers/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 55% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 62% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 78% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 50% | 0% |
You are an expert at integrating Model Context Protocol (MCP) servers into Claude Code plugins. MCP enables plugins to access external services, APIs, and tools through a standardized protocol.
Use MCP servers when:
Use other components instead when:
Best for: Local processes, custom servers, CLI tools
json{ "mcpServers": { "my-local-server": { "type": "stdio", "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/servers/my-server.js"], "env": { "API_KEY": "${MY_API_KEY}" } } } }
Use cases:
Best for: Cloud services with OAuth, hosted MCP endpoints
json{ "mcpServers": { "cloud-service": { "type": "sse", "url": "https://api.example.com/mcp/sse", "headers": { "Authorization": "Bearer ${CLOUD_API_TOKEN}" } } } }
Use cases:
Best for: REST APIs, stateless services
json{ "mcpServers": { "rest-api": { "type": "http", "url": "https://api.example.com/mcp", "headers": { "X-API-Key": "${REST_API_KEY}" } } } }
Use cases:
Best for: Real-time bidirectional communication
json{ "mcpServers": { "realtime-service": { "type": "websocket", "url": "wss://api.example.com/mcp/ws", "headers": { "Authorization": "Bearer ${WS_TOKEN}" } } } }
Use cases:
For plugins with multiple MCP servers:
plugin-name/
├── .mcp.json # MCP server configurations
├── .claude-plugin/
│ └── plugin.json
└── ....mcp.json format:
json{ "mcpServers": { "server-one": { ... }, "server-two": { ... } } }
For single-server simplicity:
json{ "name": "my-plugin", "version": "1.0.0", "mcpServers": { "my-server": { "type": "stdio", "command": "python", "args": ["${CLAUDE_PLUGIN_ROOT}/server.py"] } } }
MCP tools are automatically prefixed with the server name:
mcp__<plugin-name>_<server-name>__<tool-name>Example:
database-toolspostgresquerymcp__database-tools_postgres__queryjson// ❌ BAD - hardcoded secret { "headers": { "Authorization": "Bearer sk-12345..." } } // ✅ GOOD - environment variable { "headers": { "Authorization": "Bearer ${MY_API_KEY}" } }
json// ❌ BAD - insecure { "url": "http://api.example.com/mcp" } // ✅ GOOD - secure { "url": "https://api.example.com/mcp" }
In your plugin's README:
markdown## Required Environment Variables | Variable | Description | |----------|-------------| | `MY_API_KEY` | API key for the service | | `DATABASE_URL` | Connection string |
In plugin.json, specify which MCP tools should be auto-allowed:
json{ "mcpServers": { "my-server": { "type": "stdio", "command": "...", "allowedTools": ["query", "list"] // Only these tools auto-allowed } } }
Always use the portable path variable:
json{ "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/servers/main.js"] }
Ask:
Choose the appropriate configuration method (.mcp.json or inline).
List all required secrets and how to obtain them.
Update plugin.json to reference the MCP configuration:
json{ "name": "my-plugin", "mcp": "./.mcp.json" }
bash# Debug MCP connections claude --debug # Verify server starts claude mcp list
This skill includes a validation script:
Usage:
bashpython3 {baseDir}/scripts/validate-mcp.py <mcp-config-file>
What It Checks:
json{ "mcpServers": { "database": { "type": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres"], "env": { "DATABASE_URL": "${DATABASE_URL}" } } } }
json{ "mcpServers": { "cloud-api": { "type": "http", "url": "https://api.service.com/v1/mcp", "headers": { "Authorization": "Bearer ${SERVICE_API_KEY}", "Content-Type": "application/json" } } } }
json{ "mcpServers": { "dev-server": { "type": "stdio", "command": "python", "args": ["${CLAUDE_PLUGIN_ROOT}/servers/dev_server.py"], "env": { "DEBUG": "true" } } } }
bash# Enable debug mode claude --debug # Check MCP server status claude mcp status # View server logs claude mcp logs <server-name>
| Issue | Cause | Solution | |-------|-------|----------| | Server not starting | Missing dependencies | Check command/args paths | | Auth failures | Wrong env variable | Verify ${VAR} is set | | Connection timeout | Network/firewall | Check URL accessibility | | Tool not found | Wrong naming | Check tool name matches |
{baseDir}/templates/mcp-stdio-template.json - Stdio server template{baseDir}/templates/mcp-http-template.json - HTTP server template{baseDir}/templates/mcp-config-template.json - Full .mcp.json template{baseDir}/references/mcp-security-guide.md - Security best practices{baseDir}/references/mcp-server-types.md - Detailed server type documentationWhen the user asks to add MCP integration:
Be proactive in:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 19,797 | 15,635 | -21% | 1 | 1 | 0% | 2,747 | 4,469 | +63% | 0 | 0 | — |
case-02 | fail→pass | 20,374 | 9,553 | -53% | 1 | 1 | 0% | 2,737 | 4,250 | +55% | 0 | 0 | — |
case-03 | pass→fail | 17,571 | 15,082 | -14% | 1 | 1 | 0% | 1,937 | 3,894 | +101% | 0 | 0 | — |
case-04 | fail→fail | 20,266 | 13,392 | -34% | 1 | 1 | 0% | 2,415 | 4,866 | +101% | 0 | 0 | — |
case-05 | fail→pass | 12,272 | 7,316 | -40% | 1 | 1 | 0% | 2,217 | 3,583 | +62% | 0 | 0 | — |
case-06 | fail→pass | 10,118 | 9,210 | -9% | 1 | 1 | 0% | 1,757 | 3,122 | +78% | 0 | 0 | — |
case-07 | pass→pass | 17,689 | 8,062 | -54% | 1 | 1 | 0% | 1,707 | 2,910 | +70% | 0 | 0 | — |
case-08 | fail→pass | 18,440 | 12,028 | -35% | 1 | 1 | 0% | 2,412 | 3,609 | +50% | 0 | 0 | — |
case-09 | fail→pass | 17,612 | 8,434 | -52% | 1 | 1 | 0% | 3,538 | 2,900 | -18% | 0 | 0 | — |
case-10 | fail→pass | 14,750 | 9,040 | -39% | 1 | 1 | 0% | 2,299 | 3,113 | +35% | 0 | 0 | — |
case-11 | fail→pass | 14,741 | 5,666 | -62% | 1 | 1 | 0% | 1,937 | 3,568 | +84% | 0 | 0 | — |
case-22 | pass→pass | 12,883 | 9,573 | -26% | 1 | 1 | 0% | 2,128 | 3,209 | +51% | 0 | 0 | — |
case-12 | pass→pass | 15,393 | 2,421 | -84% | 1 | 1 | 0% | 1,772 | 2,810 | +59% | 0 | 0 | — |
case-13 | fail→pass | 4,561 | 8,206 | +80% | 1 | 1 | 0% | 809 | 2,964 | +266% | 0 | 0 | — |
case-14 | fail→pass | 10,477 | 13,189 | +26% | 1 | 1 | 0% | 2,041 | 3,936 | +93% | 0 | 0 | — |
case-15 | fail→pass | 9,761 | 11,599 | +19% | 1 | 1 | 0% | 846 | 3,428 | +305% | 0 | 0 | — |
case-16 | pass→pass | 9,918 | 4,987 | -50% | 1 | 1 | 0% | 1,699 | 3,284 | +93% | 0 | 0 | — |
case-17 | fail→pass | 10,726 | 15,225 | +42% | 1 | 1 | 0% | 671 | 2,820 | +320% | 0 | 0 | — |
case-18 | pass→pass | 10,757 | 5,923 | -45% | 1 | 1 | 0% | 2,043 | 3,477 | +70% | 0 | 0 | — |
case-19 | fail→pass | 13,138 | 2,663 | -80% | 1 | 1 | 0% | 1,511 | 2,894 | +92% | 0 | 0 | — |
case-20 | pass→pass | 15,085 | 5,367 | -64% | 1 | 1 | 0% | 1,749 | 3,449 | +97% | 0 | 0 | — |
case-21 | fail→pass | 22,082 | 9,644 | -56% | 1 | 1 | 0% | 2,855 | 4,000 | +40% | 0 | 0 | — |
case-23 | fail→pass | 16,423 | 9,470 | -42% | 1 | 1 | 0% | 1,892 | 3,211 | +70% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +61 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.