Agent skill
mcp-development
Build Model Context Protocol (MCP) servers and clients. Create custom tool providers, resource handlers, and prompt templates. Use for extending Claude Code, building AI integrations, and creating reusable MCP components. Covers TypeScript and Python SDKs.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/mcp-development-housegarofalo-claude-code-base
SKILL.md
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
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?