Skip to content
Community listing

DeepWiki MCP

v1.0.0 changelog · 4

com.deepwiki/mcp

Hosted server from Cognition that answers questions about any public GitHub repository using DeepWiki's generated documentation. No authentication required.

transport:streamable-http tools:3

Target client

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

All 3 tools, one page each

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.

Technical article

Generated September 19, 2026

Building Custom MCP Servers: Complete Implementation Guide for Enterprise Integration

Executive Summary

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.

Part 1: MCP Server Architecture

1.1 Core Architecture Components

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

1.2 Implementation Languages

Python (Recommended for Simplicity)

  • Well-supported MCP SDK
  • Rapid development
  • Excellent for prototyping
  • Production-ready frameworks (FastAPI)

JavaScript/Node (Best for Web Integration)

  • Native async/await support
  • Easy integration with web APIs
  • Good performance
  • Popular in ecosystem

Go (Best for Performance)

  • Fast compilation
  • Efficient runtime
  • Easy deployment
  • Excellent concurrency

Rust (Best for Security)

  • Memory safety guarantees
  • Excellent performance
  • Type safety
  • Production-grade reliability

Part 2: Python MCP Server Implementation

2.1 Basic Server Structure

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())

2.2 Advanced Features

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
        )

Part 3: HTTP Transport MCP Server

3.1 FastAPI-Based Server

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

Part 4: Testing MCP Servers

4.1 Unit Testing

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

4.2 Integration Testing

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

Part 5: Real-World Server Examples

5.1 Database Server

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
        )

5.2 API Gateway Server

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()

Part 6: Deployment Strategies

6.1 Local Deployment (Stdio)

# config.json
{
  "mcpServers": {
    "my-server": {
      "command": "python",
      "args": ["server.py"],
      "env": {
        "DATABASE_URL": "sqlite:///data.db"
      }
    }
  }
}

6.2 Remote Deployment (HTTP)

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"]

6.3 Docker Compose

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

Part 7: Best Practices

7.1 Security Guidelines

  • Always validate input parameters
  • Use authentication for HTTP transports
  • Implement rate limiting
  • Use HTTPS in production
  • Encrypt sensitive data
  • Log security events

7.2 Performance Guidelines

  • Implement connection pooling
  • Cache frequently accessed data
  • Use async operations
  • Monitor resource usage
  • Implement timeouts
  • Handle errors gracefully

7.3 Documentation Requirements

  • Document all tools with examples
  • Include parameter descriptions
  • Provide error handling information
  • Include security considerations
  • Add deployment instructions
  • Include troubleshooting guide

Conclusion

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.