vortex / src /modules /mcp /tools /codeforces.ts
anujjoshi3105's picture
first commit
3d23b0f
import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { safeToolHandler } from "./base";
import * as service from "../../codeforces/service";
/**
* Registers all Codeforces-related MCP tools.
*/
export function register(mcp: McpServer): void {
// Get user rating
mcp.tool(
"codeforces_get_rating",
"Fetches a Codeforces user's current rating, rank, max rating, contribution score, and avatar URL.",
{ username: z.string().describe("The Codeforces handle (username)") },
safeToolHandler(({ username }) => service.getUserRating(username))
);
// Get contest history
mcp.tool(
"codeforces_get_contest_history",
"Fetches the complete contest participation history for a Codeforces user, including rating changes after each contest.",
{ username: z.string().describe("The Codeforces handle (username)") },
safeToolHandler(({ username }) => service.getContestHistory(username))
);
// Get user status (submissions)
mcp.tool(
"codeforces_get_user_status",
"Fetches recent submissions for a Codeforces user with verdict, problem info, and submission details.",
{
username: z.string().describe("The Codeforces handle (username)"),
from: z.number().optional().default(1).describe("1-based index of the first submission to return (default: 1)"),
count: z.number().optional().default(10).describe("Number of submissions to return (default: 10)")
},
safeToolHandler(({ username, from, count }) => service.getUserStatus(username, from, count))
);
// Get user blog entries
mcp.tool(
"codeforces_get_user_blogs",
"Fetches all blog entries authored by a Codeforces user, including titles, ratings, and creation times.",
{ username: z.string().describe("The Codeforces handle (username)") },
safeToolHandler(({ username }) => service.getUserBlogs(username))
);
// Get solved problems
mcp.tool(
"codeforces_get_solved_problems",
"Fetches all problems solved by a Codeforces user, including problem ratings, tags, and direct links.",
{ username: z.string().describe("The Codeforces handle (username)") },
safeToolHandler(({ username }) => service.getSolvedProblems(username))
);
// Get contests list
mcp.tool(
"codeforces_get_contests",
"Fetches the list of all Codeforces contests (past and upcoming), optionally including gym contests.",
{ gym: z.boolean().optional().default(false).describe("If true, include gym contests (default: false)") },
safeToolHandler(({ gym }) => service.getContests(gym))
);
// Get recent actions
mcp.tool(
"codeforces_get_recent_actions",
"Fetches recent actions on Codeforces such as new blog entries and comments.",
{ maxCount: z.number().optional().default(20).describe("Maximum number of actions to return (default: 20, max: 100)") },
safeToolHandler(({ maxCount }) => service.getRecentActions(maxCount))
);
// Get problemset problems
mcp.tool(
"codeforces_get_problems",
"Fetches all problems from the Codeforces problemset, optionally filtered by tags.",
{ tags: z.string().optional().describe("Semicolon-separated tags to filter problems (e.g., 'dp;greedy')") },
safeToolHandler(({ tags }) => service.getProblems(tags))
);
// Get contest standings
mcp.tool(
"codeforces_get_contest_standings",
"Fetches the standings/leaderboard for a specific Codeforces contest with participant rankings and scores.",
{
contestId: z.number().describe("The numeric ID of the contest"),
from: z.number().optional().describe("1-based index of the first standing row"),
count: z.number().optional().describe("Number of standings rows to return"),
handles: z.string().optional().describe("Semicolon-separated handles to filter the standings"),
room: z.number().optional().describe("Room number to filter standings"),
showUnofficial: z.boolean().optional().describe("Include unofficial participants")
},
safeToolHandler(({ contestId, from, count, handles, room, showUnofficial }) =>
service.getContestStandings(contestId, from, count, handles, room, showUnofficial)
)
);
// Get contest rating changes
mcp.tool(
"codeforces_get_contest_rating_changes",
"Fetches the rating changes for all participants in a specific Codeforces contest.",
{ contestId: z.number().describe("The numeric ID of the contest") },
safeToolHandler(({ contestId }) => service.getContestRatingChanges(contestId))
);
// Get contest hacks
mcp.tool(
"codeforces_get_contest_hacks",
"Fetches all successful and unsuccessful hacks that occurred during a Codeforces contest.",
{ contestId: z.number().describe("The numeric ID of the contest") },
safeToolHandler(({ contestId }) => service.getContestHacks(contestId))
);
// Get contest status (submissions)
mcp.tool(
"codeforces_get_contest_status",
"Fetches submissions made in a specific Codeforces contest, optionally filtered by a handle.",
{
contestId: z.number().describe("The numeric ID of the contest"),
handle: z.string().optional().describe("Optional handle to filter submissions"),
from: z.number().optional().describe("1-based index of the first submission"),
count: z.number().optional().describe("Number of submissions to return")
},
safeToolHandler(({ contestId, handle, from, count }) =>
service.getContestStatus(contestId, handle, from, count)
)
);
// Get problemset recent status
mcp.tool(
"codeforces_get_problemset_recent_status",
"Fetches the most recent submissions across the entire Codeforces problemset.",
{ count: z.number().describe("Number of recent submissions to return (max: 1000)") },
safeToolHandler(({ count }) => service.getProblemsetRecentStatus(count))
);
// Get blog entry
mcp.tool(
"codeforces_get_blog_entry",
"Fetches the full content of a specific Codeforces blog entry by its ID.",
{ blogEntryId: z.number().describe("The numeric ID of the blog entry") },
safeToolHandler(({ blogEntryId }) => service.getBlogEntry(blogEntryId))
);
// Get blog comments
mcp.tool(
"codeforces_get_blog_comments",
"Fetches all comments on a specific Codeforces blog entry.",
{ blogEntryId: z.number().describe("The numeric ID of the blog entry") },
safeToolHandler(({ blogEntryId }) => service.getBlogComments(blogEntryId))
);
}