Criar um servidor MCP em Python: guia + Inspector
A promessa dos assistentes de IA sempre foi a capacidade de ajudar em tarefas do mundo real, mas houve uma limitação fundamental: a maioria dos sistemas de IA opera de forma isolada, incapaz de acessar as fontes de dados, APIs e ferramentas específicas que os tornam realmente úteis para o seu caso de uso particular. Seja para que uma IA consulte o banco de dados da sua empresa, interaja com o seu sistema de gestão de projetos ou acesse dados em tempo real de APIs especializadas, a abordagem tradicional exigia a construção de integrações personalizadas para cada plataforma de IA - um processo demorado e fragmentado.
É aqui que o Model Context Protocol (MCP) muda tudo. Em vez de os assistentes de IA ficarem limitados aos seus dados de treinamento ou exigirem integrações personalizadas complexas, o MCP oferece uma forma padronizada de conectar sistemas de IA às suas fontes de dados e ferramentas específicas. Precisa que a sua IA acesse o banco de dados de clientes? Crie um servidor MCP. Quer que ela interaja com a sua API de gestão de estoque? Crie um servidor MCP. O mesmo servidor funciona em diferentes plataformas de IA, eliminando a necessidade de reconstruir integrações para cada sistema.
A adoção do MCP está acelerando rapidamente em todo o ecossistema de IA. Grandes plataformas estão abraçando o protocolo como padrão para integração de IA. O Claude Desktop e o Claude for Code já oferecem suporte nativo ao MCP, permitindo que os usuários se conectem de forma transparente a fontes de dados e ferramentas personalizadas. Os principais provedores de APIs de IA - OpenAI, Anthropic e Google - estão adicionando compatibilidade com MCP às suas APIs de completion, permitindo que desenvolvedores criem aplicações de IA capazes de acessar sistemas externos por meio de interfaces padronizadas. Esse ecossistema em crescimento significa que os servidores MCP que você constrói hoje funcionarão com uma gama cada vez maior de plataformas e aplicações de IA.
Neste tutorial abrangente, você aprenderá a construir servidores MCP prontos para produção usando Python por meio de uma abordagem iterativa e prática. Vamos começar com um servidor mínimo e adicionar recursos progressivamente, mostrando exatamente como desenvolver, testar e estender o seu servidor passo a passo. Ao final deste guia, você terá construído um servidor MCP completo de serviço meteorológico com recursos avançados, incluindo sampling assistido por IA, autenticação OAuth e capacidades de deploy em produção.
Entendendo o MCP
O Model Context Protocol representa uma mudança de paradigma na forma como pensamos a arquitetura de integração de IA. Em sua essência, o MCP é um protocolo aberto que padroniza como as aplicações fornecem contexto a modelos de linguagem de grande porte, mas suas implicações vão muito além do simples compartilhamento de dados.
Para entender por que o MCP importa, considere o estado atual das integrações de IA. A maioria das aplicações de IA hoje opera de forma isolada, com capacidade limitada de acessar dados em tempo real ou interagir com sistemas externos. Quando os desenvolvedores querem dar a um assistente de IA acesso a um banco de dados, sistema de arquivos ou serviço web, eles normalmente precisam construir soluções personalizadas fortemente acopladas a plataformas de IA específicas. Essa abordagem cria vários problemas: dependência de fornecedor (vendor lock-in), esforço duplicado entre diferentes plataformas de IA, preocupações de segurança decorrentes do acesso direto a APIs e sobrecarga de manutenção à medida que as APIs evoluem.
O MCP enfrenta esses desafios por meio de uma arquitetura cliente-servidor que introduz uma camada intermediária padronizada. Em vez de as aplicações de IA acessarem diretamente os sistemas externos, elas se comunicam por meio de servidores MCP que atuam como gateways seguros e padronizados. Essa arquitetura oferece vários benefícios importantes que a tornam particularmente poderosa para deploys corporativos e de produção.
Arquitetura central do MCP
No cerne da arquitetura do MCP estão três participantes principais que trabalham juntos para viabilizar uma integração de IA transparente:
MCP Host: A aplicação de IA que coordena e gerencia conexões com múltiplos servidores MCP. Aplicações de IA populares como o Claude Desktop atuam como MCP hosts quando oferecem suporte ao protocolo.
MCP Client: Um componente dentro do host que mantém conexões dedicadas com servidores MCP individuais, lidando com a comunicação em nível de protocolo e o ciclo de vida da conexão.
MCP Server: O componente que expõe dados e funcionalidades aos MCP clients de forma padronizada. Os servidores podem rodar localmente (usando o transporte STDIO) ou remotamente (usando o transporte HTTP).
Os três pilares do MCP
O protocolo define três primitivas fundamentais que os servidores podem expor:
Tools (ferramentas) são funções executáveis que as aplicações de IA podem invocar para realizar ações. Elas podem incluir operações como consultar um banco de dados, enviar um e-mail ou chamar uma API externa.
Resources (recursos) fornecem informações contextuais às aplicações de IA sem realizar ações. Eles representam dados que podem ser lidos e compreendidos pela IA, como o conteúdo de arquivos ou registros de banco de dados.
Prompts são templates reutilizáveis que ajudam a estruturar interações com modelos de linguagem, oferecendo uma forma de encapsular conhecimento de domínio e boas práticas.
Configurando o seu ambiente de desenvolvimento
Antes de começarmos a construir nosso servidor MCP, vamos configurar um ambiente de desenvolvimento adequado que suporte tanto a iteração rápida quanto o deploy em produção. Usaremos o Model Context Protocol Python SDK ao longo deste tutorial.
Pré-requisitos
Certifique-se de ter o Python 3.10 ou superior instalado no seu sistema. Você pode verificar a sua versão do Python com:
python --version
# or
python3 --version
Criando o seu projeto
Crie um novo diretório de projeto e configure um ambiente virtual:
# Create project directory
mkdir weather-mcp-server
cd weather-mcp-server
# Create a virtual environment
python -m venv .venv
# Activate the virtual environment
# On macOS/Linux:
source .venv/bin/activate
# On Windows:
.venv\Scripts\activate
Instalando as dependências
Instale o MCP Python SDK e dependências adicionais usando o pip:
# Upgrade pip to the latest version
pip install --upgrade pip
# Install MCP SDK with CLI tools
pip install "mcp[cli]"
# Install HTTP client for API requests
pip install httpx
# Install JWT library for authentication (we'll use this later)
pip install PyJWT
# Install development dependencies
pip install pytest black isort mypy
Criando um arquivo de requirements
Crie um arquivo requirements.txt para rastrear as suas dependências:
# Generate requirements file
pip freeze > requirements.txt
O seu requirements.txt deve incluir entradas como:
mcp[cli]
httpx
PyJWT
pytest
black
isort
mypy
Construindo o seu primeiro servidor MCP: passo a passo
Agora vamos construir nosso servidor MCP de meteorologia iterativamente, começando com a implementação mais simples possível e adicionando recursos passo a passo. Essa abordagem ajuda você a entender cada componente e facilita a depuração.
Passo 1: Criar um servidor MCP mínimo
Vamos começar com o mínimo absoluto - um servidor que não faz nada além de responder a mensagens básicas do protocolo MCP. Crie um arquivo chamado weather_server.py:
"""
Step 1: Minimal MCP server that responds to protocol messages
"""
from mcp.server.fastmcp import FastMCP
# Create the MCP server instance
mcp = FastMCP("weather-server")
if __name__ == "__main__":
# Run the server using STDIO transport
mcp.run(transport='stdio')
Teste esse servidor mínimo:
# Start the MCP Inspector to test your server
python -m mcp dev weather_server.py
O MCP Inspector iniciará uma interface web (normalmente em http://localhost:3000), onde você poderá ver que o seu servidor está rodando e respondendo a mensagens do protocolo MCP, mesmo que ainda não exponha nenhuma ferramenta.
Passo 2: Adicionar a sua primeira ferramenta
Agora vamos adicionar uma ferramenta simples que retorna informações meteorológicas estáticas:
"""
Step 2: Add a simple weather tool with static data
"""
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
@mcp.tool()
def get_weather(city: str) -> str:
"""Get current weather for a city (demo with static data)"""
# For now, return static data to test the tool mechanism
return f"Weather in {city}: Sunny, 22°C (This is demo data)"
if __name__ == "__main__":
mcp.run(transport='stdio')
Teste a nova ferramenta no MCP Inspector. Você deve ver agora uma ferramenta get_weather que pode chamar com diferentes nomes de cidades.
Passo 3: Adicionar integração com uma API real
Agora vamos nos conectar a uma API meteorológica real. Usaremos a API do National Weather Service, que é gratuita e não exige autenticação:
"""
Step 3: Connect to real weather API
"""
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception as e:
print(f"API request failed: {e}", file=sys.stderr)
return None
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# Step 1: Get the forecast grid endpoint for this location
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return f"Unable to fetch forecast data for coordinates ({latitude}, {longitude})"
# Step 2: Get the actual forecast data
properties = points_data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
return "Error: Unable to determine forecast URL for this location"
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast data"
# Format the first few periods
periods = forecast_data.get("properties", {}).get("periods", [])
if not periods:
return "No forecast periods available for this location"
# Format the first 3 periods for display
forecasts = []
for period in periods[:3]:
forecast_text = f"""
{period.get('name', 'Unknown Period')}:
Temperature: {period.get('temperature', 'Unknown')}°{period.get('temperatureUnit', 'F')}
Wind: {period.get('windSpeed', 'Unknown')} {period.get('windDirection', '')}
Forecast: {period.get('detailedForecast', 'No detailed forecast available')}
"""
forecasts.append(forecast_text.strip())
return f"Forecast for {latitude}, {longitude}:\n" + "\n---\n".join(forecasts)
if __name__ == "__main__":
import sys
mcp.run(transport='stdio')
Teste esta versão com coordenadas reais (por exemplo, Nova York: 40.7128, -74.0060). Você deve receber agora dados reais de previsão do tempo!
Passo 4: Adicionar validação de entrada e tratamento de erros
Vamos tornar nosso servidor mais robusto adicionando validação de entrada e tratamento de erros adequados:
"""
Step 4: Add input validation and better error handling
"""
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except httpx.TimeoutException:
print(f"Request timeout for URL: {url}", file=sys.stderr)
return None
except httpx.HTTPStatusError as e:
print(f"HTTP error {e.response.status_code} for URL: {url}", file=sys.stderr)
return None
except Exception as e:
print(f"Unexpected error for URL {url}: {e}", file=sys.stderr)
return None
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# Validate coordinate ranges
if not (-90 <= latitude <= 90):
return "Error: Latitude must be between -90 and 90 degrees"
if not (-180 <= longitude <= 180):
return "Error: Longitude must be between -180 and 180 degrees"
# Step 1: Get the forecast grid endpoint for this location
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return f"Unable to fetch forecast data for coordinates ({latitude}, {longitude}). This location may be outside the US or the service may be unavailable."
# Extract the forecast URL from the points response
properties = points_data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
return "Error: Unable to determine forecast URL for this location"
# Step 2: Get the actual forecast data
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast data"
# Extract and format forecast periods
forecast_properties = forecast_data.get("properties", {})
periods = forecast_properties.get("periods", [])
if not periods:
return "No forecast periods available for this location"
# Format the first 3 periods for display
forecasts = []
for period in periods[:3]:
forecast_text = f"""
{period.get('name', 'Unknown Period')}:
Temperature: {period.get('temperature', 'Unknown')}°{period.get('temperatureUnit', 'F')}
Wind: {period.get('windSpeed', 'Unknown')} {period.get('windDirection', '')}
Forecast: {period.get('detailedForecast', 'No detailed forecast available')}
"""
forecasts.append(forecast_text.strip())
location_info = f"Forecast for {latitude}, {longitude}:\n"
return location_info + "\n---\n".join(forecasts)
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get active weather alerts for a US state"""
# Validate state code format
if not state or len(state) != 2:
return "Error: Please provide a valid two-letter US state code (e.g., 'CA', 'NY', 'TX')"
state = state.upper()
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data:
return f"Unable to fetch weather alerts for {state}. The service may be temporarily unavailable."
features = data.get("features", [])
if not features:
return f"No active weather alerts for {state}."
# Format alerts for display
alerts = []
for feature in features:
props = feature.get("properties", {})
event = props.get('event', 'Unknown Event')
area = props.get('areaDesc', 'Unknown Area')
severity = props.get('severity', 'Unknown Severity')
description = props.get('description', 'No description available')
alert_text = f"""
Event: {event}
Area: {area}
Severity: {severity}
Description: {description[:200]}{'...' if len(description) > 200 else ''}
"""
alerts.append(alert_text.strip())
alert_count = len(alerts)
header = f"Found {alert_count} active weather alert{'s' if alert_count != 1 else ''} for {state}:\n"
return header + "\n---\n".join(alerts)
if __name__ == "__main__":
mcp.run(transport='stdio')
Agora teste ambas as ferramentas com várias entradas, incluindo entradas inválidas, para ver como o tratamento de erros funciona.
Passo 5: Adicionar resources para informações contextuais
Vamos adicionar resources que fornecem informações contextuais sobre estações e zonas meteorológicas:
"""
Step 5: Add resources for contextual weather information
"""
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except httpx.TimeoutException:
print(f"Request timeout for URL: {url}", file=sys.stderr)
return None
except httpx.HTTPStatusError as e:
print(f"HTTP error {e.response.status_code} for URL: {url}", file=sys.stderr)
return None
except Exception as e:
print(f"Unexpected error for URL {url}: {e}", file=sys.stderr)
return None
# Tools (same as Step 4)
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# Validate coordinate ranges
if not (-90 <= latitude <= 90):
return "Error: Latitude must be between -90 and 90 degrees"
if not (-180 <= longitude <= 180):
return "Error: Longitude must be between -180 and 180 degrees"
# Step 1: Get the forecast grid endpoint for this location
points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
points_data = await make_nws_request(points_url)
if not points_data:
return f"Unable to fetch forecast data for coordinates ({latitude}, {longitude}). This location may be outside the US or the service may be unavailable."
# Extract the forecast URL from the points response
properties = points_data.get("properties", {})
forecast_url = properties.get("forecast")
if not forecast_url:
return "Error: Unable to determine forecast URL for this location"
# Step 2: Get the actual forecast data
forecast_data = await make_nws_request(forecast_url)
if not forecast_data:
return "Unable to fetch detailed forecast data"
# Extract and format forecast periods
forecast_properties = forecast_data.get("properties", {})
periods = forecast_properties.get("periods", [])
if not periods:
return "No forecast periods available for this location"
# Format the first 3 periods for display
forecasts = []
for period in periods[:3]:
forecast_text = f"""
{period.get('name', 'Unknown Period')}:
Temperature: {period.get('temperature', 'Unknown')}°{period.get('temperatureUnit', 'F')}
Wind: {period.get('windSpeed', 'Unknown')} {period.get('windDirection', '')}
Forecast: {period.get('detailedForecast', 'No detailed forecast available')}
"""
forecasts.append(forecast_text.strip())
location_info = f"Forecast for {latitude}, {longitude}:\n"
return location_info + "\n---\n".join(forecasts)
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get active weather alerts for a US state"""
# Validate state code format
if not state or len(state) != 2:
return "Error: Please provide a valid two-letter US state code (e.g., 'CA', 'NY', 'TX')"
state = state.upper()
url = f"{NWS_API_BASE}/alerts/active/area/{state}"
data = await make_nws_request(url)
if not data:
return f"Unable to fetch weather alerts for {state}. The service may be temporarily unavailable."
features = data.get("features", [])
if not features:
return f"No active weather alerts for {state}."
# Format alerts for display
alerts = []
for feature in features:
props = feature.get("properties", {})
event = props.get('event', 'Unknown Event')
area = props.get('areaDesc', 'Unknown Area')
severity = props.get('severity', 'Unknown Severity')
description = props.get('description', 'No description available')
alert_text = f"""
Event: {event}
Area: {area}
Severity: {severity}
Description: {description[:200]}{'...' if len(description) > 200 else ''}
"""
alerts.append(alert_text.strip())
alert_count = len(alerts)
header = f"Found {alert_count} active weather alert{'s' if alert_count != 1 else ''} for {state}:\n"
return header + "\n---\n".join(alerts)
# Resources for contextual information
@mcp.resource("weather://stations/{state}")
async def get_weather_stations(state: str) -> str:
"""Get information about weather observation stations in a state"""
if not state or len(state) != 2:
return "Error: Please provide a valid two-letter US state code"
state = state.upper()
url = f"{NWS_API_BASE}/stations?state={state}"
data = await make_nws_request(url)
if not data:
return f"Unable to fetch weather station information for {state}"
features = data.get("features", [])
if not features:
return f"No weather stations found for {state}"
stations = []
for feature in features[:10]: # Limit to first 10 stations
props = feature.get("properties", {})
name = props.get("name", "Unknown Station")
identifier = props.get("stationIdentifier", "Unknown ID")
elevation = props.get("elevation", {}).get("value", "Unknown")
stations.append(f"- {name} ({identifier}) - Elevation: {elevation}m")
station_count = len(features)
header = f"Weather stations in {state} (showing first 10 of {station_count}):\n"
return header + "\n".join(stations)
if __name__ == "__main__":
mcp.run(transport='stdio')
No MCP Inspector, você deve ver agora tanto ferramentas quanto resources. Os resources aparecem em uma seção separada e fornecem informações contextuais que as aplicações de IA podem usar para entender melhor os dados meteorológicos.
Testando o seu servidor com o MCP Inspector
Antes de integrar o seu servidor com assistentes de IA como o Claude Desktop, é essencial testá-lo minuciosamente usando o MCP Inspector. O Inspector oferece uma interface baseada na web para testar servidores MCP, permitindo verificar se todas as ferramentas e resources funcionam corretamente.
Iniciando o MCP Inspector
Para testar o seu servidor de meteorologia com o MCP Inspector, execute o seguinte comando a partir do diretório do seu projeto:
# Make sure you're in your project directory and virtual environment is activated
cd weather-mcp-server
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Start the MCP Inspector with your server
python -m mcp dev weather_server.py
Este comando irá:
- Iniciar o seu servidor de meteorologia em modo de desenvolvimento
- Abrir a interface web do MCP Inspector
- Conectar automaticamente o Inspector ao seu servidor
Você deve ver uma saída semelhante a:
Starting MCP Inspector...
Server running at: http://localhost:3000
MCP server connected successfully
Usando a interface do MCP Inspector
Abra o seu navegador web e acesse http://localhost:3000. A interface do MCP Inspector oferece várias seções para testar o seu servidor:
Painel de Informações do Servidor: Mostra o nome, a versão e o status de conexão do seu servidor. Você deve ver "weather-server" listado como conectado.
Seção de Tools: Lista todas as ferramentas disponíveis com suas descrições e esquemas de parâmetros. Para o seu servidor de meteorologia, você deve ver:
get_forecast- Obtém a previsão do tempo para coordenadasget_alerts- Obtém alertas meteorológicos ativos para um estado dos EUAanalyze_weather_trends- Análise meteorológica assistida por IA (se você tiver implementado o Passo 6)
Seção de Resources: Mostra os resources disponíveis que fornecem informações contextuais:
weather://stations/{state}- Informações de estações meteorológicas por estado
Testando as suas ferramentas
Vamos testar cada ferramenta sistematicamente:
Testando a ferramenta de Previsão:
- Clique na ferramenta
get_forecastno Inspector - Insira coordenadas de teste:
- Latitude:
40.7128(Nova York) - Longitude:
-74.0060
- Latitude:
- Clique em "Execute Tool"
- Verifique se você recebe uma previsão do tempo formatada corretamente, com temperatura, vento e informações detalhadas da previsão
Testando a ferramenta de Alertas:
- Clique na ferramenta
get_alerts - Insira o código de um estado:
CA(Califórnia) - Clique em "Execute Tool"
- Verifique se você recebe alertas ativos ou uma mensagem de "No active alerts"
Testando a validação de entrada:
- Tente coordenadas inválidas (por exemplo, latitude:
100, longitude:200) - Tente códigos de estado inválidos (por exemplo,
XYZouCalifornia) - Verifique se o seu servidor retorna mensagens de erro apropriadas
Testando os resources
Testando o Resource de Estações Meteorológicas:
- Navegue até a seção de Resources
- Procure pelo resource
weather://stations/{state} - Clique nele e insira um código de estado como
TX - Verifique se você recebe uma lista de estações meteorológicas com nomes, identificadores e elevações
Monitorando os logs do servidor
Durante os testes, fique de olho no terminal onde você iniciou o Inspector. Você deve ver mensagens de log mostrando:
- Requisições bem-sucedidas à API do National Weather Service
- Quaisquer mensagens de erro ou avisos
- Confirmações de execução de ferramentas
Exemplo de saída de log:
INFO: Tool 'get_forecast' called with params: {'latitude': 40.7128, 'longitude': -74.0060}
INFO: API request successful: https://api.weather.gov/points/40.7128,-74.0060
INFO: Forecast data retrieved successfully
Solucionando problemas comuns
Se você encontrar problemas durante os testes:
O servidor não inicia:
- Verifique se todas as dependências estão instaladas:
pip install -r requirements.txt - Confirme se o seu ambiente virtual está ativado
- Procure por erros de sintaxe no seu código
As ferramentas retornam erros:
- Verifique a sua conexão com a internet (o servidor precisa acessar weather.gov)
- Confirme se a API do National Weather Service está acessível
- Revise as mensagens de erro nos logs do servidor
Nenhum dado é retornado:
- Tente coordenadas diferentes (certifique-se de que estão dentro dos EUA)
- Verifique se os códigos de estado são abreviações válidas de duas letras
- Confirme se as respostas da API não estão sendo bloqueadas por firewalls
Validando o formato da saída
Certifique-se de que as saídas das suas ferramentas estejam formatadas corretamente:
- As previsões do tempo devem ser legíveis por humanos
- As informações de alerta devem incluir todos os detalhes relevantes
- As mensagens de erro devem ser claras e acionáveis
- Todas as respostas devem ser strings válidas (serializáveis em JSON)
Depois de testar minuciosamente o seu servidor com o MCP Inspector e confirmar que todas as ferramentas e resources funcionam corretamente, você está pronto para integrá-lo a assistentes de IA como o Claude Desktop.
Registrando o seu servidor no Claude Desktop
Agora que você tem um servidor MCP funcionando, vamos configurá-lo para funcionar com o Claude Desktop. Isso envolve editar o arquivo de configuração do Claude Desktop para registrar o seu servidor.
Localizando o arquivo de configuração
O arquivo de configuração do Claude Desktop está localizado em caminhos diferentes dependendo do seu sistema operacional:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Windows:
%APPDATA%\Claude\claude_desktop_config.json
Linux:
~/.config/Claude/claude_desktop_config.json
Configurando o seu servidor
Crie ou edite o arquivo de configuração para incluir o seu servidor de meteorologia. Aqui está a configuração básica:
{
"mcpServers": {
"weather-server": {
"command": "python",
"args": ["weather_server.py"],
"cwd": "/path/to/your/weather-mcp-server"
}
}
}
Substitua /path/to/your/weather-mcp-server pelo caminho real do diretório do seu projeto.
Configuração alternativa usando o ambiente virtual
Se você quiser usar explicitamente o interpretador Python do seu ambiente virtual:
{
"mcpServers": {
"weather-server": {
"command": "/path/to/your/weather-mcp-server/.venv/bin/python",
"args": ["weather_server.py"],
"cwd": "/path/to/your/weather-mcp-server"
}
}
}
No Windows, o caminho seria:
{
"mcpServers": {
"weather-server": {
"command": "C:\\path\\to\\your\\weather-mcp-server\\.venv\\Scripts\\python.exe",
"args": ["weather_server.py"],
"cwd": "C:\\path\\to\\your\\weather-mcp-server"
}
}
}
Testando a integração
- Salve o arquivo de configuração
- Reinicie o Claude Desktop completamente (feche e reabra)
- Inicie uma nova conversa
- Tente pedir ao Claude para obter informações meteorológicas de uma localização
Você deve ver o Claude usando as suas ferramentas de meteorologia para fornecer informações do tempo em tempo real!
Solucionando problemas de integração com o Claude Desktop
Se o seu servidor não aparecer no Claude Desktop:
- Verifique a sintaxe do arquivo de configuração - Use um validador de JSON para garantir a formatação correta
- Confira os caminhos dos arquivos - Certifique-se de que todos os caminhos na configuração são absolutos e corretos
- Verifique as permissões - Garanta que o Claude Desktop possa executar o seu ambiente Python
- Revise os logs - O Claude Desktop pode exibir mensagens de erro em sua interface
- Teste com o MCP Inspector primeiro - Sempre verifique se o seu servidor funciona com o Inspector antes de configurar o Claude Desktop
Adicionando recursos avançados
Agora vamos adicionar alguns recursos avançados para tornar nosso servidor mais poderoso e pronto para produção.
Passo 6: Adicionar MCP Sampling
O MCP sampling permite que o seu servidor solicite completions de IA ao client, viabilizando análises inteligentes de dados meteorológicos:
"""
Step 6: Add MCP sampling
"""
import sys
import httpx
from mcp.server.fastmcp import FastMCP, Context
from mcp.server.session import ServerSession
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception as e:
print(f"API request failed: {e}", file=sys.stderr)
return None
# Previous tools (get_forecast, get_alerts) - same as Step 5
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a specific location using coordinates"""
# [Previous implementation from Step 5]
# ... (keeping this concise for the tutorial)
pass
@mcp.tool()
async def get_alerts(state: str) -> str:
"""Get active weather alerts for a US state"""
# [Previous implementation from Step 5]
# ... (keeping this concise for the tutorial)
pass
# New AI-powered tool using sampling
@mcp.tool()
async def analyze_weather_trends(
state: str,
ctx: Context[ServerSession, None]
) -> str:
"""Analyze weather alert trends for a state using AI-powered analysis"""
# First, gather current weather alert data
alerts_data = await get_alerts(state)
if "No active weather alerts" in alerts_data or "Error:" in alerts_data:
return f"No weather alerts available for analysis in {state}"
# Use sampling to analyze the weather data
analysis_prompt = f"""
Analyze the following weather alert data for {state} and provide insights about:
1. The types of weather events currently affecting the region
2. The severity and geographic distribution of alerts
3. Potential impacts on daily activities and safety
4. Any notable patterns or unusual weather conditions
Weather Alert Data:
{alerts_data}
Provide a concise but comprehensive analysis that would be helpful for emergency management and public safety planning.
"""
try:
# Request AI analysis through sampling
response = await ctx.request_sampling(
messages=[{
"role": "user",
"content": {
"type": "text",
"text": analysis_prompt
}
}],
modelPreferences={
"intelligencePriority": 0.8, # High intelligence for analysis
"speedPriority": 0.4, # Moderate speed requirement
"costPriority": 0.3 # Cost is less important for analysis
},
systemPrompt="You are a meteorological analyst with expertise in weather pattern analysis and emergency management.",
maxTokens=500
)
return f"Weather Trend Analysis for {state}:\n\n{response.content.text}"
except Exception as e:
return f"Unable to generate weather analysis: {str(e)}"
if __name__ == "__main__":
mcp.run(transport='stdio')
Passo 7: Adicionar autenticação para deploy em produção
Para deploys em produção, você vai querer adicionar autenticação. Veja como adicionar autenticação básica por bearer token:
"""
Step 7: Add authentication for production deployment
"""
import os
import sys
import httpx
import jwt
from datetime import datetime
from mcp.server.fastmcp import FastMCP, Context
from mcp.server.session import ServerSession
mcp = FastMCP("weather-server")
# Configuration
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-mcp-server/1.0"
JWT_SECRET = os.getenv("JWT_SECRET", "your-secret-key")
class AuthenticationError(Exception):
"""Custom exception for authentication failures"""
pass
def verify_bearer_token(token: str) -> dict:
"""Verify and decode a JWT bearer token"""
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
# Check token expiration
if datetime.utcnow().timestamp() > payload.get("exp", 0):
raise AuthenticationError("Token has expired")
return payload
except jwt.InvalidTokenError as e:
raise AuthenticationError(f"Invalid token: {str(e)}")
def require_authentication(func):
"""Decorator for tools that require authentication"""
async def wrapper(*args, **kwargs):
# In a real implementation, you'd extract the auth header from the request context
# For this tutorial, we'll simulate authentication
# Check if running in authenticated mode
if os.getenv("REQUIRE_AUTH", "false").lower() == "true":
# In production, extract token from request headers
token = os.getenv("AUTH_TOKEN")
if not token:
return "Authentication required: Please provide a valid bearer token"
try:
user_context = verify_bearer_token(token)
kwargs['user_context'] = user_context
except AuthenticationError as e:
return f"Authentication failed: {str(e)}"
return await func(*args, **kwargs)
return wrapper
# Previous API helper function
async def make_nws_request(url: str) -> dict | None:
"""Make a request to the National Weather Service API with proper error handling"""
headers = {
"User-Agent": USER_AGENT,
"Accept": "application/geo+json"
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
response.raise_for_status()
return response.json()
except Exception as e:
print(f"API request failed: {e}", file=sys.stderr)
return None
# Authenticated tools
@mcp.tool()
@require_authentication
async def get_secure_forecast(
latitude: float,
longitude: float,
user_context: dict = None
) -> str:
"""Get weather forecast with authentication and audit logging"""
user_id = user_context.get("sub", "unknown") if user_context else "anonymous"
print(f"Forecast request from user {user_id} for {latitude}, {longitude}", file=sys.stderr)
# Use the same forecast logic as before
# [Implementation details omitted for brevity]
return f"Authenticated forecast for {latitude}, {longitude} (User: {user_id})"
if __name__ == "__main__":
# Determine transport based on environment
transport = os.getenv("MCP_TRANSPORT", "stdio")
if transport == "http":
# Production HTTP deployment with authentication
port = int(os.getenv("PORT", 8000))
host = os.getenv("HOST", "0.0.0.0")
print(f"Starting secure MCP server on {host}:{port}", file=sys.stderr)
mcp.run(transport="http", host=host, port=port)
else:
# Development STDIO deployment
print("Starting MCP server in STDIO mode", file=sys.stderr)
mcp.run(transport="stdio")
Considerações para deploy em produção
Ao fazer o deploy do seu servidor MCP em produção, considere estes fatores importantes:
Configuração de ambiente
Use variáveis de ambiente para a configuração:
# .env file for production
MCP_TRANSPORT=http
HOST=0.0.0.0
PORT=8000
REQUIRE_AUTH=true
JWT_SECRET=your-production-secret-key
NWS_API_USER_AGENT=your-production-app/1.0
Deploy com Docker
Crie um Dockerfile para deploy em contêiner:
FROM python:3.11-slim
WORKDIR /app
# Copy requirements and install dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy project files
COPY weather_server.py ./
# Expose port
EXPOSE 8000
# Run the server
CMD ["python", "weather_server.py"]
Construa e execute o contêiner Docker:
# Build the image
docker build -t weather-mcp-server .
# Run the container
docker run -p 8000:8000 -e MCP_TRANSPORT=http weather-mcp-server
Monitoramento e logging
Implemente logging adequado para produção:
import logging
import sys
# Configure logging for production
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/mcp-server.log'),
logging.StreamHandler(sys.stderr)
]
)
logger = logging.getLogger(__name__)
# Use logger throughout your application
logger.info("Server starting up")
logger.error("API request failed", exc_info=True)
Solucionando problemas comuns
Problemas de logging no STDIO
O problema mais comum é escrever no stdout em servidores STDIO:
# Wrong - breaks the protocol
print("Debug message")
# Correct - use stderr
print("Debug message", file=sys.stderr)
# Better - use logging
import logging
logging.basicConfig(stream=sys.stderr)
logger = logging.getLogger(__name__)
logger.info("Debug message")
Erros de serialização de JSON
Garanta que todos os valores de retorno das ferramentas sejam serializáveis em JSON:
# Wrong - returns complex object
@mcp.tool()
def bad_tool():
return SomeComplexObject()
# Correct - returns string
@mcp.tool()
def good_tool():
result = SomeComplexObject()
return str(result) # or result.to_dict() if available
Problemas de autenticação
Para servidores HTTP, verifique a sua configuração de autenticação:
# Debug authentication setup
def debug_auth():
required_vars = ["JWT_SECRET", "AUTH_TOKEN"]
for var in required_vars:
if not os.getenv(var):
print(f"Missing environment variable: {var}", file=sys.stderr)
Próximos passos e tópicos avançados
Com o seu servidor MCP de meteorologia completo, você está pronto para explorar padrões mais avançados:
Estendendo o seu servidor
Considere adicionar estes recursos:
- Dados meteorológicos históricos de APIs adicionais
- Integração com mapas meteorológicos usando resources de imagem
- Alertas em tempo real usando conexões WebSocket
- Previsões com machine learning usando sampling para análise
Padrões arquiteturais avançados
Explore estes padrões para deploys complexos:
- Arquiteturas com múltiplos servidores com domínios especializados
- Composição de servidores combinando múltiplos servidores MCP
- Deploys distribuídos entre regiões de nuvem
- Integração de microsserviços com sistemas existentes
Referências
[1] Introdução da Anthropic ao Model Context Protocol
[2] Documentação do Model Context Protocol
[3] Model Context Protocol Python SDK
[4] Guia oficial de construção de servidores MCP
[5] Visão geral da arquitetura do MCP
Teste seu servidor MCP no navegador
Cole a URL de um servidor MCP e veja todas as ferramentas, recursos e prompts expostos, com esquemas completos e o log de requisições. Grátis, sem instalação e sem cadastro.