@j0hanz/code-assistant 0.9.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.
- package/README.md +437 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +72 -0
- package/dist/lib/concurrency.d.ts +13 -0
- package/dist/lib/concurrency.js +77 -0
- package/dist/lib/config.d.ts +43 -0
- package/dist/lib/config.js +87 -0
- package/dist/lib/diff.d.ts +49 -0
- package/dist/lib/diff.js +241 -0
- package/dist/lib/errors.d.ts +8 -0
- package/dist/lib/errors.js +69 -0
- package/dist/lib/format.d.ts +14 -0
- package/dist/lib/format.js +33 -0
- package/dist/lib/gemini.d.ts +45 -0
- package/dist/lib/gemini.js +833 -0
- package/dist/lib/progress.d.ts +72 -0
- package/dist/lib/progress.js +204 -0
- package/dist/lib/tools.d.ts +274 -0
- package/dist/lib/tools.js +646 -0
- package/dist/prompts/index.d.ts +11 -0
- package/dist/prompts/index.js +96 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.js +115 -0
- package/dist/resources/instructions.d.ts +1 -0
- package/dist/resources/instructions.js +71 -0
- package/dist/resources/server-config.d.ts +1 -0
- package/dist/resources/server-config.js +75 -0
- package/dist/resources/tool-catalog.d.ts +1 -0
- package/dist/resources/tool-catalog.js +30 -0
- package/dist/resources/tool-info.d.ts +5 -0
- package/dist/resources/tool-info.js +105 -0
- package/dist/resources/workflows.d.ts +1 -0
- package/dist/resources/workflows.js +59 -0
- package/dist/schemas/inputs.d.ts +21 -0
- package/dist/schemas/inputs.js +46 -0
- package/dist/schemas/outputs.d.ts +121 -0
- package/dist/schemas/outputs.js +162 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +88 -0
- package/dist/tools/analyze-complexity.d.ts +2 -0
- package/dist/tools/analyze-complexity.js +50 -0
- package/dist/tools/analyze-pr-impact.d.ts +2 -0
- package/dist/tools/analyze-pr-impact.js +62 -0
- package/dist/tools/detect-api-breaking.d.ts +2 -0
- package/dist/tools/detect-api-breaking.js +49 -0
- package/dist/tools/generate-diff.d.ts +2 -0
- package/dist/tools/generate-diff.js +140 -0
- package/dist/tools/generate-review-summary.d.ts +2 -0
- package/dist/tools/generate-review-summary.js +71 -0
- package/dist/tools/generate-test-plan.d.ts +2 -0
- package/dist/tools/generate-test-plan.js +67 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +19 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# Code Assistant MCP Server
|
|
2
|
+
|
|
3
|
+
<!-- mcp-name: io.github.j0hanz/code-assistant -->
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@j0hanz/code-assistant-mcp) [](package.json) [](package.json) [](package.json) [](package.json)
|
|
6
|
+
|
|
7
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D) [](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D&quality=insiders) [](https://vs-open.link/mcp-install?%7B%22name%22%3A%22code-assistant%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D)
|
|
8
|
+
|
|
9
|
+
[](https://cursor.com/en/install-mcp?name=code-assistant&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovY29kZS1hc3Npc3RhbnQtbWNwQGxhdGVzdCJdfQ==)
|
|
10
|
+
|
|
11
|
+
Gemini-powered MCP server for code analysis with structured outputs for findings, risk assessment, and focused patch suggestions.
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
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, Flash for deep analysis) and runs over **stdio transport**.
|
|
16
|
+
|
|
17
|
+
## Key Features
|
|
18
|
+
|
|
19
|
+
- **Impact Analysis** — Objective severity scoring, breaking change detection, and rollback complexity assessment.
|
|
20
|
+
- **Review Summary** — Concise PR digest with merge recommendation and change statistics.
|
|
21
|
+
- **Deep Code Inspection** — Flash model with high thinking level for context-aware analysis using full file contents.
|
|
22
|
+
- **Search & Replace Fixes** — Verbatim, copy-paste-ready code fixes tied to specific findings.
|
|
23
|
+
- **Test Plan Generation** — Systematic test case generation with priority ranking and pseudocode.
|
|
24
|
+
- **Async Task Support** — All tools support MCP task lifecycle with progress notifications.
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Node.js `>=24`
|
|
29
|
+
- One API key: `GEMINI_API_KEY` or `GOOGLE_API_KEY`
|
|
30
|
+
- MCP client that supports stdio servers and tool calls
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"code-assistant": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
40
|
+
"env": {
|
|
41
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Client Configuration
|
|
49
|
+
|
|
50
|
+
<details>
|
|
51
|
+
<summary><b>VS Code / VS Code Insiders</b></summary>
|
|
52
|
+
|
|
53
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D) [](https://insiders.vscode.dev/redirect/mcp/install?name=Code+Assistant&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D&quality=insiders)
|
|
54
|
+
|
|
55
|
+
Add to `.vscode/mcp.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"servers": {
|
|
60
|
+
"code-assistant": {
|
|
61
|
+
"command": "npx",
|
|
62
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
63
|
+
"env": {
|
|
64
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Or via CLI:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
code --add-mcp '{"name":"code-assistant","command":"npx","args":["-y","@j0hanz/code-assistant-mcp@latest"]}'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
</details>
|
|
78
|
+
|
|
79
|
+
<details>
|
|
80
|
+
<summary><b>Cursor</b></summary>
|
|
81
|
+
|
|
82
|
+
[](https://cursor.com/en/install-mcp?name=code-assistant&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovY29kZS1hc3Npc3RhbnQtbWNwQGxhdGVzdCJdfQ==)
|
|
83
|
+
|
|
84
|
+
Add to `~/.cursor/mcp.json`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"code-assistant": {
|
|
90
|
+
"command": "npx",
|
|
91
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
92
|
+
"env": {
|
|
93
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
</details>
|
|
101
|
+
|
|
102
|
+
<details>
|
|
103
|
+
<summary><b>Visual Studio</b></summary>
|
|
104
|
+
|
|
105
|
+
[](https://vs-open.link/mcp-install?%7B%22name%22%3A%22code-assistant%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Fcode-assistant-mcp%40latest%22%5D%7D)
|
|
106
|
+
|
|
107
|
+
For more info, see [Visual Studio MCP docs](https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers).
|
|
108
|
+
|
|
109
|
+
</details>
|
|
110
|
+
|
|
111
|
+
<details>
|
|
112
|
+
<summary><b>Claude Desktop</b></summary>
|
|
113
|
+
|
|
114
|
+
Add to `claude_desktop_config.json`:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"code-assistant": {
|
|
120
|
+
"command": "npx",
|
|
121
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
122
|
+
"env": {
|
|
123
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
For more info, see [Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user).
|
|
131
|
+
|
|
132
|
+
</details>
|
|
133
|
+
|
|
134
|
+
<details>
|
|
135
|
+
<summary><b>Claude Code</b></summary>
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
claude mcp add code-assistant -- npx -y @j0hanz/code-assistant-mcp@latest
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
For more info, see [Claude Code MCP docs](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/tutorials#set-up-model-context-protocol-mcp).
|
|
142
|
+
|
|
143
|
+
</details>
|
|
144
|
+
|
|
145
|
+
<details>
|
|
146
|
+
<summary><b>Windsurf</b></summary>
|
|
147
|
+
|
|
148
|
+
Add to MCP config:
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"mcpServers": {
|
|
153
|
+
"code-assistant": {
|
|
154
|
+
"command": "npx",
|
|
155
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
156
|
+
"env": {
|
|
157
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
For more info, see [Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp).
|
|
165
|
+
|
|
166
|
+
</details>
|
|
167
|
+
|
|
168
|
+
<details>
|
|
169
|
+
<summary><b>Amp</b></summary>
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
amp mcp add code-assistant -- npx -y @j0hanz/code-assistant-mcp@latest
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For more info, see [Amp MCP docs](https://docs.amp.dev/mcp).
|
|
176
|
+
|
|
177
|
+
</details>
|
|
178
|
+
|
|
179
|
+
<details>
|
|
180
|
+
<summary><b>Cline</b></summary>
|
|
181
|
+
|
|
182
|
+
Add to `cline_mcp_settings.json`:
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"mcpServers": {
|
|
187
|
+
"code-assistant": {
|
|
188
|
+
"command": "npx",
|
|
189
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
190
|
+
"env": {
|
|
191
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
For more info, see [Cline MCP docs](https://docs.cline.bot/mcp-servers/configuring-mcp-servers).
|
|
199
|
+
|
|
200
|
+
</details>
|
|
201
|
+
|
|
202
|
+
<details>
|
|
203
|
+
<summary><b>Zed</b></summary>
|
|
204
|
+
|
|
205
|
+
Add to Zed `settings.json`:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"context_servers": {
|
|
210
|
+
"code-assistant": {
|
|
211
|
+
"command": {
|
|
212
|
+
"path": "npx",
|
|
213
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
214
|
+
"env": {
|
|
215
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
For more info, see [Zed MCP docs](https://zed.dev/docs/assistant/model-context-protocol).
|
|
224
|
+
|
|
225
|
+
</details>
|
|
226
|
+
|
|
227
|
+
<details>
|
|
228
|
+
<summary><b>Augment</b></summary>
|
|
229
|
+
|
|
230
|
+
Add to `settings.json`:
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"augment.advanced": {
|
|
235
|
+
"mcpServers": [
|
|
236
|
+
{
|
|
237
|
+
"name": "code-assistant",
|
|
238
|
+
"command": "npx",
|
|
239
|
+
"args": ["-y", "@j0hanz/code-assistant-mcp@latest"],
|
|
240
|
+
"env": {
|
|
241
|
+
"GEMINI_API_KEY": "YOUR_API_KEY"
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
</details>
|
|
250
|
+
|
|
251
|
+
<details>
|
|
252
|
+
<summary><b>Docker</b></summary>
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
{
|
|
256
|
+
"mcpServers": {
|
|
257
|
+
"code-assistant": {
|
|
258
|
+
"command": "docker",
|
|
259
|
+
"args": [
|
|
260
|
+
"run",
|
|
261
|
+
"-i",
|
|
262
|
+
"--rm",
|
|
263
|
+
"-e",
|
|
264
|
+
"GEMINI_API_KEY=YOUR_API_KEY",
|
|
265
|
+
"ghcr.io/j0hanz/code-assistant-mcp:latest"
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Or build locally:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
docker build -t code-assistant-mcp .
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
</details>
|
|
279
|
+
|
|
280
|
+
## Tools
|
|
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
|
+
|
|
295
|
+
### `analyze_pr_impact`
|
|
296
|
+
|
|
297
|
+
Assess the impact and risk of cached pull request changes using the Flash model.
|
|
298
|
+
|
|
299
|
+
| Parameter | Type | Required | Description |
|
|
300
|
+
| ------------ | -------- | -------- | ---------------------------------------- |
|
|
301
|
+
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
302
|
+
| `language` | `string` | No | Primary language hint. |
|
|
303
|
+
|
|
304
|
+
**Returns:** `severity` (low/medium/high/critical), `categories[]`, `breakingChanges[]`, `affectedAreas[]`, `rollbackComplexity`, `summary`.
|
|
305
|
+
|
|
306
|
+
### `generate_review_summary`
|
|
307
|
+
|
|
308
|
+
Summarize a pull request diff and assess high-level risk using the Flash model.
|
|
309
|
+
|
|
310
|
+
| Parameter | Type | Required | Description |
|
|
311
|
+
| ------------ | -------- | -------- | ---------------------------------------- |
|
|
312
|
+
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
313
|
+
| `language` | `string` | No | Primary language hint. |
|
|
314
|
+
|
|
315
|
+
**Returns:** `summary`, `overallRisk` (low/medium/high), `keyChanges[]`, `recommendation`, `stats` (filesChanged, linesAdded, linesRemoved).
|
|
316
|
+
|
|
317
|
+
### `generate_test_plan`
|
|
318
|
+
|
|
319
|
+
Create a test plan covering the changes in the diff using the Flash model with thinking (8K token budget).
|
|
320
|
+
|
|
321
|
+
| Parameter | Type | Required | Description |
|
|
322
|
+
| --------------- | -------- | -------- | ------------------------------------------- |
|
|
323
|
+
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
324
|
+
| `language` | `string` | No | Primary language hint. |
|
|
325
|
+
| `testFramework` | `string` | No | Test framework (e.g. jest, vitest, pytest). |
|
|
326
|
+
| `maxTestCases` | `number` | No | Maximum test cases to return (1-30). |
|
|
327
|
+
|
|
328
|
+
**Returns:** `summary`, `testCases[]` (name, type, file, description, pseudoCode, priority), `coverageSummary`.
|
|
329
|
+
|
|
330
|
+
## Resources
|
|
331
|
+
|
|
332
|
+
| URI | Type | Description |
|
|
333
|
+
| ------------------------- | --------------- | -------------------------- |
|
|
334
|
+
| `internal://instructions` | `text/markdown` | Server usage instructions. |
|
|
335
|
+
|
|
336
|
+
## Prompts
|
|
337
|
+
|
|
338
|
+
| Name | Arguments | Description |
|
|
339
|
+
| -------------- | ------------------- | --------------------------------------------------- |
|
|
340
|
+
| `get-help` | — | Return the server usage instructions. |
|
|
341
|
+
| `review-guide` | `tool`, `focusArea` | Guided workflow for a specific tool and focus area. |
|
|
342
|
+
|
|
343
|
+
## Configuration
|
|
344
|
+
|
|
345
|
+
### CLI Arguments
|
|
346
|
+
|
|
347
|
+
| Option | Description | Env Var Equivalent |
|
|
348
|
+
| ------------------ | ---------------------- | ------------------ |
|
|
349
|
+
| `--model`, `-m` | Override default model | `GEMINI_MODEL` |
|
|
350
|
+
| `--max-diff-chars` | Override max diff size | `MAX_DIFF_CHARS` |
|
|
351
|
+
|
|
352
|
+
### Environment Variables
|
|
353
|
+
|
|
354
|
+
| Variable | Description | Default | Required |
|
|
355
|
+
| ------------------------------- | ---------------------------------------------------- | ------------ | -------- |
|
|
356
|
+
| `GEMINI_API_KEY` | Gemini API key | — | Yes |
|
|
357
|
+
| `GOOGLE_API_KEY` | Alternative API key (if `GEMINI_API_KEY` not set) | — | No |
|
|
358
|
+
| `GEMINI_MODEL` | Override default model selection | — | No |
|
|
359
|
+
| `GEMINI_HARM_BLOCK_THRESHOLD` | Safety threshold (BLOCK_NONE, BLOCK_ONLY_HIGH, etc.) | `BLOCK_NONE` | No |
|
|
360
|
+
| `MAX_DIFF_CHARS` | Max chars for diff input | `120000` | No |
|
|
361
|
+
| `MAX_CONCURRENT_CALLS` | Max concurrent Gemini requests | `10` | No |
|
|
362
|
+
| `MAX_CONCURRENT_BATCH_CALLS` | Max concurrent inline batch requests | `2` | No |
|
|
363
|
+
| `MAX_CONCURRENT_CALLS_WAIT_MS` | Max wait time for a free Gemini slot | `2000` | No |
|
|
364
|
+
| `MAX_SCHEMA_RETRY_ERROR_CHARS` | Max chars from schema error injected into retry text | `1500` | No |
|
|
365
|
+
| `GEMINI_BATCH_MODE` | Request mode for Gemini calls (`off`, `inline`) | `off` | No |
|
|
366
|
+
| `GEMINI_BATCH_POLL_INTERVAL_MS` | Poll interval for batch job status | `2000` | No |
|
|
367
|
+
| `GEMINI_BATCH_TIMEOUT_MS` | Max wait for batch completion | `120000` | No |
|
|
368
|
+
|
|
369
|
+
### Models
|
|
370
|
+
|
|
371
|
+
| Tool | Model | Thinking Level |
|
|
372
|
+
| ------------------------- | ------------------------ | -------------- |
|
|
373
|
+
| `analyze_pr_impact` | `gemini-3-flash-preview` | `minimal` |
|
|
374
|
+
| `generate_review_summary` | `gemini-3-flash-preview` | `minimal` |
|
|
375
|
+
| `generate_test_plan` | `gemini-3-flash-preview` | `medium` |
|
|
376
|
+
|
|
377
|
+
## Workflows
|
|
378
|
+
|
|
379
|
+
### Quick PR Triage
|
|
380
|
+
|
|
381
|
+
1. Call `analyze_pr_impact` to get severity and category breakdown.
|
|
382
|
+
2. If low/medium — call `generate_review_summary` for a quick digest.
|
|
383
|
+
3. If high/critical — proceed to deep inspection.
|
|
384
|
+
|
|
385
|
+
### Testing
|
|
386
|
+
|
|
387
|
+
1. Call `generate_test_plan` to create a verification strategy.
|
|
388
|
+
2. Implement tests based on returned test cases and coverage summary.
|
|
389
|
+
|
|
390
|
+
## Development
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
npm ci # Install dependencies
|
|
394
|
+
npm run dev # TypeScript watch mode
|
|
395
|
+
npm run dev:run # Run built server with .env and --watch
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
| Script | Command | Purpose |
|
|
399
|
+
| -------------------- | ----------------------------------- | ------------------------------ |
|
|
400
|
+
| `npm run build` | `node scripts/tasks.mjs build` | Clean, compile, validate, copy |
|
|
401
|
+
| `npm test` | `node scripts/tasks.mjs test` | Build + run all tests |
|
|
402
|
+
| `npm run test:fast` | `node --test --import tsx/esm ...` | Run tests without build |
|
|
403
|
+
| `npm run lint` | `eslint .` | Lint all files |
|
|
404
|
+
| `npm run lint:fix` | `eslint . --fix` | Lint and auto-fix |
|
|
405
|
+
| `npm run format` | `prettier --write .` | Format all files |
|
|
406
|
+
| `npm run type-check` | `node scripts/tasks.mjs type-check` | Type-check without emitting |
|
|
407
|
+
| `npm run inspector` | Build + launch MCP Inspector | Debug with MCP Inspector |
|
|
408
|
+
|
|
409
|
+
### Debugging with MCP Inspector
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Build & Release
|
|
416
|
+
|
|
417
|
+
Releases are triggered via GitHub Actions `workflow_dispatch` with version bump selection (patch/minor/major/custom).
|
|
418
|
+
|
|
419
|
+
The pipeline runs lint, type-check, test, and build, then publishes to three targets in parallel:
|
|
420
|
+
|
|
421
|
+
- **npm** — `@j0hanz/code-assistant-mcp` with OIDC trusted publishing and provenance
|
|
422
|
+
- **Docker** — `ghcr.io/j0hanz/code-assistant-mcp` (linux/amd64, linux/arm64)
|
|
423
|
+
- **MCP Registry** — `io.github.j0hanz/code-assistant`
|
|
424
|
+
|
|
425
|
+
## Troubleshooting
|
|
426
|
+
|
|
427
|
+
| Issue | Solution |
|
|
428
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------ |
|
|
429
|
+
| `Missing GEMINI_API_KEY or GOOGLE_API_KEY` | Set one of the API key env vars in your MCP client config. |
|
|
430
|
+
| `E_INPUT_TOO_LARGE` | Diff exceeds budget. Split into smaller diffs. |
|
|
431
|
+
| `Gemini request timed out` | Deep analysis tasks may take 60-120s. Increase your client timeout. |
|
|
432
|
+
| `Too many concurrent Gemini calls` | Reduce parallel tool calls or increase `MAX_CONCURRENT_CALLS`. |
|
|
433
|
+
| No tool output visible | Ensure your MCP client is not swallowing `stderr` — the server uses stdio transport. |
|
|
434
|
+
|
|
435
|
+
## License
|
|
436
|
+
|
|
437
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { getErrorMessage } from './lib/errors.js';
|
|
5
|
+
import { createServer } from './server.js';
|
|
6
|
+
const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
|
|
7
|
+
// --- CLI Parsing ---
|
|
8
|
+
const ARG_OPTION_MODEL = 'model';
|
|
9
|
+
const ARG_OPTION_MAX_DIFF_CHARS = 'max-diff-chars';
|
|
10
|
+
const PROCESS_ARGS_START_INDEX = 2;
|
|
11
|
+
const CLI_ENV_MAPPINGS = [
|
|
12
|
+
{ option: ARG_OPTION_MODEL, envVar: 'GEMINI_MODEL' },
|
|
13
|
+
{ option: ARG_OPTION_MAX_DIFF_CHARS, envVar: 'MAX_DIFF_CHARS' },
|
|
14
|
+
];
|
|
15
|
+
const CLI_OPTIONS = {
|
|
16
|
+
[ARG_OPTION_MODEL]: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
short: 'm',
|
|
19
|
+
},
|
|
20
|
+
[ARG_OPTION_MAX_DIFF_CHARS]: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
function setStringEnv(name, value) {
|
|
25
|
+
if (typeof value !== 'string') {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
process.env[name] = value;
|
|
29
|
+
}
|
|
30
|
+
function applyCliEnvironmentOverrides(values) {
|
|
31
|
+
for (const mapping of CLI_ENV_MAPPINGS) {
|
|
32
|
+
setStringEnv(mapping.envVar, values[mapping.option]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function parseCommandLineArgs() {
|
|
36
|
+
const { values } = parseArgs({
|
|
37
|
+
args: process.argv.slice(PROCESS_ARGS_START_INDEX),
|
|
38
|
+
options: CLI_OPTIONS,
|
|
39
|
+
strict: false,
|
|
40
|
+
});
|
|
41
|
+
applyCliEnvironmentOverrides(values);
|
|
42
|
+
}
|
|
43
|
+
let shuttingDown = false;
|
|
44
|
+
async function shutdown(server) {
|
|
45
|
+
if (shuttingDown) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
shuttingDown = true;
|
|
49
|
+
await server.shutdown();
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
function registerShutdownHandlers(server) {
|
|
53
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
54
|
+
process.once(signal, () => {
|
|
55
|
+
shutdown(server).catch((error) => {
|
|
56
|
+
console.error(`[fatal] ${getErrorMessage(error)}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function main() {
|
|
63
|
+
parseCommandLineArgs();
|
|
64
|
+
const server = createServer();
|
|
65
|
+
const transport = new StdioServerTransport();
|
|
66
|
+
registerShutdownHandlers(server);
|
|
67
|
+
await server.server.connect(transport);
|
|
68
|
+
}
|
|
69
|
+
main().catch((error) => {
|
|
70
|
+
console.error(`[fatal] ${getErrorMessage(error)}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class ConcurrencyLimiter {
|
|
2
|
+
private readonly maxConcurrent;
|
|
3
|
+
private readonly waitTimeoutMs;
|
|
4
|
+
private readonly formatTimeoutError;
|
|
5
|
+
private readonly formatCancelError;
|
|
6
|
+
private activeCount;
|
|
7
|
+
private readonly waiters;
|
|
8
|
+
constructor(maxConcurrent: () => number, waitTimeoutMs: () => number, formatTimeoutError: (limit: number, timeoutMs: number) => string, formatCancelError: () => string);
|
|
9
|
+
get pendingCount(): number;
|
|
10
|
+
get active(): number;
|
|
11
|
+
acquire(signal?: AbortSignal): Promise<void>;
|
|
12
|
+
release(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export class ConcurrencyLimiter {
|
|
2
|
+
maxConcurrent;
|
|
3
|
+
waitTimeoutMs;
|
|
4
|
+
formatTimeoutError;
|
|
5
|
+
formatCancelError;
|
|
6
|
+
activeCount = 0;
|
|
7
|
+
waiters = new Set();
|
|
8
|
+
constructor(maxConcurrent, waitTimeoutMs, formatTimeoutError, formatCancelError) {
|
|
9
|
+
this.maxConcurrent = maxConcurrent;
|
|
10
|
+
this.waitTimeoutMs = waitTimeoutMs;
|
|
11
|
+
this.formatTimeoutError = formatTimeoutError;
|
|
12
|
+
this.formatCancelError = formatCancelError;
|
|
13
|
+
}
|
|
14
|
+
get pendingCount() {
|
|
15
|
+
return this.waiters.size;
|
|
16
|
+
}
|
|
17
|
+
get active() {
|
|
18
|
+
return this.activeCount;
|
|
19
|
+
}
|
|
20
|
+
acquire(signal) {
|
|
21
|
+
const limit = this.maxConcurrent();
|
|
22
|
+
if (this.activeCount < limit) {
|
|
23
|
+
this.activeCount++;
|
|
24
|
+
return Promise.resolve();
|
|
25
|
+
}
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let isSettled = false;
|
|
28
|
+
const waiter = () => {
|
|
29
|
+
if (isSettled) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
isSettled = true;
|
|
33
|
+
clearTimeout(timeoutId);
|
|
34
|
+
signal?.removeEventListener('abort', onAbort);
|
|
35
|
+
this.activeCount++;
|
|
36
|
+
resolve();
|
|
37
|
+
};
|
|
38
|
+
const onAbort = () => {
|
|
39
|
+
if (isSettled) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
isSettled = true;
|
|
43
|
+
clearTimeout(timeoutId);
|
|
44
|
+
this.waiters.delete(waiter);
|
|
45
|
+
reject(new Error(this.formatCancelError()));
|
|
46
|
+
};
|
|
47
|
+
const onTimeout = () => {
|
|
48
|
+
if (isSettled) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
isSettled = true;
|
|
52
|
+
signal?.removeEventListener('abort', onAbort);
|
|
53
|
+
this.waiters.delete(waiter);
|
|
54
|
+
reject(new Error(this.formatTimeoutError(limit, this.waitTimeoutMs())));
|
|
55
|
+
};
|
|
56
|
+
if (signal) {
|
|
57
|
+
if (signal.aborted) {
|
|
58
|
+
reject(new Error(this.formatCancelError()));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
62
|
+
}
|
|
63
|
+
const timeoutId = setTimeout(onTimeout, this.waitTimeoutMs());
|
|
64
|
+
this.waiters.add(waiter);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
release() {
|
|
68
|
+
if (this.activeCount > 0) {
|
|
69
|
+
this.activeCount--;
|
|
70
|
+
}
|
|
71
|
+
const next = this.waiters.values().next().value;
|
|
72
|
+
if (next) {
|
|
73
|
+
this.waiters.delete(next);
|
|
74
|
+
next();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface CachedEnvInt {
|
|
2
|
+
get(): number;
|
|
3
|
+
reset(): void;
|
|
4
|
+
}
|
|
5
|
+
/** Creates a cached integer value from an environment variable, with a default fallback. */
|
|
6
|
+
export declare function createCachedEnvInt(envVar: string, defaultValue: number): CachedEnvInt;
|
|
7
|
+
/** Fast, cost-effective model for summarization and light analysis. */
|
|
8
|
+
export declare const FLASH_MODEL = "gemini-3-flash-preview";
|
|
9
|
+
/** Default language hint. */
|
|
10
|
+
export declare const DEFAULT_LANGUAGE = "detect";
|
|
11
|
+
/** Default test-framework hint. */
|
|
12
|
+
export declare const DEFAULT_FRAMEWORK = "detect";
|
|
13
|
+
/** Extended timeout for deep analysis calls (ms). */
|
|
14
|
+
export declare const DEFAULT_TIMEOUT_EXTENDED_MS = 120000;
|
|
15
|
+
export declare const MODEL_TIMEOUT_MS: Readonly<{
|
|
16
|
+
readonly extended: 120000;
|
|
17
|
+
}>;
|
|
18
|
+
/** Thinking level for Flash triage. */
|
|
19
|
+
export declare const FLASH_TRIAGE_THINKING_LEVEL: "minimal";
|
|
20
|
+
/** Thinking level for Flash analysis. */
|
|
21
|
+
export declare const FLASH_THINKING_LEVEL: "medium";
|
|
22
|
+
/** Thinking level for Flash deep analysis. */
|
|
23
|
+
export declare const FLASH_HIGH_THINKING_LEVEL: "high";
|
|
24
|
+
/** Output cap for Flash API breaking-change detection. */
|
|
25
|
+
export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = 65536;
|
|
26
|
+
/** Output cap for Flash complexity analysis. */
|
|
27
|
+
export declare const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = 65536;
|
|
28
|
+
/** Output cap for Flash test-plan generation. */
|
|
29
|
+
export declare const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = 65536;
|
|
30
|
+
/** Output cap for Flash triage tools. */
|
|
31
|
+
export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = 65536;
|
|
32
|
+
/** Output cap for Flash patch generation. */
|
|
33
|
+
export declare const FLASH_PATCH_MAX_OUTPUT_TOKENS = 65536;
|
|
34
|
+
/** Output cap for Flash deep review findings. */
|
|
35
|
+
export declare const FLASH_REVIEW_MAX_OUTPUT_TOKENS = 65536;
|
|
36
|
+
/** Temperature for analytical tools. */
|
|
37
|
+
export declare const ANALYSIS_TEMPERATURE: 1;
|
|
38
|
+
/** Temperature for creative synthesis (test plans). */
|
|
39
|
+
export declare const CREATIVE_TEMPERATURE: 1;
|
|
40
|
+
/** Temperature for code patch generation. */
|
|
41
|
+
export declare const PATCH_TEMPERATURE: 1;
|
|
42
|
+
/** Temperature for triage/classification tools. */
|
|
43
|
+
export declare const TRIAGE_TEMPERATURE: 1;
|