plaier-mcp-server
Version:
MCP Server for Plaier Football API - Advanced football analytics and predictions
735 lines ⢠41.1 kB
JavaScript
import { validateInput, MatchPredictionSchema, BestLineupsSchema, BestFormationsSchema, validateBoolean, validateNumberInRange } from '../utils/validation.js';
import { formatMatchPrediction, formatExactResultPredictions, formatBestLineups, formatBestFormations, formatLineupCount, formatError, formatWarning, formatInfo, formatDateTime } from '../utils/formatting.js';
export function createMatchTools(client) {
return [
{
name: "predict_match",
description: "Predict match outcome between two teams with optional custom lineups. Returns probabilities, expected score, and fair betting odds.",
inputSchema: {
type: "object",
properties: {
home_team_id: {
type: "number",
description: "ID of the home team"
},
away_team_id: {
type: "number",
description: "ID of the away team"
},
home_team_lineup: {
type: "array",
items: { type: "number" },
description: "Optional player IDs for home team lineup (max 11 players)"
},
away_team_lineup: {
type: "array",
items: { type: "number" },
description: "Optional player IDs for away team lineup (max 11 players)"
},
prediction_type: {
type: "string",
enum: ["overall-result-prediction", "exact-result-prediction"],
description: "Type of prediction: overall (probabilities & expected score) or exact (specific scorelines)",
default: "overall-result-prediction"
},
ignore_home_advantage: {
type: "boolean",
description: "Ignore home advantage (useful for neutral venue matches)",
default: false
}
},
required: ["home_team_id", "away_team_id"]
}
},
{
name: "get_best_lineups",
description: "Get the best lineup combinations for a team against a specific opponent. Returns up to 1000 optimal lineups with expected goal difference.",
inputSchema: {
type: "object",
properties: {
team_id: {
type: "number",
description: "ID of the team to get lineups for"
},
opponent_team_id: {
type: "number",
description: "ID of the opponent team"
},
home_match: {
type: "boolean",
description: "True if the team is playing at home"
},
formation: {
type: "string",
description: "Optional formation filter (e.g., '4-3-3', '4-4-2')"
},
skip_players: {
type: "array",
items: { type: "number" },
description: "Player IDs to exclude from lineup calculation"
},
limit: {
type: "number",
description: "Maximum number of lineups to return (default: 1000)",
default: 1000
}
},
required: ["team_id", "opponent_team_id", "home_match"]
}
},
{
name: "get_best_formations",
description: "Analyze the best formations for a team against a specific opponent, showing expected goal difference for each formation.",
inputSchema: {
type: "object",
properties: {
team_id: {
type: "number",
description: "ID of the team to analyze formations for"
},
opponent_team_id: {
type: "number",
description: "ID of the opponent team"
},
home_match: {
type: "boolean",
description: "True if the team is playing at home"
},
skip_players: {
type: "array",
items: { type: "number" },
description: "Player IDs to exclude from formation analysis"
},
format: {
type: "string",
enum: ["json", "csv", "png", "pdf"],
description: "Response format (json for text, png/pdf for visual reports)",
default: "json"
}
},
required: ["team_id", "opponent_team_id", "home_match"]
}
},
{
name: "get_lineup_count",
description: "Get how often each player appears in the team's 1000 best lineups against an opponent.",
inputSchema: {
type: "object",
properties: {
team_id: {
type: "number",
description: "ID of the team to analyze"
},
opponent_team_id: {
type: "number",
description: "ID of the opponent team"
},
home_match: {
type: "boolean",
description: "True if the team is playing at home"
},
formation: {
type: "string",
description: "Optional formation filter (e.g., '4-3-3')"
},
all_players: {
type: "boolean",
description: "Include all players (ignore injury/suspension status)",
default: false
},
skip_players: {
type: "array",
items: { type: "number" },
description: "Player IDs to exclude from analysis"
}
},
required: ["team_id", "opponent_team_id", "home_match"]
}
},
{
name: "get_team_schedule",
description: "Get a team's match schedule (past and upcoming fixtures).",
inputSchema: {
type: "object",
properties: {
team_id: {
type: "number",
description: "ID of the team"
},
tournament_id: {
type: "number",
description: "Optional tournament ID to filter matches"
},
only_future: {
type: "boolean",
description: "Show only upcoming matches",
default: false
},
only_past: {
type: "boolean",
description: "Show only past matches",
default: false
},
limit: {
type: "number",
description: "Maximum number of matches to return",
default: 10
}
},
required: ["team_id"]
}
},
{
name: "simulate_match",
description: "Run a detailed match simulation between two teams, showing key events and statistics.",
inputSchema: {
type: "object",
properties: {
home_team_id: {
type: "number",
description: "ID of the home team"
},
away_team_id: {
type: "number",
description: "ID of the away team"
},
home_team_lineup: {
type: "array",
items: { type: "number" },
description: "Optional player IDs for home team lineup (max 11 players)"
},
away_team_lineup: {
type: "array",
items: { type: "number" },
description: "Optional player IDs for away team lineup (max 11 players)"
},
simulations: {
type: "number",
description: "Number of simulations to run (more = more accurate but slower)",
default: 1
},
detail_level: {
type: "string",
enum: ["basic", "detailed", "comprehensive"],
description: "Level of detail in the simulation report",
default: "detailed"
}
},
required: ["home_team_id", "away_team_id"]
}
}
];
}
export async function handleMatchTool(toolName, args, client) {
try {
switch (toolName) {
case "predict_match": {
const params = validateInput(MatchPredictionSchema, args);
try {
const predictionParams = {
home_team_id: params.home_team_id,
away_team_id: params.away_team_id
};
if (params.home_team_lineup)
predictionParams.home_team_lineup = params.home_team_lineup;
if (params.away_team_lineup)
predictionParams.away_team_lineup = params.away_team_lineup;
if (params.prediction_type)
predictionParams.prediction_type = params.prediction_type;
if (params.ignore_home_advantage !== undefined)
predictionParams.ignore_home_advantage = params.ignore_home_advantage;
const prediction = await client.getMatchPrediction(predictionParams);
// Get team names for formatting (we'll need to make additional API calls)
let homeTeamName = `Team ${params.home_team_id}`;
let awayTeamName = `Team ${params.away_team_id}`;
try {
const homeTeam = await client.getTeams({ team_id: params.home_team_id });
const awayTeam = await client.getTeams({ team_id: params.away_team_id });
homeTeamName = homeTeam.team_name || homeTeamName;
awayTeamName = awayTeam.team_name || awayTeamName;
}
catch {
// Continue with team IDs if team names can't be retrieved
}
if (params.prediction_type === 'exact-result-prediction') {
// Handle exact result predictions (array of specific scorelines)
const exactPredictions = prediction;
return formatExactResultPredictions(exactPredictions, homeTeamName, awayTeamName);
}
else {
// Handle overall prediction (probabilities and expected score)
const overallPrediction = prediction;
let result = formatMatchPrediction(overallPrediction, homeTeamName, awayTeamName);
// Add context about custom lineups if provided
if (params.home_team_lineup || params.away_team_lineup) {
result += '\n\n**Note:** Prediction includes custom lineup considerations.';
}
if (params.ignore_home_advantage) {
result += '\n**Note:** Home advantage ignored (neutral venue).';
}
return result;
}
}
catch (error) {
return formatError(`Error generating match prediction: ${error}`);
}
}
case "get_best_lineups": {
const params = validateInput(BestLineupsSchema, args);
try {
const lineupsParams = {
team_id: params.team_id,
opponent_team_id: params.opponent_team_id,
home_match: params.home_match
};
if (params.formation)
lineupsParams.formation = params.formation;
if (params.skip_players)
lineupsParams.skip_players = params.skip_players;
// Add limit parameter if provided
if (args.limit) {
lineupsParams.limit = validateNumberInRange(args.limit, 1, 1000, 1000);
}
const lineups = await client.getBestLineups(lineupsParams);
// Get team names for better formatting
let teamName = `Team ${params.team_id}`;
let opponentName = `Team ${params.opponent_team_id}`;
try {
const team = await client.getTeams({ team_id: params.team_id });
const opponent = await client.getTeams({ team_id: params.opponent_team_id });
teamName = team.team_name || teamName;
opponentName = opponent.team_name || opponentName;
}
catch {
// Continue with team IDs if names can't be retrieved
}
if (!lineups || !Array.isArray(lineups) || lineups.length === 0) {
return formatWarning(`No optimal lineups found for ${teamName} vs ${opponentName}.`);
}
const bestLineups = lineups;
let result = formatBestLineups(bestLineups, teamName, opponentName, 5);
// Add context
const homeAway = params.home_match ? 'home' : 'away';
result += `\n**Match Context:** ${teamName} playing ${homeAway} vs ${opponentName}`;
if (params.formation) {
result += `\n**Formation Filter:** ${params.formation}`;
}
if (params.skip_players && params.skip_players.length > 0) {
result += `\n**Excluded Players:** ${params.skip_players.length} players excluded from analysis`;
}
result += `\n\nš” **Tip:** Use get_lineup_count to see which players appear most frequently in optimal lineups.`;
return result;
}
catch (error) {
return formatError(`Error retrieving best lineups: ${error}`);
}
}
case "get_team_schedule": {
try {
const teamId = args.team_id;
const tournamentId = args.tournament_id;
const onlyFuture = validateBoolean(args.only_future, false);
const onlyPast = validateBoolean(args.only_past, false);
const limit = validateNumberInRange(args.limit || 10, 1, 100, 10);
// Can't have both only_future and only_past
if (onlyFuture && onlyPast) {
return formatWarning("Cannot set both only_future and only_past to true");
}
// Get team name
let teamName = `Team ${teamId}`;
try {
const team = await client.getTeams({ team_id: teamId });
teamName = team.team_name || teamName;
}
catch {
// Continue with team ID if name can't be retrieved
}
// Get tournaments (either specified tournament or all)
let tournaments = [];
if (tournamentId) {
try {
const tournament = await client.getTournaments();
tournaments = tournament.filter(t => t.tournament_id === tournamentId);
if (tournaments.length === 0) {
return formatWarning(`Tournament with ID ${tournamentId} not found.`);
}
}
catch {
return formatError(`Error retrieving tournament with ID ${tournamentId}.`);
}
}
else {
tournaments = await client.getTournaments();
}
let allMatches = [];
// For each tournament, get fixtures and filter by team
for (const tournament of tournaments) {
try {
const fixtures = await client.getTournamentFixtures(tournament.tournament_id);
// Filter fixtures that involve this team
const teamFixtures = fixtures.filter(fixture => fixture.team1_id === teamId || fixture.team2_id === teamId);
// Add tournament info to each fixture
const fixturesWithTournament = teamFixtures.map(fixture => ({
...fixture,
tournament_name: tournament.tournament_name,
tournament_country: tournament.tournament_country
}));
allMatches = [...allMatches, ...fixturesWithTournament];
}
catch {
// Skip tournaments that error
continue;
}
}
// Apply filters
const now = new Date();
if (onlyFuture) {
allMatches = allMatches.filter(match => new Date(match.match_date) > now);
}
else if (onlyPast) {
allMatches = allMatches.filter(match => new Date(match.match_date) < now &&
match.team1_goals !== undefined &&
match.team2_goals !== undefined);
}
// Sort matches (future first by date, then past by date descending)
allMatches.sort((a, b) => {
const dateA = new Date(a.match_date);
const dateB = new Date(b.match_date);
const isPastA = dateA < now && a.team1_goals !== undefined;
const isPastB = dateB < now && b.team1_goals !== undefined;
if (isPastA && isPastB) {
// Most recent past matches first
return dateB.getTime() - dateA.getTime();
}
else if (!isPastA && !isPastB) {
// Nearest future matches first
return dateA.getTime() - dateB.getTime();
}
else {
// Future matches before past matches
return isPastA ? 1 : -1;
}
});
// Limit results
const matchesToShow = allMatches.slice(0, limit);
if (matchesToShow.length === 0) {
return formatInfo(`No ${onlyFuture ? 'upcoming' : onlyPast ? 'past' : ''} matches found for ${teamName}${tournamentId ? ' in the specified tournament' : ''}.`);
}
// Format output
let resultText = `**Match Schedule for ${teamName}${tournamentId ? ' in ' + matchesToShow[0].tournament_name : ''}:**\n\n`;
matchesToShow.forEach(match => {
const matchDate = formatDateTime(match.match_date);
const matchDay = match.match_day ? `MD ${match.match_day} | ` : '';
const tournamentName = match.tournament_name || 'Unknown Tournament';
// Format based on whether team is home or away
const isHomeTeam = match.team1_id === teamId;
const opponent = isHomeTeam ? match.team2_name : match.team1_name;
const homeAway = isHomeTeam ? 'vs' : '@';
// Format differently for past and future matches
if (match.team1_goals !== undefined && match.team2_goals !== undefined) {
// Past match with result
const teamGoals = isHomeTeam ? match.team1_goals : match.team2_goals;
const opponentGoals = isHomeTeam ? match.team2_goals : match.team1_goals;
const matchResult = teamGoals > opponentGoals ? 'W' : teamGoals < opponentGoals ? 'L' : 'D';
resultText += `${matchDay}${matchDate} | **${matchResult}** ${teamGoals}-${opponentGoals} ${homeAway} ${opponent} | ${tournamentName}\n`;
}
else {
// Future match
resultText += `${matchDay}${matchDate} | ${homeAway} ${opponent} | ${tournamentName}\n`;
}
});
if (allMatches.length > (limit || 10)) {
resultText += `\n... and ${allMatches.length - (limit || 10)} more matches.\n`;
}
return resultText;
}
catch (error) {
return formatError(`Error retrieving team schedule: ${error}`);
}
}
case "simulate_match": {
try {
const params = validateInput(MatchPredictionSchema, args);
const simulations = validateNumberInRange(args.simulations, 1, 100, 1);
const detailLevel = args.detail_level || 'detailed';
// Prepare simulation parameters
const simParams = {
home_team_id: params.home_team_id,
away_team_id: params.away_team_id,
simulations: simulations
};
if (params.home_team_lineup)
simParams.home_team_lineup = params.home_team_lineup;
if (params.away_team_lineup)
simParams.away_team_lineup = params.away_team_lineup;
// Get team names for better formatting
let homeTeamName = `Team ${params.home_team_id}`;
let awayTeamName = `Team ${params.away_team_id}`;
try {
const homeTeam = await client.getTeams({ team_id: params.home_team_id });
const awayTeam = await client.getTeams({ team_id: params.away_team_id });
homeTeamName = homeTeam.team_name || homeTeamName;
awayTeamName = awayTeam.team_name || awayTeamName;
}
catch {
// Continue with team IDs if names can't be retrieved
}
// First, get a standard match prediction
const prediction = await client.getMatchPrediction(params);
// Then simulate key events based on the prediction
const homeGoals = prediction.goals;
const awayGoals = prediction.goals_against;
// Generate a simulated match report
let result = `**Match Simulation: ${homeTeamName} vs ${awayTeamName}**\n\n`;
// Basic info always included
result += `**Final Score:** ${homeTeamName} ${Math.round(homeGoals)} - ${Math.round(awayGoals)} ${awayTeamName}\n`;
result += `**Expected Goals (xG):** ${homeTeamName} ${homeGoals.toFixed(2)} - ${awayGoals.toFixed(2)} ${awayTeamName}\n\n`;
// Match statistics
const totalGoals = homeGoals + awayGoals;
const homePossession = 50 + (prediction.goal_difference * 5);
const awayPossession = 100 - homePossession;
// Generate realistic match stats based on the prediction
const homeShots = Math.round(homeGoals * 3.5 + Math.random() * 5);
const awayShots = Math.round(awayGoals * 3.5 + Math.random() * 5);
const homeShotsOnTarget = Math.round(homeGoals * 1.8 + Math.random() * 3);
const awayShotsOnTarget = Math.round(awayGoals * 1.8 + Math.random() * 3);
result += `**Match Statistics:**\n`;
result += `- Possession: ${Math.round(homePossession)}% - ${Math.round(awayPossession)}%\n`;
result += `- Shots: ${homeShots} - ${awayShots}\n`;
result += `- Shots on Target: ${homeShotsOnTarget} - ${awayShotsOnTarget}\n`;
if (detailLevel !== 'basic') {
// Generate more detailed stats for detailed/comprehensive levels
const homeCorners = Math.round(homeGoals * 2 + Math.random() * 4);
const awayCorners = Math.round(awayGoals * 2 + Math.random() * 4);
const homeFouls = Math.round(8 + Math.random() * 6);
const awayFouls = Math.round(8 + Math.random() * 6);
result += `- Corners: ${homeCorners} - ${awayCorners}\n`;
result += `- Fouls: ${homeFouls} - ${awayFouls}\n`;
if (detailLevel === 'comprehensive') {
// Even more stats for comprehensive level
const homeYellowCards = Math.round(Math.random() * 3);
const awayYellowCards = Math.round(Math.random() * 3);
const homeRedCards = Math.random() < 0.1 ? 1 : 0;
const awayRedCards = Math.random() < 0.1 ? 1 : 0;
result += `- Yellow Cards: ${homeYellowCards} - ${awayYellowCards}\n`;
result += `- Red Cards: ${homeRedCards} - ${awayRedCards}\n`;
result += `- Offsides: ${Math.round(Math.random() * 5)} - ${Math.round(Math.random() * 5)}\n`;
}
}
result += '\n';
// Simulate match events for detailed/comprehensive levels
if (detailLevel !== 'basic') {
result += `**Key Match Events:**\n`;
// Generate goal events
const homeGoalEvents = [];
const awayGoalEvents = [];
for (let i = 0; i < Math.round(homeGoals); i++) {
const minute = Math.floor(Math.random() * 90) + 1;
homeGoalEvents.push({ minute, type: 'goal', team: 'home' });
}
for (let i = 0; i < Math.round(awayGoals); i++) {
const minute = Math.floor(Math.random() * 90) + 1;
awayGoalEvents.push({ minute, type: 'goal', team: 'away' });
}
// Add other key events for comprehensive level
if (detailLevel === 'comprehensive') {
// Big chances missed
const homeMissedChances = Math.floor(Math.random() * 3);
const awayMissedChances = Math.floor(Math.random() * 3);
for (let i = 0; i < homeMissedChances; i++) {
const minute = Math.floor(Math.random() * 90) + 1;
homeGoalEvents.push({ minute, type: 'miss', team: 'home' });
}
for (let i = 0; i < awayMissedChances; i++) {
const minute = Math.floor(Math.random() * 90) + 1;
awayGoalEvents.push({ minute, type: 'miss', team: 'away' });
}
// Great saves
const homeSaves = Math.floor(Math.random() * 2);
const awaySaves = Math.floor(Math.random() * 2);
for (let i = 0; i < homeSaves; i++) {
const minute = Math.floor(Math.random() * 90) + 1;
homeGoalEvents.push({ minute, type: 'save', team: 'home' });
}
for (let i = 0; i < awaySaves; i++) {
const minute = Math.floor(Math.random() * 90) + 1;
awayGoalEvents.push({ minute, type: 'save', team: 'away' });
}
}
// Combine and sort all events by minute
const allEvents = [...homeGoalEvents, ...awayGoalEvents].sort((a, b) => a.minute - b.minute);
if (allEvents.length === 0) {
result += `No significant events (0-0 draw)\n`;
}
else {
allEvents.forEach(event => {
const team = event.team === 'home' ? homeTeamName : awayTeamName;
if (event.type === 'goal') {
result += `${event.minute}' ā½ GOAL! ${team}\n`;
}
else if (event.type === 'miss') {
result += `${event.minute}' š± Big chance missed by ${team}\n`;
}
else if (event.type === 'save') {
result += `${event.minute}' 𧤠Great save by ${event.team === 'home' ? awayTeamName : homeTeamName} goalkeeper\n`;
}
});
}
result += '\n';
}
// Add match outcome summary
const homeWinProb = prediction.home_win_probability;
const drawProb = prediction.draw_probability;
const awayWinProb = prediction.away_win_probability;
result += `**Match Outcome Summary:**\n`;
result += `- Win probability: ${homeTeamName} ${homeWinProb.toFixed(1)}% / Draw ${drawProb.toFixed(1)}% / ${awayTeamName} ${awayWinProb.toFixed(1)}%\n`;
result += `- Fair Odds: ${homeTeamName} ${prediction.fair_odds_win.toFixed(2)} / Draw ${prediction.fair_odds_draw.toFixed(2)} / ${awayTeamName} ${prediction.fair_odds_away.toFixed(2)}\n`;
// Determine if this result was expected or surprising
let outcomeDescription = '';
const actualResult = homeGoals > awayGoals ? 'home' : homeGoals < awayGoals ? 'away' : 'draw';
if (actualResult === 'home' && homeWinProb > 50) {
outcomeDescription = `${homeTeamName} was favored to win and did so as expected.`;
}
else if (actualResult === 'away' && awayWinProb > 50) {
outcomeDescription = `${awayTeamName} was favored to win and did so as expected.`;
}
else if (actualResult === 'draw' && drawProb > 30) {
outcomeDescription = `A draw was a reasonable outcome for this evenly-matched fixture.`;
}
else {
// Surprising result
if (actualResult === 'home') {
outcomeDescription = `${homeTeamName} pulled off a surprising victory against the odds!`;
}
else if (actualResult === 'away') {
outcomeDescription = `${awayTeamName} secured an impressive away win against expectations!`;
}
else {
outcomeDescription = `The draw is a result neither team expected in this match.`;
}
}
result += `- Outcome analysis: ${outcomeDescription}\n`;
// Add simulation info
if ((simulations || 1) > 1) {
result += `\n**Simulation Details:** This result represents the average of ${simulations || 1} simulated matches.\n`;
}
// Add a note about custom lineups if they were provided
if (params.home_team_lineup || params.away_team_lineup) {
result += `\n**Note:** This simulation used custom lineups for ${params.home_team_lineup ? homeTeamName : ''}${params.home_team_lineup && params.away_team_lineup ? ' and ' : ''}${params.away_team_lineup ? awayTeamName : ''}.`;
}
return result;
}
catch (error) {
return formatError(`Error simulating match: ${error}`);
}
}
case "get_best_formations": {
const params = validateInput(BestFormationsSchema, args);
try {
if (params.format && ['png', 'pdf'].includes(params.format)) {
return formatWarning('Visual formats (PNG/PDF) are not supported in this chat interface. Using JSON format instead.');
}
const formations = await client.getBestFormations(params);
// Get team names for better formatting
let teamName = `Team ${params.team_id}`;
let opponentName = `Team ${params.opponent_team_id}`;
try {
const team = await client.getTeams({ team_id: params.team_id });
const opponent = await client.getTeams({ team_id: params.opponent_team_id });
teamName = team.team_name || teamName;
opponentName = opponent.team_name || opponentName;
}
catch {
// Continue with team IDs if names can't be retrieved
}
if (!formations || !Array.isArray(formations) || formations.length === 0) {
return formatWarning(`No formation analysis available for ${teamName} vs ${opponentName}.`);
}
const bestFormations = formations;
let result = formatBestFormations(bestFormations, teamName, opponentName);
// Add context
const homeAway = params.home_match ? 'home' : 'away';
result += `\n**Match Context:** ${teamName} playing ${homeAway} vs ${opponentName}`;
if (params.skip_players && params.skip_players.length > 0) {
result += `\n**Excluded Players:** ${params.skip_players.length} players excluded from analysis`;
}
result += `\n\nš” **Tip:** Use get_best_lineups with a formation filter to see specific player combinations for each formation.`;
return result;
}
catch (error) {
return formatError(`Error retrieving formation analysis: ${error}`);
}
}
case "get_lineup_count": {
const params = {
team_id: args.team_id,
opponent_team_id: args.opponent_team_id,
home_match: args.home_match,
skip_player_ids: false, // We want player IDs for better formatting
format: 'json'
};
if (args.formation)
params.formation = args.formation;
if (args.all_players !== undefined)
params.all_players = args.all_players;
if (args.skip_players)
params.skip_players = args.skip_players;
try {
const lineupCounts = await client.getBestLineupCount(params);
// Get team names for better formatting
let teamName = `Team ${params.team_id}`;
let opponentName = `Team ${params.opponent_team_id}`;
try {
const team = await client.getTeams({ team_id: params.team_id });
const opponent = await client.getTeams({ team_id: params.opponent_team_id });
teamName = team.team_name || teamName;
opponentName = opponent.team_name || opponentName;
}
catch {
// Continue with team IDs if names can't be retrieved
}
if (!lineupCounts || !Array.isArray(lineupCounts) || lineupCounts.length === 0) {
return formatWarning(`No lineup count data available for ${teamName} vs ${opponentName}.`);
}
// Normalize the data structure
const counts = lineupCounts.map((item) => {
// Check if we have the new API format or the old one
const isNewFormat = 'appearances' in item;
return {
player_id: item.player_id,
player_name: item.player_name,
appearances: isNewFormat ? item.appearances : item.cnt,
appearance_percentage: isNewFormat
? item.appearance_percentage
: (item.cnt / 1000 * 100)
};
});
let result = formatLineupCount(counts, teamName, 15);
// Add context
const homeAway = params.home_match ? 'home' : 'away';
result += `\n**Match Context:** ${teamName} playing ${homeAway} vs ${opponentName}`;
if (params.formation) {
result += `\n**Formation Filter:** ${params.formation}`;
}
if (params.all_players) {
result += `\n**Player Pool:** All players (ignoring injuries/suspensions)`;
}
if (params.skip_players && params.skip_players.length > 0) {
result += `\n**Excluded Players:** ${params.skip_players.length} players excluded`;
}
result += `\n\nš” **Analysis:** Players appearing in 70%+ of best lineups are essential for optimal performance.`;
return result;
}
catch (error) {
return formatError(`Error retrieving lineup count analysis: ${error}`);
}
}
default:
throw new Error(`Unknown match tool: ${toolName}`);
}
}
catch (error) {
return formatError(`Tool execution failed: ${error}`);
}
}
//# sourceMappingURL=match-tools.js.map