Back

Como Construir um Servidor MCP: Passo a Passo com Exemplos de Código

Como Construir um Servidor MCP: Passo a Passo com Exemplos de Código

O Model Context Protocol (MCP) está se tornando o novo padrão para conectar modelos de IA a ferramentas e serviços do mundo real. Construir um servidor MCP permite que você exponha dados, ações e recursos para um LLM como o Claude através de uma interface simples e padronizada.

Neste guia, você aprenderá passo a passo como configurar um servidor MCP básico em Python, definir recursos e ferramentas, e conectá-lo a um cliente MCP.

Principais Pontos

  • Servidores MCP permitem que modelos de IA interajam com sistemas externos através de recursos e ferramentas padronizados.
  • Você pode construir um servidor MCP em Python usando o SDK oficial.
  • Um servidor mínimo funcional pode expor tanto dados somente leitura (recursos) quanto ações executáveis (ferramentas).
  • Segurança e tratamento de erros são críticos para implantações em produção.

O que é um Servidor MCP

Um servidor MCP atua como uma ponte entre um LLM e um sistema externo como um banco de dados, armazenamento de arquivos ou API. Ele define recursos (dados legíveis), ferramentas (ações) e prompts (instruções) de uma forma que o LLM pode usar com segurança durante suas tarefas.

Em vez de escrever uma integração personalizada para cada modelo ou ferramenta, o MCP oferece um padrão universal que funciona com a versão 0.1 do protocolo (atual em abril de 2025).

O que você precisa antes de começar

  • Python 3.8 ou posterior
  • Experiência básica com scripts Python
  • SDK MCP para Python (disponível via pip)
  • Um cliente compatível com MCP como Claude Desktop ou Cursor (opcional para testes)
  • Git para controle de versão (recomendado)
  • Um editor de texto ou IDE (Visual Studio Code recomendado)

Entendendo a estrutura central

No MCP:

  • Servidor: Fornece recursos e ferramentas para o LLM.
  • Cliente: Conecta o LLM ao seu servidor.
  • Protocolo: Gerencia a comunicação entre cliente e servidor.

Você definirá dois primitivos importantes:

  • Recurso: Informação estática ou dinâmica que o LLM pode ler.
  • Ferramenta: Uma função chamável que o LLM pode executar.

O fluxo de comunicação funciona da seguinte forma:

  1. O LLM (via cliente) solicita dados ou ações do seu servidor
  2. Seu servidor processa essas solicitações e retorna respostas padronizadas
  3. O LLM pode então usar essas informações em seu raciocínio e respostas

1. Configure seu projeto Python

Comece criando um diretório de projeto e um ambiente virtual Python.

mkdir my_mcp_server
cd my_mcp_server
python -m venv venv
source venv/bin/activate  # Linux/Mac
venvScriptsactivate     # Windows

Crie uma estrutura básica de projeto:

mkdir -p src/resources src/tools tests
touch src/__init__.py src/resources/__init__.py src/tools/__init__.py
touch requirements.txt README.md

Adicione o seguinte ao seu requirements.txt:

mcp-server>=0.1.0
pydantic>=2.0.0
pytest>=7.0.0

2. Instale o SDK MCP

Instale o SDK do servidor MCP para Python e outras dependências:

pip install -r requirements.txt

Se o SDK oficial ainda não estiver publicado, talvez seja necessário instalar a partir de um repositório GitHub:

pip install git+https://github.com/anthropic/mcp-server-python.git

3. Crie um servidor MCP básico

Crie um arquivo chamado src/server.py:

from typing import Dict, Any
from mcp_server import MCPServer
import logging

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("mcp_server")

def main() -> None:
    """Initialize and start the MCP server."""
    try:
        server = MCPServer(
            name="MyMCPServer",
            version="0.1.0",
            description="A simple MCP server example"
        )
        
        # Resources and tools will be added here
        
        logger.info("Starting MCP server...")
        server.start()
    except Exception as e:
        logger.error(f"Failed to start MCP server: {e}")
        raise

if __name__ == "__main__":
    main()

Isso configura um servidor MCP básico com registro adequado.

4. Defina um recurso

Recursos expõem dados que o modelo pode ler. Vamos criar um arquivo src/resources/user_profiles.py:

from typing import List, Dict, Any
from pydantic import BaseModel
import logging

logger = logging.getLogger("mcp_server.resources")

class UserProfile(BaseModel):
    """Data model for user profiles."""
    name: str
    role: str
    department: str = "General"
    years_experience: int = 0

