UNPKG

avp-devlanvi-tabnews-mcp-server

Version:

Servidor MCP com ferramentas de saudação dinâmica e consulta à API do TabNews

254 lines (221 loc) 7.23 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; /** * Servidor MCP Simples com Ferramenta de Saudação Dinâmica e Consulta ao TabNews */ // Criar servidor MCP const server = new Server( { name: "servidor-saudacao-dinamica", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); // Função para gerar saudação amistosa function gerarSaudacaoAmistosa(args) { const { nome, ocasiao = "encontro" } = args; // Obter data e hora atuais const agora = new Date(); const dataFormatada = agora.toLocaleDateString('pt-BR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); const horaFormatada = agora.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); // Determinar saudação baseada no horário const hora = agora.getHours(); let saudacaoHorario; let emoji; if (hora >= 5 && hora < 12) { saudacaoHorario = "Bom dia"; emoji = "🌅"; } else if (hora >= 12 && hora < 18) { saudacaoHorario = "Boa tarde"; emoji = "☀️"; } else { saudacaoHorario = "Boa noite"; emoji = "🌙"; } // Gerar mensagem personalizada const saudacao = [ `${emoji} ${saudacaoHorario}, ${nome}!`, ``, `É um prazer te encontrar neste ${ocasiao}! 🤝`, ``, `📅 Hoje é ${dataFormatada}`, `🕐 Agora são exatamente ${horaFormatada}`, ``, `Espero que você esteja tendo um dia maravilhoso! ✨`, `Como posso ajudá-lo(a) hoje? 😊` ].join('\n'); return saudacao; } // Função para consultar artigos do TabNews async function consultarTabNews(args) { const { limite = 10, pagina = 1 } = args; try { // Fazer requisição para a API do TabNews const url = `https://www.tabnews.com.br/api/v1/contents?page=${pagina}&per_page=${limite}`; const response = await fetch(url); if (!response.ok) { throw new Error(`Erro na API: ${response.status} ${response.statusText}`); } const artigos = await response.json(); // Processar e formatar os dados const resultados = artigos.map((artigo, index) => { const url = `https://www.tabnews.com.br/${artigo.owner_username}/${artigo.slug}`; const dataPublicacao = new Date(artigo.published_at).toLocaleDateString('pt-BR'); return { numero: index + 1, titulo: artigo.title, url: url, autor: artigo.owner_username, dataPublicacao: dataPublicacao, tabcoins: artigo.tabcoins || 0, comentarios: artigo.children_deep_count || 0 }; }); // Criar texto formatado const cabecalho = [ `📰 **ARTIGOS DO TABNEWS** 📰`, ``, `📊 **Página:** ${pagina} | **Limite:** ${limite}`, `🔗 **Total encontrado:** ${resultados.length} artigos`, ``, `═══════════════════════════════════════════════════`, `` ].join('\n'); const listaArtigos = resultados.map(artigo => [ `**${artigo.numero}. ${artigo.titulo}**`, `🔗 **URL:** ${artigo.url}`, `👤 **Autor:** @${artigo.autor}`, `📅 **Data:** ${artigo.dataPublicacao}`, `💰 **TabCoins:** ${artigo.tabcoins} | 💬 **Comentários:** ${artigo.comentarios}`, ``, `─────────────────────────────────────────────────────`, `` ].join('\n')).join('\n'); const rodape = [ `✨ **Dados atualizados em:** ${new Date().toLocaleString('pt-BR')}`, `🌐 **Fonte:** TabNews API (https://www.tabnews.com.br/api/v1/contents)` ].join('\n'); return `${cabecalho}${listaArtigos}${rodape}`; } catch (error) { return `❌ **Erro ao consultar TabNews:**\n\n${error.message}\n\n🔄 Tente novamente em alguns instantes.`; } } // Handler para listar ferramentas server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "saudacao_amistosa", description: "Gera uma saudação calorosa e personalizada com informações atuais de data e hora", inputSchema: { type: "object", properties: { nome: { type: "string", description: "Nome da pessoa para personalizar a saudação", }, ocasiao: { type: "string", description: "Ocasião especial ou contexto da saudação (opcional)", default: "encontro" } }, required: ["nome"], }, }, { name: "consultar_tabnews", description: "Consulta os artigos mais recentes do TabNews e retorna título, URL, autor e outras informações", inputSchema: { type: "object", properties: { limite: { type: "number", description: "Número máximo de artigos para retornar (padrão: 10, máximo: 100)", default: 10, minimum: 1, maximum: 100 }, pagina: { type: "number", description: "Número da página para paginação (padrão: 1)", default: 1, minimum: 1 } }, required: [], }, }, ], }; }); // Handler para executar ferramentas server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "saudacao_amistosa") { const saudacao = gerarSaudacaoAmistosa(args); return { content: [ { type: "text", text: saudacao, }, ], }; } if (name === "consultar_tabnews") { const resultado = await consultarTabNews(args); return { content: [ { type: "text", text: resultado, }, ], }; } throw new Error(`Ferramenta desconhecida: ${name}`); }); // Função principal async function main() { const transport = new StdioServerTransport(); // Possível usar straming await server.connect(transport); // Log de inicialização (stderr para não interferir com o protocolo) console.error("🚀 Servidor MCP de Saudação e TabNews iniciado com sucesso!"); console.error("💡 Ferramentas disponíveis:"); console.error(" • saudacao_amistosa"); console.error(" • consultar_tabnews"); } // Tratar erros globais process.on('SIGINT', () => { console.error("\n👋 Servidor MCP encerrado graciosamente"); process.exit(0); }); process.on('uncaughtException', (error) => { console.error("❌ Erro não capturado:", error); process.exit(1); }); // Executar servidor main().catch((error) => { console.error("❌ Erro ao iniciar servidor:", error); process.exit(1); });