codex-review-mcp 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,33 +2,86 @@ import 'dotenv/config';
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
4
  import { z } from 'zod';
5
+ import { readFileSync } from 'node:fs';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { dirname, join } from 'node:path';
5
8
  import { performCodeReview } from './tools/performCodeReview.js';
6
- const server = new McpServer({ name: 'codex-review-mcp', version: '0.1.0' });
9
+ // Read version from package.json
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
13
+ const VERSION = packageJson.version;
14
+ const server = new McpServer({ name: 'codex-review-mcp', version: VERSION });
15
+ server.registerTool('get_version', {
16
+ title: 'Get Version',
17
+ description: 'Get the version of the codex-review-mcp server.',
18
+ inputSchema: {}, // Empty schema - no parameters required
19
+ }, async () => {
20
+ return {
21
+ content: [{
22
+ type: 'text',
23
+ text: `codex-review-mcp version ${VERSION}`,
24
+ mimeType: 'text/plain'
25
+ }]
26
+ };
27
+ });
7
28
  server.registerTool('perform_code_review', {
8
29
  title: 'Perform Code Review',
9
- description: 'Review git diffs in the current repo and return actionable Markdown feedback. In auto mode (default), reviews uncommitted changes if present, otherwise reviews current branch vs default branch. No need to commit changes first - the tool reviews your working tree.',
30
+ description: `Review code/diffs using GPT-5 Codex with expert prompts and project-specific context.
31
+
32
+ 🎯 USAGE:
33
+
34
+ 1. Get the code/diff to review:
35
+ const diff = await runCommand("git diff");
36
+
37
+ 2. Optionally gather project context:
38
+ const rules = await readFile(".cursor/rules/project.mdc");
39
+
40
+ 3. Call with content:
41
+ await perform_code_review({
42
+ content: diff, // REQUIRED
43
+ contentType: "diff", // "diff" or "code"
44
+ customContext: rules, // Optional: saves tokens!
45
+ focus: "security and performance" // Optional: specific focus
46
+ });
47
+
48
+ 💡 KEY BENEFITS:
49
+ - Expert Reviews: GPT-5 Codex with project-specific context
50
+ - Codebase-Aware: Checks YOUR patterns, enforces YOUR rules
51
+ - Efficient: Provide customContext to skip auto-gathering
52
+
53
+ 📋 PARAMETERS:
54
+ - content: Code or diff to review (REQUIRED)
55
+ - contentType: "diff" | "code"
56
+ - customContext: Project rules/guidelines (saves tokens if provided)
57
+ - skipContextGathering: Skip auto-gathering if you don't need context
58
+ - focus: Specific areas to review (e.g., "security", "performance")
59
+ - workspaceDir: Base directory for context gathering (defaults to cwd)`,
10
60
  inputSchema: {
11
- target: z.enum(['auto', 'staged', 'head', 'range']).default('auto'),
12
- baseRef: z.string().optional(),
13
- headRef: z.string().optional(),
14
- focus: z.string().optional(),
15
- paths: z.array(z.string()).optional(),
16
- maxTokens: z.number().optional(),
17
- workspaceDir: z.string().optional().describe('Absolute path to the workspace/repository directory. If not provided, attempts to detect from environment or current working directory.'),
61
+ // REQUIRED
62
+ content: z.string().describe('Code or diff content to review (REQUIRED). Agent should run git commands or read files to get this.'),
63
+ // CONTENT TYPE
64
+ contentType: z.enum(['diff', 'code']).optional().describe('Type of content: "diff" for git diffs, "code" for static code review'),
65
+ // CONTEXT OPTIONS
66
+ customContext: z.string().optional().describe('⭐ RECOMMENDED: Project context (.cursor/rules, CODE_REVIEW.md, etc). Saves tokens and time!'),
67
+ skipContextGathering: z.boolean().optional().describe('Set to true to skip automatic context gathering (useful if no context needed)'),
68
+ workspaceDir: z.string().optional().describe('Base directory for context gathering (defaults to current directory)'),
69
+ // REVIEW OPTIONS
70
+ focus: z.string().optional().describe('Specific areas to focus on (e.g., "security and performance")'),
71
+ maxTokens: z.number().optional().describe('Maximum tokens for review response'),
18
72
  },
19
73
  }, async (input, extra) => {
20
74
  try {
21
75
  const reviewInput = {
22
- target: input.target,
23
- baseRef: input.baseRef,
24
- headRef: input.headRef,
76
+ content: input.content,
77
+ contentType: input.contentType,
78
+ workspaceDir: input.workspaceDir,
79
+ customContext: input.customContext,
80
+ skipContextGathering: input.skipContextGathering,
25
81
  focus: input.focus,
26
- paths: input.paths,
27
82
  maxTokens: input.maxTokens,
28
- workspaceDir: input.workspaceDir,
29
83
  };
30
84
  const onProgress = async (message, progress, total) => {
31
- // Attach to tool-call request via related request ID so clients can map progress
32
85
  await server.server.notification({
33
86
  method: 'notifications/progress',
34
87
  params: {
@@ -1,6 +1,10 @@
1
- export function buildPrompt({ diffText, context, focus }) {
1
+ export function buildPrompt({ diffText, context, focus, version, isStaticReview }) {
2
2
  const focusLine = focus ? `Focus areas: ${focus}.` : '';
3
+ const versionLine = version ? `codex-review-mcp v${version}` : '';
4
+ const reviewType = isStaticReview ? 'Static File Review' : 'Diff Review';
3
5
  return [
6
+ versionLine,
7
+ '',
4
8
  'You are an expert AI code reviewer. Be concise, specific, and actionable.',
5
9
  'Prefer minimal diffs and direct fixes.',
6
10
  '',
@@ -38,7 +42,7 @@ export function buildPrompt({ diffText, context, focus }) {
38
42
  '3. Does this follow the exact conventions shown in the project documentation?',
39
43
  '4. Would this change maintain consistency with the surrounding code?',
40
44
  '',
41
- '\n---\nScope and Diff (unified=0):\n',
45
+ `\n---\n${reviewType}${isStaticReview ? ' - Code Files' : ' (unified=0)'}:\n`,
42
46
  diffText,
43
47
  context ? '\n---\nProject context and guidelines (FOLLOW THESE STRICTLY):\n' + context : '',
44
48
  '\n---\nOutput strictly as Markdown with the following sections:\n',
@@ -0,0 +1,113 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildPrompt } from './buildPrompt.js';
3
+ describe('buildPrompt', () => {
4
+ const mockDiff = `diff --git a/test.ts b/test.ts
5
+ +++ b/test.ts
6
+ +export function hello() {
7
+ + return "world";
8
+ +}`;
9
+ it('should include version in prompt when provided', () => {
10
+ const prompt = buildPrompt({
11
+ diffText: mockDiff,
12
+ version: '1.4.0',
13
+ });
14
+ expect(prompt).toContain('codex-review-mcp v1.4.0');
15
+ expect(prompt.startsWith('codex-review-mcp v1.4.0')).toBe(true);
16
+ });
17
+ it('should not include version line when version is not provided', () => {
18
+ const prompt = buildPrompt({
19
+ diffText: mockDiff,
20
+ });
21
+ expect(prompt).not.toContain('codex-review-mcp v');
22
+ });
23
+ it('should indicate "Diff Review" when isStaticReview is false', () => {
24
+ const prompt = buildPrompt({
25
+ diffText: mockDiff,
26
+ isStaticReview: false,
27
+ });
28
+ expect(prompt).toContain('Diff Review (unified=0)');
29
+ });
30
+ it('should indicate "Static File Review" when isStaticReview is true', () => {
31
+ const prompt = buildPrompt({
32
+ diffText: 'File: test.ts\ncode here',
33
+ isStaticReview: true,
34
+ });
35
+ expect(prompt).toContain('Static File Review - Code Files');
36
+ });
37
+ it('should default to "Diff Review" when isStaticReview is not provided', () => {
38
+ const prompt = buildPrompt({
39
+ diffText: mockDiff,
40
+ });
41
+ expect(prompt).toContain('Diff Review (unified=0)');
42
+ });
43
+ it('should include focus areas when provided', () => {
44
+ const prompt = buildPrompt({
45
+ diffText: mockDiff,
46
+ focus: 'security and performance',
47
+ });
48
+ expect(prompt).toContain('Focus areas: security and performance');
49
+ });
50
+ it('should include context when provided', () => {
51
+ const context = 'This is a TypeScript project using React';
52
+ const prompt = buildPrompt({
53
+ diffText: mockDiff,
54
+ context,
55
+ });
56
+ expect(prompt).toContain('Project context and guidelines (FOLLOW THESE STRICTLY)');
57
+ expect(prompt).toContain(context);
58
+ });
59
+ it('should include all required sections', () => {
60
+ const prompt = buildPrompt({
61
+ diffText: mockDiff,
62
+ });
63
+ // Verify key sections are present
64
+ expect(prompt).toContain('You are an expert AI code reviewer');
65
+ expect(prompt).toContain('CRITICAL REPO-SPECIFIC GUIDANCE HIERARCHY');
66
+ expect(prompt).toContain('MANDATORY REVIEW REQUIREMENTS');
67
+ expect(prompt).toContain('SPECIFIC TECHNICAL GUIDELINES');
68
+ expect(prompt).toContain('Output strictly as Markdown with the following sections');
69
+ });
70
+ it('should include the diff text', () => {
71
+ const prompt = buildPrompt({
72
+ diffText: mockDiff,
73
+ });
74
+ expect(prompt).toContain(mockDiff);
75
+ });
76
+ it('should handle all parameters together', () => {
77
+ const prompt = buildPrompt({
78
+ diffText: mockDiff,
79
+ version: '1.4.0',
80
+ isStaticReview: true,
81
+ focus: 'code quality',
82
+ context: 'TypeScript best practices',
83
+ });
84
+ expect(prompt).toContain('codex-review-mcp v1.4.0');
85
+ expect(prompt).toContain('Static File Review - Code Files');
86
+ expect(prompt).toContain('Focus areas: code quality');
87
+ expect(prompt).toContain('TypeScript best practices');
88
+ expect(prompt).toContain(mockDiff);
89
+ });
90
+ it('should include POSIX environment assumption', () => {
91
+ const prompt = buildPrompt({
92
+ diffText: mockDiff,
93
+ });
94
+ expect(prompt).toContain('ENVIRONMENT ASSUMPTION: The runtime and tooling are POSIX (macOS/Linux)');
95
+ expect(prompt).toContain('Do NOT suggest Windows/PowerShell/cmd-specific commands');
96
+ });
97
+ it('should include z-index warning', () => {
98
+ const prompt = buildPrompt({
99
+ diffText: mockDiff,
100
+ });
101
+ expect(prompt).toContain('CRITICAL Z-INDEX WARNING');
102
+ expect(prompt).toContain('z-index changes on modals, overlays, or components');
103
+ });
104
+ it('should include guidance hierarchy with proper priorities', () => {
105
+ const prompt = buildPrompt({
106
+ diffText: mockDiff,
107
+ });
108
+ expect(prompt).toContain('1. HIGHEST PRIORITY: Project documentation');
109
+ expect(prompt).toContain('2. Configuration files');
110
+ expect(prompt).toContain('3. Existing patterns in similar files');
111
+ expect(prompt).toContain('4. General best practices');
112
+ });
113
+ });