mcp-development
MCP Server Development Skill
Triggers
Use this skill when you see:
- mcp, model context protocol, tool provider
- mcp server, mcp client, mcp tools
- resources, prompts, sampling
- claude code extension, ai integration
Instructions
MCP Architecture Overview
MCP (Model Context Protocol) enables AI models to interact with external systems through:
- Tools: Functions the AI can call
- Resources: Data the AI can read
- Prompts: Pre-defined prompt templates
- Sampling: Request AI completions
TypeScript MCP Server
Project Setup
# Initialize project
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
# Configure TypeScript
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true
},
"include": ["src/**/*"]
}
EOF
Basic Server Structure
// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// Create server instance
const server = new Server(
{
name: "my-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Define tool input schemas
const ExampleToolSchema = z.object({
input: z.string().describe("Input parameter"),
optional: z.number().optional().describe("Optional number"),
});
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "example_tool",
description: "An example tool that processes input",
inputSchema: {
type: "object",
properties: {
input: { type: "string", description: "Input parameter" },
optional: { type: "number", description: "Optional number" },
},
required: ["input"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "example_tool") {
const parsed = ExampleToolSchema.parse(args);
// Tool implementation
const result = `Processed: ${parsed.input}`;
return {
content: [
{
type: "text",
text: result,
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
});
// List resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "example://data",
name: "Example Data",
description: "Sample resource data",
mimeType: "application/json",
},
],
};
});
// Read resources
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
if (uri === "example://data") {
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify({ key: "value" }),
},
],
};
}
throw new Error(`Unknown resource: ${uri}`);
});
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
}
main().catch(console.error);
Package Configuration
{
"name": "my-mcp-server",
"version": "1.0.0",
"type": "module",
"bin": {
"my-mcp-server": "./dist/index.js"
},
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
}
}
Python MCP Server
Project Setup
# Create project with uv
uv init my-mcp-server
cd my-mcp-server
uv add mcp pydantic
# Or with pip
pip install mcp pydantic
Basic Server Structure
# src/server.py
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import (
Tool,
TextContent,
Resource,
ResourceContents,
)
from pydantic import BaseModel, Field
# Create server
server = Server("my-mcp-server")
# Define input models
class ExampleInput(BaseModel):
input: str = Field(description="Input parameter")
optional: int | None = Field(default=None, description="Optional number")
# List tools
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="example_tool",
description="An example tool that processes input",
inputSchema=ExampleInput.model_json_schema(),
)
]
# Handle tool calls
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "example_tool":
args = ExampleInput(**arguments)
result = f"Processed: {args.input}"
return [TextContent(type="text", text=result)]
raise ValueError(f"Unknown tool: {name}")
# List resources
@server.list_resources()
async def list_resources() -> list[Resource]:
return [
Resource(
uri="example://data",
name="Example Data",
description="Sample resource data",
mimeType="application/json",
)
]
# Read resources
@server.read_resource()
async def read_resource(uri: str) -> ResourceContents:
if uri == "example://data":
return ResourceContents(
uri=uri,
mimeType="application/json",
text='{"key": "value"}',
)
raise ValueError(f"Unknown resource: {uri}")
# Main entry point
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
if __name__ == "__main__":
asyncio.run(main())
Claude Code Configuration
Add to ~/.claude/mcp-servers.json or project's .claude/mcp-servers.json:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/path/to/dist/index.js"],
"env": {
"API_KEY": "${API_KEY}"
}
},
"python-server": {
"command": "python",
"args": ["-m", "my_mcp_server"],
"cwd": "/path/to/project"
}
}
}
Advanced Patterns
Error Handling
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
// Tool logic
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
},
],
isError: true,
};
}
});
Streaming Results
// For long-running operations, return progress updates
return {
content: [
{ type: "text", text: "Step 1 complete..." },
{ type: "text", text: "Step 2 complete..." },
{ type: "text", text: "Final result: success" },
],
};
Dynamic Resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
// Fetch available resources dynamically
const files = await fs.readdir("/data");
return {
resources: files.map((file) => ({
uri: `file://${file}`,
name: file,
mimeType: "text/plain",
})),
};
});
Testing MCP Servers
# Test with MCP Inspector
npx @modelcontextprotocol/inspector node dist/index.js
# Manual testing via stdio
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js
Best Practices
- Clear Tool Descriptions: Help AI understand when to use each tool
- Validate Inputs: Use Zod/Pydantic for type safety
- Handle Errors Gracefully: Return helpful error messages
- Minimize Side Effects: Tools should be predictable
- Document Resources: Clear descriptions and MIME types
- Version Your Server: Semantic versioning for compatibility
- Test Thoroughly: Use MCP Inspector for debugging
- Environment Variables: Use for secrets and configuration
More from housegarofalo/claude-code-base
mqtt-iot
Configure MQTT brokers (Mosquitto, EMQX) for IoT messaging, device communication, and smart home integration. Manage topics, QoS levels, authentication, and bridging. Use when setting up IoT messaging, smart home communication, or device-to-cloud connectivity. (project)
22devops-engineer-agent
Infrastructure and DevOps specialist. Manages Docker, Kubernetes, CI/CD pipelines, and cloud deployments. Expert in GitHub Actions, Azure DevOps, Terraform, and container orchestration. Use for deployment automation, infrastructure setup, or CI/CD optimization.
6postgresql
Design, optimize, and manage PostgreSQL databases. Covers indexing, pgvector for AI embeddings, JSON operations, full-text search, and query optimization. Use when working with PostgreSQL, database design, or building data-intensive applications.
6home-assistant
Ultimate Home Assistant skill - complete administration, wireless protocols (Zigbee/ZHA/Z2M, Z-Wave JS, Thread, Matter), ESPHome device building, advanced troubleshooting, performance optimization, security hardening, custom integration development, and professional dashboard design. Covers configuration, REST API, automation debugging, database optimization, SSL/TLS, Jinja2 templating, and HACS custom cards. Use for any HA task.
6testing
Comprehensive testing skill covering unit, integration, and E2E testing with pytest, Jest, Cypress, and Playwright. Use for writing tests, improving coverage, debugging test failures, and setting up testing infrastructure.
5react-typescript
Build modern React applications with TypeScript. Covers React 18+ patterns, hooks, component architecture, state management (Zustand, Redux Toolkit), server components, and best practices. Use for React development, TypeScript integration, component design, and frontend architecture.
5