Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "interactive-leetcode-mcp",
"owner": {
"name": "SPerekrestova"
},
"metadata": {
"description": "Interactive LeetCode MCP server plugin for Claude Code"
},
"plugins": [
{
"name": "interactive-leetcode-mcp",
"source": ".",
"description": "Interactive LeetCode practice with learning-guided hints, solution submission, and AI-driven authentication via MCP server",
"version": "3.2.0",
"homepage": "https://github.com/SPerekrestova/interactive-leetcode-mcp",
"keywords": ["leetcode", "mcp", "practice", "coding-interview"],
"category": "learning"
}
]
}
12 changes: 12 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "interactive-leetcode-mcp",
"description": "Interactive LeetCode practice with learning-guided hints, solution submission, and AI-driven authentication via MCP server",
"version": "3.2.0",
"author": {
"name": "SPerekrestova"
},
"homepage": "https://github.com/SPerekrestova/interactive-leetcode-mcp",
"repository": "https://github.com/SPerekrestova/interactive-leetcode-mcp",
"license": "MIT",
"keywords": ["leetcode", "mcp", "practice", "coding-interview", "learning"]
}
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,29 @@ To activate learning mode, tell Claude you want to practice with guidance — fo
- LeetCode may be experiencing high traffic - wait and retry
- Check your internet connection

## Skills & Plugins

This repo also ships an **agent skill** that teaches Claude (and other AI agents) how to use the MCP server correctly — including session flow, prompt invocations, learning mode, and authentication.

### Claude Code Plugin

Install the skill directly as a Claude Code plugin:

```
/plugin marketplace add SPerekrestova/interactive-leetcode-mcp
/plugin install interactive-leetcode-mcp@interactive-leetcode-mcp
```

Then start a practice session with:

```
/interactive-leetcode-mcp:interactive-leetcode-mcp
```

### ClawHub (OpenClaw / Clawbot)

