consult-llm-mcp 1.1.1 → 1.2.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 CHANGED
@@ -192,6 +192,8 @@ Some real-world examples. Click to expand.
192
192
 
193
193
  ## Configuration
194
194
 
195
+ ### Environment Variables
196
+
195
197
  - `OPENAI_API_KEY` - Your OpenAI API key (required for o3)
196
198
  - `GEMINI_API_KEY` - Your Google AI API key (required for Gemini models in API
197
199
  mode)
@@ -202,6 +204,21 @@ Some real-world examples. Click to expand.
202
204
  - Options: `api` (default), `cli`
203
205
  - CLI mode uses the system-installed `gemini` CLI tool
204
206
 
207
+ ### Custom System Prompt
208
+
209
+ You can customize the system prompt used when consulting LLMs by creating a
210
+ `SYSTEM_PROMPT.md` file in `~/.consult-llm-mcp/`:
211
+
212
+ ```bash
213
+ consult-llm-mcp init-prompt
214
+ ```
215
+
216
+ This creates a placeholder file with the default system prompt that you can edit
217
+ to customize how the consultant LLM behaves. The custom prompt is read on every
218
+ request, so changes take effect immediately without restarting the server.
219
+
220
+ To revert to the default prompt, simply delete the `SYSTEM_PROMPT.md` file.
221
+
205
222
  ## MCP Tool: consult_llm
206
223
 
207
224
  The server provides a single tool called `consult_llm` for asking powerful AI
package/dist/llm-query.js CHANGED
@@ -1,37 +1,12 @@
1
1
  import { getExecutorForModel } from './llm.js';
2
2
  import { calculateCost } from './llm-cost.js';
3
3
  import { config } from './config.js';