def fetch_user_profiles() -> List[Dict[str, Any]]:
    """
    Fetch user profiles from the database.
    
    Returns:
        List[Dict[str, Any]]: A list of user profile dictionaries.
    """
    try:
        # In a real implementation, this would query a database
        # For this example, we'll return mock data
        users = [
            UserProfile(name="Alice", role="Engineer", department="Engineering", years_experience=5),
            UserProfile(name="Bob", role="Product Manager", department="Product", years_experience=3),
            UserProfile(name="Charlie", role="Designer", department="Design", years_experience=7)
        ]
        
        logger.info(f"Successfully fetched {len(users)} user profiles")
        return [user.model_dump() for user in users]
    except Exception as e:
        logger.error(f"Error fetching user profiles: {e}")
        # In production, you might want to return an empty list or raise
        # a specific exception depending on your error handling strategy
        return []

Agora atualize src/server.py para incluir este recurso:

from typing import Dict, Any
from mcp_server import MCPServer, Resource
import logging
from src.resources.user_profiles import fetch_user_profiles

# ... existing code ...

def main() -> None:
    """Initialize and start the MCP server."""
    try:
        server = MCPServer(
            name="MyMCPServer",
            version="0.1.0",
            description="A simple MCP server example"
        )
        
        # Add the user profiles resource
        user_profiles = Resource(
            name="user_profiles",
            description="List of user profiles from the company database.",
            fetch_fn=fetch_user_profiles
        )
        
        server.add_resource(user_profiles)
        
        logger.info("Starting MCP server...")
        server.start()
    except Exception as e:
        logger.error(f"Failed to start MCP server: {e}")
        raise

if __name__ == "__main__":
    main()

O LLM agora pode consultar user_profiles através do cliente MCP.

5. Defina uma ferramenta

Ferramentas permitem que o LLM execute uma ação. Crie um arquivo src/tools/user_management.py:

from typing import Dict, Any, Optional
from pydantic import BaseModel, Field, ValidationError
import logging

logger = logging.getLogger("mcp_server.tools")

class CreateUserRequest(BaseModel):
    """Validation model for user creation requests."""
    name: str = Field(..., min_length=2, description="User's full name")
    role: str = Field(..., min_length=2, description="User's job role")
    department: Optional[str] = Field("General", description="User's department")
    years_experience: Optional[int] = Field(0, ge=0, description="Years of professional experience")

