AI Engineering Academy · Aula

Criando seu primeiro servidor MCP

Use o SDK MCP para Python para criar um servidor que disponibilize recursos, ferramentas e instruções; depois, conecte-o ao Claude Desktop para vê-lo funcionando de ponta a ponta.

Aula 2 de 413 etapas

Criando seu primeiro servidor MCP é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.

Configuração do projeto para um servidor MCP

Criar um servidor MCP em Python requer o SDK mcp e um ambiente Python. Você criará um servidor ao qual o Claude Desktop ou qualquer cliente MCP poderá se conectar por meio de stdio. Comece instalando o pacote e criando o arquivo do servidor.

# Create a project directory
# mkdir my_mcp_server && cd my_mcp_server

# Create a virtual environment
# python -m venv venv && source venv/bin/activate

# Install the MCP SDK
# pip install mcp httpx

# Project structure:
# my_mcp_server/
#   server.py          <- Your MCP server
#   requirements.txt
#   README.md

Criando o objeto do servidor

Importe do pacote mcp e crie uma instância de Server com o nome do seu servidor. O nome é mostrado aos clientes na lista de servidores MCP; escolha algo descritivo. O objeto do servidor é o ponto de entrada para registrar todas as suas ferramentas, recursos e prompts.

# server.py
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import asyncio
import httpx

# Create the server — name is shown in Claude Desktop
app = Server('weather-server')

# --- Tool registrations go here ---

# Entry point
if __name__ == '__main__':
    asyncio.run(stdio_server(app))

Registrando ferramentas com @app.list_tools()

O decorador @app.list_tools() registra um manipulador que retorna a lista de ferramentas disponíveis quando o cliente a solicita. Cada ferramenta é definida com um nome, uma descrição e um inputSchema — o esquema JSON que descreve seus parâmetros. O cliente envia essa lista ao LLM para que ele saiba quais ferramentas pode chamar.

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name='get_weather',
            description='Get current weather for a city. Use when the user asks about weather in a specific location.',
            inputSchema={
                'type': 'object',
                'properties': {
                    'city': {
                        'type': 'string',
                        'description': 'City name, e.g. London or New York'
                    },
                    'units': {
                        'type': 'string',
                        'enum': ['metric', 'imperial'],
                        'description': 'Temperature units. Default is metric.'
                    }
                },
                'required': ['city']
            }
        ),
        types.Tool(
            name='list_cities',
            description='Return a list of major cities the user can query weather for.',
            inputSchema={'type': 'object', 'properties': {}, 'required': []}
        )
    ]

Implementando a execução de ferramentas

O decorador @app.call_tool() gerencia a execução de ferramentas. Quando o cliente chama uma ferramenta, este manipulador recebe o nome e os argumentos da ferramenta. Execute a lógica apropriada e retorne uma lista de objetos TextContent contendo a string do resultado.

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    if name == 'list_cities':
        cities = ['London', 'New York', 'Tokyo', 'Paris', 'Sydney']
        return [types.TextContent(type='text', text=', '.join(cities))]

    if name == 'get_weather':
        city = arguments['city']
        units = arguments.get('units', 'metric')
        unit_symbol = 'C' if units == 'metric' else 'F'

        # Call real weather API (stub here)
        async with httpx.AsyncClient() as client:
            # Replace with actual API call
            result = f'{city}: 18{chr(176)}{unit_symbol}, partly cloudy, humidity 65%'

        return [types.TextContent(type='text', text=result)]

    raise ValueError(f'Unknown tool: {name}')

Expondo recursos

Recursos são dados estáticos ou dinâmicos que o modelo pode ler — pense neles como arquivos. Defina URIs de recursos e implemente um leitor de recursos. Os recursos aparecem no cliente como itens aos quais a IA pode fazer referência, sendo úteis para configurações, documentação ou instantâneos de dados acessados com frequência.

@app.list_resources()
async def list_resources() -> list[types.Resource]:
    return [
        types.Resource(
            uri='weather://supported-cities',
            name='Supported Cities List',
            description='Complete list of cities available in this weather server.',
            mimeType='text/plain'
        )
    ]

@app.read_resource()
async def read_resource(uri: str) -> str:
    if uri == 'weather://supported-cities':
        cities = ['London', 'New York', 'Tokyo', 'Paris', 'Sydney', 'Dubai', 'Singapore']
        return '\n'.join(cities)
    raise ValueError(f'Unknown resource URI: {uri}')

Registrando modelos de prompts

Prompts são modelos de mensagens reutilizáveis que os clientes apresentam aos usuários como comandos de barra ou ações rápidas. Eles aceitam parâmetros e retornam uma lista de mensagens que se tornam o contexto inicial de uma conversa. Os prompts são excelentes para codificar instruções complexas que os usuários acionam com um único comando.

@app.list_prompts()
async def list_prompts() -> list[types.Prompt]:
    return [
        types.Prompt(
            name='weather-report',
            description='Generate a formatted weather report for a city.',
            arguments=[
                types.PromptArgument(name='city', description='City name', required=True)
            ]
        )
    ]

@app.get_prompt()
async def get_prompt(name: str, arguments: dict) -> types.GetPromptResult:
    if name == 'weather-report':
        city = arguments.get('city', 'London')
        return types.GetPromptResult(
            description=f'Weather report for {city}',
            messages=[
                types.PromptMessage(
                    role='user',
                    content=types.TextContent(
                        type='text',
                        text=f'Use the get_weather tool to look up {city} and give me a detailed weather report including what clothing I should wear.'
                    )
                )
            ]
        )
    raise ValueError(f'Unknown prompt: {name}')

Conectando ao Claude Desktop

Para usar seu servidor MCP com o Claude Desktop, adicione-o ao arquivo de configuração do Claude Desktop. No macOS, ele fica em ~/Library/Application Support/Claude/claude_desktop_config.json. Especifique o comando para iniciar seu servidor e todas as variáveis de ambiente necessárias.

# ~/Library/Application Support/Claude/claude_desktop_config.json
# Add this JSON configuration:

# {
#   "mcpServers": {
#     "weather-server": {
#       "command": "/path/to/venv/bin/python",
#       "args": ["/path/to/my_mcp_server/server.py"],
#       "env": {
#         "WEATHER_API_KEY": "your_api_key_here"
#       }
#     }
#   }
# }

# After saving, restart Claude Desktop.
# Your server's tools will appear in Claude's tool list.

Testando seu servidor com o MCP CLI

Antes de conectar ao Claude Desktop, teste seu servidor usando o inspetor do MCP ou as ferramentas de CLI. O comando mcp dev inicia seu servidor e abre um inspetor no navegador, no qual você pode chamar ferramentas manualmente e ver as mensagens brutas do protocolo, facilitando a depuração de problemas.

# Install the MCP development tools
# pip install 'mcp[cli]'

# Start the inspector with your server
# mcp dev server.py

# The inspector opens at http://localhost:5173
# You can:
# - See all registered tools and their schemas
# - Call tools with custom arguments
# - Browse available resources
# - Test prompt templates
# - View the full JSON-RPC message exchange

Tratamento de erros em servidores MCP

Os servidores MCP nunca devem travar ao receber entradas inválidas. Envolva toda a execução de ferramentas em try/except e retorne mensagens de erro como TextContent, em vez de lançar exceções. Para erros fatais, como problemas de configuração ou chaves de API ausentes, registre-os na inicialização e lance uma exceção antes de o servidor entrar no loop principal.

@app.call_tool()
async def call_tool_safe(name: str, arguments: dict) -> list[types.TextContent]:
    try:
        if name == 'get_weather':
            city = arguments.get('city')
            if not city:
                return [types.TextContent(type='text', text='Error: city argument is required.')]
            result = await fetch_weather(city, arguments.get('units', 'metric'))
            return [types.TextContent(type='text', text=result)]
        raise ValueError(f'Unknown tool: {name}')
    except httpx.TimeoutException:
        return [types.TextContent(type='text', text='Error: Weather API timed out. Try again.')]
    except Exception as e:
        return [types.TextContent(type='text', text=f'Error: {str(e)}')]

Registro de eventos em servidores MCP

Como os servidores MCP se comunicam com o cliente por meio de stdio, instruções de impressão interromperão o protocolo. Use sempre stderr para fazer o registro — ele vai para um fluxo separado que não interfere na troca de mensagens do MCP. Configure o módulo de registro do Python para escrever em stderr.

import logging
import sys

# Configure logging to stderr (NOT stdout — that's the MCP channel)
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    stream=sys.stderr
)
logger = logging.getLogger('weather-server')

# In your tool handler:
# logger.info(f'Getting weather for {city}')
# logger.error(f'API call failed: {e}')

# Claude Desktop captures stderr to a log file:
# ~/Library/Logs/Claude/mcp-server-weather-server.log

Empacotando seu servidor MCP

Compartilhe seu servidor MCP empacotando-o com um pyproject.toml e publicando-o no PyPI, ou distribua-o como um contêiner Docker para equipes. Use variáveis de ambiente para todos os segredos — chaves de API e URLs de bancos de dados — para manter a configuração do servidor separada do código. Documente as variáveis de ambiente necessárias e um exemplo de configuração em um README claro.

Verificação rápida

Teste sua compreensão sobre a criação de um servidor MCP em Python.

Recapitulação da lição

Nesta lição, você aprendeu que: os servidores MCP expõem ferramentas por meio dos decoradores @app.list_tools() e @app.call_tool(); os recursos e prompts ampliam o servidor com dados legíveis e modelos reutilizáveis; e o registro deve usar stderr para evitar corromper o canal do protocolo MCP via stdio. A seguir, conectaremos um servidor MCP a um banco de dados e exporemos recursos dinâmicos com paginação.

Grátis para começar

Aprenda Python com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
30
Aulas
120

Perguntas Frequentes

A aula “Criando seu primeiro servidor MCP” é grátis?

Sim — o texto completo de “Criando seu primeiro servidor MCP” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.

O que vou aprender em “Criando seu primeiro servidor MCP”?

Use o SDK MCP para Python para criar um servidor que disponibilize recursos, ferramentas e instruções; depois, conecte-o ao Claude Desktop para vê-lo funcionando de ponta a ponta. Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Engineering Academy?

Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Criando seu primeiro servidor MCP”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Engineering Academy?

Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. O que é MCP e por que ele importa
  2. Criando seu primeiro servidor MCP
  3. Disponibilizando recursos de banco de dados via MCP
  4. Segurança e autenticação no MCP
← Voltar para AI Engineering Academy