diff --git a/README.md b/README.md index 781539b..d19d8c4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,14 @@ ```bash npm install -g @sperekrestova/interactive-leetcode-mcp +interactive-leetcode-mcp --version +interactive-leetcode-mcp --help +``` + +You can also run the package without installing it globally: + +```bash +npx -y @sperekrestova/interactive-leetcode-mcp@latest --version ``` ### From Source @@ -44,6 +52,24 @@ npm install && npm run build npm link ``` +### Fresh Environment Smoke Test + +Use this to verify the published npm package from a clean directory without any +LeetCode credentials: + +```bash +mkdir leetcode-mcp-smoke +cd leetcode-mcp-smoke +npm init -y +npm install @sperekrestova/interactive-leetcode-mcp +npx --no-install interactive-leetcode-mcp --version +npx --no-install interactive-leetcode-mcp --help +``` + +Those commands confirm that Node can install the package and expose the CLI +binary. For actual MCP server validation, use an integration test that connects +over stdio and completes the MCP handshake. + ## Configuration ### Claude Code & Claude Desktop @@ -61,7 +87,7 @@ Or add to your MCP configuration file (`~/.config/claude-code/mcp.json`) or (`~/ "mcpServers": { "leetcode": { "command": "npx", - "args": ["-y", "interactive-leetcode-mcp"] + "args": ["-y", "@sperekrestova/interactive-leetcode-mcp@latest"] } } } @@ -117,6 +143,14 @@ Claude: "🎉 Accepted! Runtime: 2ms (beats 95.3%)" ## Available Tools +### Getting Started + +**`get_started`** + +- Returns the server usage guide, learning flow, authentication flow, and + submission language map +- Call this at the start of a LeetCode practice session + ### Authorization **`start_leetcode_auth`** @@ -156,6 +190,56 @@ Claude: "🎉 Accepted! Runtime: 2ms (beats 95.3%)" - Search problems by difficulty, tags, keywords - Supports filtering and pagination +### Session and Learning Tools + +**`start_problem`** + +- Opens or resumes a tutoring session for a problem +- Parameters: `titleSlug`, optional `language` +- Required before problem-specific hint and solution tools + +**`request_hint`** + +- Advances progressive hint levels for the active session +- Parameters: `titleSlug` +- Unlocks community solution tools after the final hint level + +**`get_session_state`** + +- Shows current hint level and session metadata +- Parameters: `titleSlug` + +**`reset_session`** + +- Resets hint progress for a problem +- Parameters: `titleSlug` + +### Local Runner Tools + +**`runner_doctor`** + +- Reports which local runtimes are available for supported languages + +**`run_local_tests`** + +- Runs user code against sample tests in a local subprocess sandbox +- Parameters: `titleSlug`, `language`, `code`, optional `timeoutMs` + +### Solution Tools + +**`list_problem_solutions`** + +- Lists community/editorial solution articles for a problem +- Parameters: `questionSlug`, optional `limit`, `skip`, `orderBy`, `userInput`, + `tagSlugs` +- Requires the session to reach the solution-unlocked hint level + +**`get_problem_solution`** + +- Fetches a specific solution article +- Parameters: `topicId`, `titleSlug` +- Requires the session to reach the solution-unlocked hint level + ### Submission Tools **`submit_solution`** @@ -170,10 +254,30 @@ Claude: "🎉 Accepted! Runtime: 2ms (beats 95.3%)" - Retrieve user profile information -**`get_user_submissions`** +**`get_recent_submissions`** - Get submission history with filtering +**`get_recent_ac_submissions`** + +- Get recent accepted submissions + +**`get_user_status`** + +- Get authenticated user's status/profile summary + +**`get_problem_submission_report`** + +- Get submission report for one problem + +**`get_problem_progress`** + +- Get solved/attempted progress for a problem + +**`get_all_submissions`** + +- Get paginated submission history + **`get_user_contest_ranking`** - View contest performance and rankings @@ -213,10 +317,14 @@ Guides you through the complete cycle: To activate learning mode, tell Claude you want to practice with guidance — for example, "Let's practice in learning mode" or "I want to learn two-sum with hints." Once active: -1. **Fetch a problem** to see the description and get workspace setup guidance -2. **Ask for hints** rather than solutions ("Give me a hint") -3. **Implement your solution** with progressive guidance -4. **Request the solution** only when you want to compare with optimal approach ("Show me the solution") +1. **Call `get_started`** to load the server's usage guide +2. **Fetch a problem** with `get_daily_challenge`, `search_problems`, or + `get_problem` +3. **Open a session** with `start_problem` +4. **Ask for hints** via `request_hint` rather than jumping straight to solutions +5. **Implement your solution** with progressive guidance +6. **Request the solution** only after the final hint level or when you want to + compare with an optimal approach ## Dogfood Testing diff --git a/eslint.config.js b/eslint.config.js index 8004052..1c90077 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -15,7 +15,7 @@ export default defineConfig([ rules: { ...prettierRules }, - languageOptions: { globals: globals.browser } + languageOptions: { globals: globals.node } }, tseslint.configs.recommended, { @@ -31,5 +31,15 @@ export default defineConfig([ } ] } + }, + { + files: ["**/*.cjs"], + languageOptions: { + sourceType: "commonjs", + globals: globals.node + }, + rules: { + "@typescript-eslint/no-require-imports": "off" + } } ]); diff --git a/package-lock.json b/package-lock.json index 5ccba66..ea6de07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,10 +24,8 @@ "@types/minimist": "^1.2.5", "@types/node": "^22.14.0", "@vitest/coverage-v8": "^4.1.8", - "esbuild": "^0.28.1", "eslint": "^9.24.0", "eslint-config-prettier": "^10.1.2", - "eslint-plugin-prettier": "^5.2.6", "globals": "^16.0.0", "husky": "^9.1.7", "lint-staged": "^15.5.1", @@ -992,19 +990,6 @@ "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", "license": "MIT" }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", @@ -2541,37 +2526,6 @@ "eslint": ">=7.0.0" } }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.12" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -2860,13 +2814,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4691,19 +4638,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/prettier-plugin-organize-imports": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.3.0.tgz", @@ -5372,22 +5306,6 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, "node_modules/thread-stream": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", diff --git a/package.json b/package.json index f1fc3a2..3475a66 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "test:coverage": "vitest run --exclude 'tests/e2e/**' --coverage", "test:watch": "vitest watch", "test:types": "tsc -p tsconfig.test.json", + "lint": "eslint .", "build": "tsc && chmod u+x build/index.js", "start": "node build/index.js", "dev": "tsc-watch --onSuccess \"node build/index.js\"", @@ -77,10 +78,8 @@ "@types/minimist": "^1.2.5", "@types/node": "^22.14.0", "@vitest/coverage-v8": "^4.1.8", - "esbuild": "^0.28.1", "eslint": "^9.24.0", "eslint-config-prettier": "^10.1.2", - "eslint-plugin-prettier": "^5.2.6", "globals": "^16.0.0", "husky": "^9.1.7", "lint-staged": "^15.5.1", diff --git a/src/leetcode/schemas.ts b/src/leetcode/schemas.ts index 3a62f9c..1f10a25 100644 --- a/src/leetcode/schemas.ts +++ b/src/leetcode/schemas.ts @@ -76,6 +76,3 @@ export const ValidateCredentialsResponseSchema = z .passthrough() }) .passthrough(); - -export type SubmitResponse = z.infer; -export type CheckResponse = z.infer;