Skip to content

Commit ebadfd7

Browse files
committed
Add source code files
1 parent 80b074c commit ebadfd7

File tree

8 files changed

+716
-0
lines changed

8 files changed

+716
-0
lines changed

src/graphql/queries.ts

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
export const userProfileQuery = `
2+
query getUserProfile($username: String!) {
3+
matchedUser(username: $username) {
4+
username
5+
submitStats: submitStatsGlobal {
6+
acSubmissionNum {
7+
difficulty
8+
count
9+
submissions
10+
}
11+
totalSubmissionNum {
12+
difficulty
13+
count
14+
submissions
15+
}
16+
}
17+
profile {
18+
ranking
19+
reputation
20+
starRating
21+
realName
22+
aboutMe
23+
userAvatar
24+
skillTags
25+
country
26+
company
27+
school
28+
websites
29+
countryName
30+
location
31+
contestCount
32+
asciiCode
33+
socialAccounts
34+
skillSet {
35+
langLevels {
36+
langName
37+
langVerboseName
38+
level
39+
}
40+
topics {
41+
slug
42+
name
43+
level
44+
}
45+
}
46+
}
47+
}
48+
}
49+
`;
50+
51+
export const userSubmissionsQuery = `
52+
query recentSubmissions($username: String!, $limit: Int!) {
53+
recentSubmissionList(username: $username, limit: $limit) {
54+
id
55+
title
56+
titleSlug
57+
timestamp
58+
statusDisplay
59+
lang
60+
__typename
61+
}
62+
}
63+
`;
64+
65+
export const dailyChallengeQuery = `
66+
query questionOfToday {
67+
activeDailyCodingChallengeQuestion {
68+
date
69+
userStatus
70+
link
71+
question {
72+
acRate
73+
difficulty
74+
freqBar
75+
frontendQuestionId: questionFrontendId
76+
isFavor
77+
paidOnly: isPaidOnly
78+
status
79+
title
80+
titleSlug
81+
hasVideoSolution
82+
hasSolution
83+
topicTags {
84+
name
85+
id
86+
slug
87+
}
88+
}
89+
}
90+
}
91+
`;
92+
93+
export const problemDetailsQuery = `
94+
query questionData($titleSlug: String!) {
95+
question(titleSlug: $titleSlug) {
96+
questionId
97+
questionFrontendId
98+
boundTopicId
99+
title
100+
titleSlug
101+
content
102+
translatedTitle
103+
difficulty
104+
likes
105+
dislikes
106+
isLiked
107+
similarQuestions
108+
exampleTestcases
109+
contributors {
110+
username
111+
profileUrl
112+
avatarUrl
113+
}
114+
topicTags {
115+
name
116+
slug
117+
}
118+
companyTagStats
119+
codeSnippets {
120+
lang
121+
langSlug
122+
code
123+
}
124+
stats
125+
hints
126+
solution {
127+
id
128+
canSeeDetail
129+
paidOnly
130+
hasVideoSolution
131+
}
132+
status
133+
sampleTestCase
134+
metaData
135+
judgerAvailable
136+
judgeType
137+
mysqlSchemas
138+
enableRunCode
139+
enableTestMode
140+
enableDebugger
141+
envInfo
142+
}
143+
}
144+
`;
145+
146+
export const searchProblemsQuery = `
147+
query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) {
148+
problemsetQuestionList: questionList(
149+
categorySlug: $categorySlug
150+
limit: $limit
151+
skip: $skip
152+
filters: $filters
153+
) {
154+
total: totalNum
155+
questions: data {
156+
acRate
157+
difficulty
158+
freqBar
159+
frontendQuestionId: questionFrontendId
160+
isFavor
161+
paidOnly: isPaidOnly
162+
status
163+
title
164+
titleSlug
165+
topicTags {
166+
name
167+
id
168+
slug
169+
}
170+
hasSolution
171+
hasVideoSolution
172+
}
173+
}
174+
}
175+
`;
176+
177+
export const contestDetailsQuery = `
178+
query contestData($contestSlug: String!) {
179+
contest(titleSlug: $contestSlug) {
180+
title
181+
titleSlug
182+
description
183+
startTime
184+
duration
185+
originStartTime
186+
isVirtual
187+
questions {
188+
questionId
189+
title
190+
titleSlug
191+
difficulty
192+
}
193+
}
194+
}
195+
`;
196+
197+
export const userContestRankingQuery = `
198+
query userContestRankingInfo($username: String!) {
199+
userContestRanking(username: $username) {
200+
attendedContestsCount
201+
rating
202+
globalRanking
203+
totalParticipants
204+
topPercentage
205+
badge {
206+
name
207+
}
208+
}
209+
userContestRankingHistory(username: $username) {
210+
attended
211+
trendDirection
212+
problemsSolved
213+
totalProblems
214+
finishTimeInSeconds
215+
rating
216+
ranking
217+
contest {
218+
title
219+
startTime
220+
}
221+
}
222+
}
223+
`;

