skills/autumnsgrove/mcp-builder/SKILL.md
Comprehensive guide for building Model Context Protocol (MCP) servers with support for tools, resources, prompts, and authentication. Use when: (1) Creating custom MCP servers, (2) Integrating external APIs with Claude, (3) Building tool servers for specialized domains, (4) Creating resource providers for documentation, (5) Implementing authentication and security
npx skillsauth add aiskillstore/marketplace mcp-builderInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Model Context Protocol (MCP) is an open standard created by Anthropic that enables AI assistants like Claude to securely connect to external data sources and tools. Think of it as a universal adapter that allows Claude to interact with any system, API, or data source through a standardized interface.
Key Benefits:
MCP follows a client-server architecture:
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
│ Claude │ ←──MCP──→ │ MCP Server │ ←──────→ │ External API │
│ (Client) │ │ (Your Code) │ │ Database │
└─────────────┘ └─────────────┘ └──────────────┘
Components:
For detailed protocol specification, see Protocol Specification Reference.
Tools are the primary way to give Claude new capabilities. Each tool is a function that Claude can invoke with specific arguments.
Tool Definition Structure:
{
"name": "tool_name",
"description": "Clear description of what this tool does",
"inputSchema": {
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "Description of parameter"
}
},
"required": ["param1"]
}
}
Key Principles:
search_database, not db_query)For complete schema design patterns and best practices, see Tool Schema Reference.
Resources allow Claude to access files, documentation, or structured data. Unlike tools (which perform actions), resources provide information.
Resource Types:
Resource URI Patterns:
file:///path/to/file.txt # Local file
http://example.com/api/docs # HTTP resource
custom://database/users/123 # Custom scheme
template://report/{user_id} # Template resource
Prompts are pre-defined message templates that users can invoke. They help standardize common workflows and best practices.
Prompt Definition:
{
"name": "code_review",
"description": "Comprehensive code review checklist",
"arguments": [
{
"name": "language",
"description": "Programming language",
"required": True
}
]
}
MCP supports multiple authentication methods:
For complete security implementation guides, see Security Best Practices.
Create your MCP server project:
# Create project directory
mkdir my-mcp-server
cd my-mcp-server
# Initialize Python project
uv init
uv add mcp
# Create server file
touch server.py
Minimal working server:
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import asyncio
app = Server("my-mcp-server")
@app.list_tools()
async def list_tools():
return [
Tool(
name="my_tool",
description="Description of what this tool does",
inputSchema={
"type": "object",
"properties": {
"param": {"type": "string"}
},
"required": ["param"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "my_tool":
param = arguments["param"]
result = f"Processed: {param}"
return [TextContent(type="text", text=result)]
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream, app.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())
Registration Pattern:
@app.list_tools()
async def list_tools():
return [
Tool(
name="calculator_add",
description="Add two numbers",
inputSchema={
"type": "object",
"properties": {
"a": {"type": "number", "description": "First number"},
"b": {"type": "number", "description": "Second number"}
},
"required": ["a", "b"]
}
)
]
Handler Pattern:
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "calculator_add":
return await handle_calculator_add(arguments)
else:
raise ValueError(f"Unknown tool: {name}")
async def handle_calculator_add(arguments: dict):
a = arguments["a"]
b = arguments["b"]
result = a + b
return [TextContent(type="text", text=f"{a} + {b} = {result}")]
Static and dynamic resource examples:
from mcp.types import Resource, ResourceContents, TextResourceContents
@app.list_resources()
async def list_resources():
return [Resource(uri="file:///docs/readme.md", name="README",
description="Documentation", mimeType="text/markdown")]
@app.read_resource()
async def read_resource(uri: str):
if uri.startswith("file://"):
with open(uri[7:], 'r') as f:
return ResourceContents(contents=[TextResourceContents(
uri=uri, mimeType="text/markdown", text=f.read())])
See Resource Server Example for complete implementation.
Error Response Pattern:
async def call_tool(name: str, arguments: dict):
try:
return [TextContent(type="text", text=await execute_tool(name, arguments))]
except ValueError as e:
return [TextContent(type="text", text=f"Invalid input: {str(e)}", isError=True)]
except Exception as e:
logger.exception("Unexpected error")
return [TextContent(type="text", text=f"Error: {type(e).__name__}", isError=True)]
Testing:
# Test with MCP inspector
npx @modelcontextprotocol/inspector python server.py
See Testing and Debugging Guide for comprehensive strategies.
Configuration: Edit claude_desktop_config.json:
~/Library/Application Support/Claude/%APPDATA%\Claude/~/.config/Claude/{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/absolute/path/to/server.py"],
"env": {"API_KEY": "your-key"}
}
}
}
Use descriptive names:
# ✅ Good
"search_customer_by_email"
"calculate_shipping_cost"
# ❌ Bad
"search"
"calc"
Provide comprehensive descriptions:
# ✅ Good
description="""
Search for customers by email address. Returns customer profile including:
- Contact information
- Order history
- Account status
"""
# ❌ Bad
description="Search customers"
Use enums for fixed options:
# ✅ Good
"status": {
"type": "string",
"enum": ["pending", "approved", "rejected"],
"description": "Application status"
}
Categorize errors with custom exceptions and provide actionable messages:
class ValidationError(Exception): pass
class AuthenticationError(Exception): pass
async def call_tool(name: str, arguments: dict):
try:
return await execute_tool(name, arguments)
except ValidationError as e:
return [TextContent(type="text", text=f"Invalid input: {str(e)}", isError=True)]
Always validate inputs and use environment variables for secrets:
# Input validation
def validate_url(url: str) -> bool:
if urlparse(url).scheme not in ['http', 'https']:
raise ValidationError("Only HTTP/HTTPS URLs allowed")
# Secrets management
API_KEY = os.getenv("API_KEY") # ✅ Good
# API_KEY = "sk-1234" # ❌ Bad - Never hardcode!
Use connection pooling and parallel async operations:
# ✅ Parallel execution
results = await asyncio.gather(*[fetch_user_data(uid) for uid in user_ids])
# ❌ Sequential execution (slow)
for user_id in user_ids:
result = await fetch_user_data(user_id)
Missing required validation:
# ❌ Bad: No validation
async def handle_create_user(arguments: dict):
username = arguments["username"] # Will crash if missing!
# ✅ Good: Validate inputs
async def handle_create_user(arguments: dict):
if "username" not in arguments:
return [TextContent(type="text", text="Error: username required", isError=True)]
username = arguments["username"]
Insecure storage:
# ❌ Bad: Hardcoded API key
API_KEY = "sk-1234567890abcdef"
# ✅ Good: Environment variables
API_KEY = os.getenv("API_KEY")
if not API_KEY:
raise ValueError("API_KEY environment variable required")
Path issues:
# ❌ Bad: Relative path
{
"command": "python",
"args": ["server.py"] # Won't work!
}
# ✅ Good: Absolute path
{
"command": "python",
"args": ["/Users/username/projects/mcp-server/server.py"]
}
Silent failures:
# ❌ Bad: Silent failure
async def call_tool(name: str, arguments: dict):
try:
return await execute_tool(name, arguments)
except Exception:
return [TextContent(type="text", text="Something went wrong")]
# ✅ Good: Descriptive errors
async def call_tool(name: str, arguments: dict):
try:
return await execute_tool(name, arguments)
except ValueError as e:
return [TextContent(type="text", text=f"Invalid input: {str(e)}", isError=True)]
except Exception as e:
logger.exception("Unexpected error")
return [TextContent(type="text", text=f"Error: {type(e).__name__}", isError=True)]
Not marking errors:
# ❌ Bad
return [TextContent(type="text", text="Error: Failed")]
# ✅ Good
return [TextContent(type="text", text="Error: Failed", isError=True)]
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import asyncio
app = Server("my-server")
@app.list_tools()
async def list_tools():
return [Tool(name="my_tool", description="...", inputSchema={...})]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "my_tool":
return [TextContent(type="text", text="Result")]
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream, app.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())
Error handling:
return [TextContent(type="text", text="Error message", isError=True)]
Async operations:
results = await asyncio.gather(*tasks)
Input validation:
if "required_param" not in arguments:
return [TextContent(type="text", text="Missing parameter", isError=True)]
End of MCP Builder Skill Guide
For complete working examples and detailed technical references, explore the examples/ and references/ directories.
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.