Lint JavaScript/TypeScript files via the official ESLint MCP server
How do I lint JS/TS files through MCP and get structured ESLint diagnostics — rule ID, line, column, message, and auto-fix suggestions — without running eslint CLI directly?
Recipe: Lint JS/TS with @eslint/mcp via stdio
Server: @eslint/mcp v0.3.6 (npm: npx @eslint/mcp) SDK: @modelcontextprotocol/sdk v1.29.0 Transport: stdio — NDJSON framing (newline-delimited JSON, NOT Content-Length headers). Each message is JSON\n. Tools: 1 tool — lint-files Prereqs: Project must have an ESLint config (eslint.config.mjs or similar) and eslint + @eslint/js installed.
Wire protocol (critical)
SDK v1.29.0 switched from Content-Length: N\r\n\r\n{json} to plain newline-delimited JSON: send {json}\n, receive {json}\n. If you send Content-Length framing, the server silently ignores you (zero bytes on stdout). This applies to ALL MCP servers using SDK ≥1.x recent versions.
Tool: lint-files
Input: { filePaths: string[] } — array of absolute file paths. Output: Array of text content blocks. The middle block contains a JSON-stringified ESLint result object per file with: filePath, messages[] (each with ruleId, severity, message, line, column, suggestions[]), errorCount, warningCount, source.
Latency
- Initialize: ~236ms (cold npx start)
- tools/list: ~2ms
- tools/call (lint-files): ~49ms for a single file
- Total handshake→result: ~287ms
Failure modes
- Missing ESLint config → ESLint throws "No ESLint configuration found"
- Relative file paths → may resolve incorrectly depending on cwd
- No
eslintin node_modules → import fails at server startup
{ "server": "@eslint/mcp", "version": "0.3.6", "sdk": "@modelcontextprotocol/[email protected]", "transport": "stdio", "framing": "ndjson", "launch": "npx @eslint/mcp", "handshake": [ { "direction": "client→server", "message": { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "pathfinder-probe", "version": "1.0.0" } } } }, { "direction": "server→client", "elapsed_ms": 236, "message": { "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": { "listChanged": true } }, "serverInfo": { "name": "ESLint", "version": "0.3.6" } }, "jsonrpc": "2.0", "id": 1 } }, { "direction": "client→server", "message": { "jsonrpc": "2.0", "method": "notifications/initialized" } }, { "direction": "client→server", "message": { "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} } }, { "direction": "server→client", "elapsed_ms": 238, "message": { "result": { "tools": [ { "name": "lint-files", "description": "Lint files using ESLint. You must provide a list of absolute file paths to the files you want to lint.", "inputSchema": { "type": "object", "properties": { "filePaths": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1 } }, "required": ["filePaths"], "additionalProperties": false } } ] }, "jsonrpc": "2.0", "id": 2 } } ], "tool_call": { "direction": "client→server", "message": { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "lint-files", "arguments": { "filePaths": ["/tmp/eslint-mcp-test/test.js"] } } } }, "tool_result": { "direction": "server→client", "elapsed_ms": 287, "message": { "result": { "content": [ { "type": "text", "text": "Here are the results of running ESLint on the provided files. Before doing anything else, you must display the full list to the user:" }, { "type": "text", "text": "{"filePath":"/tmp/eslint-mcp-test/test.js","messages":[{"ruleId":"no-unused-vars","severity":2,"message":"'y' is assigned a value but never used.","line":2,"column":5},{"ruleId":"no-undef","severity":2,"message":"'console' is not defined.","line":3,"column":1},{"ruleId":"no-unused-vars","severity":2,"message":"'unused' is defined but never used.","line":5,"column":10},{"ruleId":"no-constant-condition","severity":2,"message":"Unexpected constant condition.","line":9,"column":5},{"ruleId":"no-unused-vars","severity":2,"message":"'z' is assigned a value but never used.","line":10,"column":7}],"errorCount":5,"fatalErrorCount":0,"warningCount":0}" }, { "type": "text", "text": "If the user asked to fix any issues found, proceed in fixing them." } ] }, "jsonrpc": "2.0", "id": 3 } }, "test_file_content": "var x = 1; var y = 2; console.log(x) function unused() { return 42; } if (true) { var z = "hello" } ", "eslint_config": "import js from '@eslint/js'; export default [js.configs.recommended];", "total_latency_ms": 287, "errors_found": 5, "rules_triggered": ["no-unused-vars", "no-undef", "no-constant-condition"] }