src/index.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3+
import { LeetCodeService } from "./services/leetcode-service.js";
4+
import { registerProblemTools } from "./tools/problem-tools.js";
5+
import { registerUserTools } from "./tools/user-tools.js";
6+
import { registerContestTools } from "./tools/contest-tools.js";
7+
import { registerProblemResources } from "./resources/problem-resources.js";
8+
import { registerUserResources } from "./resources/user-resources.js";
9+
10+
async function main() {
11+
// Create the MCP Server
12+
const server = new McpServer({
13+
name: "LeetCode MCP Server",
14+
version: "1.0.0"
15+
});
16+
17+
// Initialize the LeetCode service
18+
const leetcodeService = new LeetCodeService();
19+
20+
// Register tools
21+
registerProblemTools(server, leetcodeService);
22+
registerUserTools(server, leetcodeService);
23+
registerContestTools(server, leetcodeService);
24+
25+
// Register resources
26+
registerProblemResources(server, leetcodeService);
27+
registerUserResources(server, leetcodeService);
28+
29+
// Connect with stdio transport
30+
const transport = new StdioServerTransport();
31+
await server.connect(transport);
32+
33+
console.error("LeetCode MCP Server running");
34+
}
35+
36+
main().catch(error => {
37+
console.error("Fatal error:", error);
38+
process.exit(1);
39+
});

src/resources/problem-resources.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2+
import { LeetCodeService } from "../services/leetcode-service.js";
3+
4+
export function registerProblemResources(server: McpServer, leetcodeService: LeetCodeService) {
5+
// Daily challenge resource
6+
server.resource(
7+
"daily-challenge",
8+
"leetcode://daily-challenge",
9+
async (uri) => {
10+
try {
11+
const data = await leetcodeService.fetchDailyChallenge();
12+
return {
13+
contents: [{
14+
uri: uri.href,
15+
text: JSON.stringify(data, null, 2),
16+
mimeType: "application/json"
17+
}]
18+
};
19+
} catch (error: unknown) {
20+
const errorMessage = error instanceof Error ? error.message : String(error);
21+
throw new Error(`Failed to fetch daily challenge: ${errorMessage}`);
22+
}
23+
}
24+
);
25+
26+
// Problem details resource
27+
server.resource(
28+
"problem-details",
29+
new ResourceTemplate("leetcode://problem/{titleSlug}", { list: undefined }),
30+
async (uri, variables) => {
31+
const titleSlug = variables.titleSlug as string;
32+
try {
33+
const data = await leetcodeService.fetchProblem(titleSlug);
34+
return {
35+
contents: [{
36+
uri: uri.href,
37+
text: JSON.stringify(data, null, 2),
38+
mimeType: "application/json"
39+
}]
40+
};
41+
} catch (error: unknown) {
42+
const errorMessage = error instanceof Error ? error.message : String(error);
43+
throw new Error(`Failed to fetch problem details: ${errorMessage}`);
44+
}
45+
}
46+
);
47+
48+
// Problems list resource
49+
server.resource(
50+
"problems-list",
51+
new ResourceTemplate("leetcode://problems{?tags,difficulty,limit,skip}", { list: undefined }),
52+
async (uri, variables) => {
53+
const tags = variables.tags as string | undefined;
54+
const difficulty = variables.difficulty as string | undefined;
55+
const limit = variables.limit as string | undefined;
56+
const skip = variables.skip as string | undefined;
57+
try {
58+
const data = await leetcodeService.searchProblems(
59+
tags as string | undefined,
60+
difficulty as string | undefined,
61+
parseInt(limit as string || "20"),
62+
parseInt(skip as string || "0")
63+
);
64+
return {
65+
contents: [{
66+
uri: uri.href,
67+
text: JSON.stringify(data, null, 2),
68+
mimeType: "application/json"
69+
}]
70+
};
71+
} catch (error: unknown) {
72+
const errorMessage = error instanceof Error ? error.message : String(error);
73+
throw new Error(`Failed to fetch problems list: ${errorMessage}`);
74+
}
75+
}
76+
);
77+
}

0 commit comments

Comments
 (0)