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 +17 -0
- package/dist/llm-query.js +4 -29
- package/dist/llm.js +1 -3
- package/dist/logger.d.ts +2 -2
- package/dist/logger.js +2 -2
- package/dist/main.js +30 -2
- package/dist/system-prompt.d.ts +2 -0
- package/dist/system-prompt.js +45 -0
- package/package.json +11 -3
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
|
-
|
|
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
|
-
//
|
|
32
|
-
const
|
|
33
|
-
|
|
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
|
|
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,
|
|
7
|
-
export declare function logCliDebug(message: string, data?:
|
|
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
|
|
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
|
|
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 {
|
|
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,
|
|
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.
|
|
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
|
}
|