Skip to main content
Glama
kodaimaehata

Cursor Reviewer MCP

by kodaimaehata

cursor.review

Execute automated code reviews using GPT-5 through Cursor CLI. Analyze target files against reference documentation and review requests to generate structured JSON feedback with audit logging.

Instructions

Review deliverables via Cursor CLI (GPT‑5) and return review JSON only.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
targetsYesレビュー対象ファイル一覧(表示名とパス)
previous_reviewsNo前回レビュー結果JSON(must_fixes/チェックリスト等)への参照一覧
referenceYesレビューで参照すべきドキュメント一覧(表示名とパス)
review_requestYesレビューワへの依頼文(自然文)
timeout_msNo外部レビュー実行のタイムアウト(ミリ秒)
policyNo将来予約(LGTM基準等)。初期バージョンは null 固定・不使用

Implementation Reference

  • The primary handler function `runCursorReview` for the 'cursor.review' tool. It builds a prompt, calls the Cursor CLI via `cursor-agent`, parses the JSON output (with fallback retry), extracts embedded review JSON, persists it, and returns the review object.
    export async function runCursorReview(input: ReviewInput): Promise<any> { const prompt = buildPrompt(input); const timeout = input.timeout_ms ?? 1_800_000; // 30m default try { return await callCursorAndParse(prompt, timeout); } catch (_) { const retryPrompt = `${prompt}\n\n重要: 必ずJSONのみを返し、説明文やコードフェンスは含めないこと。`; return await callCursorAndParse(retryPrompt, timeout); } } async function callCursorAndParse(prompt: string, timeoutMs: number): Promise<any> { const allowPlainFallback = process.env.REVIEWER_MCP_ALLOW_PLAINTEXT_FALLBACK === '1' || process.env.REVIEWER_MCP_ALLOW_PLAINTEXT_FALLBACK === 'true'; let stdout: string; try { ({ stdout } = await execWithTimeout( 'cursor-agent', ['-p', '--model', 'gpt-5', '--output-format', 'json', prompt], timeoutMs )); } catch (e: any) { if (e && (e.code === 'ENOENT' || /ENOENT/.test(e.message))) { throw new Error("Cursor CLI not found: install 'cursor-agent'."); } throw e; } // First parse: Cursor CLI JSON let top: any; try { top = JSON.parse(stdout.trim()); } catch (e) { throw new Error(`Cursor output is not valid JSON: ${(e as Error).message}`); } if (typeof top !== 'object' || top === null) { throw new Error('Cursor JSON missing object'); } if (typeof top.result !== 'string') { if (allowPlainFallback) { try { return JSON.stringify(top.result); } catch { return String(top.result); } } throw new Error('Cursor JSON missing string field "result"'); } // Second parse: The actual review JSON inside `result` try { const extracted = extractJsonString(top.result); if (!extracted) { if (allowPlainFallback) { return top.result.trim(); } throw new Error('Could not locate JSON in Cursor result'); } const reviewObj = JSON.parse(extracted); persistReview(reviewObj); return reviewObj; } catch (e) { if (allowPlainFallback) { return top.result.trim(); } throw new Error(`Review JSON parse failed: ${(e as Error).message}`); } }
  • src/server.ts:64-80 (registration)
    Registration of the 'cursor.review' tool in the MCP server's `listTools` response, defining its metadata and referencing the input schema.
    return ListToolsResultSchema.parse({ tools: [ { name: 'cursor.review', title: 'Run review via Cursor (GPT‑5)', description: 'Review deliverables via Cursor CLI (GPT‑5) and return review JSON only.', inputSchema: cursorInputSchema }, { name: 'codex.review', title: 'Run review via Codex CLI', description: 'Review deliverables via Codex CLI and return review JSON only.', inputSchema: codexInputSchema } ] }); });
  • Dispatch logic in the MCP `callTool` handler that invokes `runCursorReview` when the tool name is 'cursor.review'.
    const review = name === 'cursor.review' ? await runCursorReview(input) : await runCodexReview(input);
  • TypeScript type definitions for `ReviewInput` and supporting types, which define the structure matching the tool's input schema.
    export type Target = { file: string; path: string }; export type Reference = { file: string; path: string }; export type ReviewInput = { targets: Target[]; reference: Reference[]; previous_reviews?: Reference[]; review_request: string; timeout_ms?: number; policy?: string | null; };
  • Helper function `buildPrompt` that generates the review prompt from the tool input by loading a template and interpolating targets, references, and previous reviews.
    export function buildPrompt(input: ReviewInput): string { const tmplPathOverride = process.env.REVIEWER_MCP_TEMPLATE_PATH; const tmplPath = tmplPathOverride ?? fileURLToPath(new URL('./prompt/template.txt', import.meta.url)); const tmpl = readFileSync(tmplPath, 'utf8'); const targets_json = JSON.stringify(input.targets, null, 2); const reference_json = JSON.stringify(input.reference, null, 2); const prevList = input.previous_reviews ?? []; const previous_reviews_objects: any[] = []; for (const p of prevList) { try { const raw = readFileSync(p.path, 'utf8'); const obj = JSON.parse(raw); previous_reviews_objects.push({ file: p.file, path: p.path, review: obj }); } catch { previous_reviews_objects.push({ file: p.file, path: p.path, review: null, error: 'unreadable_or_invalid_json' }); } } const previous_reviews_json = JSON.stringify(previous_reviews_objects, null, 2); const follow_up_instructions = prevList.length > 0 ? '前回レビュー(must_fixes と acceptance_checklist)に基づき、各指摘が解消済みかを厳密に確認し、未解消の場合は理由と改善指示を明確に示してください。新規の懸念点があれば suggestions に含めてください。出力はJSONのみです。' : ''; return tmpl .replace('{{review_request}}', input.review_request) .replace('{{targets_json}}', targets_json) .replace('{{reference_json}}', reference_json) .replace('{{previous_reviews_json}}', previous_reviews_json) .replace('{{follow_up_instructions}}', follow_up_instructions); }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kodaimaehata/reviewer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server