ai-cli-mcp 2.0.0 → 2.1.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/.claude/settings.local.json +2 -1
- package/README.md +53 -8
- package/dist/parsers.js +14 -0
- package/dist/server.js +69 -12
- package/package.json +2 -2
- package/src/parsers.ts +15 -1
- package/src/server.ts +85 -21
package/README.md
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# AI CLI MCP Server
|
|
2
2
|
|
|
3
|
-
<img src="assets/claude_code_mcp_logo.png" alt="AI CLI MCP Logo">
|
|
4
|
-
|
|
5
3
|
[](https://www.npmjs.com/package/ai-cli-mcp)
|
|
6
4
|
[](/CHANGELOG.md)
|
|
7
5
|
|
|
8
6
|
> **📦 Package Migration Notice**: This package was formerly `@mkxultra/claude-code-mcp` and has been renamed to `ai-cli-mcp` to reflect its expanded support for multiple AI CLI tools.
|
|
9
7
|
|
|
10
|
-
An MCP (Model Context Protocol) server that allows running AI CLI tools (Claude and
|
|
8
|
+
An MCP (Model Context Protocol) server that allows running AI CLI tools (Claude, Codex, and Gemini) in background processes with automatic permission handling.
|
|
11
9
|
|
|
12
10
|
Did you notice that Cursor sometimes struggles with complex, multi-step edits or operations? This server, with its powerful unified `run` tool, enables multiple AI agents to handle your coding tasks more effectively.
|
|
13
11
|
|
|
@@ -19,7 +17,8 @@ This MCP server provides tools that can be used by LLMs to interact with AI CLI
|
|
|
19
17
|
|
|
20
18
|
- Run Claude CLI with all permissions bypassed (using `--dangerously-skip-permissions`)
|
|
21
19
|
- Execute Codex CLI with automatic approval mode (using `--full-auto`)
|
|
22
|
-
-
|
|
20
|
+
- Execute Gemini CLI with automatic approval mode (using `-y`)
|
|
21
|
+
- Support multiple AI models: Claude (sonnet, opus, haiku), Codex (gpt-5-low, gpt-5-medium, gpt-5-high), and Gemini (gemini-2.5-pro, gemini-2.5-flash)
|
|
23
22
|
- Manage background processes with PID tracking
|
|
24
23
|
- Parse and return structured outputs from both tools
|
|
25
24
|
|
|
@@ -31,13 +30,12 @@ This MCP server provides tools that can be used by LLMs to interact with AI CLI
|
|
|
31
30
|
- Claude has wider system access and can do things that Cursor/Windsurf can't do (or believe they can't), so whenever they are stuck just ask them "use claude code" and it will usually un-stuck them.
|
|
32
31
|
- Agents in Agents rules.
|
|
33
32
|
|
|
34
|
-
<img src="assets/agents_in_agents_meme.jpg" alt="Agents in Agents Meme">
|
|
35
|
-
|
|
36
33
|
## Prerequisites
|
|
37
34
|
|
|
38
35
|
- Node.js v20 or later (Use fnm or nvm to install)
|
|
39
36
|
- Claude CLI installed locally (run it and call /doctor) and `--dangerously-skip-permissions` accepted
|
|
40
37
|
- Codex CLI installed (optional, for Codex support)
|
|
38
|
+
- Gemini CLI installed (optional, for Gemini support)
|
|
41
39
|
|
|
42
40
|
## Configuration
|
|
43
41
|
|
|
@@ -45,9 +43,10 @@ This MCP server provides tools that can be used by LLMs to interact with AI CLI
|
|
|
45
43
|
|
|
46
44
|
- `CLAUDE_CLI_NAME`: Override the Claude CLI binary name or provide an absolute path (default: `claude`)
|
|
47
45
|
- `CODEX_CLI_NAME`: Override the Codex CLI binary name or provide an absolute path (default: `codex`)
|
|
46
|
+
- `GEMINI_CLI_NAME`: Override the Gemini CLI binary name or provide an absolute path (default: `gemini`)
|
|
48
47
|
- `MCP_CLAUDE_DEBUG`: Enable debug logging (set to `true` for verbose output)
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
All CLI name variables support:
|
|
51
50
|
- Simple name: `CLAUDE_CLI_NAME=claude-custom` or `CODEX_CLI_NAME=codex-v2`
|
|
52
51
|
- Absolute path: `CLAUDE_CLI_NAME=/path/to/custom/claude`
|
|
53
52
|
|
|
@@ -112,7 +111,15 @@ Follow the prompts to accept. Once this is done, the MCP server will be able to
|
|
|
112
111
|
codex login
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
### For Gemini CLI:
|
|
115
|
+
|
|
116
|
+
**For Gemini, ensure you're logged in and have configured your credentials:**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
gemini auth login
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
macOS might ask for folder permissions the first time any of these tools run. If the first run fails, subsequent runs should work.
|
|
116
123
|
|
|
117
124
|
## Connecting to Your MCP Client
|
|
118
125
|
|
|
@@ -155,6 +162,7 @@ Executes a prompt using either Claude CLI or Codex CLI. The appropriate CLI is a
|
|
|
155
162
|
- `model` (string, optional): The model to use:
|
|
156
163
|
- Claude models: "sonnet", "opus", "haiku"
|
|
157
164
|
- Codex models: "gpt-5-low", "gpt-5-medium", "gpt-5-high"
|
|
165
|
+
- Gemini models: "gemini-2.5-pro", "gemini-2.5-flash"
|
|
158
166
|
- `session_id` (string, optional): Optional session ID to resume a previous session. Supported for: haiku, sonnet, opus.
|
|
159
167
|
|
|
160
168
|
### `list_processes`
|
|
@@ -199,6 +207,18 @@ Terminates a running AI agent process by PID.
|
|
|
199
207
|
}
|
|
200
208
|
```
|
|
201
209
|
|
|
210
|
+
**Example with Gemini:**
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"toolName": "run",
|
|
214
|
+
"arguments": {
|
|
215
|
+
"prompt": "Generate unit tests for the Calculator class",
|
|
216
|
+
"workFolder": "/Users/username/my_project",
|
|
217
|
+
"model": "gemini-2.5-pro"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
202
222
|
### Examples
|
|
203
223
|
|
|
204
224
|
Here are some visual examples of the server in action:
|
|
@@ -308,6 +328,31 @@ npm run test:coverage
|
|
|
308
328
|
|
|
309
329
|
For detailed testing documentation, see our [E2E Testing Guide](./docs/e2e-testing.md).
|
|
310
330
|
|
|
331
|
+
## Manual Testing with MCP Inspector
|
|
332
|
+
|
|
333
|
+
You can manually test the MCP server using the Model Context Protocol Inspector:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# Build the project first
|
|
337
|
+
npm run build
|
|
338
|
+
|
|
339
|
+
# Start the MCP Inspector with the server
|
|
340
|
+
npx @modelcontextprotocol/inspector node dist/server.js
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
This will open a web interface where you can:
|
|
344
|
+
1. View all available tools (`run`, `list_processes`, `get_result`, `kill_process`)
|
|
345
|
+
2. Test each tool with different parameters
|
|
346
|
+
3. Test different AI models including:
|
|
347
|
+
- Claude models: `sonnet`, `opus`, `haiku`
|
|
348
|
+
- Codex models: `gpt-5-low`, `gpt-5-medium`, `gpt-5-high`
|
|
349
|
+
- Gemini models: `gemini-2.5-pro`, `gemini-2.5-flash`
|
|
350
|
+
|
|
351
|
+
Example test: Select the `run` tool and provide:
|
|
352
|
+
- `prompt`: "What is 2+2?"
|
|
353
|
+
- `workFolder`: "/tmp"
|
|
354
|
+
- `model`: "gemini-2.5-flash"
|
|
355
|
+
|
|
311
356
|
## Configuration via Environment Variables
|
|
312
357
|
|
|
313
358
|
The server's behavior can be customized using these environment variables:
|
package/dist/parsers.js
CHANGED
|
@@ -52,3 +52,17 @@ export function parseClaudeOutput(stdout) {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Parse Gemini JSON output
|
|
57
|
+
*/
|
|
58
|
+
export function parseGeminiOutput(stdout) {
|
|
59
|
+
if (!stdout)
|
|
60
|
+
return null;
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(stdout);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
debugLog(`[Debug] Failed to parse Gemini JSON output: ${e}`);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -7,9 +7,9 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
8
|
import { join, resolve as pathResolve } from 'node:path';
|
|
9
9
|
import * as path from 'path';
|
|
10
|
-
import { parseCodexOutput, parseClaudeOutput } from './parsers.js';
|
|
10
|
+
import { parseCodexOutput, parseClaudeOutput, parseGeminiOutput } from './parsers.js';
|
|
11
11
|
// Server version - update this when releasing new versions
|
|
12
|
-
const SERVER_VERSION = "2.0.
|
|
12
|
+
const SERVER_VERSION = "2.0.1";
|
|
13
13
|
// Model alias mappings for user-friendly model names
|
|
14
14
|
const MODEL_ALIASES = {
|
|
15
15
|
'haiku': 'claude-3-5-haiku-20241022'
|
|
@@ -28,6 +28,42 @@ export function debugLog(message, ...optionalParams) {
|
|
|
28
28
|
console.error(message, ...optionalParams);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Determine the Gemini CLI command/path.
|
|
33
|
+
* Similar to findClaudeCli but for Gemini
|
|
34
|
+
*/
|
|
35
|
+
export function findGeminiCli() {
|
|
36
|
+
debugLog('[Debug] Attempting to find Gemini CLI...');
|
|
37
|
+
// Check for custom CLI name from environment variable
|
|
38
|
+
const customCliName = process.env.GEMINI_CLI_NAME;
|
|
39
|
+
if (customCliName) {
|
|
40
|
+
debugLog(`[Debug] Using custom Gemini CLI name from GEMINI_CLI_NAME: ${customCliName}`);
|
|
41
|
+
// If it's an absolute path, use it directly
|
|
42
|
+
if (path.isAbsolute(customCliName)) {
|
|
43
|
+
debugLog(`[Debug] GEMINI_CLI_NAME is an absolute path: ${customCliName}`);
|
|
44
|
+
return customCliName;
|
|
45
|
+
}
|
|
46
|
+
// If it starts with ~ or ./, reject as relative paths are not allowed
|
|
47
|
+
if (customCliName.startsWith('./') || customCliName.startsWith('../') || customCliName.includes('/')) {
|
|
48
|
+
throw new Error(`Invalid GEMINI_CLI_NAME: Relative paths are not allowed. Use either a simple name (e.g., 'gemini') or an absolute path (e.g., '/tmp/gemini-test')`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const cliName = customCliName || 'gemini';
|
|
52
|
+
// Try local install path: ~/.gemini/local/gemini
|
|
53
|
+
const userPath = join(homedir(), '.gemini', 'local', 'gemini');
|
|
54
|
+
debugLog(`[Debug] Checking for Gemini CLI at local user path: ${userPath}`);
|
|
55
|
+
if (existsSync(userPath)) {
|
|
56
|
+
debugLog(`[Debug] Found Gemini CLI at local user path: ${userPath}. Using this path.`);
|
|
57
|
+
return userPath;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
debugLog(`[Debug] Gemini CLI not found at local user path: ${userPath}.`);
|
|
61
|
+
}
|
|
62
|
+
// Fallback to CLI name (PATH lookup)
|
|
63
|
+
debugLog(`[Debug] Falling back to "${cliName}" command name, relying on spawn/PATH lookup.`);
|
|
64
|
+
console.warn(`[Warning] Gemini CLI not found at ~/.gemini/local/gemini. Falling back to "${cliName}" in PATH. Ensure it is installed and accessible.`);
|
|
65
|
+
return cliName;
|
|
66
|
+
}
|
|
31
67
|
/**
|
|
32
68
|
* Determine the Codex CLI command/path.
|
|
33
69
|
* Similar to findClaudeCli but for Codex
|
|
@@ -163,14 +199,17 @@ export class ClaudeCodeServer {
|
|
|
163
199
|
server;
|
|
164
200
|
claudeCliPath;
|
|
165
201
|
codexCliPath;
|
|
202
|
+
geminiCliPath;
|
|
166
203
|
sigintHandler;
|
|
167
204
|
packageVersion;
|
|
168
205
|
constructor() {
|
|
169
206
|
// Use the simplified findClaudeCli function
|
|
170
207
|
this.claudeCliPath = findClaudeCli(); // Removed debugMode argument
|
|
171
208
|
this.codexCliPath = findCodexCli();
|
|
209
|
+
this.geminiCliPath = findGeminiCli();
|
|
172
210
|
console.error(`[Setup] Using Claude CLI command/path: ${this.claudeCliPath}`);
|
|
173
211
|
console.error(`[Setup] Using Codex CLI command/path: ${this.codexCliPath}`);
|
|
212
|
+
console.error(`[Setup] Using Gemini CLI command/path: ${this.geminiCliPath}`);
|
|
174
213
|
this.packageVersion = SERVER_VERSION;
|
|
175
214
|
this.server = new Server({
|
|
176
215
|
name: 'ai_cli_mcp',
|
|
@@ -197,7 +236,7 @@ export class ClaudeCodeServer {
|
|
|
197
236
|
tools: [
|
|
198
237
|
{
|
|
199
238
|
name: 'run',
|
|
200
|
-
description: `AI Agent Runner: Starts a Claude or
|
|
239
|
+
description: `AI Agent Runner: Starts a Claude, Codex, or Gemini CLI process in the background and returns a PID immediately. Use list_processes and get_result to monitor progress.
|
|
201
240
|
|
|
202
241
|
• File ops: Create, read, (fuzzy) edit, move, copy, delete, list files, analyze/ocr images, file content analysis
|
|
203
242
|
• Code: Generate / analyse / refactor / fix
|
|
@@ -208,8 +247,8 @@ export class ClaudeCodeServer {
|
|
|
208
247
|
|
|
209
248
|
**IMPORTANT**: This tool now returns immediately with a PID. Use other tools to check status and get results.
|
|
210
249
|
|
|
211
|
-
**Supported models**:
|
|
212
|
-
"sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high"
|
|
250
|
+
**Supported models**:
|
|
251
|
+
"sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high", "gemini-2.5-pro", "gemini-2.5-flash"
|
|
213
252
|
|
|
214
253
|
**Prompt input**: You must provide EITHER prompt (string) OR prompt_file (file path), but not both.
|
|
215
254
|
|
|
@@ -223,11 +262,6 @@ export class ClaudeCodeServer {
|
|
|
223
262
|
inputSchema: {
|
|
224
263
|
type: 'object',
|
|
225
264
|
properties: {
|
|
226
|
-
agent: {
|
|
227
|
-
type: 'string',
|
|
228
|
-
description: 'The agent to use: "claude" or "codex". Defaults to "claude".',
|
|
229
|
-
enum: ['claude', 'codex'],
|
|
230
|
-
},
|
|
231
265
|
prompt: {
|
|
232
266
|
type: 'string',
|
|
233
267
|
description: 'The detailed natural language prompt for the agent to execute. Either this or prompt_file is required.',
|
|
@@ -242,7 +276,7 @@ export class ClaudeCodeServer {
|
|
|
242
276
|
},
|
|
243
277
|
model: {
|
|
244
278
|
type: 'string',
|
|
245
|
-
description: 'The model to use: "sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high".',
|
|
279
|
+
description: 'The model to use: "sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high", "gemini-2.5-pro", "gemini-2.5-flash".',
|
|
246
280
|
},
|
|
247
281
|
session_id: {
|
|
248
282
|
type: 'string',
|
|
@@ -360,7 +394,16 @@ export class ClaudeCodeServer {
|
|
|
360
394
|
}
|
|
361
395
|
// Determine which agent to use based on model name
|
|
362
396
|
const model = toolArguments.model || '';
|
|
363
|
-
|
|
397
|
+
let agent;
|
|
398
|
+
if (model.startsWith('gpt-')) {
|
|
399
|
+
agent = 'codex';
|
|
400
|
+
}
|
|
401
|
+
else if (model.startsWith('gemini')) {
|
|
402
|
+
agent = 'gemini';
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
agent = 'claude';
|
|
406
|
+
}
|
|
364
407
|
let cliPath;
|
|
365
408
|
let processArgs;
|
|
366
409
|
if (agent === 'codex') {
|
|
@@ -378,6 +421,17 @@ export class ClaudeCodeServer {
|
|
|
378
421
|
}
|
|
379
422
|
processArgs.push('--full-auto', '--json', prompt);
|
|
380
423
|
}
|
|
424
|
+
else if (agent === 'gemini') {
|
|
425
|
+
// Handle Gemini
|
|
426
|
+
cliPath = this.geminiCliPath;
|
|
427
|
+
processArgs = ['-y', '--output-format', 'json'];
|
|
428
|
+
// Add model if specified
|
|
429
|
+
if (toolArguments.model) {
|
|
430
|
+
processArgs.push('--model', toolArguments.model);
|
|
431
|
+
}
|
|
432
|
+
// Add prompt as positional argument
|
|
433
|
+
processArgs.push(prompt);
|
|
434
|
+
}
|
|
381
435
|
else {
|
|
382
436
|
// Handle Claude (default)
|
|
383
437
|
cliPath = this.claudeCliPath;
|
|
@@ -515,6 +569,9 @@ export class ClaudeCodeServer {
|
|
|
515
569
|
else if (process.toolType === 'claude') {
|
|
516
570
|
agentOutput = parseClaudeOutput(process.stdout);
|
|
517
571
|
}
|
|
572
|
+
else if (process.toolType === 'gemini') {
|
|
573
|
+
agentOutput = parseGeminiOutput(process.stdout);
|
|
574
|
+
}
|
|
518
575
|
}
|
|
519
576
|
// Construct response with agent's output and process metadata
|
|
520
577
|
const response = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-cli-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "MCP server for AI CLI tools (Claude and
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "MCP server for AI CLI tools (Claude, Codex, and Gemini) with background process management",
|
|
5
5
|
"author": "mkXultra",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/server.js",
|
package/src/parsers.ts
CHANGED
|
@@ -45,11 +45,25 @@ export function parseCodexOutput(stdout: string): any {
|
|
|
45
45
|
*/
|
|
46
46
|
export function parseClaudeOutput(stdout: string): any {
|
|
47
47
|
if (!stdout) return null;
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
try {
|
|
50
50
|
return JSON.parse(stdout);
|
|
51
51
|
} catch (e) {
|
|
52
52
|
debugLog(`[Debug] Failed to parse Claude JSON output: ${e}`);
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parse Gemini JSON output
|
|
59
|
+
*/
|
|
60
|
+
export function parseGeminiOutput(stdout: string): any {
|
|
61
|
+
if (!stdout) return null;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(stdout);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
debugLog(`[Debug] Failed to parse Gemini JSON output: ${e}`);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
55
69
|
}
|
package/src/server.ts
CHANGED
|
@@ -13,10 +13,10 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
13
13
|
import { homedir } from 'node:os';
|
|
14
14
|
import { join, resolve as pathResolve } from 'node:path';
|
|
15
15
|
import * as path from 'path';
|
|
16
|
-
import { parseCodexOutput, parseClaudeOutput } from './parsers.js';
|
|
16
|
+
import { parseCodexOutput, parseClaudeOutput, parseGeminiOutput } from './parsers.js';
|
|
17
17
|
|
|
18
18
|
// Server version - update this when releasing new versions
|
|
19
|
-
const SERVER_VERSION = "2.
|
|
19
|
+
const SERVER_VERSION = "2.1.0";
|
|
20
20
|
|
|
21
21
|
// Model alias mappings for user-friendly model names
|
|
22
22
|
const MODEL_ALIASES: Record<string, string> = {
|
|
@@ -39,7 +39,7 @@ interface ClaudeProcess {
|
|
|
39
39
|
prompt: string;
|
|
40
40
|
workFolder: string;
|
|
41
41
|
model?: string;
|
|
42
|
-
toolType: 'claude' | 'codex'; // Identify which CLI tool
|
|
42
|
+
toolType: 'claude' | 'codex' | 'gemini'; // Identify which CLI tool
|
|
43
43
|
startTime: string;
|
|
44
44
|
stdout: string;
|
|
45
45
|
stderr: string;
|
|
@@ -57,6 +57,49 @@ export function debugLog(message?: any, ...optionalParams: any[]): void {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Determine the Gemini CLI command/path.
|
|
62
|
+
* Similar to findClaudeCli but for Gemini
|
|
63
|
+
*/
|
|
64
|
+
export function findGeminiCli(): string {
|
|
65
|
+
debugLog('[Debug] Attempting to find Gemini CLI...');
|
|
66
|
+
|
|
67
|
+
// Check for custom CLI name from environment variable
|
|
68
|
+
const customCliName = process.env.GEMINI_CLI_NAME;
|
|
69
|
+
if (customCliName) {
|
|
70
|
+
debugLog(`[Debug] Using custom Gemini CLI name from GEMINI_CLI_NAME: ${customCliName}`);
|
|
71
|
+
|
|
72
|
+
// If it's an absolute path, use it directly
|
|
73
|
+
if (path.isAbsolute(customCliName)) {
|
|
74
|
+
debugLog(`[Debug] GEMINI_CLI_NAME is an absolute path: ${customCliName}`);
|
|
75
|
+
return customCliName;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// If it starts with ~ or ./, reject as relative paths are not allowed
|
|
79
|
+
if (customCliName.startsWith('./') || customCliName.startsWith('../') || customCliName.includes('/')) {
|
|
80
|
+
throw new Error(`Invalid GEMINI_CLI_NAME: Relative paths are not allowed. Use either a simple name (e.g., 'gemini') or an absolute path (e.g., '/tmp/gemini-test')`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const cliName = customCliName || 'gemini';
|
|
85
|
+
|
|
86
|
+
// Try local install path: ~/.gemini/local/gemini
|
|
87
|
+
const userPath = join(homedir(), '.gemini', 'local', 'gemini');
|
|
88
|
+
debugLog(`[Debug] Checking for Gemini CLI at local user path: ${userPath}`);
|
|
89
|
+
|
|
90
|
+
if (existsSync(userPath)) {
|
|
91
|
+
debugLog(`[Debug] Found Gemini CLI at local user path: ${userPath}. Using this path.`);
|
|
92
|
+
return userPath;
|
|
93
|
+
} else {
|
|
94
|
+
debugLog(`[Debug] Gemini CLI not found at local user path: ${userPath}.`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Fallback to CLI name (PATH lookup)
|
|
98
|
+
debugLog(`[Debug] Falling back to "${cliName}" command name, relying on spawn/PATH lookup.`);
|
|
99
|
+
console.warn(`[Warning] Gemini CLI not found at ~/.gemini/local/gemini. Falling back to "${cliName}" in PATH. Ensure it is installed and accessible.`);
|
|
100
|
+
return cliName;
|
|
101
|
+
}
|
|
102
|
+
|
|
60
103
|
/**
|
|
61
104
|
* Determine the Codex CLI command/path.
|
|
62
105
|
* Similar to findClaudeCli but for Codex
|
|
@@ -232,6 +275,7 @@ export class ClaudeCodeServer {
|
|
|
232
275
|
private server: Server;
|
|
233
276
|
private claudeCliPath: string;
|
|
234
277
|
private codexCliPath: string;
|
|
278
|
+
private geminiCliPath: string;
|
|
235
279
|
private sigintHandler?: () => Promise<void>;
|
|
236
280
|
private packageVersion: string;
|
|
237
281
|
|
|
@@ -239,8 +283,10 @@ export class ClaudeCodeServer {
|
|
|
239
283
|
// Use the simplified findClaudeCli function
|
|
240
284
|
this.claudeCliPath = findClaudeCli(); // Removed debugMode argument
|
|
241
285
|
this.codexCliPath = findCodexCli();
|
|
286
|
+
this.geminiCliPath = findGeminiCli();
|
|
242
287
|
console.error(`[Setup] Using Claude CLI command/path: ${this.claudeCliPath}`);
|
|
243
288
|
console.error(`[Setup] Using Codex CLI command/path: ${this.codexCliPath}`);
|
|
289
|
+
console.error(`[Setup] Using Gemini CLI command/path: ${this.geminiCliPath}`);
|
|
244
290
|
this.packageVersion = SERVER_VERSION;
|
|
245
291
|
|
|
246
292
|
this.server = new Server(
|
|
@@ -274,7 +320,7 @@ export class ClaudeCodeServer {
|
|
|
274
320
|
tools: [
|
|
275
321
|
{
|
|
276
322
|
name: 'run',
|
|
277
|
-
description: `AI Agent Runner: Starts a Claude or
|
|
323
|
+
description: `AI Agent Runner: Starts a Claude, Codex, or Gemini CLI process in the background and returns a PID immediately. Use list_processes and get_result to monitor progress.
|
|
278
324
|
|
|
279
325
|
• File ops: Create, read, (fuzzy) edit, move, copy, delete, list files, analyze/ocr images, file content analysis
|
|
280
326
|
• Code: Generate / analyse / refactor / fix
|
|
@@ -285,8 +331,8 @@ export class ClaudeCodeServer {
|
|
|
285
331
|
|
|
286
332
|
**IMPORTANT**: This tool now returns immediately with a PID. Use other tools to check status and get results.
|
|
287
333
|
|
|
288
|
-
**Supported models**:
|
|
289
|
-
"sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high"
|
|
334
|
+
**Supported models**:
|
|
335
|
+
"sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high", "gemini-2.5-pro", "gemini-2.5-flash"
|
|
290
336
|
|
|
291
337
|
**Prompt input**: You must provide EITHER prompt (string) OR prompt_file (file path), but not both.
|
|
292
338
|
|
|
@@ -300,11 +346,6 @@ export class ClaudeCodeServer {
|
|
|
300
346
|
inputSchema: {
|
|
301
347
|
type: 'object',
|
|
302
348
|
properties: {
|
|
303
|
-
agent: {
|
|
304
|
-
type: 'string',
|
|
305
|
-
description: 'The agent to use: "claude" or "codex". Defaults to "claude".',
|
|
306
|
-
enum: ['claude', 'codex'],
|
|
307
|
-
},
|
|
308
349
|
prompt: {
|
|
309
350
|
type: 'string',
|
|
310
351
|
description: 'The detailed natural language prompt for the agent to execute. Either this or prompt_file is required.',
|
|
@@ -319,7 +360,7 @@ export class ClaudeCodeServer {
|
|
|
319
360
|
},
|
|
320
361
|
model: {
|
|
321
362
|
type: 'string',
|
|
322
|
-
description: 'The model to use: "sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high".',
|
|
363
|
+
description: 'The model to use: "sonnet", "opus", "haiku", "gpt-5-low", "gpt-5-medium", "gpt-5-high", "gemini-2.5-pro", "gemini-2.5-flash".',
|
|
323
364
|
},
|
|
324
365
|
session_id: {
|
|
325
366
|
type: 'string',
|
|
@@ -449,16 +490,24 @@ export class ClaudeCodeServer {
|
|
|
449
490
|
|
|
450
491
|
// Determine which agent to use based on model name
|
|
451
492
|
const model = toolArguments.model || '';
|
|
452
|
-
|
|
453
|
-
|
|
493
|
+
let agent: 'codex' | 'claude' | 'gemini';
|
|
494
|
+
|
|
495
|
+
if (model.startsWith('gpt-')) {
|
|
496
|
+
agent = 'codex';
|
|
497
|
+
} else if (model.startsWith('gemini')) {
|
|
498
|
+
agent = 'gemini';
|
|
499
|
+
} else {
|
|
500
|
+
agent = 'claude';
|
|
501
|
+
}
|
|
502
|
+
|
|
454
503
|
let cliPath: string;
|
|
455
504
|
let processArgs: string[];
|
|
456
|
-
|
|
505
|
+
|
|
457
506
|
if (agent === 'codex') {
|
|
458
507
|
// Handle Codex
|
|
459
508
|
cliPath = this.codexCliPath;
|
|
460
509
|
processArgs = ['exec'];
|
|
461
|
-
|
|
510
|
+
|
|
462
511
|
// Parse model format for Codex (e.g., gpt-5-low -> model: gpt-5, effort: low)
|
|
463
512
|
if (toolArguments.model) {
|
|
464
513
|
// Split by "gpt-5-" to get the effort level
|
|
@@ -468,19 +517,32 @@ export class ClaudeCodeServer {
|
|
|
468
517
|
}
|
|
469
518
|
processArgs.push('--model', 'gpt-5');
|
|
470
519
|
}
|
|
471
|
-
|
|
520
|
+
|
|
472
521
|
processArgs.push('--full-auto', '--json', prompt);
|
|
473
|
-
|
|
522
|
+
|
|
523
|
+
} else if (agent === 'gemini') {
|
|
524
|
+
// Handle Gemini
|
|
525
|
+
cliPath = this.geminiCliPath;
|
|
526
|
+
processArgs = ['-y', '--output-format', 'json'];
|
|
527
|
+
|
|
528
|
+
// Add model if specified
|
|
529
|
+
if (toolArguments.model) {
|
|
530
|
+
processArgs.push('--model', toolArguments.model);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Add prompt as positional argument
|
|
534
|
+
processArgs.push(prompt);
|
|
535
|
+
|
|
474
536
|
} else {
|
|
475
537
|
// Handle Claude (default)
|
|
476
538
|
cliPath = this.claudeCliPath;
|
|
477
539
|
processArgs = ['--dangerously-skip-permissions', '--output-format', 'json'];
|
|
478
|
-
|
|
540
|
+
|
|
479
541
|
// Add session_id if provided (Claude only)
|
|
480
542
|
if (toolArguments.session_id && typeof toolArguments.session_id === 'string') {
|
|
481
543
|
processArgs.push('-r', toolArguments.session_id);
|
|
482
544
|
}
|
|
483
|
-
|
|
545
|
+
|
|
484
546
|
processArgs.push('-p', prompt);
|
|
485
547
|
if (toolArguments.model && typeof toolArguments.model === 'string') {
|
|
486
548
|
const resolvedModel = resolveModelAlias(toolArguments.model);
|
|
@@ -507,7 +569,7 @@ export class ClaudeCodeServer {
|
|
|
507
569
|
prompt,
|
|
508
570
|
workFolder: effectiveCwd,
|
|
509
571
|
model: toolArguments.model,
|
|
510
|
-
toolType: agent
|
|
572
|
+
toolType: agent,
|
|
511
573
|
startTime: new Date().toISOString(),
|
|
512
574
|
stdout: '',
|
|
513
575
|
stderr: '',
|
|
@@ -625,6 +687,8 @@ export class ClaudeCodeServer {
|
|
|
625
687
|
agentOutput = parseCodexOutput(process.stdout);
|
|
626
688
|
} else if (process.toolType === 'claude') {
|
|
627
689
|
agentOutput = parseClaudeOutput(process.stdout);
|
|
690
|
+
} else if (process.toolType === 'gemini') {
|
|
691
|
+
agentOutput = parseGeminiOutput(process.stdout);
|
|
628
692
|
}
|
|
629
693
|
}
|
|
630
694
|
|