ai-cli-mcp 2.3.1 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,22 +2,17 @@ import { describe, it, expect, beforeEach, afterEach, afterAll } from 'vitest';
2
2
  import { mkdtempSync, rmSync, readFileSync, existsSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { MCPTestClient } from './utils/mcp-client.js';
5
+ import { createTestClient } from './utils/mcp-client.js';
6
6
  import { getSharedMock, cleanupSharedMock } from './utils/persistent-mock.js';
7
7
  describe('Claude Code MCP E2E Tests', () => {
8
8
  let client;
9
9
  let testDir;
10
- const serverPath = 'dist/server.js';
11
10
  beforeEach(async () => {
12
11
  // Ensure mock exists
13
12
  await getSharedMock();
14
13
  // Create a temporary directory for test files
15
14
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-test-'));
16
- // Initialize MCP client with debug mode and custom binary name using absolute path
17
- client = new MCPTestClient(serverPath, {
18
- MCP_CLAUDE_DEBUG: 'true',
19
- CLAUDE_CLI_NAME: '/tmp/claude-code-test-mock/claudeMocked',
20
- });
15
+ client = createTestClient();
21
16
  await client.connect();
22
17
  });
23
18
  afterEach(async () => {
@@ -198,9 +193,7 @@ describe('Integration Tests (Local Only)', () => {
198
193
  beforeEach(async () => {
199
194
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-integration-'));
200
195
  // Initialize client without mocks for real Claude testing
201
- client = new MCPTestClient('dist/server.js', {
202
- MCP_CLAUDE_DEBUG: 'true',
203
- });
196
+ client = createTestClient({ claudeCliName: '' });
204
197
  });
205
198
  afterEach(async () => {
206
199
  if (client) {
@@ -2,22 +2,17 @@ import { describe, it, expect, beforeEach, afterEach, afterAll } from 'vitest';
2
2
  import { mkdtempSync, rmSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { MCPTestClient } from './utils/mcp-client.js';
5
+ import { createTestClient } from './utils/mcp-client.js';
6
6
  import { getSharedMock, cleanupSharedMock } from './utils/persistent-mock.js';
7
7
  describe('Claude Code Edge Cases', () => {
8
8
  let client;
9
9
  let testDir;
10
- const serverPath = 'dist/server.js';
11
10
  beforeEach(async () => {
12
11
  // Ensure mock exists
13
12
  await getSharedMock();
14
13
  // Create test directory
15
14
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-edge-'));
16
- // Initialize client with custom binary name using absolute path
17
- client = new MCPTestClient(serverPath, {
18
- MCP_CLAUDE_DEBUG: 'true',
19
- CLAUDE_CLI_NAME: '/tmp/claude-code-test-mock/claudeMocked',
20
- });
15
+ client = createTestClient();
21
16
  await client.connect();
22
17
  });
23
18
  afterEach(async () => {
@@ -80,10 +75,7 @@ describe('Claude Code Edge Cases', () => {
80
75
  describe('Error Recovery', () => {
81
76
  it('should handle Claude CLI not found gracefully', async () => {
82
77
  // Create a client with a different binary name that doesn't exist
83
- const errorClient = new MCPTestClient(serverPath, {
84
- MCP_CLAUDE_DEBUG: 'true',
85
- CLAUDE_CLI_NAME: 'non-existent-claude',
86
- });
78
+ const errorClient = createTestClient({ claudeCliName: 'non-existent-claude' });
87
79
  await errorClient.connect();
88
80
  await expect(errorClient.callTool('run', {
89
81
  prompt: 'Test prompt',
@@ -102,3 +102,20 @@ export class MCPTestClient extends EventEmitter {
102
102
  return response.result?.tools || [];
103
103
  }
104
104
  }
105
+ /**
106
+ * Default server path
107
+ */
108
+ const DEFAULT_SERVER_PATH = 'dist/server.js';
109
+ /**
110
+ * Create a test client with standard configuration
111
+ * Automatically unsets VITEST env so the server actually starts
112
+ */
113
+ export function createTestClient(options = {}) {
114
+ const { serverPath = DEFAULT_SERVER_PATH, claudeCliName = '/tmp/claude-code-test-mock/claudeMocked', debug = true, env = {}, } = options;
115
+ return new MCPTestClient(serverPath, {
116
+ VITEST: '', // Unset so server starts
117
+ MCP_CLAUDE_DEBUG: debug ? 'true' : '',
118
+ CLAUDE_CLI_NAME: claudeCliName,
119
+ ...env,
120
+ });
121
+ }
@@ -2,13 +2,12 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
2
  import { mkdtempSync, rmSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { MCPTestClient } from './utils/mcp-client.js';
5
+ import { createTestClient } from './utils/mcp-client.js';
6
6
  import { getSharedMock } from './utils/persistent-mock.js';
7
7
  describe('Version Print on First Use', () => {
8
8
  let client;
9
9
  let testDir;
10
10
  let consoleErrorSpy;
11
- const serverPath = 'dist/server.js';
12
11
  beforeEach(async () => {
13
12
  // Ensure mock exists
14
13
  await getSharedMock();
@@ -16,10 +15,7 @@ describe('Version Print on First Use', () => {
16
15
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-test-'));
17
16
  // Spy on console.error
18
17
  consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
19
- // Initialize MCP client with custom binary name using absolute path
20
- client = new MCPTestClient(serverPath, {
21
- CLAUDE_CLI_NAME: '/tmp/claude-code-test-mock/claudeMocked',
22
- });
18
+ client = createTestClient({ debug: false });
23
19
  await client.connect();
24
20
  });
25
21
  afterEach(async () => {
package/dist/server.js CHANGED
@@ -6,7 +6,6 @@ import { spawn } from 'node:child_process';
6
6
  import { existsSync, readFileSync } from 'node:fs';
7
7
  import { homedir } from 'node:os';
8
8
  import { join, resolve as pathResolve } from 'node:path';
9
- import { fileURLToPath } from 'node:url';
10
9
  import * as path from 'path';
11
10
  import { parseCodexOutput, parseClaudeOutput, parseGeminiOutput } from './parsers.js';
12
11
  // Server version - update this when releasing new versions
@@ -766,9 +765,8 @@ export class ClaudeCodeServer {
766
765
  await this.server.close();
767
766
  }
768
767
  }
769
- // Create and run the server if this is the main module
770
- const __filename = fileURLToPath(import.meta.url);
771
- if (process.argv[1] === __filename) {
768
+ // Create and run the server (skip during tests)
769
+ if (!process.env.VITEST) {
772
770
  const server = new ClaudeCodeServer();
773
771
  server.run().catch(console.error);
774
772
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-cli-mcp",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "MCP server for AI CLI tools (Claude, Codex, and Gemini) with background process management",
5
5
  "author": "mkXultra",
6
6
  "license": "MIT",
@@ -2,13 +2,12 @@ import { describe, it, expect, beforeEach, afterEach, afterAll } from 'vitest';
2
2
  import { mkdtempSync, rmSync, readFileSync, existsSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { MCPTestClient } from './utils/mcp-client.js';
5
+ import { createTestClient, MCPTestClient } from './utils/mcp-client.js';
6
6
  import { getSharedMock, cleanupSharedMock } from './utils/persistent-mock.js';
7
7
 
8
8
  describe('Claude Code MCP E2E Tests', () => {
9
9
  let client: MCPTestClient;
10
10
  let testDir: string;
11
- const serverPath = 'dist/server.js';
12
11
 
13
12
  beforeEach(async () => {
14
13
  // Ensure mock exists
@@ -17,11 +16,7 @@ describe('Claude Code MCP E2E Tests', () => {
17
16
  // Create a temporary directory for test files
18
17
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-test-'));
19
18
 
20
- // Initialize MCP client with debug mode and custom binary name using absolute path
21
- client = new MCPTestClient(serverPath, {
22
- MCP_CLAUDE_DEBUG: 'true',
23
- CLAUDE_CLI_NAME: '/tmp/claude-code-test-mock/claudeMocked',
24
- });
19
+ client = createTestClient();
25
20
 
26
21
  await client.connect();
27
22
  });
@@ -241,9 +236,7 @@ describe('Integration Tests (Local Only)', () => {
241
236
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-integration-'));
242
237
 
243
238
  // Initialize client without mocks for real Claude testing
244
- client = new MCPTestClient('dist/server.js', {
245
- MCP_CLAUDE_DEBUG: 'true',
246
- });
239
+ client = createTestClient({ claudeCliName: '' });
247
240
  });
248
241
 
249
242
  afterEach(async () => {
@@ -2,27 +2,21 @@ import { describe, it, expect, beforeEach, afterEach, afterAll } from 'vitest';
2
2
  import { mkdtempSync, rmSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { MCPTestClient } from './utils/mcp-client.js';
5
+ import { createTestClient, MCPTestClient } from './utils/mcp-client.js';
6
6
  import { getSharedMock, cleanupSharedMock } from './utils/persistent-mock.js';
7
7
 
8
8
  describe('Claude Code Edge Cases', () => {
9
9
  let client: MCPTestClient;
10
10
  let testDir: string;
11
- const serverPath = 'dist/server.js';
12
11
 
13
12
  beforeEach(async () => {
14
13
  // Ensure mock exists
15
14
  await getSharedMock();
16
-
15
+
17
16
  // Create test directory
18
17
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-edge-'));
19
-
20
- // Initialize client with custom binary name using absolute path
21
- client = new MCPTestClient(serverPath, {
22
- MCP_CLAUDE_DEBUG: 'true',
23
- CLAUDE_CLI_NAME: '/tmp/claude-code-test-mock/claudeMocked',
24
- });
25
-
18
+
19
+ client = createTestClient();
26
20
  await client.connect();
27
21
  });
28
22
 
@@ -106,10 +100,7 @@ describe('Claude Code Edge Cases', () => {
106
100
  describe('Error Recovery', () => {
107
101
  it('should handle Claude CLI not found gracefully', async () => {
108
102
  // Create a client with a different binary name that doesn't exist
109
- const errorClient = new MCPTestClient(serverPath, {
110
- MCP_CLAUDE_DEBUG: 'true',
111
- CLAUDE_CLI_NAME: 'non-existent-claude',
112
- });
103
+ const errorClient = createTestClient({ claudeCliName: 'non-existent-claude' });
113
104
  await errorClient.connect();
114
105
 
115
106
  await expect(
@@ -126,4 +126,34 @@ export class MCPTestClient extends EventEmitter {
126
126
  const response = await this.sendRequest('tools/list');
127
127
  return response.result?.tools || [];
128
128
  }
129
+ }
130
+
131
+ /**
132
+ * Default server path
133
+ */
134
+ const DEFAULT_SERVER_PATH = 'dist/server.js';
135
+
136
+ /**
137
+ * Create a test client with standard configuration
138
+ * Automatically unsets VITEST env so the server actually starts
139
+ */
140
+ export function createTestClient(options: {
141
+ serverPath?: string;
142
+ claudeCliName?: string;
143
+ debug?: boolean;
144
+ env?: Record<string, string>;
145
+ } = {}): MCPTestClient {
146
+ const {
147
+ serverPath = DEFAULT_SERVER_PATH,
148
+ claudeCliName = '/tmp/claude-code-test-mock/claudeMocked',
149
+ debug = true,
150
+ env = {},
151
+ } = options;
152
+
153
+ return new MCPTestClient(serverPath, {
154
+ VITEST: '', // Unset so server starts
155
+ MCP_CLAUDE_DEBUG: debug ? 'true' : '',
156
+ CLAUDE_CLI_NAME: claudeCliName,
157
+ ...env,
158
+ });
129
159
  }
@@ -2,30 +2,25 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
2
  import { mkdtempSync, rmSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
- import { MCPTestClient } from './utils/mcp-client.js';
5
+ import { createTestClient, MCPTestClient } from './utils/mcp-client.js';
6
6
  import { getSharedMock } from './utils/persistent-mock.js';
7
7
 
8
8
  describe('Version Print on First Use', () => {
9
9
  let client: MCPTestClient;
10
10
  let testDir: string;
11
11
  let consoleErrorSpy: any;
12
- const serverPath = 'dist/server.js';
13
12
 
14
13
  beforeEach(async () => {
15
14
  // Ensure mock exists
16
15
  await getSharedMock();
17
-
16
+
18
17
  // Create a temporary directory for test files
19
18
  testDir = mkdtempSync(join(tmpdir(), 'claude-code-test-'));
20
-
19
+
21
20
  // Spy on console.error
22
21
  consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
23
-
24
- // Initialize MCP client with custom binary name using absolute path
25
- client = new MCPTestClient(serverPath, {
26
- CLAUDE_CLI_NAME: '/tmp/claude-code-test-mock/claudeMocked',
27
- });
28
-
22
+
23
+ client = createTestClient({ debug: false });
29
24
  await client.connect();
30
25
  });
31
26
 
package/src/server.ts CHANGED
@@ -12,7 +12,6 @@ import { spawn, ChildProcess } from 'node:child_process';
12
12
  import { existsSync, readFileSync } from 'node:fs';
13
13
  import { homedir } from 'node:os';
14
14
  import { join, resolve as pathResolve } from 'node:path';
15
- import { fileURLToPath } from 'node:url';
16
15
  import * as path from 'path';
17
16
  import { parseCodexOutput, parseClaudeOutput, parseGeminiOutput } from './parsers.js';
18
17
 
@@ -917,9 +916,8 @@ export class ClaudeCodeServer {
917
916
  }
918
917
  }
919
918
 
920
- // Create and run the server if this is the main module
921
- const __filename = fileURLToPath(import.meta.url);
922
- if (process.argv[1] === __filename) {
919
+ // Create and run the server (skip during tests)
920
+ if (!process.env.VITEST) {
923
921
  const server = new ClaudeCodeServer();
924
922
  server.run().catch(console.error);
925
923
  }