@j0hanz/code-review-analyst-mcp 1.3.0 → 1.4.1

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.
@@ -1,6 +1,7 @@
1
1
  import { validateContextBudget } from '../lib/context-budget.js';
2
2
  import { validateDiffBudget } from '../lib/diff-budget.js';
3
3
  import { computeDiffStatsAndSummaryFromFiles, parseDiffFiles, } from '../lib/diff-parser.js';
4
+ import { createNoDiffError } from '../lib/diff-store.js';
4
5
  import { requireToolContract } from '../lib/tool-contracts.js';
5
6
  import { registerStructuredToolTask } from '../lib/tool-factory.js';
6
7
  import { InspectCodeQualityInputSchema } from '../schemas/inputs.js';
@@ -49,31 +50,11 @@ ${sanitizeContent(file.content)}
49
50
  }
50
51
  return `${FILE_CONTEXT_HEADING}${fileBlocks.join('\n')}`;
51
52
  }
52
- function buildInspectPrompt(input) {
53
- const parsedFiles = parseDiffFiles(input.diff);
54
- const { summary: fileSummary } = computeDiffStatsAndSummaryFromFiles(parsedFiles);
55
- const fileContext = formatFileContext(input.files);
56
- const languageLine = formatOptionalLine('Language', input.language);
57
- const maxFindingsLine = formatOptionalLine('Max Findings', input.maxFindings);
58
- const noFilesNote = !input.files?.length
59
- ? '\nNote: No file context provided. Leave contextualInsights empty.'
60
- : '';
61
- return `
62
- Repository: ${input.repository}${languageLine}
63
- Focus Areas: ${input.focusAreas?.join(', ') ?? DEFAULT_FOCUS_AREAS}${maxFindingsLine}${noFilesNote}
64
- Changed Files:
65
- ${fileSummary}
66
-
67
- Diff:
68
- ${input.diff}
69
- ${fileContext}
70
- `;
71
- }
72
53
  export function registerInspectCodeQualityTool(server) {
73
54
  registerStructuredToolTask(server, {
74
55
  name: 'inspect_code_quality',
75
56
  title: 'Inspect Code Quality',
76
- description: 'Deep-dive code review with optional file context.',
57
+ description: 'Deep code review. Prerequisite: generate_diff. Auto-infer repo/language/focus. Provide file content for best results.',
77
58
  inputSchema: InspectCodeQualityInputSchema,
78
59
  fullInputSchema: InspectCodeQualityInputSchema,
79
60
  resultSchema: CodeQualityOutputSchema,
@@ -89,13 +70,16 @@ export function registerInspectCodeQualityTool(server) {
89
70
  const fileCount = input.files?.length;
90
71
  return fileCount ? `+${fileCount} files` : '';
91
72
  },
92
- formatOutcome: (result) => `${result.findings.length} findings, risk: ${result.overallRisk}`,
93
- validateInput: (input) => {
94
- const diffError = validateDiffBudget(input.diff);
73
+ validateInput: (input, ctx) => {
74
+ const slot = ctx.diffSlot;
75
+ if (!slot)
76
+ return createNoDiffError();
77
+ const diffError = validateDiffBudget(slot.diff);
95
78
  if (diffError)
96
79
  return diffError;
97
- return validateContextBudget(input.diff, input.files);
80
+ return validateContextBudget(slot.diff, input.files);
98
81
  },
82
+ formatOutcome: (result) => `${result.findings.length} findings, risk: ${result.overallRisk}`,
99
83
  formatOutput: (result) => {
100
84
  const count = result.findings.length;
101
85
  const total = result.totalFindings ?? count;
@@ -109,9 +93,29 @@ export function registerInspectCodeQualityTool(server) {
109
93
  const cappedFindings = capFindings(result.findings, input.maxFindings);
110
94
  return { ...result, findings: cappedFindings, totalFindings };
111
95
  },
112
- buildPrompt: (input) => ({
113
- systemInstruction: SYSTEM_INSTRUCTION,
114
- prompt: buildInspectPrompt(input),
115
- }),
96
+ buildPrompt: (input, ctx) => {
97
+ const diff = ctx.diffSlot?.diff ?? '';
98
+ const parsedFiles = parseDiffFiles(diff);
99
+ const { summary: fileSummary } = computeDiffStatsAndSummaryFromFiles(parsedFiles);
100
+ const fileContext = formatFileContext(input.files);
101
+ const languageLine = formatOptionalLine('Language', input.language);
102
+ const maxFindingsLine = formatOptionalLine('Max Findings', input.maxFindings);
103
+ const noFilesNote = !input.files?.length
104
+ ? '\nNote: No file context provided. Leave contextualInsights empty.'
105
+ : '';
106
+ return {
107
+ systemInstruction: SYSTEM_INSTRUCTION,
108
+ prompt: `
109
+ Repository: ${input.repository}${languageLine}
110
+ Focus Areas: ${input.focusAreas?.join(', ') ?? DEFAULT_FOCUS_AREAS}${maxFindingsLine}${noFilesNote}
111
+ Changed Files:
112
+ ${fileSummary}
113
+
114
+ Diff:
115
+ ${diff}
116
+ ${fileContext}
117
+ `,
118
+ };
119
+ },
116
120
  });
117
121
  }
@@ -1,5 +1,6 @@
1
1
  import { validateDiffBudget } from '../lib/diff-budget.js';
2
2
  import { extractChangedPathsFromFiles, parseDiffFiles, } from '../lib/diff-parser.js';
3
+ import { createNoDiffError } from '../lib/diff-store.js';
3
4
  import { requireToolContract } from '../lib/tool-contracts.js';
4
5
  import { registerStructuredToolTask } from '../lib/tool-factory.js';
5
6
  import { SuggestSearchReplaceInputSchema } from '../schemas/inputs.js';
@@ -14,23 +15,11 @@ const TOOL_CONTRACT = requireToolContract('suggest_search_replace');
14
15
  function formatPatchCount(count) {
15
16
  return `${count} ${count === 1 ? 'patch' : 'patches'}`;
16
17
  }
17
- function buildSuggestSearchReplacePrompt(input) {
18
- const files = parseDiffFiles(input.diff);
19
- const paths = extractChangedPathsFromFiles(files);
20
- return `
21
- Finding: ${input.findingTitle}
22
- Details: ${input.findingDetails}
23
- Changed Files: ${paths.join(', ')}
24
-
25
- Diff:
26
- ${input.diff}
27
- `;
28
- }
29
18
  export function registerSuggestSearchReplaceTool(server) {
30
19
  registerStructuredToolTask(server, {
31
20
  name: 'suggest_search_replace',
32
21
  title: 'Suggest Search & Replace',
33
- description: 'Generate search-and-replace blocks to fix a finding.',
22
+ description: 'Generate fix patches. Prerequisite: inspect_code_quality findings. Pass verbatim finding title/details.',
34
23
  inputSchema: SuggestSearchReplaceInputSchema,
35
24
  fullInputSchema: SuggestSearchReplaceInputSchema,
36
25
  resultSchema: SearchReplaceResultSchema,
@@ -41,16 +30,33 @@ export function registerSuggestSearchReplaceTool(server) {
41
30
  ...(TOOL_CONTRACT.thinkingBudget !== undefined
42
31
  ? { thinkingBudget: TOOL_CONTRACT.thinkingBudget }
43
32
  : undefined),
44
- validateInput: (input) => validateDiffBudget(input.diff),
33
+ validateInput: (_input, ctx) => {
34
+ const slot = ctx.diffSlot;
35
+ if (!slot)
36
+ return createNoDiffError();
37
+ return validateDiffBudget(slot.diff);
38
+ },
45
39
  formatOutcome: (result) => formatPatchCount(result.blocks.length),
46
40
  formatOutput: (result) => {
47
41
  const count = result.blocks.length;
48
42
  const patches = formatPatchCount(count);
49
43
  return `${result.summary}\n${patches} • Checklist: ${result.validationChecklist.join(' | ')}`;
50
44
  },
51
- buildPrompt: (input) => ({
52
- systemInstruction: SYSTEM_INSTRUCTION,
53
- prompt: buildSuggestSearchReplacePrompt(input),
54
- }),
45
+ buildPrompt: (input, ctx) => {
46
+ const diff = ctx.diffSlot?.diff ?? '';
47
+ const files = parseDiffFiles(diff);
48
+ const paths = extractChangedPathsFromFiles(files);
49
+ return {
50
+ systemInstruction: SYSTEM_INSTRUCTION,
51
+ prompt: `
52
+ Finding: ${input.findingTitle}
53
+ Details: ${input.findingDetails}
54
+ Changed Files: ${paths.join(', ')}
55
+
56
+ Diff:
57
+ ${diff}
58
+ `,
59
+ };
60
+ },
55
61
  });
56
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@j0hanz/code-review-analyst-mcp",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "mcpName": "io.github.j0hanz/code-review-analyst",
5
5
  "description": "Gemini-powered MCP server for code review analysis.",
6
6
  "type": "module",
@@ -32,7 +32,6 @@
32
32
  },
33
33
  "scripts": {
34
34
  "clean": "node scripts/tasks.mjs clean",
35
- "validate:instructions": "node scripts/tasks.mjs validate:instructions",
36
35
  "build": "node scripts/tasks.mjs build",
37
36
  "copy:assets": "node scripts/tasks.mjs copy:assets",
38
37
  "prepare": "npm run build",
@@ -1,7 +0,0 @@
1
- # CODE REVIEW ANALYST MCP INSTRUCTIONS
2
-
3
- Runtime instructions are generated from `src/lib/tool-contracts.ts` by
4
- `buildServerInstructions()` in `src/resources/instructions.ts`.
5
-
6
- This file is kept as a packaging placeholder for build pipelines that expect an
7
- `instructions.md` artifact in `dist/`.