UNPKG

plaier-mcp-server

Version:

MCP Server for Plaier Football API - Advanced football analytics and predictions

254 lines • 14.3 kB
import { validateInput, TournamentSearchSchema, TournamentFixturesSchema, TournamentPredictionSchema } from '../utils/validation.js'; import { formatTournamentsList, formatTournamentFixtures, formatTournamentPrediction, formatError, formatWarning, formatDataSummary } from '../utils/formatting.js'; export function createTournamentTools(client) { return [ { name: "get_tournaments", description: "Get a list of all tournaments available in the Plaier API with their details and fair market values.", inputSchema: { type: "object", properties: { country_filter: { type: "string", description: "Optional filter to show only tournaments from a specific country" } } } }, { name: "search_tournaments", description: "Search for tournaments by name using fuzzy search. Returns the tournament ID that can be used with other tournament tools.", inputSchema: { type: "object", properties: { tournament_name: { type: "string", description: "Tournament name to search for (minimum 3 characters). Supports partial matches." } }, required: ["tournament_name"] } }, { name: "get_tournament_fixtures", description: "Get all matches and results for a specific tournament, including scheduled fixtures and completed matches with scores.", inputSchema: { type: "object", properties: { tournament_id: { type: "number", description: "The unique ID of the tournament" }, limit: { type: "number", description: "Maximum number of fixtures to display (default 30)", default: 30 }, show_only_completed: { type: "boolean", description: "Show only completed matches with results", default: false } }, required: ["tournament_id"] } }, { name: "predict_tournament", description: "Get end-of-season table prediction for a tournament showing expected final standings with points, goals, and goal difference.", inputSchema: { type: "object", properties: { tournament_id: { type: "number", description: "The unique ID of the tournament" } }, required: ["tournament_id"] } }, { name: "get_tournament_probabilities", description: "Get probability matrix showing the likelihood of each team finishing in each position at the end of the season.", inputSchema: { type: "object", properties: { tournament_id: { type: "number", description: "The unique ID of the tournament" } }, required: ["tournament_id"] } } ]; } export async function handleTournamentTool(toolName, args, client) { try { switch (toolName) { case "get_tournaments": { try { const tournaments = await client.getTournaments(); if (tournaments.length === 0) { return formatWarning('No tournaments found in the API.'); } // Filter by country if specified let filteredTournaments = tournaments; if (args.country_filter) { const countryFilter = args.country_filter.toLowerCase(); filteredTournaments = tournaments.filter(t => t.tournament_country.toLowerCase().includes(countryFilter)); if (filteredTournaments.length === 0) { return formatError(`No tournaments found for country filter "${args.country_filter}".`); } } // Sort by fair market value (highest first) and then by tournament level const sortedTournaments = filteredTournaments.sort((a, b) => { if (b.fair_market_value !== a.fair_market_value) { return b.fair_market_value - a.fair_market_value; } return a.tournament_level - b.tournament_level; }); let result = formatTournamentsList(sortedTournaments); if (args.country_filter) { result = result.replace('Available Tournaments', `Tournaments in "${args.country_filter}"`); } result += '\nšŸ’” **Tip:** Use search_tournaments to find a specific tournament, or use the tournament ID with other tournament tools.'; return result; } catch (error) { return formatError(`Error retrieving tournaments: ${error}`); } } case "search_tournaments": { const params = validateInput(TournamentSearchSchema, args); try { const tournamentId = await client.searchTournament(params.tournament_name); if (tournamentId === "0") { return formatError(`No tournament found matching "${params.tournament_name}". Try using broader search terms.`); } return `Found tournament ID: ${tournamentId}\n\nšŸ’” **Tip:** Use this ID with other tournament tools like get_tournament_fixtures or predict_tournament.`; } catch (error) { return formatError(`No tournament found matching "${params.tournament_name}". The search requires at least 3 characters and uses fuzzy matching.`); } } case "get_tournament_fixtures": { const params = validateInput(TournamentFixturesSchema, args); try { const fixtures = await client.getTournamentFixtures(params.tournament_id); if (fixtures.length === 0) { return formatWarning(`No fixtures found for tournament ID ${params.tournament_id}. This might be a tournament without fixture data.`); } // Filter fixtures if requested let filteredFixtures = fixtures; if (args.show_only_completed) { filteredFixtures = fixtures.filter(f => f.team1_goals !== undefined && f.team2_goals !== undefined); if (filteredFixtures.length === 0) { return formatWarning(`No completed matches found for tournament ID ${params.tournament_id}.`); } } // Sort by date (most recent first for completed, upcoming first for scheduled) const sortedFixtures = filteredFixtures.sort((a, b) => { const dateA = new Date(a.match_date).getTime(); const dateB = new Date(b.match_date).getTime(); return dateB - dateA; }); const displayLimit = args.limit || 30; let result = formatTournamentFixtures(sortedFixtures, displayLimit); // Add summary information const completedMatches = fixtures.filter(f => f.team1_goals !== undefined && f.team2_goals !== undefined).length; const upcomingMatches = fixtures.length - completedMatches; result += `\n${formatDataSummary('Tournament Fixtures', displayLimit, filteredFixtures.length)}`; result += `\n**Match Status:** ${completedMatches} completed, ${upcomingMatches} scheduled`; if (args.show_only_completed) { result += '\n**Filter:** Showing only completed matches'; } result += '\n\nšŸ’” **Tip:** Use predict_tournament to see expected end-of-season standings.'; return result; } catch (error) { return formatError(`Error retrieving fixtures for tournament ID ${params.tournament_id}: ${error}`); } } case "predict_tournament": { const params = validateInput(TournamentPredictionSchema, args); try { const predictions = await client.getTournamentPrediction(params.tournament_id); if (predictions.length === 0) { return formatWarning(`No tournament prediction available for tournament ID ${params.tournament_id}. This might be a tournament type that doesn't support predictions.`); } // Sort by points (descending), then by goal difference const sortedPredictions = predictions.sort((a, b) => { if (b.points_per_season !== a.points_per_season) { return b.points_per_season - a.points_per_season; } return b.goal_difference_per_season - a.goal_difference_per_season; }); let result = formatTournamentPrediction(sortedPredictions); // Add analysis const topTeams = sortedPredictions.slice(0, 3); const bottomTeams = sortedPredictions.slice(-3).reverse(); result += `\n\n**Key Insights:**`; result += `\nšŸ† **Title Contenders:** ${topTeams.map(t => t.team_name).join(', ')}`; result += `\nāš ļø **Relegation Battle:** ${bottomTeams.map(t => t.team_name).join(', ')}`; // Calculate points gaps if (sortedPredictions.length > 1) { const titleGap = sortedPredictions[0].points_per_season - sortedPredictions[1].points_per_season; result += `\nšŸ“Š **Title Race:** ${titleGap.toFixed(1)} point gap predicted`; } result += `\n\nšŸ’” **Note:** Prediction combines actual results with simulated outcomes for remaining matches.`; result += '\nšŸ’” **Tip:** Use get_tournament_probabilities for detailed position probability analysis.'; return result; } catch (error) { return formatError(`Error retrieving tournament prediction for ID ${params.tournament_id}: ${error}`); } } case "get_tournament_probabilities": { const params = validateInput(TournamentPredictionSchema, args); try { const probabilities = await client.getTournamentProbabilities(params.tournament_id); if (!probabilities) { return formatWarning(`No probability data available for tournament ID ${params.tournament_id}. This feature may not be supported for this tournament type.`); } // Note: The exact structure of tournament probabilities response may vary // This is a simplified implementation that handles the response gracefully let result = `**Tournament Position Probabilities (Tournament ID: ${params.tournament_id}):**\n\n`; if (Array.isArray(probabilities)) { // If it's an array format result += `šŸ“Š **Probability Matrix:** Data shows likelihood of each finishing position\n`; result += `Total teams analyzed: ${probabilities.length}\n\n`; probabilities.slice(0, 10).forEach((team, index) => { result += `${index + 1}. **${team.team_name || `Team ${team.team_id}`}**\n`; if (team.probabilities) { const topPositions = Object.entries(team.probabilities) .sort((a, b) => b[1] - a[1]) .slice(0, 3); result += ` Most likely positions: ${topPositions.map(([pos, prob]) => `${pos}th (${(prob * 100).toFixed(1)}%)`).join(', ')}\n`; } result += '\n'; }); if (probabilities.length > 10) { result += `... and ${probabilities.length - 10} more teams.\n`; } } else { // If it's an object or different format result += `šŸ“Š **Probability Data:** ${JSON.stringify(probabilities, null, 2)}\n`; } result += '\nšŸ’” **Analysis:** Higher percentages indicate more likely final positions based on current form and remaining fixtures.'; return result; } catch (error) { return formatError(`Error retrieving tournament probabilities for ID ${params.tournament_id}: ${error}`); } } default: throw new Error(`Unknown tournament tool: ${toolName}`); } } catch (error) { return formatError(`Tool execution failed: ${error}`); } } //# sourceMappingURL=tournament-tools.js.map