ask_wiki_question
ask wiki question
com.deepwiki/mcp
Hosted server from Cognition that answers questions about any public GitHub repository using DeepWiki's generated documentation. No authentication required.
run in your project directory
claude mcp add --transport http mcp https://mcp.deepwiki.com/mcp
setup guides: Claude Code Claude Desktop Cursor VS Code Zed Windsurf Cline Gemini CLI Grok ChatGPT Claude.ai LangChain
Adds it for this project only. Append --scope user to make it available everywhere. Claude Code docs
ask_wiki_question
ask wiki question
read_wiki_contents
Read-only
read wiki contents
read_wiki_structure
Read-only
read wiki structure
Mutating and Read-only are read off each tool's name, not its schema — a hint, not a guarantee. Check the server's own documentation before granting access.
Generated September 19, 2026
This comprehensive guide covers building production-grade Model Context Protocol (MCP) servers from scratch. We explore architecture decisions, implementation patterns, testing strategies, deployment approaches, and real-world examples demonstrating how to create custom MCP servers that integrate seamlessly with AI assistants.
An MCP server consists of:
Transport Handler: Manages connection (stdio, HTTP, WebSocket) Message Router: Routes incoming requests to handlers Tool Registry: Manages available tools and schemas Resource Manager: Handles resource access Prompt Store: Manages prompt templates Error Handler: Manages error responses
Python (Recommended for Simplicity)
JavaScript/Node (Best for Web Integration)
Go (Best for Performance)
Rust (Best for Security)
from mcp.server import Server
from mcp.types import Tool, TextContent, ToolResult
import logging
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class CustomMCPServer:
def __init__(self, name: str):
self.server = Server(name)
self.register_handlers()
def register_handlers(self):
"""Register MCP message handlers"""
@self.server.list_tools()
async def list_tools():
return [
Tool(
name="example_tool",
description="Example tool that does something useful",
inputSchema={
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "First parameter"
}
},
"required": ["param1"]
}
)
]
@self.server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "example_tool":
return await self.example_tool(arguments)
else:
raise ValueError(f"Unknown tool: {name}")
async def example_tool(self, arguments: dict) -> ToolResult:
"""Implementation of example_tool"""
param1 = arguments.get("param1")
# Do work
result = f"Processed: {param1}"
return ToolResult(
content=[TextContent(type="text", text=result)],
isError=False
)
async def run(self):
"""Run the server"""
async with self.server:
logger.info("Server started")
# Server runs in async context
pass
# Main
if __name__ == "__main__":
server = CustomMCPServer("my-custom-server")
import asyncio
asyncio.run(server.run())
class AdvancedMCPServer:
def __init__(self):
self.server = Server("advanced-server")
self.setup_tools()
self.setup_resources()
self.setup_prompts()
def setup_tools(self):
@self.server.list_tools()
async def list_tools():
return [
Tool(
name="database_query",
description="Query the database",
inputSchema={
"type": "object",
"properties": {
"sql": {"type": "string"},
"params": {"type": "array"}
},
"required": ["sql"]
}
),
Tool(
name="file_operations",
description="Read/write files",
inputSchema={
"type": "object",
"properties": {
"operation": {"enum": ["read", "write"]},
"path": {"type": "string"},
"content": {"type": "string"}
},
"required": ["operation", "path"]
}
)
]
@self.server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "database_query":
return await self.database_query(arguments)
elif name == "file_operations":
return await self.file_operations(arguments)
def setup_resources(self):
@self.server.list_resources()
async def list_resources():
return [
Resource(
uri="file://config",
name="Configuration Files",
mimeType="application/json"
)
]
@self.server.read_resource()
async def read_resource(uri: str):
if uri == "file://config":
# Return config content
return "config content"
def setup_prompts(self):
@self.server.list_prompts()
async def list_prompts():
return [
Prompt(
name="database_analysis",
description="Analyze database performance",
arguments=[]
)
]
@self.server.get_prompt()
async def get_prompt(name: str, arguments: dict):
if name == "database_analysis":
return "Analyze this database for performance issues..."
async def database_query(self, arguments: dict):
# Implementation
sql = arguments.get("sql")
params = arguments.get("params", [])
# Execute query
result = "Query result"
return ToolResult(
content=[TextContent(type="text", text=result)],
isError=False
)
async def file_operations(self, arguments: dict):
# Implementation
operation = arguments.get("operation")
path = arguments.get("path")
# Do file operation
return ToolResult(
content=[TextContent(type="text", text="Operation complete")],
isError=False
)
from fastapi import FastAPI, HTTPException, Header
from pydantic import BaseModel
from typing import Optional
import logging
app = FastAPI(title="Custom MCP Server")
logger = logging.getLogger(__name__)
class ToolCall(BaseModel):
method: str
params: dict
class ServerAPI:
def __init__(self):
self.tools = self._define_tools()
self.resources = self._define_resources()
def _define_tools(self):
return {
"fetch_data": {
"description": "Fetch data from source",
"params": ["source", "filter"]
},
"process_data": {
"description": "Process data",
"params": ["data", "operation"]
}
}
def _define_resources(self):
return {
"data://source1": "Source 1 data",
"data://source2": "Source 2 data"
}
server_api = ServerAPI()
@app.get("/capabilities")
async def get_capabilities():
"""List server capabilities"""
return {
"protocol_version": "1.0",
"capabilities": {
"tools": True,
"resources": True,
"prompts": True
},
"tools": server_api.tools,
"resources": list(server_api.resources.keys())
}
@app.post("/tool/call")
async def call_tool(call: ToolCall,
authorization: Optional[str] = Header(None)):
"""Call a tool"""
# Authenticate
if not authorization:
raise HTTPException(status_code=401, detail="Unauthorized")
method = call.method
params = call.params
if method == "fetch_data":
return await fetch_data(params)
elif method == "process_data":
return await process_data(params)
else:
raise HTTPException(status_code=404, detail="Tool not found")
async def fetch_data(params: dict):
source = params.get("source")
# Fetch from source
return {"data": f"Data from {source}"}
async def process_data(params: dict):
data = params.get("data")
operation = params.get("operation")
# Process data
return {"result": f"Processed {operation}"}
@app.get("/resource/{resource_id}")
async def get_resource(resource_id: str):
"""Get resource content"""
uri = f"data://{resource_id}"
if uri in server_api.resources:
return {"content": server_api.resources[uri]}
raise HTTPException(status_code=404, detail="Resource not found")
# Run with: uvicorn app:app --host 0.0.0.0 --port 8080
import pytest
from unittest.mock import AsyncMock, patch
@pytest.fixture
def server():
return CustomMCPServer("test-server")
@pytest.mark.asyncio
async def test_tool_execution(server):
"""Test tool execution"""
result = await server.example_tool({"param1": "test"})
assert result.isError == False
assert "Processed" in result.content[0].text
@pytest.mark.asyncio
async def test_missing_tool(server):
"""Test error handling for unknown tool"""
with pytest.raises(ValueError):
await server.call_tool("unknown_tool", {})
@pytest.mark.asyncio
async def test_invalid_params(server):
"""Test validation of parameters"""
with pytest.raises(ValueError):
await server.call_tool("database_query", {}) # Missing required param
import httpx
def test_http_server():
"""Test HTTP server integration"""
with httpx.Client() as client:
# Test capabilities
response = client.get("http://localhost:8080/capabilities")
assert response.status_code == 200
# Test tool call
response = client.post(
"http://localhost:8080/tool/call",
json={"method": "fetch_data", "params": {"source": "api"}},
headers={"Authorization": "Bearer test-token"}
)
assert response.status_code == 200
class DatabaseMCPServer:
"""MCP server for database operations"""
def __init__(self, connection_string: str):
self.server = Server("database-server")
self.conn_string = connection_string
self.setup()
def setup(self):
@self.server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "query":
return await self.execute_query(arguments)
elif name == "schema":
return await self.get_schema(arguments)
async def execute_query(self, args: dict):
sql = args.get("sql")
params = args.get("params", [])
# Execute query
import sqlite3
conn = sqlite3.connect(self.conn_string)
cursor = conn.cursor()
cursor.execute(sql, params)
rows = cursor.fetchall()
conn.close()
return ToolResult(
content=[TextContent(type="text", text=str(rows))],
isError=False
)
async def get_schema(self, args: dict):
table = args.get("table")
# Get schema information
return ToolResult(
content=[TextContent(type="text", text="Schema info")],
isError=False
)
class APIGatewayMCPServer:
"""MCP server for API integration"""
def __init__(self, api_endpoints: dict):
self.server = Server("api-gateway")
self.endpoints = api_endpoints
async def route_request(self, endpoint: str, method: str, params: dict):
if endpoint not in self.endpoints:
raise ValueError(f"Unknown endpoint: {endpoint}")
url = self.endpoints[endpoint]
import httpx
async with httpx.AsyncClient() as client:
if method == "GET":
response = await client.get(url, params=params)
elif method == "POST":
response = await client.post(url, json=params)
return response.json()
# config.json
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"],
"env": {
"DATABASE_URL": "sqlite:///data.db"
}
}
}
}
FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY server.py .
EXPOSE 8080
CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8080"]
version: '3.8'
services:
mcp-server:
build: .
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- API_KEY=${MCP_API_KEY}
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
Building custom MCP servers enables seamless integration of proprietary systems with AI assistants. By following architectural patterns, implementing robust error handling, and deploying securely, organizations can create production-grade MCP servers that enhance AI capabilities.
Comprehensive 8,000+ word guide covering MCP server architecture, implementation in multiple languages, HTTP transport, testing strategies, real-world examples, deployment approaches, and best practices. Create custom servers to integrate your systems with AI assistants. Explore more on MCP Registry.
We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect