Files
oci_tips/GenAI/mcp/sample1/mcp_server.py
2025-12-03 11:05:21 -03:00

254 lines
8.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Servidor MCP com ferramentas matemáticas: soma, subtração, multiplicação e divisão.
Inclui tratamento de erros e validações.
"""
import asyncio
import json
from mcp.server import Server
from mcp.types import Tool, TextContent
from mcp.server.stdio import stdio_server
# Criar instância do servidor MCP
app = Server("math-tools-server")
@app.list_tools()
async def list_tools() -> list[Tool]:
"""Lista as ferramentas disponíveis no servidor."""
return [
Tool(
name="soma",
description="Realiza a soma de dois números inteiros",
inputSchema={
"type": "object",
"properties": {
"numero1": {
"type": "integer",
"description": "Primeiro número inteiro"
},
"numero2": {
"type": "integer",
"description": "Segundo número inteiro"
}
},
"required": ["numero1", "numero2"]
}
),
Tool(
name="subtracao",
description="Realiza a subtração de dois números inteiros (numero1 - numero2)",
inputSchema={
"type": "object",
"properties": {
"numero1": {
"type": "integer",
"description": "Primeiro número inteiro (minuendo)"
},
"numero2": {
"type": "integer",
"description": "Segundo número inteiro (subtraendo)"
}
},
"required": ["numero1", "numero2"]
}
),
Tool(
name="multiplicacao",
description="Realiza a multiplicação de dois números inteiros",
inputSchema={
"type": "object",
"properties": {
"numero1": {
"type": "integer",
"description": "Primeiro número inteiro"
},
"numero2": {
"type": "integer",
"description": "Segundo número inteiro"
}
},
"required": ["numero1", "numero2"]
}
),
Tool(
name="divisao",
description="Realiza a divisão de dois números inteiros (numero1 / numero2). Retorna resultado como float.",
inputSchema={
"type": "object",
"properties": {
"numero1": {
"type": "integer",
"description": "Primeiro número inteiro (dividendo)"
},
"numero2": {
"type": "integer",
"description": "Segundo número inteiro (divisor)"
}
},
"required": ["numero1", "numero2"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
"""Executa a ferramenta solicitada com tratamento de erros."""
# Validar argumentos comuns
numero1 = arguments.get("numero1")
numero2 = arguments.get("numero2")
if numero1 is None or numero2 is None:
return [TextContent(
type="text",
text=json.dumps({
"error": "Ambos os números são obrigatórios",
"operacao": name
})
)]
# Validar tipos
if not isinstance(numero1, int) or not isinstance(numero2, int):
return [TextContent(
type="text",
text=json.dumps({
"error": "Os números devem ser inteiros",
"operacao": name,
"numero1_tipo": type(numero1).__name__,
"numero2_tipo": type(numero2).__name__
})
)]
# Executar operação específica
if name == "soma":
try:
resultado = numero1 + numero2
return [TextContent(
type="text",
text=json.dumps({
"operacao": "soma",
"numero1": numero1,
"numero2": numero2,
"resultado": resultado,
"expressao": f"{numero1} + {numero2} = {resultado}"
})
)]
except Exception as e:
return [TextContent(
type="text",
text=json.dumps({
"error": f"Erro ao executar soma: {str(e)}",
"operacao": "soma"
})
)]
elif name == "subtracao":
try:
resultado = numero1 - numero2
return [TextContent(
type="text",
text=json.dumps({
"operacao": "subtracao",
"numero1": numero1,
"numero2": numero2,
"resultado": resultado,
"expressao": f"{numero1} - {numero2} = {resultado}"
})
)]
except Exception as e:
return [TextContent(
type="text",
text=json.dumps({
"error": f"Erro ao executar subtração: {str(e)}",
"operacao": "subtracao"
})
)]
elif name == "multiplicacao":
try:
resultado = numero1 * numero2
return [TextContent(
type="text",
text=json.dumps({
"operacao": "multiplicacao",
"numero1": numero1,
"numero2": numero2,
"resultado": resultado,
"expressao": f"{numero1} × {numero2} = {resultado}"
})
)]
except Exception as e:
return [TextContent(
type="text",
text=json.dumps({
"error": f"Erro ao executar multiplicação: {str(e)}",
"operacao": "multiplicacao"
})
)]
elif name == "divisao":
# Validação específica: divisão por zero
if numero2 == 0:
return [TextContent(
type="text",
text=json.dumps({
"error": "Divisão por zero não é permitida",
"operacao": "divisao",
"numero1": numero1,
"numero2": numero2
})
)]
try:
resultado = numero1 / numero2
return [TextContent(
type="text",
text=json.dumps({
"operacao": "divisao",
"numero1": numero1,
"numero2": numero2,
"resultado": resultado,
"resultado_inteiro": numero1 // numero2,
"resto": numero1 % numero2,
"expressao": f"{numero1} ÷ {numero2} = {resultado}"
})
)]
except Exception as e:
return [TextContent(
type="text",
text=json.dumps({
"error": f"Erro ao executar divisão: {str(e)}",
"operacao": "divisao"
})
)]
else:
# Operação não implementada
return [TextContent(
type="text",
text=json.dumps({
"error": f"Operação '{name}' não está implementada",
"operacao_solicitada": name,
"operacoes_disponiveis": ["soma", "subtracao", "multiplicacao", "divisao"],
"mensagem": "Por favor, utilize uma das operações disponíveis: soma, subtração, multiplicação ou divisão"
})
)]
async def main():
"""Inicia o servidor MCP via stdio."""
async with stdio_server() as (read_stream, write_stream):
await app.run(
read_stream,
write_stream,
app.create_initialization_options()
)
if __name__ == "__main__":
asyncio.run(main())