The skill is also published on [ClawHub](https://clawhub.ai/SPerekrestova/interactive-leetcode) for use with OpenClaw-compatible agents.

## Acknowledgements

Forked from [Leetcode mcp](https://github.com/jinzcdev/leetcode-mcp-server))
Expand Down
161 changes: 161 additions & 0 deletions clawhub-skill/interactive-leetcode-mcp/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
name: interactive-leetcode-mcp
description: Use when the user wants to practice LeetCode problems, submit solutions, or set up LeetCode integration. Covers MCP server installation, learning-guided practice flow, solution submission, and authentication.
homepage: https://github.com/SPerekrestova/interactive-leetcode-mcp
disable-model-invocation: true
metadata:
clawdbot:
requires:
bins: [npx]
config: [~/.leetcode-mcp/credentials.json]
credentials:
stores: ~/.leetcode-mcp/credentials.json
contents: csrftoken, LEETCODE_SESSION, createdAt timestamp
permissions: "0600"
---

# Interactive LeetCode MCP

MCP server for LeetCode practice with learning-guided hints, solution submission, and AI-driven authentication.

## Prerequisite: Ensure MCP Server Is Connected

Before anything else, check whether the `get_started` tool is available. If it is, the server is connected — skip to the next section.

**If `get_started` is NOT available**, the MCP server needs to be installed. **Ask the user for confirmation before proceeding** — explain that this will download and run an npm package.

The npm package is [`@sperekrestova/interactive-leetcode-mcp`](https://www.npmjs.com/package/@sperekrestova/interactive-leetcode-mcp) (source: [GitHub](https://github.com/SPerekrestova/interactive-leetcode-mcp)). It runs over stdio transport. Requires Node.js >= 20.

After the user confirms, add to the client's MCP configuration (the exact file varies by client):

```json
{
"mcpServers": {
"leetcode": {
"command": "npx",
"args": ["-y", "@sperekrestova/interactive-leetcode-mcp@3.2.0"]
}
}
}
```

For Claude Code specifically, you can also run:

```bash
claude mcp add --transport stdio leetcode -- npx -y @sperekrestova/interactive-leetcode-mcp@3.2.0
```

**Pin a specific version** (shown above) rather than using `@latest` to avoid executing untested code. Users can check for newer versions at the [npm page](https://www.npmjs.com/package/@sperekrestova/interactive-leetcode-mcp) or [GitHub releases](https://github.com/SPerekrestova/interactive-leetcode-mcp/releases) and update the pinned version after reviewing the changelog.

After adding the server, tell the user to restart their session so the MCP tools become available. Do not proceed with the session flow until `get_started` is accessible.

## First Action: Always Call get_started

At the START of every LeetCode session, call the `get_started` tool. It returns the full usage guide: prompt invocation rules, session flow, learning mode rules, auth flow, and language map.

**Do not skip this** — it is a single fast call, not redundant with tool descriptions. The server has MCP prompts that must be explicitly invoked — they are NOT auto-active. The `get_started` response tells you exactly when and how.

## Session Flow (Critical)

```
1. Call get_started <-- FIRST, every session
2. Invoke leetcode_learning_mode <-- BEFORE any problem discussion
3. User picks a problem
4. Invoke leetcode_problem_workflow(problemSlug, difficulty)
5. Invoke leetcode_workspace_setup(language, problemSlug, codeTemplate)
6. Guide user with progressive hints (4 levels)
7. submit_solution when ready
```

Steps 2, 4, and 5 are MCP prompt invocations. Invoke them via the Skill tool or equivalent prompt mechanism. All three must happen BEFORE the user starts coding.

**Step 2 is non-negotiable.** If you skip `leetcode_learning_mode`, you will bypass the progressive hint system and may show solutions prematurely. Invoke it before searching for or discussing any problem.

## Prompt Invocation Rules

| Prompt | When | Params |
| ------------------------------- | --------------------------------------- | ----------------------------------- |
| `leetcode_learning_mode` | START of session, before any problem | none |
| `leetcode_problem_workflow` | After user selects a problem | problemSlug, difficulty |
| `leetcode_workspace_setup` | Before user starts coding | language, problemSlug, codeTemplate |
| `leetcode_authentication_guide` | On auth need, 401 errors, expired creds | none |

## Learning Mode Rules

- Never show a full solution without working through hint levels 1 → 2 → 3
- Level 1: Guiding questions ("What pattern do you see?")
- Level 2: General approaches ("Consider using a hash map...")
- Level 3: Specific hints ("Iterate once, tracking seen values...")
- Level 4: Pseudocode or partial implementation
- Only show complete solutions when explicitly requested AFTER earlier hints
- `get_problem_solution` returns full community solutions — Level 4 or explicit request only

## Tool Quick Reference

| Tool | Purpose | Auth? |
| ------------------------------- | -------------------------------- | ------- |
| `get_daily_challenge` | Today's challenge | No |
| `get_problem` | Problem by slug | No |
| `search_problems` | Find by tags/difficulty/keywords | No |
| `list_problem_solutions` | Solution metadata (topicIds) | No |
| `get_problem_solution` | Full solution — **Level 4 only** | No |
| `submit_solution` | Submit code | No\* |
| `get_user_profile` | Any user's stats | No |
| `get_recent_submissions` | Recent submissions | No |
| `get_recent_ac_submissions` | Accepted submissions | No |
| `get_user_contest_ranking` | Contest ranking | No |
| `start_leetcode_auth` | Start auth flow | No |
| `save_leetcode_credentials` | Validate + save creds | No |
| `check_auth_status` | Check credential state | No |
| `get_user_status` | Current user info | **Yes** |
| `get_problem_submission_report` | Submission detail | **Yes** |
| `get_problem_progress` | Progress with filters | **Yes** |
| `get_all_submissions` | All submissions | **Yes** |

\*`submit_solution` requires saved credentials to succeed.

## Auth Flow

1. Before auth-sensitive actions → call `check_auth_status`
2. If not authenticated or expired → **ask the user if they want to authenticate.** Explain that this will store LeetCode session cookies locally at `~/.leetcode-mcp/credentials.json` (owner-read/write only). Do not proceed without consent.
3. After consent → invoke `leetcode_authentication_guide` prompt
4. Call `start_leetcode_auth` → the prompt will guide the user through providing credentials → call `save_leetcode_credentials` with the values the user provides
5. On success → retry original action
6. On 401 from any tool → repeat from step 1

**Always delegate auth guidance to the `leetcode_authentication_guide` prompt.** Do not improvise your own auth instructions — the prompt handles browser-specific guidance, error recovery, and troubleshooting.

**Credential storage:** The MCP server stores credentials locally at `~/.leetcode-mcp/credentials.json` with file permissions `0o600` (owner-read/write only). Only `csrftoken`, `LEETCODE_SESSION`, and a `createdAt` timestamp are stored. Credentials are never transmitted to any third party — they are used exclusively for direct LeetCode API calls. Typical credential lifetime is 7-14 days.

## Submission Language Map

| User says | Pass to submit_solution |
| ----------------- | ----------------------- |
| Python / Python 3 | `python3` |
| Python 2 | `python` |
| Java | `java` |
| C++ | `cpp` |
| JavaScript | `javascript` |
| TypeScript | `typescript` |

Default: "Python" without version → `python3`.

## Resources (Read-Only Lookups)

| Resource URI | What it provides |
| --------------------------- | ------------------------------------------------ |
| `categories://problems/all` | All problem categories |
| `tags://problems/all` | All 60+ topic tags |
| `langs://problems/all` | All supported submission languages |
| `problem://{titleSlug}` | Problem detail |
| `solution://{topicId}` | Solution detail (same learning-mode rules apply) |

## Common Mistakes

- Jumping to problem search before invoking `leetcode_learning_mode`
- Showing full solutions without progressing through hint levels 1 → 2 → 3
- Not invoking `leetcode_workspace_setup` — code should live in a file, not only in chat
- Guiding auth manually instead of invoking `leetcode_authentication_guide`
- Passing `"Python"` to `submit_solution` instead of `"python3"`
- Not calling `check_auth_status` before auth-sensitive operations
- Skipping `get_started` and assuming tool descriptions are sufficient
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@sperekrestova/interactive-leetcode-mcp",
"description": "Interactive LeetCode MCP server with authorization and submission capabilities for seamless problem-solving with Claude",
"version": "3.1.0",
"version": "3.2.0",
"mcpName": "io.github.SPerekrestova/interactive-leetcode-mcp",
"author": "SPerekrestova",
"main": "./build/index.js",
Expand Down Expand Up @@ -31,7 +31,7 @@
"dev": "tsc-watch --onSuccess \"node build/index.js\"",
"format": "prettier --write .",
"prepare": "husky",
"sync-version": "node -e \"const pkg=require('./package.json');const server=require('./server.json');server.version=pkg.version;server.packages[0].version=pkg.version;require('fs').writeFileSync('server.json',JSON.stringify(server,null,4)+'\\n')\"",
"sync-version": "node scripts/sync-version.cjs",
"prepublishOnly": "npm run sync-version && npm run build"
},
"bin": {
Expand Down
69 changes: 69 additions & 0 deletions scripts/sync-version.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env node

/**
* Syncs the version from package.json to:
* - server.json (MCP registry metadata)
* - .claude-plugin/plugin.json (Claude Code plugin manifest)
* - All SKILL.md files (pinned npm package version in install instructions)
*
* Run: npm run sync-version
* Runs automatically before publish via prepublishOnly hook.
*/

const fs = require("fs");
const path = require("path");

const ROOT = path.resolve(__dirname, "..");
const pkg = require(path.join(ROOT, "package.json"));
const version = pkg.version;

// --- server.json ---
const serverPath = path.join(ROOT, "server.json");
const server = JSON.parse(fs.readFileSync(serverPath, "utf-8"));
server.version = version;
server.packages[0].version = version;
fs.writeFileSync(serverPath, JSON.stringify(server, null, 4) + "\n");

// --- .claude-plugin/plugin.json ---
const pluginPath = path.join(ROOT, ".claude-plugin", "plugin.json");
if (fs.existsSync(pluginPath)) {
const plugin = JSON.parse(fs.readFileSync(pluginPath, "utf-8"));
plugin.version = version;
fs.writeFileSync(pluginPath, JSON.stringify(plugin, null, 2) + "\n");
}

// --- .claude-plugin/marketplace.json ---
const marketplacePath = path.join(ROOT, ".claude-plugin", "marketplace.json");
if (fs.existsSync(marketplacePath)) {
const marketplace = JSON.parse(fs.readFileSync(marketplacePath, "utf-8"));
for (const p of marketplace.plugins || []) {
p.version = version;
}
fs.writeFileSync(
marketplacePath,
JSON.stringify(marketplace, null, 2) + "\n"
);
}

// --- SKILL.md files (update pinned @version in install instructions) ---
const skillPaths = [
"skills/interactive-leetcode-mcp/SKILL.md",
".claude/skills/using-interactive-leetcode-mcp/SKILL.md",
"clawhub-skill/interactive-leetcode-mcp/SKILL.md",
];

const versionPattern =
/@sperekrestova\/interactive-leetcode-mcp@[\w.-]+/g;
const versionReplacement = `@sperekrestova/interactive-leetcode-mcp@${version}`;

for (const rel of skillPaths) {
const fullPath = path.join(ROOT, rel);
if (!fs.existsSync(fullPath)) continue;
const content = fs.readFileSync(fullPath, "utf-8");
const updated = content.replace(versionPattern, versionReplacement);
if (updated !== content) {
fs.writeFileSync(fullPath, updated);
}
}

console.log(`Synced version ${version} to all targets.`);
4 changes: 2 additions & 2 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
"url": "https://github.com/SPerekrestova/interactive-leetcode-mcp",
"source": "github"
},
"version": "3.1.0",
"version": "3.2.0",
"packages": [
{
"registryType": "npm",
"identifier": "@sperekrestova/interactive-leetcode-mcp",
"version": "3.1.0",
"version": "3.2.0",
"transport": {
"type": "stdio"
},
Expand Down
Loading