@j0hanz/code-review-analyst-mcp 1.7.0 → 1.7.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.
package/README.md CHANGED
@@ -12,13 +12,13 @@ Gemini-powered MCP server for pull request analysis with structured outputs for
12
12
 
13
13
  ## Overview
14
14
 
15
- This server accepts unified diffs and returns structured JSON results — findings with severity, impact categories, merge risk, test plans, and verbatim search/replace fixes. It uses Gemini Thinking models (Flash for fast tools, Pro for deep analysis) and runs over **stdio transport**.
15
+ This server accepts unified diffs and returns structured JSON results — findings with severity, impact categories, merge risk, test plans, and verbatim search/replace fixes. It uses Gemini Thinking models (Flash for fast tools, Flash for deep analysis) and runs over **stdio transport**.
16
16
 
17
17
  ## Key Features
18
18
 
19
19
  - **Impact Analysis** — Objective severity scoring, breaking change detection, and rollback complexity assessment.
20
20
  - **Review Summary** — Concise PR digest with merge recommendation and change statistics.
21
- - **Deep Code Inspection** — Pro model with high thinking level for context-aware analysis using full file contents.
21
+ - **Deep Code Inspection** — Flash model with high thinking level for context-aware analysis using full file contents.
22
22
  - **Search & Replace Fixes** — Verbatim, copy-paste-ready code fixes tied to specific findings.
23
23
  - **Test Plan Generation** — Systematic test case generation with priority ranking and pseudocode.
24
24
  - **Async Task Support** — All tools support MCP task lifecycle with progress notifications.
@@ -279,13 +279,25 @@ docker build -t code-review-analyst-mcp .
279
279
 
280
280
  ## Tools
281
281
 
282
+ > [!IMPORTANT]
283
+ > Call `generate_diff` first (`mode: "unstaged"` or `"staged"`). All review tools read the cached server-side diff (`diff://current`) and do not accept a direct `diff` parameter.
284
+
285
+ ### `generate_diff`
286
+
287
+ Generate and cache the current branch diff for downstream review tools.
288
+
289
+ | Parameter | Type | Required | Description |
290
+ | --------- | -------- | -------- | -------------------------------------------------- |
291
+ | `mode` | `string` | Yes | `unstaged` (working tree) or `staged` (git index). |
292
+
293
+ **Returns:** `diffRef`, `stats` (files, added, deleted), `generatedAt`, `mode`, `message`.
294
+
282
295
  ### `analyze_pr_impact`
283
296
 
284
- Assess the impact and risk of a pull request diff using the Flash model.
297
+ Assess the impact and risk of cached pull request changes using the Flash model.
285
298
 
286
299
  | Parameter | Type | Required | Description |
287
300
  | ------------ | -------- | -------- | ---------------------------------------- |
288
- | `diff` | `string` | Yes | Unified diff text. |
289
301
  | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
290
302
  | `language` | `string` | No | Primary language hint. |
291
303
 
@@ -297,7 +309,6 @@ Summarize a pull request diff and assess high-level risk using the Flash model.
297
309
 
298
310
  | Parameter | Type | Required | Description |
299
311
  | ------------ | -------- | -------- | ---------------------------------------- |
300
- | `diff` | `string` | Yes | Unified diff text. |
301
312
  | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
302
313
  | `language` | `string` | No | Primary language hint. |
303
314
 
@@ -305,11 +316,10 @@ Summarize a pull request diff and assess high-level risk using the Flash model.
305
316
 
306
317
  ### `inspect_code_quality`
307
318
 
308
- Deep-dive code review using the Pro model with thinking (16K token budget).
319
+ Deep-dive code review using the Flash model with high thinking (16K token budget).
309
320
 
310
321
  | Parameter | Type | Required | Description |
311
322
  | ------------- | ---------- | -------- | --------------------------------------------- |
312
- | `diff` | `string` | Yes | Unified diff text. |
313
323
  | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
314
324
  | `language` | `string` | No | Primary language hint. |
315
325
  | `focusAreas` | `string[]` | No | Areas to inspect: security, correctness, etc. |
@@ -322,11 +332,10 @@ Deep-dive code review using the Pro model with thinking (16K token budget).
322
332
 
323
333
  ### `suggest_search_replace`
324
334
 
325
- Generate verbatim search-and-replace blocks to fix a specific finding using the Pro model with thinking.
335
+ Generate verbatim search-and-replace blocks to fix a specific finding using the Flash model with high thinking.
326
336
 
327
337
  | Parameter | Type | Required | Description |
328
338
  | ---------------- | -------- | -------- | ---------------------------------------- |
329
- | `diff` | `string` | Yes | Unified diff that contains the issue. |
330
339
  | `findingTitle` | `string` | Yes | Short title of the finding to fix. |
331
340
  | `findingDetails` | `string` | Yes | Detailed explanation of the bug or risk. |
332
341
 
@@ -338,7 +347,6 @@ Create a test plan covering the changes in the diff using the Flash model with t
338
347
 
339
348
  | Parameter | Type | Required | Description |
340
349
  | --------------- | -------- | -------- | ------------------------------------------- |
