Skip to main content
Glama
zafronix

World Cup History MCP

list_stadiums

List all World Cup stadiums with capacity, location, elevation, opening year, and hosted tournaments. Filter by country to find specific venues.

Instructions

List World Cup venues. 206 stadiums total across history, with capacity, lat/long, elevation in meters, opening year, and the list of WC years each one hosted. Useful for "which stadiums hosted the most World Cup matches?" or "where was the 1986 final?". Filterable by country.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
countryNo

Implementation Reference

  • src/index.ts:113-331 (registration)
    The `tools` array lists all MCP tool definitions. `list_stadiums` is registered here alongside all other tools.
    const tools = [
      {
        name: 'list_tournaments',
        description:
          'List every FIFA World Cup tournament (1930 → 2026) with year, host country list, ' +
          'champion (or null for the upcoming 2026 cup). Useful as a starting point when the ' +
          'user is exploring history or needs to disambiguate a year.',
        schema: z.object({}).strict(),
        handler: async () => api('/tournaments'),
      },
      {
        name: 'get_tournament',
        description:
          'Get full details for a single World Cup tournament: every team that played, group ' +
          'stages, knockout brackets, awards (top scorer, best player, best young player, best ' +
          'GK), full squads with DOB/position/club, attendance, and trivia notes. Use this when ' +
          'the user asks about a specific year ("1986 World Cup", "what happened at Italia 90"). ' +
          'For comparisons across multiple tournaments use compare_tournaments instead.',
        schema: z.object({
          year: z.number().int().min(1930).max(2030).describe('Tournament year, e.g. 1986'),
        }).strict(),
        handler: async (args: { year: number }) => api(`/tournaments/${args.year}`),
      },
      {
        name: 'compare_tournaments',
        description:
          'Side-by-side comparison of 2-6 World Cup tournaments. Returns total goals, goals ' +
          'per match, attendance, top scorer, best player, champion, runner-up, third place ' +
          'for each year. Use this when the user asks "compare 1986 vs 2022" or "what changed ' +
          'between 1990 and 2014". For a single year use get_tournament.',
        schema: z.object({
          years: z.array(z.number().int().min(1930).max(2030)).min(1).max(6)
            .describe('Years to compare, e.g. [1986, 2002, 2022]'),
        }).strict(),
        handler: async (args: { years: number[] }) =>
          api(`/compare?years=${args.years.join(',')}`),
      },
      {
        name: 'search_players',
        description:
          'Search players by name. Returns every World Cup squad row matching the query, ' +
          'with team, position, DOB, club, and tournament-year goals. Use this when the user ' +
          'mentions a player by name. For a player\'s full multi-tournament career path use ' +
          'get_player_career.',
        schema: z.object({
          q: z.string().min(2).describe('Name fragment, e.g. "Maradona", "Mbappe", "Klose"'),
          limit: z.number().int().min(1).max(50).optional()
            .describe('Max results (default 20)'),
        }).strict(),
        handler: async (args: { q: string; limit?: number }) => {
          const params = new URLSearchParams({ q: args.q });
          if (args.limit) params.set('limit', String(args.limit));
          return api(`/players?${params.toString()}`);
        },
      },
      {
        name: 'get_player_career',
        description:
          'Get a player\'s full World Cup career: every tournament they appeared in, with ' +
          'team/position/jersey/goals/captain status per year. Use this when the user wants a ' +
          '"all of Pelé\'s World Cup matches" or "compare Messi\'s 4 World Cups" view. The ' +
          'name should be the canonical name (use search_players first if unsure).',
        schema: z.object({
          name: z.string().min(2).describe('Player name, e.g. "Diego Maradona", "Lionel Messi"'),
        }).strict(),
        handler: async (args: { name: string }) =>
          api(`/players/${encodeURIComponent(args.name)}`),
      },
      {
        name: 'list_teams',
        description:
          'List every national team that has ever played a World Cup, with confederation, ' +
          'first/last appearance year, and total appearances. Useful for "which African nations ' +
          'have made the World Cup?" or "list every CONMEBOL team". Pair with get_team for a ' +
          'specific country.',
        schema: z.object({
          confederation: z.enum(['UEFA', 'CONMEBOL', 'CONCACAF', 'AFC', 'CAF', 'OFC']).optional()
            .describe('Filter by confederation (optional)'),
        }).strict(),
        handler: async (args: { confederation?: string }) => {
          const params = new URLSearchParams();
          if (args.confederation) params.set('confederation', args.confederation);
          const path = `/teams${params.toString() ? `?${params.toString()}` : ''}`;
          return api(path);
        },
      },
      {
        name: 'get_team',
        description:
          'Cross-tournament summary for a national team: every appearance, final position by ' +
          'year, total titles, knockout records. Use this for "Brazil\'s World Cup history" ' +
          'or "how many times has Argentina reached the final?". For a specific year\'s squad ' +
          'use get_team_roster.',
        schema: z.object({
          name: z.string().min(2).describe('Country name, e.g. "Brazil", "West Germany", "England"'),
        }).strict(),
        handler: async (args: { name: string }) =>
          api(`/teams/${encodeURIComponent(args.name)}`),
      },
      {
        name: 'get_team_roster',
        description:
          'Full squad for one team in one tournament — every player with jersey, position, ' +
          'DOB, club, goals, captain flag. Use this for "who was on Spain\'s 2010 squad?" or ' +
          '"show me Italy\'s 2006 roster".',
        schema: z.object({
          name: z.string().min(2).describe('Team name, e.g. "Brazil"'),
          year: z.number().int().min(1930).max(2030).describe('Tournament year'),
        }).strict(),
        handler: async (args: { name: string; year: number }) =>
          api(`/teams/${encodeURIComponent(args.name)}/roster?year=${args.year}`),
      },
      {
        name: 'list_stadiums',
        description:
          'List World Cup venues. 206 stadiums total across history, with capacity, lat/long, ' +
          'elevation in meters, opening year, and the list of WC years each one hosted. Useful ' +
          'for "which stadiums hosted the most World Cup matches?" or "where was the 1986 final?". ' +
          'Filterable by country.',
        schema: z.object({
          country: z.string().optional().describe('Filter by country, e.g. "Mexico", "Brazil"'),
        }).strict(),
        handler: async (args: { country?: string }) => {
          const path = args.country ? `/stadiums?country=${encodeURIComponent(args.country)}` : '/stadiums';
          return api(path);
        },
      },
      {
        name: 'get_stadium',
        description:
          'Single venue details by stable slug ID. Slugs are kebab-case ("estadio-azteca", ' +
          '"maracana", "wembley-stadium-old", "metlife-stadium"). Use list_stadiums first if ' +
          'you need to discover the right ID.',
        schema: z.object({
          id: z.string().min(2).describe('Stadium slug, e.g. "estadio-azteca"'),
        }).strict(),
        handler: async (args: { id: string }) => api(`/stadiums/${args.id}`),
      },
      {
        name: 'list_matches',
        description:
          'List World Cup matches. Filterable by year and/or stage (group_a..group_h, ' +
          'round_of_16, quarter_final, semi_final, third_place, final). Returns kickoff time, ' +
          'home/away team, score, stadium, attendance. Use this for "show me all the 1990 ' +
          'group matches" or "list every World Cup final". Pair with get_match for a specific ' +
          'match\'s full details.',
        schema: z.object({
          year:  z.number().int().min(1930).max(2030).optional().describe('Tournament year (optional)'),
          stage: z.string().optional().describe('Stage filter, e.g. "final", "semi_final", "group_a"'),
          date:  z.string().optional().describe('YYYY-MM-DD — match-day filter (optional)'),
        }).strict(),
        handler: async (args: { year?: number; stage?: string; date?: string }) => {
          const params = new URLSearchParams();
          if (args.year)  params.set('year',  String(args.year));
          if (args.stage) params.set('stage', args.stage);
          if (args.date)  params.set('date',  args.date);
          const q = params.toString();
          return api(`/matches${q ? `?${q}` : ''}`);
        },
      },
      {
        name: 'get_match',
        description:
          'Single match by ID. IDs follow {year}-{ordinal} zero-padded — the 1986 final is ' +
          '"1986-052", the 2022 final is "2022-064", the 2026 opener is "2026-001". Returns ' +
          'kickoff, both teams, score, extra time, penalties, stadium, city, attendance, referee, ' +
          'and (with denormalize=true) the full stadium block.',
        schema: z.object({
          id: z.string().regex(/^\d{4}-\d{3}$/).describe('Match ID, e.g. "1986-052"'),
          denormalize: z.boolean().optional().describe('Embed full stadium details (default false)'),
        }).strict(),
        handler: async (args: { id: string; denormalize?: boolean }) => {
          const q = args.denormalize ? '?denormalize=true' : '';
          return api(`/matches/${args.id}${q}`);
        },
      },
      {
        name: 'get_trivia',
        description:
          'Curated factual nuggets about a tournament — record-setting moments, oddities, ' +
          'historical context. Each entry is a single fact with category. Use this when the ' +
          'user wants "interesting facts about 1958" or "tell me something I don\'t know about ' +
          'Italia 90". Far less hallucination-prone than free-recall about old tournaments.',
        schema: z.object({
          year: z.number().int().min(1930).max(2030).optional().describe('Tournament year (optional — omit for all)'),
        }).strict(),
        handler: async (args: { year?: number }) => {
          const path = args.year ? `/trivia?year=${args.year}` : '/trivia';
          return api(path);
        },
      },
      {
        name: 'get_standings',
        description:
          'Computed group standings with FIFA tiebreakers applied. Returns the order teams ' +
          'finished within each group of the given year, including W/D/L, GF, GA, GD, points. ' +
          'Use this for "show me the 1990 Group F table" or "who finished where in 2022 Group H?".',
        schema: z.object({
          year:  z.number().int().min(1930).max(2030).describe('Tournament year'),
          group: z.string().regex(/^[A-Z]$/).optional().describe('Single group letter (optional)'),
        }).strict(),
        handler: async (args: { year: number; group?: string }) => {
          const params = new URLSearchParams({ year: String(args.year) });
          if (args.group) params.set('group', args.group);
          return api(`/standings?${params.toString()}`);
        },
      },
      {
        name: 'get_bracket',
        description:
          'Full knockout bracket for a tournament — Round of 16 through Final, with each ' +
          'match\'s teams + result. Use this for "show me the 2014 World Cup bracket" or ' +
          '"trace France\'s 2018 path to the title".',
        schema: z.object({
          year: z.number().int().min(1930).max(2030).describe('Tournament year'),
        }).strict(),
        handler: async (args: { year: number }) => api(`/bracket?year=${args.year}`),
      },
    ] as const;
  • Zod schema for list_stadiums: accepts an optional 'country' string parameter for filtering by country.
    schema: z.object({
      country: z.string().optional().describe('Filter by country, e.g. "Mexico", "Brazil"'),
    }).strict(),
  • The handler function for list_stadiums. If a country filter is provided, it calls `/stadiums?country=...`, otherwise calls `/stadiums`. Delegates to the shared `api()` helper.
    handler: async (args: { country?: string }) => {
      const path = args.country ? `/stadiums?country=${encodeURIComponent(args.country)}` : '/stadiums';
      return api(path);
    },
  • The `api()` helper function that all tool handlers (including list_stadiums) use to make authenticated HTTP requests to the Zafronix World Cup API.
    async function api<T = unknown>(path: string): Promise<T> {
      if (!API_KEY) {
        throw new Error(
          'WC_API_KEY is not set in the environment. Get a free key at ' +
          'https://api.zafronix.com/signup and add it to your MCP client ' +
          'config: { "env": { "WC_API_KEY": "zwc_pk_..." } }',
        );
      }
      const url = path.startsWith('http') ? path : `${API_BASE}${path}`;
      const res = await fetch(url, {
        headers: {
          'X-API-Key':  API_KEY,
          'Accept':     'application/json',
          'User-Agent': 'wc-mcp/0.1.2',
        },
      });
      if (!res.ok) {
        const body = await res.text().catch(() => '');
        throw new Error(`API ${res.status} ${res.statusText} on ${path}: ${body.slice(0, 240)}`);
      }
      return res.json() as Promise<T>;
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, description correctly discloses that the tool returns a list of 206 stadiums with specific fields, but does not mention pagination, rate limits, or auth requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three concise sentences: purpose, details, and examples. No redundant information, front-loaded with key action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and simple parameter, description covers returned fields, total count, and filter, but lacks details on sorting, default behavior, or how it differs from similar tools like 'get_stadium'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter 'country' has no schema description (0% coverage), but the description adds that it is a filter, providing some semantic meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 'List World Cup venues' and lists returned fields (capacity, lat/long, etc.), distinguishing it from siblings like 'get_stadium' which likely retrieves a single stadium.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides example queries ('which stadiums hosted the most World Cup matches?', 'where was the 1986 final?') and mentions filterability by country, giving clear usage context, though does not explicitly state when not to use or name alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zafronix/wc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server