def create_user_profile(request_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Create a new user profile in the database.
    
    Args:
        request_data (Dict[str, Any]): User data containing name, role, etc.
        
    Returns:
        Dict[str, Any]: Response with status and user info
    """
    try:
        # Validate the input data
        user_data = CreateUserRequest(**request_data)
        
        # In a real implementation, this would insert into a database
        # For this example, we'll just log the action
        logger.info(f"Creating new user: {user_data.name} - {user_data.role} in {user_data.department}")
        
        # Return success response with created user data
        return {
            "status": "success",
            "message": f"User {user_data.name} created successfully",
            "user": user_data.model_dump()
        }
    except ValidationError as e:
        # Handle validation errors
        logger.error(f"Validation error: {e}")
        return {
            "status": "error",
            "message": "Invalid user data provided",
            "details": str(e)
        }
    except Exception as e:
        # Handle other errors
        logger.error(f"Error creating user: {e}")
        return {
            "status": "error",
            "message": "Failed to create user",
            "details": str(e)
        }

Agora atualize src/server.py para incluir esta ferramenta:

from typing import Dict, Any
from mcp_server import MCPServer, Resource, Tool
import logging
from src.resources.user_profiles import fetch_user_profiles
from src.tools.user_management import create_user_profile

# ... existing code ...

def main() -> None:
    """Initialize and start the MCP server."""
    try:
        server = MCPServer(
            name="MyMCPServer",
            version="0.1.0",
            description="A simple MCP server example"
        )
        
        # Add the user profiles resource
        user_profiles = Resource(
            name="user_profiles",
            description="List of user profiles from the company database.",
            fetch_fn=fetch_user_profiles
        )
        
        # Add the create user tool
        create_user = Tool(
            name="create_user_profile",
            description="Create a new user profile in the database.",
            parameters={
                "name": {"type": "string", "description": "User's full name"},
                "role": {"type": "string", "description": "User's job role"},
                "department": {"type": "string", "description": "User's department (optional)"},
                "years_experience": {"type": "integer", "description": "Years of experience (optional)"}
            },
            execute_fn=create_user_profile
        )
        
        server.add_resource(user_profiles)
        server.add_tool(create_user)
        
        logger.info("Starting MCP server...")
        server.start()
    except Exception as e:
        logger.error(f"Failed to start MCP server: {e}")
        raise

6. Tratamento de erros e validação

Crie um arquivo src/utils/validation.py para centralizar sua lógica de validação:

from typing import Dict, Any, List, Optional, Type
from pydantic import BaseModel, ValidationError
import logging

logger = logging.getLogger("mcp_server.validation")

def validate_request(
    data: Dict[str, Any],
    model_class: Type[BaseModel]
) -> tuple[Optional[BaseModel], Optional[Dict[str, Any]]]:
    """
    Validate request data against a Pydantic model.
    
    Args:
        data: The input data to validate
        model_class: The Pydantic model class to use for validation
        
    Returns:
        tuple: (validated_model, error_dict)
            - If valid: (model instance, None)
            - If invalid: (None, error dictionary)
    """
    try:
        validated_data = model_class(**data)
        return validated_data, None
    except ValidationError as e:
        errors = e.errors()
        error_dict = {
            "status": "error",
            "message": "Validation failed",
            "errors": errors
        }
        logger.error(f"Validation error: {errors}")
        return None, error_dict

Esta função utilitária pode ser usada em todas as suas ferramentas para validar dados de entrada de forma consistente.

7. Execute e teste o servidor MCP

Crie um script de teste simples test_server.py para verificar se seu servidor funciona:

import requests
import json
import time
import subprocess
import sys
from pathlib import Path

def test_server():
    """Simple test to verify the MCP server is running correctly."""
    # Start the server in a separate process
    server_process = subprocess.Popen([sys.executable, "src/server.py"])
    
    try:
        # Wait for server to start
        time.sleep(2)
        
        # Test the server using the MCP client
        # In a real test, you would use the MCP client SDK
        # For this example, we'll simulate a client using HTTP requests
        
        # Assuming the server is running on localhost:8000
        base_url = "http://localhost:8000"
        
        # Test fetching resources
        response = requests.get(f"{base_url}/resources/user_profiles")
        assert response.status_code == 200
        data = response.json()
        print("Resource response:", json.dumps(data, indent=2))
        
        # Test executing a tool
        tool_data = {
            "name": "Test User",
            "role": "Tester",
            "department": "QA"
        }
        response = requests.post(
            f"{base_url}/tools/create_user_profile",
            json=tool_data
        )
        assert response.status_code == 200
        data = response.json()
        print("Tool response:", json.dumps(data, indent=2))
        
        print("All tests passed!")
        
    finally:
        # Clean up: terminate the server process
        server_process.terminate()
        server_process.wait()

if __name__ == "__main__":
    test_server()

Execute seu servidor:

python src/server.py

Em um terminal separado, você pode ver uma saída como esta quando o servidor estiver em execução:

2025-04-28 10:15:23 - mcp_server - INFO - Starting MCP server...
2025-04-28 10:15:23 - mcp_server - INFO - Server listening on 0.0.0.0:8000
2025-04-28 10:15:30 - mcp_server.resources - INFO - Successfully fetched 3 user profiles
2025-04-28 10:15:35 - mcp_server.tools - INFO - Creating new user: Test User - Tester in QA

Em seguida, configure seu cliente MCP (como o Claude Desktop) para se conectar ao seu servidor MCP local fornecendo a URL do servidor ou o comando para iniciar o servidor.

Considerações de segurança

Ao implantar um servidor MCP, considere estas melhores práticas de segurança:

  1. Autenticação: Implemente chaves de API ou OAuth para autenticar clientes.
def authenticate_request(request):
    api_key = request.headers.get("X-API-Key")
    if not api_key or api_key != os.environ.get("MCP_API_KEY"):
        raise ValueError("Invalid API key")
  1. Validação de Entrada: Sempre valide todas as entradas usando modelos Pydantic.
  2. Limitação de Taxa: Implemente limitação de taxa para prevenir abusos.
  3. HTTPS: Sempre use HTTPS em produção.
  4. Ações Restritas: Defina limites claros para o que as ferramentas podem fazer.

Otimização de desempenho

  1. Cache: Armazene em cache buscas de recursos caras:
from functools import lru_cache

@lru_cache(maxsize=128, ttl=300)  # Cache for 5 minutes
def fetch_user_profiles():
    # Expensive database query
    pass
  1. Processamento Assíncrono: Use async para operações limitadas por I/O:
async def fetch_user_profiles():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.example.com/users") as response:
            data = await response.json()
            return data
  1. Pool de Conexões: Use pools de conexão para acesso ao banco de dados.

Implantação

Desenvolvimento local

Para desenvolvimento local, execute:

python src/server.py

Implantação com Docker

Crie um Dockerfile:

FROM python:3.10-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["python", "src/server.py"]

Construa e execute:

docker build -t mcp-server .
docker run -p 8000:8000 mcp-server

Implantação na nuvem (AWS)

  1. Crie uma instância EC2 ou use AWS App Runner
  2. Implante seu contêiner Docker
  3. Configure um Application Load Balancer
  4. Configure grupos de segurança para restringir o acesso

Testando seu servidor MCP

Crie um arquivo de teste tests/test_resources.py:

import pytest
from src.resources.user_profiles import fetch_user_profiles

def test_fetch_user_profiles():
    """Test that user profiles can be fetched successfully."""
    profiles = fetch_user_profiles()
    
    # Check structure
    assert isinstance(profiles, list)
    assert len(profiles) > 0
    
    # Check content
    first_profile = profiles[0]
    assert "name" in first_profile
    assert "role" in first_profile
    assert isinstance(first_profile["name"], str)

Execute os testes com:

pytest

Erros comuns e solução de problemas

Problema Solução Exemplo Não consegue conectar ao servidor MCP Verifique se seu servidor está em execução e a porta está correta netstat -tulpn | grep 8000 LLM não consegue encontrar recursos Verifique se os campos name e description estão configurados corretamente Verifique sua inicialização de Resource Erros na execução de ferramentas Valide se os parâmetros de entrada correspondem aos tipos esperados Use Pydantic para validação Cliente não consegue analisar a saída Certifique-se de que suas funções retornem dados serializáveis em JSON Use .model_dump() em vez de objetos personalizados Servidor falha na inicialização Verifique suas importações e variáveis de ambiente Configure DEBUG=True para registro detalhado Timeout da ferramenta Adicione tratamento de timeout para chamadas de API externas Use asyncio.wait_for() com um timeout Falhas de autenticação Verifique chaves de API e permissões Verifique os cabeçalhos de requisição Erros de análise XML/JSON Use cabeçalhos de tipo de conteúdo adequados Configure Content-Type: application/json

Próximos passos

Depois de construir seu servidor MCP básico, considere estas extensões avançadas:

  1. Integração com Banco de Dados: Conecte-se a PostgreSQL, MongoDB ou outros bancos de dados.
  2. Operações de Arquivo: Adicione ferramentas para leitura, escrita e transformação de arquivos.
  3. APIs Externas: Integre-se com serviços populares como GitHub, Slack ou Google Drive.
  4. Webhooks: Permita que o LLM acione eventos em outros sistemas.
  5. Recursos de Streaming: Suporte para streaming de grandes conjuntos de dados.
  6. Ações Sensíveis ao Contexto: Adicione ferramentas que entendam o contexto atual do LLM.

Exemplo: Adicionando uma conexão de banco de dados

import psycopg2
from contextlib import contextmanager

@contextmanager
def get_db_connection():
    """Create a database connection context manager."""
    conn = None
    try:
        conn = psycopg2.connect(
            host=os.environ.get("DB_HOST"),
            database=os.environ.get("DB_NAME"),
            user=os.environ.get("DB_USER"),
            password=os.environ.get("DB_PASSWORD")
        )
        yield conn
    finally:
        if conn is not None:
            conn.close()

def fetch_user_profiles_from_db():
    """Fetch user profiles from a PostgreSQL database."""
    with get_db_connection() as conn:
        with conn.cursor() as cur:
            cur.execute("SELECT name, role, department FROM users")
            columns = [desc[0] for desc in cur.description]
            return [dict(zip(columns, row)) for row in cur.fetchall()]

Conclusão

Construir um servidor MCP simples em Python abre as portas para tornar os LLMs muito mais poderosos. Ao expor dados e ações através de um protocolo limpo e padronizado, você facilita a interação segura e significativa dos sistemas de IA com serviços externos.

Comece pequeno, concentre-se em um recurso e uma ferramenta, e você pode expandir ao longo do tempo para casos de uso mais avançados como bancos de dados, armazenamento em nuvem ou APIs internas.

O ecossistema MCP está crescendo rapidamente, e implementar esses padrões agora posicionará suas aplicações para se beneficiar das melhorias tanto no protocolo quanto nos LLMs que o utilizam.

FAQs

Alguma experiência com Python é necessária. Servidores MCP são processos de software que precisam de definições corretas para recursos e ferramentas.

Sim. A Anthropic e colaboradores estão lançando SDKs para múltiplas linguagens, incluindo Python e TypeScript.

Sim. Você pode hospedar seu servidor MCP em plataformas de nuvem, atrás de firewalls, e disponibilizá-lo com segurança para seus clientes LLM.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers