| | import { z } from "zod"; |
| | import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; |
| | import { safeToolHandler } from "./base"; |
| | import * as userService from "../../leetcode/services/user"; |
| | import * as contestService from "../../leetcode/services/contest"; |
| | import * as problemService from "../../leetcode/services/problem"; |
| | import * as discussionService from "../../leetcode/services/discussion"; |
| |
|
| | export function register(mcp: McpServer): void { |
| | |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_rating", |
| | "Fetches the LeetCode contest rating for a user, including their global ranking, attended contests count, and rating percentile.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserRating(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_profile", |
| | "Fetches the complete LeetCode profile for a user, including basic info, company, school, skills, and social links.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserProfile(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_details", |
| | "Fetches detailed user information from LeetCode including profile data, submission stats, and problem solving summary.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserDetails(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_badges", |
| | "Fetches all badges earned by a LeetCode user, including annual badges and special achievements.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserBadges(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_solved", |
| | "Fetches the solved problems count for a LeetCode user, broken down by difficulty (Easy, Medium, Hard).", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserSolved(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_contest_ranking", |
| | "Fetches detailed contest ranking information for a LeetCode user, including rating, ranking, and top percentage.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserContest(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_contest_history", |
| | "Fetches the complete contest participation history for a LeetCode user, including each contest's ranking and rating changes.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserContestHistory(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_submissions", |
| | "Fetches recent submissions for a LeetCode user, including problem title, status, language, and timestamp.", |
| | { |
| | username: z.string().describe("The LeetCode username to look up"), |
| | limit: z.number().optional().default(20).describe("Maximum number of submissions to return (default: 20)") |
| | }, |
| | safeToolHandler(({ username, limit }) => userService.getUserSubmission(username, limit)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_ac_submissions", |
| | "Fetches recent accepted (AC) submissions for a LeetCode user, filtered to only show successful solutions.", |
| | { |
| | username: z.string().describe("The LeetCode username to look up"), |
| | limit: z.number().optional().default(20).describe("Maximum number of AC submissions to return (default: 20)") |
| | }, |
| | safeToolHandler(({ username, limit }) => userService.getUserAcSubmission(username, limit)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_calendar", |
| | "Fetches the submission calendar/heatmap data for a LeetCode user for a specific year, showing daily activity.", |
| | { |
| | username: z.string().describe("The LeetCode username to look up"), |
| | year: z.number().describe("The year to fetch calendar data for (e.g., 2024)") |
| | }, |
| | safeToolHandler(({ username, year }) => userService.getUserCalendar(username, year)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_skill_stats", |
| | "Fetches the skill/tag statistics for a LeetCode user, showing proficiency in different problem categories like DP, Graph, etc.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserSkill(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_languages", |
| | "Fetches the programming language statistics for a LeetCode user, showing problems solved per language.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserLanguage(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_progress", |
| | "Fetches the overall problem-solving progress for a LeetCode user across all categories.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => userService.getUserProgress(username)) |
| | ); |
| |
|
| | |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_contest_ranking_info", |
| | "Fetches detailed contest ranking information including rating, global rank, and percentile for a user.", |
| | { username: z.string().describe("The LeetCode username to look up") }, |
| | safeToolHandler(({ username }) => contestService.getContestRankingInfo(username)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_contest_histogram", |
| | "Fetches the contest rating distribution histogram showing how many users are at each rating level.", |
| | {}, |
| | safeToolHandler(() => contestService.getContestHistogram()) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_all_contests", |
| | "Fetches a list of all LeetCode contests including past weekly and biweekly contests with their details.", |
| | {}, |
| | safeToolHandler(() => contestService.getAllContests()) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_upcoming_contests", |
| | "Fetches a list of upcoming LeetCode contests that haven't started yet.", |
| | {}, |
| | safeToolHandler(() => contestService.getUpcomingContests()) |
| | ); |
| |
|
| | |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_daily_problem", |
| | "Fetches today's LeetCode Daily Challenge problem with its details, difficulty, and constraints.", |
| | { |
| | raw: z.boolean().optional().default(false).describe("Return raw API response if true (default: false)") |
| | }, |
| | safeToolHandler(({ raw }) => problemService.getDailyProblem(raw)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_problem", |
| | "Fetches detailed information about a specific LeetCode problem by its title slug (e.g., 'two-sum').", |
| | { |
| | titleSlug: z.string().describe("The URL slug of the problem (e.g., 'two-sum', 'add-two-numbers')"), |
| | raw: z.boolean().optional().default(false).describe("Return raw API response if true (default: false)") |
| | }, |
| | safeToolHandler(({ titleSlug, raw }) => problemService.getSelectProblem(titleSlug, raw)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_problems", |
| | "Fetches a filtered list of LeetCode problems with pagination, difficulty filter, and category support.", |
| | { |
| | limit: z.number().optional().default(20).describe("Number of problems to return"), |
| | skip: z.number().optional().default(0).describe("Number of problems to skip (for pagination)"), |
| | categorySlug: z.string().optional().describe("Category slug to filter by (e.g., 'algorithms', 'database')"), |
| | filters: z.object({ |
| | difficulty: z.string().optional().describe("Difficulty filter: 'EASY', 'MEDIUM', or 'HARD'"), |
| | tags: z.array(z.string()).optional().describe("Array of tag slugs to filter by") |
| | }).optional().describe("Optional filters object") |
| | }, |
| | safeToolHandler((params) => problemService.getProblems(params)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_official_solution", |
| | "Fetches the official LeetCode solution/editorial for a specific problem.", |
| | { |
| | titleSlug: z.string().describe("The URL slug of the problem (e.g., 'two-sum')") |
| | }, |
| | safeToolHandler(({ titleSlug }) => problemService.getOfficialSolution(titleSlug)) |
| | ); |
| |
|
| | |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_trending_discussions", |
| | "Fetches the top trending discussions from LeetCode's discussion forum.", |
| | { |
| | first: z.number().optional().default(10).describe("Number of trending discussions to return (default: 10)") |
| | }, |
| | safeToolHandler(({ first }) => discussionService.getTrendingDiscuss(first)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_discussion_topic", |
| | "Fetches a specific discussion topic by its ID, including the full content and metadata.", |
| | { |
| | topicId: z.number().describe("The numeric ID of the discussion topic") |
| | }, |
| | safeToolHandler(({ topicId }) => discussionService.getDiscussTopic(topicId)) |
| | ); |
| |
|
| | |
| | mcp.tool( |
| | "leetcode_get_discussion_comments", |
| | "Fetches comments/replies on a specific LeetCode discussion topic.", |
| | { |
| | topicId: z.number().describe("The numeric ID of the discussion topic"), |
| | orderBy: z.string().optional().default("hot").describe("Order by: 'hot', 'newest', or 'oldest'"), |
| | pageNo: z.number().optional().default(1).describe("Page number for pagination"), |
| | numPerPage: z.number().optional().default(10).describe("Number of comments per page") |
| | }, |
| | safeToolHandler((params) => discussionService.getDiscussComments(params)) |
| | ); |
| | } |
| |
|