plaier-mcp-server
Version:
MCP Server for Plaier Football API - Advanced football analytics and predictions
253 lines • 10.3 kB
JavaScript
/**
* Parameter validation utilities using Zod
*/
import { z } from 'zod';
// ==================== TEAM VALIDATION SCHEMAS ====================
export const TeamSearchSchema = z.object({
team_name: z.string().min(3, 'Team name must be at least 3 characters'),
show_details: z.boolean().optional().default(false)
});
export const TeamDetailsSchema = z.object({
team_id: z.number().int().positive('Team ID must be a positive integer')
});
export const TeamsByTournamentSchema = z.object({
tournament_id: z.number().int().positive('Tournament ID must be a positive integer')
});
export const AllTeamsSchema = z.object({
skip_national_teams: z.boolean().optional().default(true)
});
// ==================== PLAYER VALIDATION SCHEMAS ====================
export const PlayerSearchSchema = z.object({
player_name: z.string().min(3, 'Player name must be at least 3 characters'),
team_name: z.string().optional(),
show_details: z.boolean().optional().default(false)
});
export const PlayerDetailsSchema = z.object({
player_id: z.number().int().positive('Player ID must be a positive integer')
});
export const PlayerRankingSchema = z.object({
tournament_ids: z.array(z.number().int().positive()).optional(),
team_ids: z.array(z.number().int().positive()).optional(),
age: z.number().int().min(16).max(50).optional(),
min_age: z.number().int().min(16).max(50).optional(),
max_age: z.number().int().min(16).max(50).optional(),
nationality_ids: z.array(z.number().int().positive()).optional(),
position_ids: z.array(z.number().int().positive()).optional(),
position_group_ids: z.array(z.number().int().positive()).optional(),
in_national_team: z.boolean().optional(),
sort_by: z.enum(['score', 'fair-market-value', 'value-for-money']).optional().default('score'),
limit: z.number().int().min(1).max(1000).optional().default(50)
}).refine(data => {
// Can't use age with min_age or max_age
if (data.age && (data.min_age || data.max_age)) {
return false;
}
// Can't use both tournament_ids and team_ids
if (data.tournament_ids && data.team_ids) {
return false;
}
// Can't use both position_ids and position_group_ids
if (data.position_ids && data.position_group_ids) {
return false;
}
// min_age must be less than max_age
if (data.min_age && data.max_age && data.min_age >= data.max_age) {
return false;
}
return true;
}, {
message: "Invalid parameter combination"
});
export const TeamPlayersSchema = z.object({
team_id: z.number().int().positive('Team ID must be a positive integer')
});
export const TournamentPlayersSchema = z.object({
tournament_id: z.number().int().positive('Tournament ID must be a positive integer')
});
// ==================== MATCH VALIDATION SCHEMAS ====================
export const MatchPredictionSchema = z.object({
home_team_id: z.number().int().positive('Home team ID must be a positive integer'),
away_team_id: z.number().int().positive('Away team ID must be a positive integer'),
home_team_lineup: z.array(z.number().int().positive()).max(11, 'Maximum 11 players in lineup').optional(),
away_team_lineup: z.array(z.number().int().positive()).max(11, 'Maximum 11 players in lineup').optional(),
prediction_type: z.enum(['overall-result-prediction', 'exact-result-prediction']).optional().default('overall-result-prediction'),
ignore_home_advantage: z.boolean().optional().default(false)
}).refine(data => {
// Home and away teams must be different
return data.home_team_id !== data.away_team_id;
}, {
message: "Home and away teams must be different"
});
export const BestLineupsSchema = z.object({
team_id: z.number().int().positive('Team ID must be a positive integer'),
opponent_team_id: z.number().int().positive('Opponent team ID must be a positive integer'),
home_match: z.boolean(),
formation: z.string().optional(),
skip_players: z.array(z.number().int().positive()).optional()
}).refine(data => {
return data.team_id !== data.opponent_team_id;
}, {
message: "Team and opponent must be different"
});
export const BestFormationsSchema = z.object({
team_id: z.number().int().positive('Team ID must be a positive integer'),
opponent_team_id: z.number().int().positive('Opponent team ID must be a positive integer'),
home_match: z.boolean(),
skip_players: z.array(z.number().int().positive()).optional(),
format: z.enum(['json', 'csv', 'png', 'pdf']).optional().default('json'),
dark_mode: z.boolean().optional().default(true),
orientation: z.enum(['portrait', 'landscape']).optional().default('landscape')
}).refine(data => {
return data.team_id !== data.opponent_team_id;
}, {
message: "Team and opponent must be different"
});
// ==================== TOURNAMENT VALIDATION SCHEMAS ====================
export const TournamentSearchSchema = z.object({
tournament_name: z.string().min(3, 'Tournament name must be at least 3 characters')
});
export const TournamentFixturesSchema = z.object({
tournament_id: z.number().int().positive('Tournament ID must be a positive integer')
});
export const TournamentPredictionSchema = z.object({
tournament_id: z.number().int().positive('Tournament ID must be a positive integer')
});
// ==================== TRANSFER VALIDATION SCHEMAS ====================
export const TransferImpactSchema = z.object({
player_id: z.number().int().positive('Player ID must be a positive integer'),
team_ids: z.array(z.number().int().positive()).optional(),
tournament_id: z.number().int().positive().optional()
}).refine(data => {
// Must have either team_ids or tournament_id, but not both
return (data.team_ids && !data.tournament_id) || (!data.team_ids && data.tournament_id);
}, {
message: "Must specify either team_ids or tournament_id, but not both"
});
// ==================== ADVANCED ANALYSIS SCHEMAS ====================
export const TeamPerformanceSchema = z.object({
tournament_id: z.number().int().positive('Tournament ID must be a positive integer'),
report_type: z.enum(['nominal-score', 'effective-score', 'effective-score-vs-nominal-score', 'goal-difference-per-season']),
team_id: z.number().int().positive().optional(),
position_group: z.string().optional(),
only_best_player: z.boolean().optional().default(false),
format: z.enum(['json', 'csv', 'png', 'pdf']).optional().default('json'),
dark_mode: z.boolean().optional().default(true),
orientation: z.enum(['portrait', 'landscape']).optional().default('landscape')
});
export const TeamImprovementSchema = z.object({
team_id: z.number().int().positive('Team ID must be a positive integer'),
report_type: z.enum(['matrix']).default('matrix'),
format: z.enum(['json', 'csv']).optional().default('json')
});
export const MostImportantPlayersSchema = z.object({
team_id: z.number().int().positive('Team ID must be a positive integer'),
format: z.enum(['json', 'csv']).optional().default('json')
});
// ==================== EXPORT DATA SCHEMAS ====================
export const ExportDataSchema = z.object({
endpoint: z.string(),
parameters: z.record(z.any()).optional(),
format: z.enum(['csv', 'xlsx', 'json']).default('csv'),
filename: z.string().optional()
});
// ==================== VALIDATION HELPER FUNCTIONS ====================
/**
* Validate input parameters against a schema
*/
export function validateInput(schema, input) {
const result = schema.safeParse(input);
if (!result.success) {
const errors = result.error.errors.map(e => {
const path = e.path.length > 0 ? `${e.path.join('.')}` : 'root';
return `${path}: ${e.message}`;
});
throw new Error(`Validation error: ${errors.join(', ')}`);
}
return result.data;
}
/**
* Validate and sanitize team ID
*/
export function validateTeamId(teamId) {
const result = z.number().int().positive().safeParse(teamId);
if (!result.success) {
throw new Error('Team ID must be a positive integer');
}
return result.data;
}
/**
* Validate and sanitize player ID
*/
export function validatePlayerId(playerId) {
const result = z.number().int().positive().safeParse(playerId);
if (!result.success) {
throw new Error('Player ID must be a positive integer');
}
return result.data;
}
/**
* Validate and sanitize tournament ID
*/
export function validateTournamentId(tournamentId) {
const result = z.number().int().positive().safeParse(tournamentId);
if (!result.success) {
throw new Error('Tournament ID must be a positive integer');
}
return result.data;
}
/**
* Validate array of IDs
*/
export function validateIdArray(ids, name) {
const result = z.array(z.number().int().positive()).safeParse(ids);
if (!result.success) {
throw new Error(`${name} must be an array of positive integers`);
}
return result.data;
}
/**
* Validate search term
*/
export function validateSearchTerm(term) {
const result = z.string().min(3).safeParse(term);
if (!result.success) {
throw new Error('Search term must be at least 3 characters long');
}
return result.data;
}
/**
* Validate boolean parameter
*/
export function validateBoolean(value, defaultValue = false) {
if (value === undefined || value === null) {
return defaultValue;
}
const result = z.boolean().safeParse(value);
if (!result.success) {
return defaultValue;
}
return result.data;
}
/**
* Validate and clamp numeric parameter within range
*/
export function validateNumberInRange(value, min, max, defaultValue) {
if (value === undefined || value === null) {
return defaultValue;
}
const result = z.number().min(min).max(max).safeParse(value);
if (!result.success) {
if (defaultValue !== undefined) {
return defaultValue;
}
throw new Error(`Value must be between ${min} and ${max}`);
}
return result.data;
}
/**
* Create a validation error message
*/
export function createValidationError(field, message) {
return new Error(`Validation error for ${field}: ${message}`);
}
//# sourceMappingURL=validation.js.map