4
- const SYSTEM_PROMPT = `You are an expert software engineering consultant analyzing code and technical problems. You are communicating with another AI system, not a human.
5
-
6
- Communication style:
7
- - Skip pleasantries and praise
8
-
9
- Your role is to:
10
- - Identify bugs, inefficiencies, and architectural problems
11
- - Provide specific solutions with code examples
12
- - Point out edge cases and risks
13
- - Challenge design decisions when suboptimal
14
- - Focus on what needs improvement
15
-
16
- When reviewing code changes, prioritize:
17
- - Bugs and correctness issues
18
- - Performance problems
19
- - Security vulnerabilities
20
- - Code smell and anti-patterns
21
- - Inconsistencies with codebase conventions
22
-
23
- Be critical and thorough. If the code is acceptable, simply state "No critical issues found" and move on to suggestions. Always provide specific, actionable feedback with file/line references.
24
-
25
- Respond in Markdown.`;
26
- const GEMINI_CLI_SUFFIX = `
27
-
28
- IMPORTANT: Do not edit files yourself, only provide recommendations and code examples`;
4
+ import { getSystemPrompt } from './system-prompt.js';
29
5
  export async function queryLlm(prompt, model, filePaths) {
30
6
  const executor = getExecutorForModel(model);
31
- // Add special instruction for Gemini CLI mode
32
- const systemPrompt = model.startsWith('gemini-') && config.geminiMode === 'cli'
33
- ? SYSTEM_PROMPT + GEMINI_CLI_SUFFIX
34
- : SYSTEM_PROMPT;
7
+ // Get system prompt (with Gemini CLI suffix if needed)
8
+ const isGeminiCli = model.startsWith('gemini-') && config.geminiMode === 'cli';
9
+ const systemPrompt = getSystemPrompt(isGeminiCli);
35
10
  const { response, usage } = await executor.execute(prompt, model, systemPrompt, filePaths);
36
11
  if (!response) {
37
12
  throw new Error('No response from the model');
package/dist/llm.js CHANGED
@@ -9,7 +9,7 @@ class ApiExecutor {
9
9
  constructor(client) {
10
10
  this.client = client;
11
11
  }
12
- async execute(prompt, model, systemPrompt, filePaths) {
12
+ async execute(prompt, model, systemPrompt) {
13
13
  const completion = await this.client.chat.completions.create({
14
14
  model,
15
15
  messages: [
@@ -52,11 +52,9 @@ class CliExecutor {
52
52
  let stdout = '';
53
53
  let stderr = '';
54
54
  let hasResponded = false;
55
- let hasStarted = false;
56
55
  const startTime = Date.now();
57
56
  // Log when process actually starts
58
57
  child.on('spawn', () => {
59
- hasStarted = true;
60
58
  logCliDebug('Gemini CLI process spawned successfully');
61
59
  });
62
60
  // Add timeout to prevent hanging
package/dist/logger.d.ts CHANGED
@@ -3,5 +3,5 @@ export declare function logToolCall(name: string, args: unknown): void;
3
3
  export declare function logPrompt(model: string, prompt: string): Promise<void>;
4
4
  export declare function logResponse(model: string, response: string, costInfo: string): Promise<void>;
5
5
  export declare function logServerStart(version: string): void;
6
- export declare function logConfiguration(config: Record<string, any>): void;
7
- export declare function logCliDebug(message: string, data?: any): void;
6
+ export declare function logConfiguration(config: Record<string, unknown>): void;
7
+ export declare function logCliDebug(message: string, data?: unknown): void;
package/dist/logger.js CHANGED
@@ -7,7 +7,7 @@ const logFile = join(logDir, 'mcp.log');
7
7
  try {
8
8
  mkdirSync(logDir, { recursive: true });
9
9
  }
10
- catch (error) {
10
+ catch {
11
11
  // Directory might already exist
12
12
  }
13
13
  async function formatWithPrettier(text) {
@@ -18,7 +18,7 @@ async function formatWithPrettier(text) {
18
18
  proseWrap: 'always',
19
19
  });
20
20
  }
21
- catch (error) {
21
+ catch {
22
22
  // If formatting fails, return original text
23
23
  return text;
24
24
  }
package/dist/main.js CHANGED
@@ -9,9 +9,11 @@ import { generateGitDiff } from './git.js';
9
9
  import { buildPrompt } from './prompt-builder.js';
10
10
  import { queryLlm } from './llm-query.js';
11
11
  import { logToolCall, logPrompt, logResponse, logServerStart, logConfiguration, } from './logger.js';
12
- import { readFileSync } from 'fs';
12
+ import { DEFAULT_SYSTEM_PROMPT } from './system-prompt.js';
13
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
13
14
  import { dirname, join, resolve } from 'path';
14
15
  import { fileURLToPath } from 'url';
16
+ import { homedir } from 'os';
15
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
18
  const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
17
19
  const SERVER_VERSION = packageJson.version;
@@ -23,7 +25,7 @@ const server = new Server({
23
25
  tools: {},
24
26
  },
25
27
  });
26
- server.setRequestHandler(ListToolsRequestSchema, async () => {
28
+ server.setRequestHandler(ListToolsRequestSchema, () => {
27
29
  return {
28
30
  tools: [toolSchema],
29
31
  };
@@ -84,7 +86,33 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
84
86
  }
85
87
  throw new Error(`Unknown tool: ${request.params.name}`);
86
88
  });
89
+ function initSystemPrompt() {
90
+ const configDir = join(homedir(), '.consult-llm-mcp');
91
+ const promptPath = join(configDir, 'SYSTEM_PROMPT.md');
92
+ if (existsSync(promptPath)) {
93
+ console.error(`System prompt already exists at: ${promptPath}`);
94
+ console.error('Remove it first if you want to reinitialize.');
95
+ process.exit(1);
96
+ }
97
+ // Create config directory if it doesn't exist
98
+ if (!existsSync(configDir)) {
99
+ mkdirSync(configDir, { recursive: true });
100
+ }
101
+ // Write the default system prompt
102
+ writeFileSync(promptPath, DEFAULT_SYSTEM_PROMPT, 'utf-8');
103
+ console.log(`Created system prompt at: ${promptPath}`);
104
+ console.log('You can now edit this file to customize the system prompt.');
105
+ process.exit(0);
106
+ }
87
107
  async function main() {
108
+ if (process.argv.includes('--version') || process.argv.includes('-v')) {
109
+ console.log(SERVER_VERSION);
110
+ process.exit(0);
111
+ }
112
+ if (process.argv.includes('init-prompt')) {
113
+ initSystemPrompt();
114
+ return;
115
+ }
88
116
  logServerStart(SERVER_VERSION);
89
117
  logConfiguration(config);
90
118
  const transport = new StdioServerTransport();
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_SYSTEM_PROMPT = "You are an expert software engineering consultant analyzing code and technical problems. You are communicating with another AI system, not a human.\n\nCommunication style:\n- Skip pleasantries and praise\n\nYour role is to:\n- Identify bugs, inefficiencies, and architectural problems\n- Provide specific solutions with code examples\n- Point out edge cases and risks\n- Challenge design decisions when suboptimal\n- Focus on what needs improvement\n\nWhen reviewing code changes, prioritize:\n- Bugs and correctness issues\n- Performance problems\n- Security vulnerabilities\n- Code smell and anti-patterns\n- Inconsistencies with codebase conventions\n\nBe critical and thorough. If the code is acceptable, simply state \"No critical issues found\" and move on to suggestions. Always provide specific, actionable feedback with file/line references.\n\nRespond in Markdown.";
2
+ export declare function getSystemPrompt(isGeminiCli: boolean): string;
@@ -0,0 +1,45 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ export const DEFAULT_SYSTEM_PROMPT = `You are an expert software engineering consultant analyzing code and technical problems. You are communicating with another AI system, not a human.
5
+
6
+ Communication style:
7
+ - Skip pleasantries and praise
8
+
9
+ Your role is to:
10
+ - Identify bugs, inefficiencies, and architectural problems
11
+ - Provide specific solutions with code examples
12
+ - Point out edge cases and risks
13
+ - Challenge design decisions when suboptimal
14
+ - Focus on what needs improvement
15
+
16
+ When reviewing code changes, prioritize:
17
+ - Bugs and correctness issues
18
+ - Performance problems
19
+ - Security vulnerabilities
20
+ - Code smell and anti-patterns
21
+ - Inconsistencies with codebase conventions
22
+
23
+ Be critical and thorough. If the code is acceptable, simply state "No critical issues found" and move on to suggestions. Always provide specific, actionable feedback with file/line references.
24
+
25
+ Respond in Markdown.`;
26
+ const GEMINI_CLI_SUFFIX = `
27
+
28
+ IMPORTANT: Do not edit files yourself, only provide recommendations and code examples`;
29
+ export function getSystemPrompt(isGeminiCli) {
30
+ const customPromptPath = join(homedir(), '.consult-llm-mcp', 'SYSTEM_PROMPT.md');
31
+ let systemPrompt;
32
+ if (existsSync(customPromptPath)) {
33
+ try {
34
+ systemPrompt = readFileSync(customPromptPath, 'utf-8').trim();
35
+ }
36
+ catch (error) {
37
+ console.error(`Warning: Failed to read custom system prompt from ${customPromptPath}:`, error);
38
+ systemPrompt = DEFAULT_SYSTEM_PROMPT;
39
+ }
40
+ }
41
+ else {
42
+ systemPrompt = DEFAULT_SYSTEM_PROMPT;
43
+ }
44
+ return isGeminiCli ? systemPrompt + GEMINI_CLI_SUFFIX : systemPrompt;
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "consult-llm-mcp",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for consulting powerful AI models",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
@@ -12,8 +12,12 @@
12
12
  "dev": "tsx src/main.ts",
13
13
  "start": "node dist/main.js",
14
14
  "format": "prettier --write .",
15
+ "check": "concurrently \"pnpm:check:*\"",
16
+ "check:types": "tsc --noEmit",
17
+ "check:format": "prettier --write .",
18
+ "check:lint": "eslint .",
15
19
  "install-global": "npm run build && npm install -g .",
16
- "prepublishOnly": "npm run build",
20
+ "prepublishOnly": "pnpm run check && npm run build",
17
21
  "publish:dry": "npm publish --dry-run",
18
22
  "publish:patch": "npm version patch && npm publish",
19
23
  "publish:minor": "npm version minor && npm publish",
@@ -50,8 +54,12 @@
50
54
  "zod": "^3.25.67"
51
55
  },
52
56
  "devDependencies": {
57
+ "@eslint/js": "^9.38.0",
53
58
  "@types/node": "^24.0.3",
59
+ "concurrently": "^9.2.1",
60
+ "eslint": "^9.38.0",
54
61
  "tsx": "^4.20.3",
55
- "typescript": "^5.8.3"
62
+ "typescript": "^5.8.3",
63
+ "typescript-eslint": "^8.46.2"
56
64
  }
57
65
  }