File size: 6,911 Bytes
3d23b0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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))
    );
}