ctftime_top_teams
Retrieve top CTF teams ranked for a specified year, or the current year if no year is given.
Instructions
Get top teams for a year (or current year if year omitted).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| year | No | Year (e.g., 2025). | |
| limit | No | Max teams (1-100). |
Implementation Reference
- src/index.ts:113-144 (registration)Registration of the 'ctftime_top_teams' tool using server.registerTool(). This is where the tool is registered with the MCP server, including its name, description, input schema (year and limit), and the handler callback.
server.registerTool( "ctftime_top_teams", { description: "Get top teams for a year (or current year if year omitted).", inputSchema: { year: z .number() .int() .min(2011) .max(2100) .optional() .describe("Year (e.g., 2025)."), limit: z .number() .int() .min(1) .max(100) .default(10) .describe("Max teams (1-100)."), }, }, async ({ year, limit }) => { const base = year ? `${CTFtime_API_BASE}/top/${year}/` : `${CTFtime_API_BASE}/top/`; const url = `${base}${qs({ limit })}`; const data = await getJson<any[]>(url); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], }; } ); - src/index.ts:134-143 (handler)Handler function for ctftime_top_teams. Constructs the CTFtime API URL (with optional year and limit query params), fetches data via getJson helper, and returns the result as JSON text content.
async ({ year, limit }) => { const base = year ? `${CTFtime_API_BASE}/top/${year}/` : `${CTFtime_API_BASE}/top/`; const url = `${base}${qs({ limit })}`; const data = await getJson<any[]>(url); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], }; } - src/index.ts:115-132 (schema)Input schema for ctftime_top_teams using Zod validation. Defines optional 'year' (int, 2011-2100) and optional 'limit' (int, 1-100, default 10).
{ description: "Get top teams for a year (or current year if year omitted).", inputSchema: { year: z .number() .int() .min(2011) .max(2100) .optional() .describe("Year (e.g., 2025)."), limit: z .number() .int() .min(1) .max(100) .default(10) .describe("Max teams (1-100)."), }, - src/index.ts:9-26 (helper)Generic helper function getJson<T> used by the handler to fetch JSON from the CTFtime API. Also used by all other tools.
async function getJson<T>(url: string): Promise<T> { const res = await fetch(url, { headers: { Accept: "application/json", // CTFtime doesn't require a UA header for this API, but it helps with debugging and etiquette. "User-Agent": "mcp-ctftime/0.1.0 (+https://ctftime.org/api/)", }, }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error( `CTFtime API error ${res.status} for ${url}${ text ? `: ${text.slice(0, 300)}` : "" }` ); } return (await res.json()) as T; } - src/index.ts:28-36 (helper)Helper function qs (query string builder) used to construct URL query parameters, used by the ctftime_top_teams handler to append the limit parameter.
function qs(params: Record<string, string | number | undefined>): string { const u = new URLSearchParams(); for (const [k, v] of Object.entries(params)) { if (v === undefined) continue; u.set(k, String(v)); } const s = u.toString(); return s ? `?${s}` : ""; }