@rlabs-inc/gemini-mcp 0.6.2 → 0.7.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 +46 -43
- package/dist/cli/commands/config.d.ts +8 -0
- package/dist/cli/commands/config.js +147 -0
- package/dist/cli/commands/image.d.ts +7 -0
- package/dist/cli/commands/image.js +133 -0
- package/dist/cli/commands/query.d.ts +7 -0
- package/dist/cli/commands/query.js +94 -0
- package/dist/cli/commands/research.d.ts +7 -0
- package/dist/cli/commands/research.js +147 -0
- package/dist/cli/commands/search.d.ts +7 -0
- package/dist/cli/commands/search.js +152 -0
- package/dist/cli/commands/speak.d.ts +7 -0
- package/dist/cli/commands/speak.js +168 -0
- package/dist/cli/commands/tokens.d.ts +8 -0
- package/dist/cli/commands/tokens.js +105 -0
- package/dist/cli/commands/video.d.ts +7 -0
- package/dist/cli/commands/video.js +154 -0
- package/dist/cli/config.d.ts +23 -0
- package/dist/cli/config.js +89 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +180 -0
- package/dist/cli/ui/box.d.ts +20 -0
- package/dist/cli/ui/box.js +112 -0
- package/dist/cli/ui/colors.d.ts +46 -0
- package/dist/cli/ui/colors.js +106 -0
- package/dist/cli/ui/index.d.ts +21 -0
- package/dist/cli/ui/index.js +42 -0
- package/dist/cli/ui/progress.d.ts +37 -0
- package/dist/cli/ui/progress.js +125 -0
- package/dist/cli/ui/spinner.d.ts +42 -0
- package/dist/cli/ui/spinner.js +96 -0
- package/dist/cli/ui/theme.d.ts +48 -0
- package/dist/cli/ui/theme.js +200 -0
- package/dist/gemini-client.d.ts +1 -0
- package/dist/gemini-client.js +35 -8
- package/dist/index.d.ts +6 -3
- package/dist/index.js +26 -218
- package/dist/server.d.ts +7 -0
- package/dist/server.js +221 -0
- package/dist/tools/deep-research.js +9 -2
- package/package.json +9 -3
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme System for Gemini CLI
|
|
3
|
+
*
|
|
4
|
+
* Provides beautiful, consistent styling across all CLI output.
|
|
5
|
+
* Default theme adapts to terminal colors.
|
|
6
|
+
*/
|
|
7
|
+
import { cyan, magenta, green, red, yellow, blue, brightBlack, white, brightCyan, hex, dim, bold, } from './colors.js';
|
|
8
|
+
// Terminal theme - adapts to user's terminal colors
|
|
9
|
+
export const terminalTheme = {
|
|
10
|
+
name: 'terminal',
|
|
11
|
+
colors: {
|
|
12
|
+
primary: cyan,
|
|
13
|
+
secondary: magenta,
|
|
14
|
+
success: green,
|
|
15
|
+
error: red,
|
|
16
|
+
warning: yellow,
|
|
17
|
+
info: blue,
|
|
18
|
+
muted: brightBlack,
|
|
19
|
+
text: white,
|
|
20
|
+
highlight: brightCyan,
|
|
21
|
+
},
|
|
22
|
+
symbols: {
|
|
23
|
+
success: '✓',
|
|
24
|
+
error: '✗',
|
|
25
|
+
warning: '⚠',
|
|
26
|
+
info: 'ℹ',
|
|
27
|
+
spinner: ['◐', '◓', '◑', '◒'],
|
|
28
|
+
arrow: '→',
|
|
29
|
+
bullet: '•',
|
|
30
|
+
pointer: '❯',
|
|
31
|
+
star: '★',
|
|
32
|
+
},
|
|
33
|
+
box: {
|
|
34
|
+
topLeft: '┌',
|
|
35
|
+
topRight: '┐',
|
|
36
|
+
bottomLeft: '└',
|
|
37
|
+
bottomRight: '┘',
|
|
38
|
+
horizontal: '─',
|
|
39
|
+
vertical: '│',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
// Neon theme - cyberpunk vibes
|
|
43
|
+
export const neonTheme = {
|
|
44
|
+
name: 'neon',
|
|
45
|
+
colors: {
|
|
46
|
+
primary: hex('#ff00ff'), // Hot pink
|
|
47
|
+
secondary: hex('#00ffff'), // Cyan
|
|
48
|
+
success: hex('#39ff14'), // Neon green
|
|
49
|
+
error: hex('#ff3131'), // Neon red
|
|
50
|
+
warning: hex('#ffff00'), // Neon yellow
|
|
51
|
+
info: hex('#00bfff'), // Deep sky blue
|
|
52
|
+
muted: hex('#666666'),
|
|
53
|
+
text: hex('#ffffff'),
|
|
54
|
+
highlight: hex('#ff6ec7'), // Pink
|
|
55
|
+
},
|
|
56
|
+
symbols: {
|
|
57
|
+
success: '◆',
|
|
58
|
+
error: '◆',
|
|
59
|
+
warning: '◆',
|
|
60
|
+
info: '◆',
|
|
61
|
+
spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
|
|
62
|
+
arrow: '▸',
|
|
63
|
+
bullet: '▪',
|
|
64
|
+
pointer: '▶',
|
|
65
|
+
star: '✦',
|
|
66
|
+
},
|
|
67
|
+
box: {
|
|
68
|
+
topLeft: '╔',
|
|
69
|
+
topRight: '╗',
|
|
70
|
+
bottomLeft: '╚',
|
|
71
|
+
bottomRight: '╝',
|
|
72
|
+
horizontal: '═',
|
|
73
|
+
vertical: '║',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
// Minimal theme - subtle, mostly monochrome
|
|
77
|
+
export const minimalTheme = {
|
|
78
|
+
name: 'minimal',
|
|
79
|
+
colors: {
|
|
80
|
+
primary: white,
|
|
81
|
+
secondary: brightBlack,
|
|
82
|
+
success: green,
|
|
83
|
+
error: red,
|
|
84
|
+
warning: yellow,
|
|
85
|
+
info: brightBlack,
|
|
86
|
+
muted: dim,
|
|
87
|
+
text: white,
|
|
88
|
+
highlight: bold,
|
|
89
|
+
},
|
|
90
|
+
symbols: {
|
|
91
|
+
success: '+',
|
|
92
|
+
error: 'x',
|
|
93
|
+
warning: '!',
|
|
94
|
+
info: '-',
|
|
95
|
+
spinner: ['-', '\\', '|', '/'],
|
|
96
|
+
arrow: '>',
|
|
97
|
+
bullet: '-',
|
|
98
|
+
pointer: '>',
|
|
99
|
+
star: '*',
|
|
100
|
+
},
|
|
101
|
+
box: {
|
|
102
|
+
topLeft: '+',
|
|
103
|
+
topRight: '+',
|
|
104
|
+
bottomLeft: '+',
|
|
105
|
+
bottomRight: '+',
|
|
106
|
+
horizontal: '-',
|
|
107
|
+
vertical: '|',
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
// Ocean theme - blues and teals
|
|
111
|
+
export const oceanTheme = {
|
|
112
|
+
name: 'ocean',
|
|
113
|
+
colors: {
|
|
114
|
+
primary: hex('#00ced1'), // Dark turquoise
|
|
115
|
+
secondary: hex('#4682b4'), // Steel blue
|
|
116
|
+
success: hex('#20b2aa'), // Light sea green
|
|
117
|
+
error: hex('#ff6347'), // Tomato
|
|
118
|
+
warning: hex('#ffa500'), // Orange
|
|
119
|
+
info: hex('#87ceeb'), // Sky blue
|
|
120
|
+
muted: hex('#708090'), // Slate gray
|
|
121
|
+
text: hex('#e0ffff'), // Light cyan
|
|
122
|
+
highlight: hex('#00ffff'), // Aqua
|
|
123
|
+
},
|
|
124
|
+
symbols: {
|
|
125
|
+
success: '●',
|
|
126
|
+
error: '●',
|
|
127
|
+
warning: '●',
|
|
128
|
+
info: '●',
|
|
129
|
+
spinner: ['∙∙∙', '●∙∙', '∙●∙', '∙∙●', '∙●∙', '●∙∙'],
|
|
130
|
+
arrow: '➜',
|
|
131
|
+
bullet: '○',
|
|
132
|
+
pointer: '➤',
|
|
133
|
+
star: '✧',
|
|
134
|
+
},
|
|
135
|
+
box: {
|
|
136
|
+
topLeft: '╭',
|
|
137
|
+
topRight: '╮',
|
|
138
|
+
bottomLeft: '╰',
|
|
139
|
+
bottomRight: '╯',
|
|
140
|
+
horizontal: '─',
|
|
141
|
+
vertical: '│',
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
// Forest theme - greens and earth tones
|
|
145
|
+
export const forestTheme = {
|
|
146
|
+
name: 'forest',
|
|
147
|
+
colors: {
|
|
148
|
+
primary: hex('#228b22'), // Forest green
|
|
149
|
+
secondary: hex('#8b4513'), // Saddle brown
|
|
150
|
+
success: hex('#32cd32'), // Lime green
|
|
151
|
+
error: hex('#dc143c'), // Crimson
|
|
152
|
+
warning: hex('#daa520'), // Goldenrod
|
|
153
|
+
info: hex('#6b8e23'), // Olive drab
|
|
154
|
+
muted: hex('#696969'), // Dim gray
|
|
155
|
+
text: hex('#f5f5dc'), // Beige
|
|
156
|
+
highlight: hex('#98fb98'), // Pale green
|
|
157
|
+
},
|
|
158
|
+
symbols: {
|
|
159
|
+
success: '✓',
|
|
160
|
+
error: '✗',
|
|
161
|
+
warning: '⚡',
|
|
162
|
+
info: '❧',
|
|
163
|
+
spinner: ['🌱', '🌿', '🌳', '🌲'],
|
|
164
|
+
arrow: '➔',
|
|
165
|
+
bullet: '❀',
|
|
166
|
+
pointer: '➣',
|
|
167
|
+
star: '❁',
|
|
168
|
+
},
|
|
169
|
+
box: {
|
|
170
|
+
topLeft: '┏',
|
|
171
|
+
topRight: '┓',
|
|
172
|
+
bottomLeft: '┗',
|
|
173
|
+
bottomRight: '┛',
|
|
174
|
+
horizontal: '━',
|
|
175
|
+
vertical: '┃',
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
// All available themes
|
|
179
|
+
export const themes = {
|
|
180
|
+
terminal: terminalTheme,
|
|
181
|
+
neon: neonTheme,
|
|
182
|
+
minimal: minimalTheme,
|
|
183
|
+
ocean: oceanTheme,
|
|
184
|
+
forest: forestTheme,
|
|
185
|
+
};
|
|
186
|
+
// Current active theme (default to terminal)
|
|
187
|
+
let currentTheme = terminalTheme;
|
|
188
|
+
export function setTheme(themeName) {
|
|
189
|
+
const theme = themes[themeName];
|
|
190
|
+
if (theme) {
|
|
191
|
+
currentTheme = theme;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export function getTheme() {
|
|
195
|
+
return currentTheme;
|
|
196
|
+
}
|
|
197
|
+
// Convenience function to get themed colors
|
|
198
|
+
export function t() {
|
|
199
|
+
return currentTheme;
|
|
200
|
+
}
|
package/dist/gemini-client.d.ts
CHANGED
package/dist/gemini-client.js
CHANGED
|
@@ -418,14 +418,14 @@ const DEEP_RESEARCH_AGENT = 'deep-research-pro-preview-12-2025';
|
|
|
418
418
|
*/
|
|
419
419
|
export async function startDeepResearch(prompt) {
|
|
420
420
|
try {
|
|
421
|
-
// The Interactions API
|
|
421
|
+
// The Interactions API is properly typed in @google/genai v1.34.0+
|
|
422
422
|
const interaction = await genAI.interactions.create({
|
|
423
423
|
input: prompt,
|
|
424
424
|
agent: DEEP_RESEARCH_AGENT,
|
|
425
425
|
background: true,
|
|
426
|
-
|
|
426
|
+
agent_config: {
|
|
427
427
|
type: 'deep-research',
|
|
428
|
-
|
|
428
|
+
thinking_summaries: 'auto',
|
|
429
429
|
},
|
|
430
430
|
});
|
|
431
431
|
return {
|
|
@@ -446,17 +446,36 @@ export async function checkDeepResearch(researchId) {
|
|
|
446
446
|
const interaction = await genAI.interactions.get(researchId);
|
|
447
447
|
const status = interaction.status || 'unknown';
|
|
448
448
|
if (status === 'completed') {
|
|
449
|
+
// Save the FULL raw response to the output directory
|
|
450
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
451
|
+
const outputPath = path.join(getOutputDir(), `deep-research-${timestamp}.json`);
|
|
452
|
+
const fullResponse = {
|
|
453
|
+
id: researchId,
|
|
454
|
+
status: interaction.status,
|
|
455
|
+
created: interaction.created,
|
|
456
|
+
agent: interaction.agent,
|
|
457
|
+
model: interaction.model,
|
|
458
|
+
outputs: interaction.outputs,
|
|
459
|
+
rawInteraction: interaction,
|
|
460
|
+
};
|
|
461
|
+
fs.writeFileSync(outputPath, JSON.stringify(fullResponse, null, 2));
|
|
462
|
+
logger.info(`Full deep research response saved to: ${outputPath}`);
|
|
463
|
+
// Extract text for the summary (but full data is saved)
|
|
464
|
+
const textOutputs = (interaction.outputs || [])
|
|
465
|
+
.filter((output) => 'type' in output && output.type === 'text')
|
|
466
|
+
.map(output => ({ text: output.text }));
|
|
449
467
|
return {
|
|
450
468
|
id: researchId,
|
|
451
469
|
status: 'completed',
|
|
452
|
-
outputs:
|
|
470
|
+
outputs: textOutputs,
|
|
471
|
+
savedPath: outputPath,
|
|
453
472
|
};
|
|
454
473
|
}
|
|
455
|
-
else if (status === 'failed') {
|
|
474
|
+
else if (status === 'failed' || status === 'cancelled') {
|
|
456
475
|
return {
|
|
457
476
|
id: researchId,
|
|
458
477
|
status: 'failed',
|
|
459
|
-
error:
|
|
478
|
+
error: 'Research task failed or was cancelled',
|
|
460
479
|
};
|
|
461
480
|
}
|
|
462
481
|
return {
|
|
@@ -477,10 +496,18 @@ export async function followUpResearch(researchId, question) {
|
|
|
477
496
|
const interaction = await genAI.interactions.create({
|
|
478
497
|
input: question,
|
|
479
498
|
model: proModelName,
|
|
480
|
-
|
|
499
|
+
previous_interaction_id: researchId,
|
|
481
500
|
});
|
|
501
|
+
// Extract text from TextContent outputs
|
|
482
502
|
const outputs = interaction.outputs || [];
|
|
483
|
-
|
|
503
|
+
const textOutputs = outputs
|
|
504
|
+
.filter((output) => 'type' in output && output.type === 'text')
|
|
505
|
+
.map(output => output.text)
|
|
506
|
+
.filter((text) => !!text);
|
|
507
|
+
if (textOutputs.length > 0) {
|
|
508
|
+
return textOutputs[textOutputs.length - 1];
|
|
509
|
+
}
|
|
510
|
+
return 'No text response received';
|
|
484
511
|
}
|
|
485
512
|
catch (error) {
|
|
486
513
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Gemini - Dual Mode Entry Point
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 1. MCP Server Mode (default): `gemini-mcp` or `gemini serve`
|
|
6
|
+
* 2. CLI Mode: `gemini <command> [options]`
|
|
7
|
+
*
|
|
8
|
+
* This integrates Google's Gemini models with Claude Code (MCP)
|
|
9
|
+
* and provides a beautiful standalone CLI experience.
|
|
7
10
|
*/
|
|
8
11
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,224 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Gemini - Dual Mode Entry Point
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 1. MCP Server Mode (default): `gemini-mcp` or `gemini serve`
|
|
6
|
+
* 2. CLI Mode: `gemini <command> [options]`
|
|
7
|
+
*
|
|
8
|
+
* This integrates Google's Gemini models with Claude Code (MCP)
|
|
9
|
+
* and provides a beautiful standalone CLI experience.
|
|
7
10
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import { registerCacheTool } from './tools/cache.js';
|
|
26
|
-
import { registerSpeechTool } from './tools/speech.js';
|
|
27
|
-
import { registerTokenCountTool } from './tools/token-count.js';
|
|
28
|
-
import { registerDeepResearchTool } from './tools/deep-research.js';
|
|
29
|
-
// Import Gemini client and logger
|
|
30
|
-
import { initGeminiClient } from './gemini-client.js';
|
|
31
|
-
import { setupLogger, logger } from './utils/logger.js';
|
|
32
|
-
// Parse command line arguments
|
|
33
|
-
const { values } = parseArgs({
|
|
34
|
-
options: {
|
|
35
|
-
verbose: {
|
|
36
|
-
type: 'boolean',
|
|
37
|
-
short: 'v',
|
|
38
|
-
default: false,
|
|
39
|
-
},
|
|
40
|
-
quiet: {
|
|
41
|
-
type: 'boolean',
|
|
42
|
-
short: 'q',
|
|
43
|
-
default: false,
|
|
44
|
-
},
|
|
45
|
-
help: {
|
|
46
|
-
type: 'boolean',
|
|
47
|
-
short: 'h',
|
|
48
|
-
default: false,
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
// Show help if requested
|
|
53
|
-
if (values.help) {
|
|
54
|
-
console.log(`
|
|
55
|
-
MCP Server Gemini - Integrates Google's Gemini models with Claude Code
|
|
56
|
-
|
|
57
|
-
Usage:
|
|
58
|
-
gemini-mcp [options]
|
|
59
|
-
|
|
60
|
-
Options:
|
|
61
|
-
-v, --verbose Enable verbose logging (shows all prompts and responses)
|
|
62
|
-
-q, --quiet Run in quiet mode (minimal logging)
|
|
63
|
-
-h, --help Show this help message
|
|
64
|
-
|
|
65
|
-
Environment Variables:
|
|
66
|
-
GEMINI_API_KEY (required) Your Google Gemini API key
|
|
67
|
-
VERBOSE (optional) Set to "true" to enable verbose logging
|
|
68
|
-
QUIET (optional) Set to "true" to enable quiet mode
|
|
69
|
-
GEMINI_MODEL (optional) Default Gemini model to use
|
|
70
|
-
GEMINI_PRO_MODEL (optional) Specify Pro model variant
|
|
71
|
-
GEMINI_FLASH_MODEL (optional) Specify Flash model variant
|
|
72
|
-
`);
|
|
73
|
-
process.exit(0);
|
|
74
|
-
}
|
|
75
|
-
// Configure logging mode based on command line args or environment variables
|
|
76
|
-
let logLevel = 'normal';
|
|
77
|
-
if (values.verbose || process.env.VERBOSE === 'true') {
|
|
78
|
-
logLevel = 'verbose';
|
|
79
|
-
}
|
|
80
|
-
else if (values.quiet || process.env.QUIET === 'true') {
|
|
81
|
-
logLevel = 'quiet';
|
|
82
|
-
}
|
|
83
|
-
setupLogger(logLevel);
|
|
84
|
-
// Check for required API key
|
|
85
|
-
if (!process.env.GEMINI_API_KEY) {
|
|
86
|
-
logger.error('Error: GEMINI_API_KEY environment variable is required');
|
|
87
|
-
process.exit(1);
|
|
11
|
+
import { runCli } from './cli/index.js';
|
|
12
|
+
import { startMcpServer } from './server.js';
|
|
13
|
+
// Get command line arguments
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
// Determine mode based on first argument
|
|
16
|
+
const firstArg = args[0];
|
|
17
|
+
// MCP server mode conditions:
|
|
18
|
+
// 1. No arguments (default behavior for MCP)
|
|
19
|
+
// 2. Explicit 'serve' command
|
|
20
|
+
// 3. Legacy flags that were for MCP server
|
|
21
|
+
const mcpServerFlags = ['--verbose', '-v', '--quiet', '-q', '--help', '-h'];
|
|
22
|
+
const isMcpMode = args.length === 0 ||
|
|
23
|
+
firstArg === 'serve' ||
|
|
24
|
+
(args.length === 1 && mcpServerFlags.includes(firstArg));
|
|
25
|
+
if (isMcpMode) {
|
|
26
|
+
// Start MCP server (existing behavior)
|
|
27
|
+
startMcpServer(args);
|
|
88
28
|
}
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
const geminiModel = process.env.GEMINI_MODEL || defaultModel;
|
|
93
|
-
// Log model configuration for debugging
|
|
94
|
-
logger.debug(`Model configuration:
|
|
95
|
-
- GEMINI_MODEL: ${process.env.GEMINI_MODEL || '(not set, using default)'}
|
|
96
|
-
- GEMINI_PRO_MODEL: ${process.env.GEMINI_PRO_MODEL || '(not set, using default)'}
|
|
97
|
-
- GEMINI_FLASH_MODEL: ${process.env.GEMINI_FLASH_MODEL || '(not set, using default)'}`);
|
|
98
|
-
async function main() {
|
|
99
|
-
logger.info(`Starting MCP Gemini Server with model: ${geminiModel}`);
|
|
100
|
-
logger.info(`Logging mode: ${logLevel}`);
|
|
101
|
-
// Handle unexpected stdio errors
|
|
102
|
-
process.stdin.on('error', (err) => {
|
|
103
|
-
logger.error('STDIN error:', err);
|
|
104
|
-
// Don't exit, just log
|
|
105
|
-
});
|
|
106
|
-
process.stdout.on('error', (err) => {
|
|
107
|
-
logger.error('STDOUT error:', err);
|
|
108
|
-
// Don't exit, just log
|
|
109
|
-
});
|
|
110
|
-
try {
|
|
111
|
-
// Initialize Gemini client
|
|
112
|
-
await initGeminiClient();
|
|
113
|
-
// Create MCP server
|
|
114
|
-
const server = new McpServer({
|
|
115
|
-
name: 'Gemini',
|
|
116
|
-
version: '0.6.2',
|
|
117
|
-
});
|
|
118
|
-
// Register tools
|
|
119
|
-
registerQueryTool(server);
|
|
120
|
-
registerBrainstormTool(server);
|
|
121
|
-
registerAnalyzeTool(server);
|
|
122
|
-
registerSummarizeTool(server);
|
|
123
|
-
registerImageGenTool(server);
|
|
124
|
-
registerImageEditTool(server);
|
|
125
|
-
registerVideoGenTool(server);
|
|
126
|
-
registerCodeExecTool(server);
|
|
127
|
-
registerSearchTool(server);
|
|
128
|
-
registerStructuredTool(server);
|
|
129
|
-
registerYouTubeTool(server);
|
|
130
|
-
registerDocumentTool(server);
|
|
131
|
-
registerUrlContextTool(server);
|
|
132
|
-
registerCacheTool(server);
|
|
133
|
-
registerSpeechTool(server);
|
|
134
|
-
registerTokenCountTool(server);
|
|
135
|
-
registerDeepResearchTool(server);
|
|
136
|
-
// Start server with stdio transport with enhanced error handling
|
|
137
|
-
const transport = new StdioServerTransport();
|
|
138
|
-
// Set up error handling for transport with improved error recovery
|
|
139
|
-
transport.onclose = () => {
|
|
140
|
-
logger.warn('MCP transport connection closed');
|
|
141
|
-
logger.debug('Connection closed event triggered');
|
|
142
|
-
// Attempt to recover connection after brief delay with backoff strategy
|
|
143
|
-
let reconnectAttempts = 0;
|
|
144
|
-
const maxReconnectAttempts = 5;
|
|
145
|
-
const attemptReconnect = () => {
|
|
146
|
-
if (reconnectAttempts >= maxReconnectAttempts) {
|
|
147
|
-
logger.error(`Failed to reconnect after ${maxReconnectAttempts} attempts`);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
reconnectAttempts++;
|
|
151
|
-
const delay = Math.min(1000 * Math.pow(1.5, reconnectAttempts - 1), 10000);
|
|
152
|
-
logger.info(`Attempting to reconnect (${reconnectAttempts}/${maxReconnectAttempts}) after ${delay}ms...`);
|
|
153
|
-
setTimeout(() => {
|
|
154
|
-
try {
|
|
155
|
-
// Check if stdin/stdout are still available
|
|
156
|
-
if (process.stdin.destroyed || process.stdout.destroyed) {
|
|
157
|
-
logger.error('Cannot reconnect: stdin or stdout is destroyed');
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
server.connect(transport)
|
|
161
|
-
.then(() => {
|
|
162
|
-
logger.info('Successfully reconnected to MCP transport');
|
|
163
|
-
reconnectAttempts = 0;
|
|
164
|
-
})
|
|
165
|
-
.catch(e => {
|
|
166
|
-
logger.error('Reconnection failed:', e);
|
|
167
|
-
attemptReconnect(); // Try again with backoff
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
catch (e) {
|
|
171
|
-
logger.error('Error during reconnection attempt:', e);
|
|
172
|
-
attemptReconnect(); // Try again with backoff
|
|
173
|
-
}
|
|
174
|
-
}, delay);
|
|
175
|
-
};
|
|
176
|
-
attemptReconnect();
|
|
177
|
-
};
|
|
178
|
-
transport.onerror = (error) => {
|
|
179
|
-
logger.error('MCP transport error:', error);
|
|
180
|
-
// Log detailed error information for debugging
|
|
181
|
-
if (error instanceof Error) {
|
|
182
|
-
logger.debug(`Error name: ${error.name}, message: ${error.message}`);
|
|
183
|
-
logger.debug(`Stack trace: ${error.stack}`);
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
// Set up error handling for the connection with more diagnostics
|
|
187
|
-
try {
|
|
188
|
-
// Log environment diagnostic info before connecting
|
|
189
|
-
logger.debug(`Process details - PID: ${process.pid}, Node version: ${process.version}`);
|
|
190
|
-
logger.debug(`Environment variables: API_KEY=${process.env.GEMINI_API_KEY ? 'SET' : 'NOT_SET'}, VERBOSE=${process.env.VERBOSE || 'not set'}`);
|
|
191
|
-
logger.debug(`Process stdin/stdout state - isTTY: ${process.stdin.isTTY}, ${process.stdout.isTTY}`);
|
|
192
|
-
await server.connect(transport);
|
|
193
|
-
logger.info('MCP Gemini Server running');
|
|
194
|
-
}
|
|
195
|
-
catch (err) {
|
|
196
|
-
logger.error('Failed to connect MCP server transport:', err);
|
|
197
|
-
// More detailed error logging
|
|
198
|
-
if (err instanceof Error) {
|
|
199
|
-
logger.debug(`Error stack: ${err.stack}`);
|
|
200
|
-
logger.debug(`Error details: name=${err.name}, message=${err.message}`);
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
logger.debug(`Non-Error object thrown: ${JSON.stringify(err)}`);
|
|
204
|
-
}
|
|
205
|
-
logger.warn('Server will attempt to continue running despite connection error');
|
|
206
|
-
}
|
|
207
|
-
// Handle process termination
|
|
208
|
-
process.on('SIGINT', async () => {
|
|
209
|
-
logger.info('Shutting down MCP Gemini Server');
|
|
210
|
-
await server.close();
|
|
211
|
-
process.exit(0);
|
|
212
|
-
});
|
|
213
|
-
process.on('SIGTERM', async () => {
|
|
214
|
-
logger.info('Shutting down MCP Gemini Server');
|
|
215
|
-
await server.close();
|
|
216
|
-
process.exit(0);
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
logger.error('Failed to start MCP Gemini Server:', error);
|
|
221
|
-
process.exit(1);
|
|
222
|
-
}
|
|
29
|
+
else {
|
|
30
|
+
// Run CLI
|
|
31
|
+
runCli(args);
|
|
223
32
|
}
|
|
224
|
-
main();
|
package/dist/server.d.ts
ADDED