341
- | `diff` | `string` | Yes | Unified diff to generate tests for. |
342
350
  | `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
343
351
  | `language` | `string` | No | Primary language hint. |
344
352
  | `testFramework` | `string` | No | Test framework (e.g. jest, vitest, pytest). |
@@ -391,8 +399,8 @@ Create a test plan covering the changes in the diff using the Flash model with t
391
399
  | ------------------------- | ------------------------ | -------------- |
392
400
  | `analyze_pr_impact` | `gemini-3-flash-preview` | `minimal` |
393
401
  | `generate_review_summary` | `gemini-3-flash-preview` | `minimal` |
394
- | `inspect_code_quality` | `gemini-3-pro-preview` | `high` |
395
- | `suggest_search_replace` | `gemini-3-pro-preview` | `high` |
402
+ | `inspect_code_quality` | `gemini-3-flash-preview` | `high` |
403
+ | `suggest_search_replace` | `gemini-3-flash-preview` | `high` |
396
404
  | `generate_test_plan` | `gemini-3-flash-preview` | `medium` |
397
405
 
398
406
  ## Workflows
@@ -456,7 +464,7 @@ The pipeline runs lint, type-check, test, and build, then publishes to three tar
456
464
  | ------------------------------------------ | ------------------------------------------------------------------------------------ |
457
465
  | `Missing GEMINI_API_KEY or GOOGLE_API_KEY` | Set one of the API key env vars in your MCP client config. |
458
466
  | `E_INPUT_TOO_LARGE` | Diff exceeds budget. Split into smaller diffs. |
459
- | `Gemini request timed out` | Pro model tasks may take 60-120s. Increase your client timeout. |
467
+ | `Gemini request timed out` | Deep analysis tasks may take 60-120s. Increase your client timeout. |
460
468
  | `Too many concurrent Gemini calls` | Reduce parallel tool calls or increase `MAX_CONCURRENT_CALLS`. |
461
469
  | No tool output visible | Ensure your MCP client is not swallowing `stderr` — the server uses stdio transport. |
462
470
 
@@ -2,6 +2,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { ParsedFile } from './diff.js';
3
3
  import { createErrorToolResponse } from './tool-response.js';
4
4
  export declare const DIFF_RESOURCE_URI = "diff://current";
5
+ export declare const diffStaleWarningMs: import("./env-config.js").CachedEnvInt;
5
6
  export interface DiffStats {
6
7
  files: number;
7
8
  added: number;
@@ -3,6 +3,8 @@ import { createErrorToolResponse } from './tool-response.js';
3
3
  export const DIFF_RESOURCE_URI = 'diff://current';
4
4
  const diffCacheTtlMs = createCachedEnvInt('DIFF_CACHE_TTL_MS', 60 * 60 * 1_000 // 1 hour default
5
5
  );
6
+ export const diffStaleWarningMs = createCachedEnvInt('DIFF_STALE_WARNING_MS', 5 * 60 * 1_000 // 5 minutes default
7
+ );
6
8
  const diffSlots = new Map();
7
9
  let sendResourceUpdated;
8
10
  function setDiffSlot(key, data) {
@@ -39,6 +39,7 @@ const TRUE_ENV_VALUES = new Set(['1', 'true', 'yes', 'on']);
39
39
  const FALSE_ENV_VALUES = new Set(['0', 'false', 'no', 'off']);
40
40
  const SLEEP_UNREF_OPTIONS = { ref: false };
41
41
  const JSON_CODE_BLOCK_PATTERN = /```(?:json)?\n?([\s\S]*?)(?=\n?```)/u;
42
+ const NEVER_ABORT_SIGNAL = new AbortController().signal;
42
43
  const maxConcurrentCallsConfig = createCachedEnvInt('MAX_CONCURRENT_CALLS', 10);
43
44
  const maxConcurrentBatchCallsConfig = createCachedEnvInt('MAX_CONCURRENT_BATCH_CALLS', 2);
44
45
  const concurrencyWaitMsConfig = createCachedEnvInt('MAX_CONCURRENT_CALLS_WAIT_MS', 2_000);
@@ -746,12 +747,13 @@ async function runInlineBatchWithPolling(request, model, onLog) {
746
747
  let completed = false;
747
748
  let timedOut = false;
748
749
  try {
750
+ const createSignal = request.signal ?? NEVER_ABORT_SIGNAL;
749
751
  const createPayload = {
750
752
  model,
751
753
  src: [
752
754
  {
753
755
  contents: [{ role: 'user', parts: [{ text: request.prompt }] }],
754
- config: buildGenerationConfig(request, new AbortController().signal),
756
+ config: buildGenerationConfig(request, createSignal),
755
757
  },
756
758
  ],
757
759
  };
@@ -1,34 +1,32 @@
1
1
  /** Fast, cost-effective model for summarization and light analysis. */
2
2
  export declare const FLASH_MODEL = "gemini-3-flash-preview";
3
- /** High-capability model for deep reasoning, quality inspection, and reliable code generation. */
4
- export declare const PRO_MODEL = "gemini-3-pro-preview";
5
3
  /** Default language hint. */
6
4
  export declare const DEFAULT_LANGUAGE = "detect";
7
5
  /** Default test-framework hint. */
8
6
  export declare const DEFAULT_FRAMEWORK = "detect";
9
- /** Extended timeout for Pro model calls (ms). */
10
- export declare const DEFAULT_TIMEOUT_PRO_MS = 120000;
7
+ /** Extended timeout for deep analysis calls (ms). */
8
+ export declare const DEFAULT_TIMEOUT_EXTENDED_MS = 120000;
11
9
  export declare const MODEL_TIMEOUT_MS: {
12
- readonly defaultPro: 120000;
10
+ readonly extended: 120000;
13
11
  };
14
12
  /** Thinking level for Flash triage. */
15
13
  export declare const FLASH_TRIAGE_THINKING_LEVEL: "minimal";
16
14
  /** Thinking level for Flash analysis. */
17
15
  export declare const FLASH_THINKING_LEVEL: "medium";
18
- /** Thinking level for Pro deep analysis. */
19
- export declare const PRO_THINKING_LEVEL: "high";
16
+ /** Thinking level for Flash deep analysis. */
17
+ export declare const FLASH_HIGH_THINKING_LEVEL: "high";
20
18
  /** Output cap for Flash API breaking-change detection. */
21
- export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS: 4096;
19
+ export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = 65536;
22
20
  /** Output cap for Flash complexity analysis. */
23
- export declare const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS: 4096;
21
+ export declare const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = 65536;
24
22
  /** Output cap for Flash test-plan generation. */
25
- export declare const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS: 8192;
23
+ export declare const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = 65536;
26
24
  /** Output cap for Flash triage tools. */
27
- export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS: 4096;
28
- /** Output cap for Pro patch generation. */
29
- export declare const PRO_PATCH_MAX_OUTPUT_TOKENS: 8192;
30
- /** Output cap for Pro deep review findings. */
31
- export declare const PRO_REVIEW_MAX_OUTPUT_TOKENS: 12288;
25
+ export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = 65536;
26
+ /** Output cap for Flash patch generation. */
27
+ export declare const FLASH_PATCH_MAX_OUTPUT_TOKENS = 65536;
28
+ /** Output cap for Flash deep review findings. */
29
+ export declare const FLASH_REVIEW_MAX_OUTPUT_TOKENS = 65536;
32
30
  /** Temperature for analytical tools. */
33
31
  export declare const ANALYSIS_TEMPERATURE: 1;
34
32
  /** Temperature for creative synthesis (test plans). */
@@ -1,15 +1,13 @@
1
1
  /** Fast, cost-effective model for summarization and light analysis. */
2
2
  export const FLASH_MODEL = 'gemini-3-flash-preview';
3
- /** High-capability model for deep reasoning, quality inspection, and reliable code generation. */
4
- export const PRO_MODEL = 'gemini-3-pro-preview';
5
3
  /** Default language hint. */
6
4
  export const DEFAULT_LANGUAGE = 'detect';
7
5
  /** Default test-framework hint. */
8
6
  export const DEFAULT_FRAMEWORK = 'detect';
9
- /** Extended timeout for Pro model calls (ms). */
10
- export const DEFAULT_TIMEOUT_PRO_MS = 120_000;
7
+ /** Extended timeout for deep analysis calls (ms). */
8
+ export const DEFAULT_TIMEOUT_EXTENDED_MS = 120_000;
11
9
  export const MODEL_TIMEOUT_MS = {
12
- defaultPro: DEFAULT_TIMEOUT_PRO_MS,
10
+ extended: DEFAULT_TIMEOUT_EXTENDED_MS,
13
11
  };
14
12
  Object.freeze(MODEL_TIMEOUT_MS);
15
13
  // ---------------------------------------------------------------------------
@@ -21,35 +19,28 @@ const THINKING_LEVELS = {
21
19
  /** Medium thinking for analysis tasks. */
22
20
  flash: 'medium',
23
21
  /** High thinking for deep review and patches. */
24
- pro: 'high',
25
- };
26
- // Thinking budget in tokens for Flash and Pro tools. Note that these are not hard limits, but rather guidelines to encourage concise responses and manage latency/cost.
27
- const OUTPUT_TOKEN_BUDGET = {
28
- flashApiBreaking: 4_096,
29
- flashComplexity: 4_096,
30
- flashTestPlan: 8_192,
31
- flashTriage: 4_096,
32
- proPatch: 8_192,
33
- proReview: 12_288,
22
+ flashHigh: 'high',
34
23
  };
35
24
  /** Thinking level for Flash triage. */
36
25
  export const FLASH_TRIAGE_THINKING_LEVEL = THINKING_LEVELS.flashTriage;
37
26
  /** Thinking level for Flash analysis. */
38
27
  export const FLASH_THINKING_LEVEL = THINKING_LEVELS.flash;
39
- /** Thinking level for Pro deep analysis. */
40
- export const PRO_THINKING_LEVEL = THINKING_LEVELS.pro;
28
+ /** Thinking level for Flash deep analysis. */
29
+ export const FLASH_HIGH_THINKING_LEVEL = THINKING_LEVELS.flashHigh;
30
+ // Output token caps for various tools. Set to a high default to avoid cutting off important information, but can be adjusted as needed.
31
+ const DEFAULT_OUTPUT_CAP = 65_536;
41
32
  /** Output cap for Flash API breaking-change detection. */
42
- export const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = OUTPUT_TOKEN_BUDGET.flashApiBreaking;
33
+ export const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
43
34
  /** Output cap for Flash complexity analysis. */
44
- export const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = OUTPUT_TOKEN_BUDGET.flashComplexity;
35
+ export const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
45
36
  /** Output cap for Flash test-plan generation. */
46
- export const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = OUTPUT_TOKEN_BUDGET.flashTestPlan;
37
+ export const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
47
38
  /** Output cap for Flash triage tools. */
48
- export const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = OUTPUT_TOKEN_BUDGET.flashTriage;
49
- /** Output cap for Pro patch generation. */
50
- export const PRO_PATCH_MAX_OUTPUT_TOKENS = OUTPUT_TOKEN_BUDGET.proPatch;
51
- /** Output cap for Pro deep review findings. */
52
- export const PRO_REVIEW_MAX_OUTPUT_TOKENS = OUTPUT_TOKEN_BUDGET.proReview;
39
+ export const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
40
+ /** Output cap for Flash patch generation. */
41
+ export const FLASH_PATCH_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
42
+ /** Output cap for Flash deep review findings. */
43
+ export const FLASH_REVIEW_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
53
44
  // ---------------------------------------------------------------------------
54
45
  // Temperatures
55
46
  // ---------------------------------------------------------------------------
@@ -57,7 +57,7 @@ export declare const TOOL_CONTRACTS: readonly [{
57
57
  readonly model: "gemini-3-flash-preview";
58
58
  readonly timeoutMs: 90000;
59
59
  readonly thinkingLevel: "minimal";
60
- readonly maxOutputTokens: 4096;
60
+ readonly maxOutputTokens: 65536;
61
61
  readonly temperature: 1;
62
62
  readonly deterministicJson: true;
63
63
  readonly params: readonly [{
@@ -82,7 +82,7 @@ export declare const TOOL_CONTRACTS: readonly [{
82
82
  readonly model: "gemini-3-flash-preview";
83
83
  readonly timeoutMs: 90000;
84
84
  readonly thinkingLevel: "minimal";
85
- readonly maxOutputTokens: 4096;
85
+ readonly maxOutputTokens: 65536;
86
86
  readonly temperature: 1;
87
87
  readonly deterministicJson: true;
88
88
  readonly params: readonly [{
@@ -104,10 +104,10 @@ export declare const TOOL_CONTRACTS: readonly [{
104
104
  }, {
105
105
  readonly name: "inspect_code_quality";
106
106
  readonly purpose: "Deep code review over the cached diff.";
107
- readonly model: "gemini-3-pro-preview";
107
+ readonly model: "gemini-3-flash-preview";
108
108
  readonly timeoutMs: 120000;
109
109
  readonly thinkingLevel: "high";
110
- readonly maxOutputTokens: 12288;
110
+ readonly maxOutputTokens: 65536;
111
111
  readonly temperature: 1;
112
112
  readonly deterministicJson: true;
113
113
  readonly params: readonly [{
@@ -142,10 +142,10 @@ export declare const TOOL_CONTRACTS: readonly [{
142
142
  }, {
143
143
  readonly name: "suggest_search_replace";
144
144
  readonly purpose: "Generate verbatim search/replace fix blocks for one finding.";
145
- readonly model: "gemini-3-pro-preview";
145
+ readonly model: "gemini-3-flash-preview";
146
146
  readonly timeoutMs: 120000;
147
147
  readonly thinkingLevel: "high";
148
- readonly maxOutputTokens: 8192;
148
+ readonly maxOutputTokens: 65536;
149
149
  readonly temperature: 1;
150
150
  readonly deterministicJson: true;
151
151
  readonly params: readonly [{
@@ -171,7 +171,7 @@ export declare const TOOL_CONTRACTS: readonly [{
171
171
  readonly model: "gemini-3-flash-preview";
172
172
  readonly timeoutMs: 90000;
173
173
  readonly thinkingLevel: "medium";
174
- readonly maxOutputTokens: 8192;
174
+ readonly maxOutputTokens: 65536;
175
175
  readonly temperature: 1;
176
176
  readonly deterministicJson: true;
177
177
  readonly params: readonly [{
@@ -208,7 +208,7 @@ export declare const TOOL_CONTRACTS: readonly [{
208
208
  readonly model: "gemini-3-flash-preview";
209
209
  readonly timeoutMs: 90000;
210
210
  readonly thinkingLevel: "medium";
211
- readonly maxOutputTokens: 4096;
211
+ readonly maxOutputTokens: 65536;
212
212
  readonly temperature: 1;
213
213
  readonly deterministicJson: true;
214
214
  readonly params: readonly [{
@@ -227,7 +227,7 @@ export declare const TOOL_CONTRACTS: readonly [{
227
227
  readonly model: "gemini-3-flash-preview";
228
228
  readonly timeoutMs: 90000;
229
229
  readonly thinkingLevel: "minimal";
230
- readonly maxOutputTokens: 4096;
230
+ readonly maxOutputTokens: 65536;
231
231
  readonly temperature: 1;
232
232
  readonly deterministicJson: true;
233
233
  readonly params: readonly [{
@@ -1,4 +1,4 @@
1
- import { ANALYSIS_TEMPERATURE, CREATIVE_TEMPERATURE, DEFAULT_TIMEOUT_PRO_MS, FLASH_API_BREAKING_MAX_OUTPUT_TOKENS, FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS, FLASH_MODEL, FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS, FLASH_THINKING_LEVEL, FLASH_TRIAGE_MAX_OUTPUT_TOKENS, FLASH_TRIAGE_THINKING_LEVEL, PATCH_TEMPERATURE, PRO_MODEL, PRO_PATCH_MAX_OUTPUT_TOKENS, PRO_REVIEW_MAX_OUTPUT_TOKENS, PRO_THINKING_LEVEL, TRIAGE_TEMPERATURE, } from './model-config.js';
1
+ import { ANALYSIS_TEMPERATURE, CREATIVE_TEMPERATURE, DEFAULT_TIMEOUT_EXTENDED_MS, FLASH_API_BREAKING_MAX_OUTPUT_TOKENS, FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS, FLASH_HIGH_THINKING_LEVEL, FLASH_MODEL, FLASH_PATCH_MAX_OUTPUT_TOKENS, FLASH_REVIEW_MAX_OUTPUT_TOKENS, FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS, FLASH_THINKING_LEVEL, FLASH_TRIAGE_MAX_OUTPUT_TOKENS, FLASH_TRIAGE_THINKING_LEVEL, PATCH_TEMPERATURE, TRIAGE_TEMPERATURE, } from './model-config.js';
2
2
  const DEFAULT_TIMEOUT_FLASH_MS = 90_000;
3
3
  export const INSPECTION_FOCUS_AREAS = [
4
4
  'security',
@@ -119,10 +119,10 @@ export const TOOL_CONTRACTS = [
119
119
  {
120
120
  name: 'inspect_code_quality',
121
121
  purpose: 'Deep code review over the cached diff.',
122
- model: PRO_MODEL,
123
- timeoutMs: DEFAULT_TIMEOUT_PRO_MS,
124
- thinkingLevel: PRO_THINKING_LEVEL,
125
- maxOutputTokens: PRO_REVIEW_MAX_OUTPUT_TOKENS,
122
+ model: FLASH_MODEL,
123
+ timeoutMs: DEFAULT_TIMEOUT_EXTENDED_MS,
124
+ thinkingLevel: FLASH_HIGH_THINKING_LEVEL,
125
+ maxOutputTokens: FLASH_REVIEW_MAX_OUTPUT_TOKENS,
126
126
  temperature: ANALYSIS_TEMPERATURE,
127
127
  deterministicJson: true,
128
128
  params: [
@@ -169,10 +169,10 @@ export const TOOL_CONTRACTS = [
169
169
  {
170
170
  name: 'suggest_search_replace',
171
171
  purpose: 'Generate verbatim search/replace fix blocks for one finding.',
172
- model: PRO_MODEL,
173
- timeoutMs: DEFAULT_TIMEOUT_PRO_MS,
174
- thinkingLevel: PRO_THINKING_LEVEL,
175
- maxOutputTokens: PRO_PATCH_MAX_OUTPUT_TOKENS,
172
+ model: FLASH_MODEL,
173
+ timeoutMs: DEFAULT_TIMEOUT_EXTENDED_MS,
174
+ thinkingLevel: FLASH_HIGH_THINKING_LEVEL,
175
+ maxOutputTokens: FLASH_PATCH_MAX_OUTPUT_TOKENS,
176
176
  temperature: PATCH_TEMPERATURE,
177
177
  deterministicJson: true,
178
178
  params: [
@@ -1,4 +1,3 @@
1
- import type { CreateTaskRequestHandlerExtra } from '@modelcontextprotocol/sdk/experimental/tasks/interfaces.js';
2
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
2
  import type { ZodRawShapeCompat } from '@modelcontextprotocol/sdk/server/zod-compat.js';
4
3
  import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
@@ -26,6 +25,11 @@ interface ProgressNotificationParams {
26
25
  total?: number;
27
26
  message?: string;
28
27
  }
28
+ interface ProgressPayload {
29
+ current: number;
30
+ total?: number;
31
+ message?: string;
32
+ }
29
33
  interface ProgressExtra {
30
34
  _meta?: {
31
35
  progressToken?: unknown;
@@ -66,8 +70,6 @@ export interface StructuredToolTaskConfig<TInput extends object = Record<string,
66
70
  requiresDiff?: boolean;
67
71
  /** Optional override for schema validation retries. Defaults to GEMINI_SCHEMA_RETRIES env var. */
68
72
  schemaRetries?: number;
69
- /** Optional Gemini model to use (e.g. 'gemini-3-pro-preview'). */
70
- model?: string;
71
73
  /** Optional thinking level. */
72
74
  thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
73
75
  /** Optional timeout in ms for the Gemini call. Defaults to 90,000 ms. Use DEFAULT_TIMEOUT_PRO_MS for Pro model calls. */
@@ -101,29 +103,33 @@ export declare function wrapToolHandler<TInput, TResult extends CallToolResult>(
101
103
  toolName: string;
102
104
  progressContext?: (input: TInput) => string;
103
105
  }, handler: (input: TInput, extra: ProgressExtra) => Promise<TResult> | TResult): (input: TInput, extra: ProgressExtra) => Promise<TResult>;
104
- interface TaskLike {
105
- taskId: string;
106
+ interface TaskStatusReporter {
107
+ updateStatus: (message: string) => Promise<void>;
108
+ storeResult?: (status: 'completed' | 'failed', result: CallToolResult) => Promise<void>;
106
109
  }
107
- export declare class ToolTaskRunner<TInput extends object, TResult extends object, TFinal extends TResult> {
108
- private readonly server;
110
+ export declare class ToolExecutionRunner<TInput extends object, TResult extends object, TFinal extends TResult> {
109
111
  private readonly config;
110
- private readonly extra;
111
- private readonly task;
112
+ private readonly signal?;
112
113
  private diffSlotSnapshot;
113
114
  private hasSnapshot;
114
115
  private responseSchema;
115
116
  private readonly onLog;
116
117
  private readonly reportProgress;
118
+ private readonly statusReporter;
117
119
  private progressContext;
118
120
  private lastStatusMessage;
119
- constructor(server: McpServer, config: StructuredToolTaskConfig<TInput, TResult, TFinal>, extra: CreateTaskRequestHandlerExtra, task: TaskLike);
121
+ constructor(config: StructuredToolTaskConfig<TInput, TResult, TFinal>, dependencies: {
122
+ onLog: (level: string, data: unknown) => Promise<void>;
123
+ reportProgress: (payload: ProgressPayload) => Promise<void>;
124
+ statusReporter: TaskStatusReporter;
125
+ }, signal?: AbortSignal | undefined);
120
126
  setResponseSchemaOverride(responseSchema: Record<string, unknown>): void;
121
127
  setDiffSlotSnapshot(diffSlotSnapshot: DiffSlot | undefined): void;
122
128
  private updateStatusMessage;
123
129
  private storeResultSafely;
124
130
  private executeValidation;
125
131
  private executeModelCall;
126
- run(input: unknown): Promise<void>;
132
+ run(input: unknown): Promise<CallToolResult>;
127
133
  }
128
134
  export declare function registerStructuredToolTask<TInput extends object, TResult extends object = Record<string, unknown>, TFinal extends TResult = TResult>(server: McpServer, config: StructuredToolTaskConfig<TInput, TResult, TFinal>): void;
129
135
  export {};
@@ -1,13 +1,12 @@
1
1
  import { z } from 'zod';
2
2
  import { DefaultOutputSchema } from '../schemas/outputs.js';
3
- import { createNoDiffError, getDiff } from './diff-store.js';
3
+ import { createNoDiffError, diffStaleWarningMs, getDiff, } from './diff-store.js';
4
4
  import { validateDiffBudget } from './diff.js';
5
5
  import { createCachedEnvInt } from './env-config.js';
6
6
  import { getErrorMessage, RETRYABLE_UPSTREAM_ERROR_PATTERN } from './errors.js';
7
7
  import { stripJsonSchemaConstraints } from './gemini-schema.js';
8
- import { generateStructuredJson, getCurrentRequestId } from './gemini.js';
8
+ import { generateStructuredJson } from './gemini.js';
9
9
  import { createErrorToolResponse, createToolResponse, } from './tool-response.js';
10
- const DEFAULT_TASK_TTL_MS = 30 * 60 * 1_000;
11
10
  // Named progress step indices for 7-step progress (0–6).
12
11
  const STEP_STARTING = 0;
13
12
  const STEP_VALIDATING = 1;
@@ -28,7 +27,6 @@ const DEFAULT_SCHEMA_RETRY_ERROR_CHARS = 1_500;
28
27
  const schemaRetryErrorCharsConfig = createCachedEnvInt('MAX_SCHEMA_RETRY_ERROR_CHARS', DEFAULT_SCHEMA_RETRY_ERROR_CHARS);
29
28
  const DETERMINISTIC_JSON_RETRY_NOTE = 'Deterministic JSON mode: keep key names exactly as schema-defined and preserve stable field ordering.';
30
29
  const JSON_PARSE_ERROR_PATTERN = /model produced invalid json/i;
31
- const MODEL_IMMEDIATE_RESPONSE_META_KEY = 'io.modelcontextprotocol/model-immediate-response';
32
30
  const responseSchemaCache = new WeakMap();
33
31
  const progressReporterCache = new WeakMap();
34
32
  function buildToolAnnotations(annotations) {
@@ -107,9 +105,6 @@ function createGenerationRequest(config, promptParts, responseSchema, onLog, sig
107
105
  responseSchema,
108
106
  onLog,
109
107
  };
110
- if (config.model !== undefined) {
111
- request.model = config.model;
112
- }
113
108
  if (config.thinkingLevel !== undefined) {
114
109
  request.thinkingLevel = config.thinkingLevel;
115
110
  }
@@ -248,16 +243,6 @@ function normalizeProgressContext(context) {
248
243
  function formatProgressStep(toolName, context, metadata) {
249
244
  return `${toolName}: ${context} [${metadata}]`;
250
245
  }
251
- function friendlyModelName(model) {
252
- if (!model)
253
- return 'calling model';
254
- const normalized = model.toLowerCase();
255
- if (normalized.includes('pro'))
256
- return 'calling Pro';
257
- if (normalized.includes('flash'))
258
- return 'calling Flash';
259
- return 'calling model';
260
- }
261
246
  function formatProgressCompletion(toolName, context, outcome) {
262
247
  return `🗒 ${toolName}: ${context} • ${outcome}`;
263
248
  }
@@ -318,32 +303,6 @@ function asObjectRecord(value) {
318
303
  }
319
304
  return { payload: value };
320
305
  }
321
- function createGeminiLogger(server, taskId) {
322
- return async (level, data) => {
323
- try {
324
- await server.sendLoggingMessage({
325
- level: toLoggingLevel(level),
326
- logger: 'gemini',
327
- data: {
328
- requestId: getCurrentRequestId(),
329
- taskId,
330
- ...asObjectRecord(data),
331
- },
332
- });
333
- }
334
- catch {
335
- try {
336
- const timestamp = new Date().toISOString();
337
- const payload = JSON.stringify(asObjectRecord(data));
338
- console.error(`[${timestamp}] [gemini:${level}] ${taskId} - ${payload}`);
339
- }
340
- catch {
341
- // Safe fallback if JSON stringify fails
342
- console.error(`[gemini:${level}] ${taskId} - (logging failed)`);
343
- }
344
- }
345
- };
346
- }
347
306
  export function wrapToolHandler(options, handler) {
348
307
  return async (input, extra) => {
349
308
  const context = normalizeProgressContext(options.progressContext?.(input));
@@ -396,26 +355,24 @@ async function validateRequest(config, inputRecord, ctx) {
396
355
  }
397
356
  return undefined;
398
357
  }
399
- export class ToolTaskRunner {
400
- server;
358
+ export class ToolExecutionRunner {
401
359
  config;
402
- extra;
403
- task;
360
+ signal;
404
361
  diffSlotSnapshot;
405
362
  hasSnapshot = false;
406
363
  responseSchema;
407
364
  onLog;
408
365
  reportProgress;
366
+ statusReporter;
409
367
  progressContext;
410
368
  lastStatusMessage;
411
- constructor(server, config, extra, task) {
412
- this.server = server;
369
+ constructor(config, dependencies, signal) {
413
370
  this.config = config;
414
- this.extra = extra;
415
- this.task = task;
371
+ this.signal = signal;
416
372
  this.responseSchema = getCachedGeminiResponseSchema(config);
417
- this.onLog = createGeminiLogger(server, task.taskId);
418
- this.reportProgress = createProgressReporter(extra);
373
+ this.onLog = dependencies.onLog;
374
+ this.reportProgress = dependencies.reportProgress;
375
+ this.statusReporter = dependencies.statusReporter;
419
376
  this.progressContext = DEFAULT_PROGRESS_CONTEXT;
420
377
  }
421
378
  setResponseSchemaOverride(responseSchema) {
@@ -431,7 +388,7 @@ export class ToolTaskRunner {
431
388
  return;
432
389
  }
433
390
  try {
434
- await this.extra.taskStore.updateTaskStatus(this.task.taskId, 'working', message);
391
+ await this.statusReporter.updateStatus(message);
435
392
  this.lastStatusMessage = message;
436
393
  }
437
394
  catch {
@@ -439,8 +396,11 @@ export class ToolTaskRunner {
439
396
  }
440
397
  }
441
398
  async storeResultSafely(status, result) {
399
+ if (!this.statusReporter.storeResult) {
400
+ return;
401
+ }
442
402
  try {
443
- await this.extra.taskStore.storeTaskResult(this.task.taskId, status, result);
403
+ await this.statusReporter.storeResult(status, result);
444
404
  }
445
405
  catch (storeErr) {
446
406
  await this.onLog('error', {
@@ -468,9 +428,9 @@ export class ToolTaskRunner {
468
428
  await this.updateStatusMessage(validationMessage);
469
429
  await reportProgressCompletionUpdate(this.reportProgress, this.config.name, this.progressContext, 'rejected');
470
430
  await this.storeResultSafely('completed', validationError);
471
- return false;
431
+ return validationError;
472
432
  }
473
- return true;
433
+ return undefined;
474
434
  }
475
435
  async executeModelCall(systemInstruction, prompt) {
476
436
  let parsed;
@@ -478,7 +438,7 @@ export class ToolTaskRunner {
478
438
  const maxRetries = this.config.schemaRetries ?? geminiSchemaRetriesConfig.get();
479
439
  for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
480
440
  try {
481
- const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.extra.signal));
441
+ const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.signal));
482
442
  if (attempt === 0) {
483
443
  await this.updateStatusMessage('validating response');
484
444
  await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, 'validating response');
@@ -513,8 +473,6 @@ export class ToolTaskRunner {
513
473
  try {
514
474
  const inputRecord = parseToolInput(input, this.config.fullInputSchema);
515
475
  this.progressContext = normalizeProgressContext(this.config.progressContext?.(inputRecord));
516
- // Prefer createTask snapshot; fallback preserves backward compatibility
517
- // for any direct constructor callers.
518
476
  const ctx = {
519
477
  diffSlot: this.hasSnapshot ? this.diffSlotSnapshot : getDiff(),
520
478
  };
@@ -522,40 +480,52 @@ export class ToolTaskRunner {
522
480
  await this.updateStatusMessage('starting');
523
481
  await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, 'validating input');
524
482
  await this.updateStatusMessage('validating input');
525
- if (!(await this.executeValidation(inputRecord, ctx))) {
526
- return;
483
+ const validationError = await this.executeValidation(inputRecord, ctx);
484
+ if (validationError) {
485
+ return validationError;
527
486
  }
528
487
  await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_BUILDING_PROMPT, 'building prompt');
529
488
  await this.updateStatusMessage('building prompt');
530
489
  const promptParts = this.config.buildPrompt(inputRecord, ctx);
531
490
  const { prompt, systemInstruction } = promptParts;
532
- const modelLabel = friendlyModelName(this.config.model);
533
- await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, modelLabel);
534
- await this.updateStatusMessage(modelLabel);
491
+ await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, 'calling model');
492
+ await this.updateStatusMessage('calling model');
535
493
  const parsed = await this.executeModelCall(systemInstruction, prompt);
536
494
  await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_FINALIZING, 'finalizing');
537
495
  await this.updateStatusMessage('finalizing');
538
496
  const finalResult = (this.config.transformResult
539
497
  ? this.config.transformResult(inputRecord, parsed, ctx)
540
498
  : parsed);
541
- const textContent = this.config.formatOutput
499
+ let textContent = this.config.formatOutput
542
500
  ? this.config.formatOutput(finalResult)
543
501
  : undefined;
502
+ if (ctx.diffSlot) {
503
+ const ageMs = Date.now() - new Date(ctx.diffSlot.generatedAt).getTime();
504
+ if (ageMs > diffStaleWarningMs.get()) {
505
+ const ageMinutes = Math.round(ageMs / 60_000);
506
+ const warning = `\n\n⚠️ Warning: The analyzed diff is over ${ageMinutes} minutes old. If you have made recent changes, please run generate_diff again.`;
507
+ textContent = textContent ? textContent + warning : warning;
508
+ }
509
+ }
544
510
  const outcome = this.config.formatOutcome?.(finalResult) ?? 'completed';
545
511
  await reportProgressCompletionUpdate(this.reportProgress, this.config.name, this.progressContext, outcome);
546
512
  await this.updateStatusMessage(`completed: ${outcome}`);
547
- await this.storeResultSafely('completed', createToolResponse({
513
+ const successResponse = createToolResponse({
548
514
  ok: true,
549
515
  result: finalResult,
550
- }, textContent));
516
+ }, textContent);
517
+ await this.storeResultSafely('completed', successResponse);
518
+ return successResponse;
551
519
  }
552
520
  catch (error) {
553
521
  const errorMessage = getErrorMessage(error);
554
522
  const errorMeta = classifyErrorMeta(error, errorMessage);
555
523
  const outcome = errorMeta.kind === 'cancelled' ? 'cancelled' : 'failed';
556
524
  await this.updateStatusMessage(createFailureStatusMessage(outcome, errorMessage));
557
- await this.storeResultSafely('failed', createErrorToolResponse(this.config.errorCode, errorMessage, undefined, errorMeta));
525
+ const errorResponse = createErrorToolResponse(this.config.errorCode, errorMessage, undefined, errorMeta);
526
+ await this.storeResultSafely('failed', errorResponse);
558
527
  await reportProgressCompletionUpdate(this.reportProgress, this.config.name, this.progressContext, outcome);
528
+ return errorResponse; // Return safe error response
559
529
  }
560
530
  }
561
531
  }
@@ -564,50 +534,35 @@ export function registerStructuredToolTask(server, config) {
564
534
  geminiSchema: config.geminiSchema,
565
535
  resultSchema: config.resultSchema,
566
536
  });
567
- server.experimental.tasks.registerToolTask(config.name, {
537
+ server.registerTool(config.name, {
568
538
  title: config.title,
569
539
  description: config.description,
570
540
  inputSchema: config.inputSchema,
571
541
  outputSchema: DefaultOutputSchema,
572
542
  annotations: buildToolAnnotations(config.annotations),
573
- }, {
574
- createTask: async (input, extra) => {
575
- const task = await extra.taskStore.createTask({
576
- ttl: extra.taskRequestedTtl ?? DEFAULT_TASK_TTL_MS,
577
- });
578
- const currentDiff = getDiff();
579
- // Snapshot by reference: diff-store replaces slots on update, so this
580
- // preserves task-level TOCTOU safety without deep-clone overhead.
581
- const diffSlotSnapshot = currentDiff;
582
- const runner = new ToolTaskRunner(server, config, extra, task);
583
- runner.setResponseSchemaOverride(responseSchema);
584
- runner.setDiffSlotSnapshot(diffSlotSnapshot);
585
- setImmediate(() => {
586
- void runner.run(input).catch(async (error) => {
587
- try {
588
- await server.sendLoggingMessage({
589
- level: 'error',
590
- logger: 'task-runner',
591
- data: { task: config.name, error: getErrorMessage(error) },
592
- });
593
- }
594
- catch {
595
- console.error(`[task-runner:${config.name}] ${getErrorMessage(error)}`);
596
- }
597
- });
598
- });
599
- return {
600
- task,
601
- _meta: {
602
- [MODEL_IMMEDIATE_RESPONSE_META_KEY]: `${config.name} accepted as task ${task.taskId}`,
543
+ }, async (input, extra) => {
544
+ const runner = new ToolExecutionRunner(config, {
545
+ onLog: async (level, data) => {
546
+ // Standard logging for tool calls
547
+ try {
548
+ await server.sendLoggingMessage({
549
+ level: toLoggingLevel(level),
550
+ logger: 'gemini',
551
+ data: asObjectRecord(data),
552
+ });
553
+ }
554
+ catch {
555
+ // Fallback if logging fails
556
+ }
557
+ },
558
+ reportProgress: createProgressReporter(extra),
559
+ statusReporter: {
560
+ updateStatus: async () => {
561
+ // No-op for standard tool calls as they don't have a persistent task status
603
562
  },
604
- };
605
- },
606
- getTask: async (_input, extra) => {
607
- return await extra.taskStore.getTask(extra.taskId);
608
- },
609
- getTaskResult: async (_input, extra) => {
610
- return (await extra.taskStore.getTaskResult(extra.taskId));
611
- },
563
+ },
564
+ });
565
+ runner.setResponseSchemaOverride(responseSchema);
566
+ return await runner.run(input);
612
567
  });
613
568
  }
@@ -83,7 +83,7 @@ function registerToolInfoResources(server) {
83
83
  }
84
84
  export const DIFF_RESOURCE_DESCRIPTION = 'The most recently generated diff, cached by generate_diff. Read by all review tools automatically.';
85
85
  function registerDiffResource(server) {
86
- server.registerResource('diff-current', new ResourceTemplate(DIFF_RESOURCE_URI, { list: undefined }), {
86
+ server.registerResource('diff-current', DIFF_RESOURCE_URI, {
87
87
  title: 'Current Diff',
88
88
  description: DIFF_RESOURCE_DESCRIPTION,
89
89
  mimeType: PATCH_MIME_TYPE,
@@ -22,7 +22,7 @@ ${parameterLines.join('\n')}
22
22
  - **Output**: \`${contract.outputShape}\``;
23
23
  }
