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
JavaScript
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);
});