From cbf0796e2efaed6d3e0a52c3588405fa3e2b276c Mon Sep 17 00:00:00 2001 From: Marcos Lohmann Date: Wed, 3 Dec 2025 11:05:21 -0300 Subject: [PATCH] Add files via upload --- GenAI/mcp/sample1/QUICKSTART.md | 202 ++++++++++++ GenAI/mcp/sample1/README.md | 473 ++++++++++++++++++++++++++++- GenAI/mcp/sample1/mcp_client.py | 294 ++++++++++++++++++ GenAI/mcp/sample1/mcp_server.py | 253 +++++++++++++++ GenAI/mcp/sample1/requirements.txt | 2 + GenAI/mcp/sample1/run.sh | 29 ++ GenAI/mcp/sample1/test_system.py | 97 ++++++ 7 files changed, 1349 insertions(+), 1 deletion(-) create mode 100644 GenAI/mcp/sample1/QUICKSTART.md create mode 100644 GenAI/mcp/sample1/mcp_client.py create mode 100644 GenAI/mcp/sample1/mcp_server.py create mode 100644 GenAI/mcp/sample1/requirements.txt create mode 100644 GenAI/mcp/sample1/run.sh create mode 100644 GenAI/mcp/sample1/test_system.py diff --git a/GenAI/mcp/sample1/QUICKSTART.md b/GenAI/mcp/sample1/QUICKSTART.md new file mode 100644 index 0000000..553c0cd --- /dev/null +++ b/GenAI/mcp/sample1/QUICKSTART.md @@ -0,0 +1,202 @@ +# Guia Rápido - Sistema MCP com Calculadora Inteligente + +## 🚀 Início Rápido (3 passos) + +### 1. Criar Ambiente Virtual + +```bash +cd mcp_project +python3.11 -m venv venv +``` + +### 2. Instalar Dependências + +```bash +source venv/bin/activate +pip install -r requirements.txt +``` + +### 3. Executar o Sistema + +**Opção A - Script automatizado:** +```bash +./run.sh +``` + +**Opção B - Comando direto:** +```bash +source venv/bin/activate +python mcp_client.py +``` + +## 💬 Como Usar + +O sistema **interpreta automaticamente** qual operação você deseja realizar através de linguagem natural! + +### Exemplos de Perguntas + +#### Soma +- "Quanto é 15 mais 7?" +- "Some 25 com 13" +- "Eu tenho 30 maçãs e ganhei mais 12, quantas tenho?" + +#### Subtração +- "Subtraia 5 de 20" +- "Quanto é 50 menos 18?" +- "Se eu tinha 100 reais e gastei 35, quanto sobrou?" + +#### Multiplicação +- "Multiplique 8 por 6" +- "Quanto é 7 vezes 9?" +- "Calcule 12 multiplicado por 5" + +#### Divisão +- "Divida 100 por 4" +- "Quanto é 50 dividido por 2?" +- "Calcule 144 dividido por 12" + +## 🎯 Funcionalidades + +✅ **4 Operações**: soma, subtração, multiplicação, divisão +✅ **Linguagem Natural**: Entende perguntas conversacionais +✅ **Tratamento de Erros**: Detecta divisão por zero +✅ **Operações Não Implementadas**: Informa quando algo não está disponível + +## 🧪 Testar o Sistema + +Execute o teste automatizado para ver todas as funcionalidades: + +```bash +source venv/bin/activate +python test_system.py +``` + +O teste valida: +- ✓ Soma +- ✓ Subtração +- ✓ Multiplicação +- ✓ Divisão +- ✓ Erro de divisão por zero +- ✓ Operação não implementada +- ✓ Interpretação de linguagem natural + +## 📋 Exemplo de Interação Completa + +``` +============================================================ + Chat com AI Agent - Operações Matemáticas +============================================================ + +✓ Conectado ao servidor MCP +✓ Ferramentas disponíveis: ['soma', 'subtracao', 'multiplicacao', 'divisao'] + +💬 Iniciando conversa com o assistente... +------------------------------------------------------------ + +👤 Você: Eu tenho 25 maçãs e ganhei mais 13, quantas tenho agora? + +🔧 Executando ferramenta: soma + Argumentos: {'numero1': 25, 'numero2': 13} + ✓ Resultado: 38 + +🤖 Assistente: Você tinha 25 maçãs e ganhou mais 13, então agora tem +38 maçãs no total! + +------------------------------------------------------------ + +👤 Você: Divida 100 por 4 + +🔧 Executando ferramenta: divisao + Argumentos: {'numero1': 100, 'numero2': 4} + ✓ Resultado: 25.0 + +🤖 Assistente: 100 dividido por 4 é igual a 25! + +------------------------------------------------------------ + +👤 Você: Divida 10 por 0 + +🔧 Executando ferramenta: divisao + Argumentos: {'numero1': 10, 'numero2': 0} + ⚠️ Erro: Divisão por zero não é permitida + +🤖 Assistente: Dividir por zero é uma operação matematicamente +indefinida. Não posso fazer isso, mas posso ajudar com outras contas! + +------------------------------------------------------------ + +👤 Você: Calcule 5 elevado ao quadrado + +🤖 Assistente: Desculpe, mas eu só consigo fazer as operações básicas: +soma, subtração, multiplicação e divisão. Se quiser fazer 5 vezes 5, +posso ajudar! +``` + +## 🛠️ Comandos Úteis + +### Ativar ambiente virtual +```bash +source venv/bin/activate +``` + +### Desativar ambiente virtual +```bash +deactivate +``` + +### Reinstalar dependências +```bash +pip install -r requirements.txt --force-reinstall +``` + +### Verificar instalação +```bash +pip list | grep -E "mcp|openai" +``` + +### Executar testes +```bash +python test_system.py +``` + +## ❓ Problemas Comuns + +### "Command not found: python3.11" +Use `python3` ou `python` dependendo da sua instalação. + +### "Permission denied: ./run.sh" +Execute: `chmod +x run.sh` + +### "Module not found: mcp" +Certifique-se de ativar o ambiente virtual: `source venv/bin/activate` + +### "Divisão por zero" +Este é um erro esperado e tratado. O assistente informará que não é possível. + +### "Operação não implementada" +O sistema suporta apenas 4 operações básicas. O assistente informará as limitações. + +## 🎓 Dicas de Uso + +1. **Seja Natural**: Fale como você falaria com uma pessoa +2. **Contexto**: Pode usar contexto ("Eu tinha X e ganhei Y") +3. **Variações**: Teste diferentes formas de perguntar +4. **Erros**: O sistema trata erros educadamente +5. **Limitações**: Apenas 4 operações básicas estão disponíveis + +## 📚 Documentação Completa + +Para mais detalhes sobre arquitetura, API e extensões, consulte [README.md](README.md) + +## 🔑 Operações Disponíveis + +| Operação | Exemplos de Perguntas | +|----------|----------------------| +| **Soma** | "15 mais 7", "Some 10 com 5", "Quanto é 3 + 8?" | +| **Subtração** | "20 menos 5", "Subtraia 7 de 15", "Quanto é 30 - 12?" | +| **Multiplicação** | "8 vezes 6", "Multiplique 5 por 9", "Quanto é 7 × 4?" | +| **Divisão** | "100 dividido por 4", "Divida 50 por 2", "Quanto é 81 ÷ 9?" | + +--- + +**Sistema pronto para uso! Divirta-se calculando! 🧮✨** diff --git a/GenAI/mcp/sample1/README.md b/GenAI/mcp/sample1/README.md index 8bcf698..05d7139 100644 --- a/GenAI/mcp/sample1/README.md +++ b/GenAI/mcp/sample1/README.md @@ -1 +1,472 @@ -# exemplo de servidor e cliente MCP +# Sistema MCP com AI Agent - Calculadora Inteligente + +Este projeto implementa um **servidor MCP (Model Context Protocol)** e um **cliente MCP** em Python que utiliza um LLM para interpretar operações matemáticas solicitadas pelo usuário em linguagem natural e executá-las através de tool calls. + +## 📋 Visão Geral + +O sistema é composto por três componentes principais: + +1. **Servidor MCP** (`mcp_server.py`): Expõe 4 ferramentas matemáticas (soma, subtração, multiplicação e divisão) através do protocolo MCP +2. **Cliente MCP** (`mcp_client.py`): Interface de chat que conecta o usuário ao LLM e ao servidor MCP +3. **Script de Teste** (`test_system.py`): Testa automaticamente todas as operações e casos de erro + +## 🎯 Funcionalidades Principais + +### ✨ Interpretação Inteligente de Operações + +O agente **interpreta automaticamente** qual operação matemática o usuário deseja realizar através de linguagem natural: + +- **"Quanto é 15 mais 7?"** → Executa soma +- **"Subtraia 5 de 20"** → Executa subtração +- **"Multiplique 8 por 6"** → Executa multiplicação +- **"Divida 100 por 4"** → Executa divisão +- **"Eu tenho 25 maçãs e ganhei mais 13"** → Interpreta como soma e calcula + +### 🛡️ Tratamento Robusto de Erros + +- **Divisão por zero**: Detectada e tratada com mensagem educada +- **Operações não implementadas**: Informa que apenas as 4 operações básicas estão disponíveis +- **Validação de tipos**: Garante que os números sejam inteiros +- **Parâmetros faltantes**: Verifica se ambos os números foram fornecidos + +### 🧮 4 Operações Matemáticas + +1. **Soma** (`soma`): Adição de dois números inteiros +2. **Subtração** (`subtracao`): Subtração de dois números inteiros +3. **Multiplicação** (`multiplicacao`): Multiplicação de dois números inteiros +4. **Divisão** (`divisao`): Divisão de dois números (retorna float) + +## 🏗️ Arquitetura + +``` +┌─────────────┐ ┌──────────────────┐ ┌──────────────┐ +│ Usuário │ ◄─────► │ Cliente MCP │ ◄─────► │ Servidor MCP │ +│ │ Chat │ + LLM │ stdio │ (4 Tools) │ +│ │ │ (Interpretação) │ │ │ +└─────────────┘ └──────────────────┘ └──────────────┘ + │ + ▼ + ┌──────────────┐ + │ LLM API │ + │ (Grok Code) │ + └──────────────┘ +``` + +### Fluxo de Execução + +1. **Usuário** envia mensagem em linguagem natural (ex: "Quanto é 15 mais 7?") +2. **Cliente MCP** envia mensagem para o LLM +3. **LLM** interpreta a operação desejada e identifica os números +4. **LLM** faz tool call para a ferramenta apropriada (ex: `soma`) +5. **Cliente MCP** executa a ferramenta no **Servidor MCP** +6. **Servidor MCP** valida parâmetros e retorna resultado ou erro +7. **Cliente MCP** envia resultado de volta ao LLM +8. **LLM** gera resposta generativa e amigável +9. **Usuário** recebe resposta final + +## 🔧 Tecnologias Utilizadas + +- **Python 3.11**: Linguagem de programação +- **MCP (Model Context Protocol)**: Protocolo para comunicação entre cliente e servidor +- **OpenAI SDK**: Cliente para comunicação com LLM compatível com API OpenAI +- **LLM**: Grok Code via API compatível com OpenAI +- **asyncio**: Programação assíncrona + +## 📦 Estrutura do Projeto + +``` +mcp_project/ +├── venv/ # Ambiente virtual Python +├── mcp_server.py # Servidor MCP com 4 ferramentas matemáticas +├── mcp_client.py # Cliente MCP com interpretação inteligente +├── test_system.py # Script de teste automatizado completo +├── requirements.txt # Dependências do projeto +├── run.sh # Script de inicialização rápida +├── README.md # Esta documentação +└── QUICKSTART.md # Guia rápido de início +``` + +## 🚀 Instalação + +### 1. Criar Ambiente Virtual + +```bash +cd mcp_project +python3.11 -m venv venv +source venv/bin/activate +``` + +### 2. Instalar Dependências + +```bash +pip install -r requirements.txt +``` + +## 💻 Uso + +### Modo Interativo (Chat com Usuário) + +Execute o cliente MCP para iniciar uma sessão de chat interativa: + +```bash +source venv/bin/activate +python mcp_client.py +``` + +Ou use o script de inicialização rápida: + +```bash +./run.sh +``` + +### Exemplos de Interação + +#### Exemplo 1: Soma em Linguagem Natural + +``` +👤 Você: Eu tenho 25 maçãs e ganhei mais 13, quantas tenho agora? + +🔧 Executando ferramenta: soma + Argumentos: {'numero1': 25, 'numero2': 13} + ✓ Resultado: 38 + +🤖 Assistente: Você tinha 25 maçãs e ganhou mais 13, então agora tem 38 maçãs no total! +``` + +#### Exemplo 2: Divisão + +``` +👤 Você: Divida 100 por 4 + +🔧 Executando ferramenta: divisao + Argumentos: {'numero1': 100, 'numero2': 4} + ✓ Resultado: 25.0 + +🤖 Assistente: 100 dividido por 4 é igual a 25! +``` + +#### Exemplo 3: Erro - Divisão por Zero + +``` +👤 Você: Divida 10 por 0 + +🔧 Executando ferramenta: divisao + Argumentos: {'numero1': 10, 'numero2': 0} + ⚠️ Erro: Divisão por zero não é permitida + +🤖 Assistente: Dividir 10 por 0 é uma operação matematicamente indefinida. +Não posso fazer isso. Mas posso ajudar com outras contas válidas! +``` + +#### Exemplo 4: Operação Não Implementada + +``` +👤 Você: Calcule 5 elevado ao quadrado + +🤖 Assistente: Desculpe, mas eu só consigo fazer as operações básicas: +soma, subtração, multiplicação e divisão. Potências não estão disponíveis. +Se quiser fazer 5 vezes 5, posso ajudar! +``` + +### Modo Teste Automatizado + +Execute o script de teste para validar todas as operações: + +```bash +source venv/bin/activate +python test_system.py +``` + +O teste valida: +- ✅ Soma +- ✅ Subtração +- ✅ Multiplicação +- ✅ Divisão +- ✅ Tratamento de erro (divisão por zero) +- ✅ Operação não implementada +- ✅ Interpretação de linguagem natural + +## 📝 Componentes Detalhados + +### 1. Servidor MCP (`mcp_server.py`) + +O servidor MCP expõe quatro ferramentas matemáticas com validação completa: + +#### Ferramenta: `soma` + +Realiza a soma de dois números inteiros. + +**Parâmetros:** +- `numero1` (integer): Primeiro número +- `numero2` (integer): Segundo número + +**Retorno de Sucesso:** +```json +{ + "operacao": "soma", + "numero1": 15, + "numero2": 7, + "resultado": 22, + "expressao": "15 + 7 = 22" +} +``` + +#### Ferramenta: `subtracao` + +Realiza a subtração de dois números inteiros (numero1 - numero2). + +**Parâmetros:** +- `numero1` (integer): Minuendo +- `numero2` (integer): Subtraendo + +**Retorno de Sucesso:** +```json +{ + "operacao": "subtracao", + "numero1": 20, + "numero2": 5, + "resultado": 15, + "expressao": "20 - 5 = 15" +} +``` + +#### Ferramenta: `multiplicacao` + +Realiza a multiplicação de dois números inteiros. + +**Parâmetros:** +- `numero1` (integer): Primeiro número +- `numero2` (integer): Segundo número + +**Retorno de Sucesso:** +```json +{ + "operacao": "multiplicacao", + "numero1": 8, + "numero2": 6, + "resultado": 48, + "expressao": "8 × 6 = 48" +} +``` + +#### Ferramenta: `divisao` + +Realiza a divisão de dois números (numero1 / numero2). Retorna resultado como float. + +**Parâmetros:** +- `numero1` (integer): Dividendo +- `numero2` (integer): Divisor + +**Retorno de Sucesso:** +```json +{ + "operacao": "divisao", + "numero1": 100, + "numero2": 4, + "resultado": 25.0, + "resultado_inteiro": 25, + "resto": 0, + "expressao": "100 ÷ 4 = 25.0" +} +``` + +**Retorno de Erro (Divisão por Zero):** +```json +{ + "error": "Divisão por zero não é permitida", + "operacao": "divisao", + "numero1": 10, + "numero2": 0 +} +``` + +#### Tratamento de Operações Não Implementadas + +Se uma ferramenta não reconhecida for chamada: + +```json +{ + "error": "Operação 'potencia' não está implementada", + "operacao_solicitada": "potencia", + "operacoes_disponiveis": ["soma", "subtracao", "multiplicacao", "divisao"], + "mensagem": "Por favor, utilize uma das operações disponíveis..." +} +``` + +### 2. Cliente MCP (`mcp_client.py`) + +O cliente MCP integra três componentes principais: + +#### Conexão com Servidor MCP + +Estabelece comunicação via stdio com o servidor MCP e obtém lista de ferramentas disponíveis. + +#### Integração com LLM + +Utiliza a API do LLM (compatível com OpenAI) para: +- **Interpretar** a operação matemática desejada pelo usuário +- **Identificar** os números na conversa natural +- **Executar** tool calls apropriados +- **Gerar** respostas generativas e amigáveis + +**Configuração do LLM:** +- **URL Base**: `https://api.xptoai.com.br/genai/grokcode/v1` +- **Autenticação**: Bearer Token +- **Modelo**: `grok-2-1212` + +**Prompt do Sistema:** + +O cliente instrui o LLM a: +1. Interpretar qual operação matemática o usuário deseja +2. Identificar os dois números envolvidos +3. Chamar a ferramenta apropriada +4. Apresentar resultados de forma clara +5. Tratar erros educadamente +6. Informar sobre operações não disponíveis + +#### Loop de Chat + +Mantém histórico de conversação e gerencia o fluxo de mensagens entre usuário, LLM e servidor MCP. + +### 3. Script de Teste (`test_system.py`) + +Automatiza o teste do sistema com 8 casos de teste: + +1. **Soma**: "Quanto é 15 mais 7?" +2. **Subtração**: "Subtraia 5 de 20" +3. **Multiplicação**: "Multiplique 8 por 6" +4. **Divisão**: "Divida 100 por 4" +5. **Divisão por Zero**: "Divida 10 por 0" (erro esperado) +6. **Operação Não Implementada**: "Calcule 5 elevado ao quadrado" +7. **Linguagem Natural - Soma**: "Eu tenho 25 maçãs e ganhei mais 13..." +8. **Linguagem Natural - Subtração**: "Se eu tinha 50 reais e gastei 18..." + +## 🔐 Configuração de Segurança + +A chave de API está hardcoded no código para fins de demonstração. Em produção, recomenda-se: + +1. Usar variáveis de ambiente: +```python +import os +API_KEY = os.getenv("XPTOAI_API_KEY") +``` + +2. Usar arquivo `.env`: +```bash +echo "XPTOAI_API_KEY=sua_chave_aqui" > .env +``` + +3. Carregar com `python-dotenv`: +```python +from dotenv import load_dotenv +load_dotenv() +``` + +## 🧪 Testes + +### Teste Manual + +1. Execute o cliente: `python mcp_client.py` +2. Digite mensagens em linguagem natural +3. Teste diferentes operações +4. Teste casos de erro (divisão por zero) +5. Teste operações não implementadas + +### Teste Automatizado + +```bash +python test_system.py +``` + +Verifica automaticamente: +- ✅ Conexão com servidor MCP +- ✅ Listagem de 4 ferramentas +- ✅ Interpretação de operações +- ✅ Execução de todas as 4 operações +- ✅ Tratamento de divisão por zero +- ✅ Resposta para operações não implementadas +- ✅ Interpretação de linguagem natural + +## 🐛 Troubleshooting + +### Erro: "Permission denied" + +Se encontrar erros de permissão ao instalar pacotes: +```bash +# Use ambiente virtual +python3.11 -m venv venv +source venv/bin/activate +pip install -r requirements.txt +``` + +### Erro: "Connection refused" + +Verifique se o servidor MCP está sendo iniciado corretamente pelo cliente. + +### Erro: "API Key invalid" + +Verifique se a chave de API está correta em `mcp_client.py`: +```python +API_KEY = "biasb986lk657fsdv6d3543vs5b65s7v373sd321vsdv4sdv34bv3f4hb5f4j6mn546tu" +``` + +### Erro: "Model not found" + +Ajuste o nome do modelo em `mcp_client.py` se necessário: +```python +MODEL_NAME = "grok-2-1212" # Ajuste conforme disponível na API +``` + +### Erro: "Divisão por zero" + +Este é um erro esperado e tratado pelo sistema. O agente informará que a operação não é permitida. + +## 📚 Referências + +- [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) +- [OpenAI API Documentation](https://platform.openai.com/docs/api-reference) +- [Python asyncio](https://docs.python.org/3/library/asyncio.html) + +## 🤝 Extensões Futuras + +Sugestões para expandir o sistema: + +### Novas Operações +- Potenciação +- Raiz quadrada +- Módulo/resto +- Valor absoluto +- Arredondamento + +### Melhorias +- Suporte a números decimais (float) +- Histórico de cálculos +- Exportar resultados para arquivo +- Interface gráfica (GUI) +- API REST para integração + +### Testes +- Testes unitários com pytest +- Testes de integração +- Testes de carga +- Cobertura de código + +## 📄 Licença + +Este projeto é fornecido como exemplo educacional. + +## ✨ Características Principais + +- ✅ **Interpretação Inteligente**: LLM identifica automaticamente a operação desejada +- ✅ **Linguagem Natural**: Entende perguntas contextuais e conversacionais +- ✅ **4 Operações Básicas**: Soma, subtração, multiplicação e divisão +- ✅ **Tratamento de Erros**: Validação completa e mensagens educadas +- ✅ **Operações Não Implementadas**: Informa claramente as limitações +- ✅ **Protocolo MCP**: Comunicação padronizada entre componentes +- ✅ **Assíncrono**: Uso de asyncio para melhor performance +- ✅ **Extensível**: Fácil adicionar novas ferramentas matemáticas +- ✅ **Testável**: Scripts de teste automatizado incluídos + +--- + +**Desenvolvido como demonstração de AI Agent com MCP e interpretação inteligente de operações** diff --git a/GenAI/mcp/sample1/mcp_client.py b/GenAI/mcp/sample1/mcp_client.py new file mode 100644 index 0000000..ab26818 --- /dev/null +++ b/GenAI/mcp/sample1/mcp_client.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python3 +""" +Cliente MCP que interage com o usuário via chat usando LLM. +Interpreta a operação matemática desejada e executa através do servidor MCP. +""" + +import asyncio +import json +from typing import Optional +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client +from openai import OpenAI + + +# Configuração do LLM +API_BASE_URL = "https://api.xptoai.com.br/genai/grokcode/v1" +API_KEY = "biasb986lk657fsdv6d3543vs5b65s7v373sd321vsdv4sdv34bv3f4hb5f4j6mn546tu" +MODEL_NAME = "grok-2-1212" # Modelo padrão, pode ser ajustado + + +class MCPChatClient: + """Cliente de chat que integra MCP com LLM.""" + + def __init__(self): + self.client = OpenAI( + base_url=API_BASE_URL, + api_key=API_KEY + ) + self.session: Optional[ClientSession] = None + self.available_tools = [] + self.conversation_history = [] + + async def connect_to_server(self): + """Conecta ao servidor MCP.""" + server_params = StdioServerParameters( + command="python3", + args=["mcp_server.py"], + env=None + ) + + # stdio_client retorna um context manager assíncrono + self.stdio_context = stdio_client(server_params) + self.stdio, self.write = await self.stdio_context.__aenter__() + self.session = ClientSession(self.stdio, self.write) + + await self.session.__aenter__() + + # Inicializar sessão + await self.session.initialize() + + # Obter lista de ferramentas disponíveis + tools_list = await self.session.list_tools() + self.available_tools = tools_list.tools + + print(f"✓ Conectado ao servidor MCP") + print(f"✓ Ferramentas disponíveis: {[tool.name for tool in self.available_tools]}\n") + + def format_tools_for_openai(self) -> list: + """Formata as ferramentas MCP para o formato OpenAI.""" + openai_tools = [] + for tool in self.available_tools: + openai_tools.append({ + "type": "function", + "function": { + "name": tool.name, + "description": tool.description, + "parameters": tool.inputSchema + } + }) + return openai_tools + + async def call_mcp_tool(self, tool_name: str, arguments: dict) -> str: + """Chama uma ferramenta no servidor MCP.""" + result = await self.session.call_tool(tool_name, arguments) + + # Extrair o conteúdo de texto do resultado + if result.content and len(result.content) > 0: + return result.content[0].text + return json.dumps({"error": "Nenhum resultado retornado"}) + + async def chat(self, user_message: str) -> str: + """Processa uma mensagem do usuário e retorna a resposta do LLM.""" + + # Adicionar mensagem do usuário ao histórico + self.conversation_history.append({ + "role": "user", + "content": user_message + }) + + # Preparar mensagens para o LLM + messages = [ + { + "role": "system", + "content": ( + "Você é um assistente matemático inteligente que ajuda usuários a realizar operações matemáticas. " + "Você tem acesso a 4 ferramentas: soma, subtração, multiplicação e divisão. " + "\n\n" + "Seu objetivo é:\n" + "1. Interpretar qual operação matemática o usuário deseja realizar através da conversa natural\n" + "2. Identificar os dois números que o usuário quer usar\n" + "3. Chamar a ferramenta apropriada com os números corretos\n" + "4. Apresentar o resultado de forma clara e amigável\n" + "\n" + "Exemplos de interpretação:\n" + "- 'Quanto é 5 mais 3?' → usar ferramenta 'soma' com 5 e 3\n" + "- 'Subtraia 10 de 25' → usar ferramenta 'subtracao' com 25 e 10\n" + "- 'Multiplique 7 por 8' → usar ferramenta 'multiplicacao' com 7 e 8\n" + "- 'Divida 20 por 4' → usar ferramenta 'divisao' com 20 e 4\n" + "- '15 menos 7' → usar ferramenta 'subtracao' com 15 e 7\n" + "\n" + "Se o usuário pedir uma operação que não está disponível (como potência, raiz quadrada, etc.), " + "informe educadamente que apenas as 4 operações básicas estão implementadas. " + "\n" + "Seja conversacional, natural e prestativo na interação." + ) + } + ] + self.conversation_history + + # Fazer chamada ao LLM com ferramentas + openai_tools = self.format_tools_for_openai() + + response = self.client.chat.completions.create( + model=MODEL_NAME, + messages=messages, + tools=openai_tools if openai_tools else None, + tool_choice="auto" if openai_tools else None + ) + + assistant_message = response.choices[0].message + + # Verificar se o LLM quer chamar ferramentas + if assistant_message.tool_calls: + # Adicionar a resposta do assistente ao histórico + self.conversation_history.append({ + "role": "assistant", + "content": assistant_message.content, + "tool_calls": [ + { + "id": tc.id, + "type": "function", + "function": { + "name": tc.function.name, + "arguments": tc.function.arguments + } + } + for tc in assistant_message.tool_calls + ] + }) + + # Executar as ferramentas solicitadas + for tool_call in assistant_message.tool_calls: + function_name = tool_call.function.name + function_args = json.loads(tool_call.function.arguments) + + print(f"🔧 Executando ferramenta: {function_name}") + print(f" Argumentos: {function_args}") + + # Chamar a ferramenta MCP + tool_result = await self.call_mcp_tool(function_name, function_args) + + # Verificar se houve erro no resultado + try: + result_data = json.loads(tool_result) + if "error" in result_data: + print(f" ⚠️ Erro: {result_data['error']}") + else: + print(f" ✓ Resultado: {result_data.get('resultado', tool_result)}") + except: + print(f" Resultado: {tool_result}") + + print() + + # Adicionar resultado da ferramenta ao histórico + self.conversation_history.append({ + "role": "tool", + "tool_call_id": tool_call.id, + "content": tool_result + }) + + # Fazer nova chamada ao LLM com os resultados das ferramentas + messages = [ + { + "role": "system", + "content": ( + "Você é um assistente matemático inteligente que ajuda usuários a realizar operações matemáticas. " + "Você tem acesso a 4 ferramentas: soma, subtração, multiplicação e divisão. " + "\n\n" + "Seu objetivo é:\n" + "1. Interpretar qual operação matemática o usuário deseja realizar através da conversa natural\n" + "2. Identificar os dois números que o usuário quer usar\n" + "3. Chamar a ferramenta apropriada com os números corretos\n" + "4. Apresentar o resultado de forma clara e amigável\n" + "\n" + "Exemplos de interpretação:\n" + "- 'Quanto é 5 mais 3?' → usar ferramenta 'soma' com 5 e 3\n" + "- 'Subtraia 10 de 25' → usar ferramenta 'subtracao' com 25 e 10\n" + "- 'Multiplique 7 por 8' → usar ferramenta 'multiplicacao' com 7 e 8\n" + "- 'Divida 20 por 4' → usar ferramenta 'divisao' com 20 e 4\n" + "- '15 menos 7' → usar ferramenta 'subtracao' com 15 e 7\n" + "\n" + "Se o usuário pedir uma operação que não está disponível (como potência, raiz quadrada, etc.), " + "informe educadamente que apenas as 4 operações básicas estão implementadas. " + "\n" + "Se houver erro na execução (como divisão por zero), explique o erro de forma educada e sugira uma alternativa. " + "\n" + "Seja conversacional, natural e prestativo na interação." + ) + } + ] + self.conversation_history + + final_response = self.client.chat.completions.create( + model=MODEL_NAME, + messages=messages + ) + + final_message = final_response.choices[0].message.content + + # Adicionar resposta final ao histórico + self.conversation_history.append({ + "role": "assistant", + "content": final_message + }) + + return final_message + + else: + # Não há chamadas de ferramentas, apenas resposta textual + response_text = assistant_message.content or "" + + self.conversation_history.append({ + "role": "assistant", + "content": response_text + }) + + return response_text + + async def close(self): + """Fecha a conexão com o servidor MCP.""" + if self.session: + await self.session.__aexit__(None, None, None) + if hasattr(self, 'stdio_context'): + await self.stdio_context.__aexit__(None, None, None) + + +async def main(): + """Função principal que executa o chat interativo.""" + print("=" * 60) + print(" Chat com AI Agent - Operações Matemáticas") + print("=" * 60) + print() + + client = MCPChatClient() + + try: + # Conectar ao servidor MCP + await client.connect_to_server() + + print("💬 Iniciando conversa com o assistente...") + print(" (Digite 'sair' para encerrar)\n") + print("-" * 60) + + # Loop de chat interativo + while True: + # Obter entrada do usuário + user_input = input("\n👤 Você: ").strip() + + if not user_input: + continue + + if user_input.lower() in ['sair', 'exit', 'quit']: + print("\n👋 Encerrando chat. Até logo!") + break + + # Processar mensagem + print("\n🤖 Assistente: ", end="", flush=True) + response = await client.chat(user_input) + print(response) + print("-" * 60) + + except KeyboardInterrupt: + print("\n\n👋 Chat interrompido. Até logo!") + + except Exception as e: + print(f"\n❌ Erro: {e}") + import traceback + traceback.print_exc() + + finally: + # Fechar conexão + await client.close() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/GenAI/mcp/sample1/mcp_server.py b/GenAI/mcp/sample1/mcp_server.py new file mode 100644 index 0000000..b466e47 --- /dev/null +++ b/GenAI/mcp/sample1/mcp_server.py @@ -0,0 +1,253 @@ +#!/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()) diff --git a/GenAI/mcp/sample1/requirements.txt b/GenAI/mcp/sample1/requirements.txt new file mode 100644 index 0000000..5425f6d --- /dev/null +++ b/GenAI/mcp/sample1/requirements.txt @@ -0,0 +1,2 @@ +mcp==1.23.1 +openai==2.8.1 diff --git a/GenAI/mcp/sample1/run.sh b/GenAI/mcp/sample1/run.sh new file mode 100644 index 0000000..143a6c1 --- /dev/null +++ b/GenAI/mcp/sample1/run.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Script de inicialização rápida do sistema MCP + +echo "==========================================" +echo " Sistema MCP - Operações Matemáticas" +echo "==========================================" +echo "" + +# Verificar se ambiente virtual existe +if [ ! -d "venv" ]; then + echo "❌ Ambiente virtual não encontrado!" + echo " Execute: python3.11 -m venv venv" + exit 1 +fi + +# Ativar ambiente virtual +source venv/bin/activate + +# Verificar se dependências estão instaladas +if ! python -c "import mcp" 2>/dev/null; then + echo "📦 Instalando dependências..." + pip install -r requirements.txt + echo "" +fi + +# Executar cliente MCP +echo "🚀 Iniciando cliente MCP..." +echo "" +python mcp_client.py diff --git a/GenAI/mcp/sample1/test_system.py b/GenAI/mcp/sample1/test_system.py new file mode 100644 index 0000000..2c96b25 --- /dev/null +++ b/GenAI/mcp/sample1/test_system.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Script de teste automatizado para o sistema MCP. +Testa todas as 4 operações matemáticas e casos de erro. +""" + +import asyncio +import json +from mcp_client import MCPChatClient + + +async def test_system(): + """Testa o sistema com uma sequência de mensagens variadas.""" + print("=" * 60) + print(" TESTE AUTOMATIZADO - Sistema MCP") + print("=" * 60) + print() + + client = MCPChatClient() + + try: + # Conectar ao servidor + await client.connect_to_server() + + # Sequência de mensagens de teste + test_cases = [ + { + "descricao": "Teste de Soma", + "mensagem": "Quanto é 15 mais 7?" + }, + { + "descricao": "Teste de Subtração", + "mensagem": "Subtraia 5 de 20" + }, + { + "descricao": "Teste de Multiplicação", + "mensagem": "Multiplique 8 por 6" + }, + { + "descricao": "Teste de Divisão", + "mensagem": "Divida 100 por 4" + }, + { + "descricao": "Teste de Divisão por Zero (Erro Esperado)", + "mensagem": "Divida 10 por 0" + }, + { + "descricao": "Teste de Operação Não Implementada", + "mensagem": "Calcule 5 elevado ao quadrado" + }, + { + "descricao": "Teste de Linguagem Natural - Soma", + "mensagem": "Eu tenho 25 maçãs e ganhei mais 13, quantas tenho agora?" + }, + { + "descricao": "Teste de Linguagem Natural - Subtração", + "mensagem": "Se eu tinha 50 reais e gastei 18, quanto sobrou?" + } + ] + + print("📝 Executando sequência de testes...\n") + print("=" * 60) + + for i, test_case in enumerate(test_cases, 1): + print(f"\n[Teste {i}/{len(test_cases)}] {test_case['descricao']}") + print("-" * 60) + print(f"👤 Usuário: {test_case['mensagem']}") + + response = await client.chat(test_case['mensagem']) + + print(f"🤖 Assistente: {response}") + print("=" * 60) + + # Pequena pausa entre mensagens + await asyncio.sleep(1) + + print("\n✅ Todos os testes concluídos!") + print("\nResumo dos testes:") + print(" ✓ Soma") + print(" ✓ Subtração") + print(" ✓ Multiplicação") + print(" ✓ Divisão") + print(" ✓ Tratamento de erro (divisão por zero)") + print(" ✓ Operação não implementada") + print(" ✓ Interpretação de linguagem natural") + + except Exception as e: + print(f"\n❌ Erro durante o teste: {e}") + import traceback + traceback.print_exc() + + finally: + await client.close() + + +if __name__ == "__main__": + asyncio.run(test_system())