24
24
  const modelInfo = [
25
- contract.model.includes('flash') ? 'Flash' : 'Pro',
25
+ 'Flash',
26
26
  contract.thinkingLevel ? `Thinking:${contract.thinkingLevel}` : '',
27
27
  `${Math.round(contract.timeoutMs / 1_000)}s`,
28
28
  `MaxTokens:${contract.maxOutputTokens}`,
@@ -26,8 +26,8 @@ generate_review_summary ──→ overallRisk ──────┤
26
26
 
27
27
  ## When to Use Each Tool
28
28
 
29
- - **Triage**: \`analyze_pr_impact\`, \`generate_review_summary\` (Flash).
30
- - **Inspection**: \`inspect_code_quality\` (Pro).
29
+ - **Triage**: \`analyze_pr_impact\`, \`generate_review_summary\`.
30
+ - **Inspection**: \`inspect_code_quality\`.
31
31
  - **Fixes**: \`suggest_search_replace\` (one finding/call).
32
32
  - **Tests**: \`generate_test_plan\`.
33
33
  - **Complexity**: \`analyze_time_space_complexity\`.
@@ -19,7 +19,6 @@ export function registerAnalyzeComplexityTool(server) {
19
19
  fullInputSchema: AnalyzeComplexityInputSchema,
20
20
  resultSchema: AnalyzeComplexityResultSchema,
21
21
  errorCode: 'E_ANALYZE_COMPLEXITY',
22
- model: TOOL_CONTRACT.model,
23
22
  timeoutMs: TOOL_CONTRACT.timeoutMs,
24
23
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
25
24
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
@@ -22,7 +22,6 @@ export function registerAnalyzePrImpactTool(server) {
22
22
  fullInputSchema: AnalyzePrImpactInputSchema,
23
23
  resultSchema: PrImpactResultSchema,
24
24
  errorCode: 'E_ANALYZE_IMPACT',
25
- model: TOOL_CONTRACT.model,
26
25
  timeoutMs: TOOL_CONTRACT.timeoutMs,
27
26
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
28
27
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
@@ -19,7 +19,6 @@ export function registerDetectApiBreakingTool(server) {
19
19
  fullInputSchema: DetectApiBreakingInputSchema,
20
20
  resultSchema: DetectApiBreakingResultSchema,
21
21
  errorCode: 'E_DETECT_API_BREAKING',
22
- model: TOOL_CONTRACT.model,
23
22
  timeoutMs: TOOL_CONTRACT.timeoutMs,
24
23
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
25
24
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
@@ -36,7 +36,6 @@ export function registerGenerateReviewSummaryTool(server) {
36
36
  fullInputSchema: GenerateReviewSummaryInputSchema,
37
37
  resultSchema: ReviewSummaryModelSchema,
38
38
  errorCode: 'E_REVIEW_SUMMARY',
39
- model: TOOL_CONTRACT.model,
40
39
  timeoutMs: TOOL_CONTRACT.timeoutMs,
41
40
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
42
41
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
@@ -23,7 +23,6 @@ export function registerGenerateTestPlanTool(server) {
23
23
  fullInputSchema: GenerateTestPlanInputSchema,
24
24
  resultSchema: TestPlanResultSchema,
25
25
  errorCode: 'E_GENERATE_TEST_PLAN',
26
- model: TOOL_CONTRACT.model,
27
26
  timeoutMs: TOOL_CONTRACT.timeoutMs,
28
27
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
29
28
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
@@ -28,7 +28,6 @@ export function registerInspectCodeQualityTool(server) {
28
28
  resultSchema: CodeQualityOutputSchema,
29
29
  geminiSchema: CodeQualityResultSchema,
30
30
  errorCode: 'E_INSPECT_QUALITY',
31
- model: TOOL_CONTRACT.model,
32
31
  timeoutMs: TOOL_CONTRACT.timeoutMs,
33
32
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
34
33
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
@@ -23,7 +23,6 @@ export function registerSuggestSearchReplaceTool(server) {
23
23
  fullInputSchema: SuggestSearchReplaceInputSchema,
24
24
  resultSchema: SearchReplaceResultSchema,
25
25
  errorCode: 'E_SUGGEST_SEARCH_REPLACE',
26
- model: TOOL_CONTRACT.model,
27
26
  timeoutMs: TOOL_CONTRACT.timeoutMs,
28
27
  maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
29
28
  ...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@j0hanz/code-review-analyst-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.7.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",