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:
- O LLM (via cliente) solicita dados ou ações do seu servidor
- Seu servidor processa essas solicitações e retorna respostas padronizadas
- 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:
- 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")
- Validação de Entrada: Sempre valide todas as entradas usando modelos Pydantic.
- Limitação de Taxa: Implemente limitação de taxa para prevenir abusos.
- HTTPS: Sempre use HTTPS em produção.
- Ações Restritas: Defina limites claros para o que as ferramentas podem fazer.
Otimização de desempenho
- 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
- 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
- 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)
- Crie uma instância EC2 ou use AWS App Runner
- Implante seu contêiner Docker
- Configure um Application Load Balancer
- 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:
- Integração com Banco de Dados: Conecte-se a PostgreSQL, MongoDB ou outros bancos de dados.
- Operações de Arquivo: Adicione ferramentas para leitura, escrita e transformação de arquivos.
- APIs Externas: Integre-se com serviços populares como GitHub, Slack ou Google Drive.
- Webhooks: Permita que o LLM acione eventos em outros sistemas.
- Recursos de Streaming: Suporte para streaming de grandes conjuntos de dados.
- 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.