@anzchy/mcp-server-gemini 0.5.1

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.
@@ -0,0 +1,1226 @@
1
+ #!/usr/bin/env node
2
+ import { GoogleGenAI } from '@google/genai';
3
+ import { createInterface } from 'readline';
4
+ // Increase max buffer size for large images (10MB)
5
+ if (process.stdin.setEncoding) {
6
+ process.stdin.setEncoding('utf8');
7
+ }
8
+ // Available Gemini models as of February 2026
9
+ const GEMINI_MODELS = {
10
+ // Gemini 3 series - latest and most capable
11
+ 'gemini-3-pro-preview': {
12
+ description: 'Most capable reasoning model, state-of-the-art multimodal and agentic',
13
+ features: ['thinking', 'function_calling', 'json_mode', 'grounding', 'system_instructions'],
14
+ contextWindow: 1048576, // 1M tokens
15
+ maxOutputTokens: 65536,
16
+ thinking: true,
17
+ thinkingLevels: ['low', 'high']
18
+ },
19
+ 'gemini-3-flash-preview': {
20
+ description: 'Best balance of speed, scale, and frontier intelligence',
21
+ features: ['thinking', 'function_calling', 'json_mode', 'grounding', 'system_instructions'],
22
+ contextWindow: 1048576, // 1M tokens
23
+ maxOutputTokens: 65536,
24
+ thinking: true,
25
+ thinkingLevels: ['minimal', 'low', 'medium', 'high']
26
+ },
27
+ // Legacy models (2.5 series)
28
+ 'gemini-2.5-pro': {
29
+ description: 'Previous generation thinking model, complex reasoning and coding',
30
+ features: ['thinking', 'function_calling', 'json_mode', 'grounding', 'system_instructions'],
31
+ contextWindow: 2000000,
32
+ thinking: true
33
+ },
34
+ 'gemini-2.5-flash': {
35
+ description: 'Previous generation fast thinking model',
36
+ features: ['thinking', 'function_calling', 'json_mode', 'grounding', 'system_instructions'],
37
+ contextWindow: 1000000,
38
+ thinking: true
39
+ },
40
+ 'gemini-2.5-flash-lite': {
41
+ description: 'Previous generation ultra-fast, cost-efficient thinking model',
42
+ features: ['thinking', 'function_calling', 'json_mode', 'system_instructions'],
43
+ contextWindow: 1000000,
44
+ thinking: true
45
+ }
46
+ };
47
+ // Configurable default model via GEMINI_DEFAULT_MODEL env var.
48
+ // Falls back to 'gemini-3-pro-preview' if unset or not a known model.
49
+ const DEFAULT_MODEL = (() => {
50
+ const envModel = process.env.GEMINI_DEFAULT_MODEL;
51
+ if (envModel) {
52
+ if (envModel in GEMINI_MODELS)
53
+ return envModel;
54
+ process.stderr.write(`[warn] GEMINI_DEFAULT_MODEL="${envModel}" is not a known model. Falling back to gemini-3-pro-preview.\n`);
55
+ }
56
+ return 'gemini-3-pro-preview';
57
+ })();
58
+ class EnhancedStdioMCPServer {
59
+ genAI;
60
+ conversations = new Map();
61
+ constructor(apiKey) {
62
+ this.genAI = new GoogleGenAI({ apiKey });
63
+ this.setupStdioInterface();
64
+ }
65
+ setupStdioInterface() {
66
+ const rl = createInterface({
67
+ input: process.stdin,
68
+ output: process.stdout,
69
+ terminal: false,
70
+ // Increase max line length for large image data
71
+ crlfDelay: Infinity
72
+ });
73
+ rl.on('line', (line) => {
74
+ if (line.trim()) {
75
+ try {
76
+ const request = JSON.parse(line);
77
+ this.handleRequest(request);
78
+ }
79
+ catch (error) {
80
+ console.error('Failed to parse message:', error);
81
+ }
82
+ }
83
+ });
84
+ process.stdin.on('error', (err) => {
85
+ console.error('stdin error:', err);
86
+ });
87
+ }
88
+ async handleRequest(request) {
89
+ console.error('Handling request:', request.method);
90
+ try {
91
+ let response;
92
+ switch (request.method) {
93
+ case 'initialize':
94
+ response = {
95
+ jsonrpc: '2.0',
96
+ id: request.id,
97
+ result: {
98
+ protocolVersion: '2024-11-05',
99
+ serverInfo: {
100
+ name: 'mcp-server-gemini-enhanced',
101
+ version: '0.5.1'
102
+ },
103
+ capabilities: {
104
+ tools: {},
105
+ resources: {},
106
+ prompts: {}
107
+ }
108
+ }
109
+ };
110
+ break;
111
+ case 'tools/list':
112
+ response = {
113
+ jsonrpc: '2.0',
114
+ id: request.id,
115
+ result: {
116
+ tools: this.getAvailableTools()
117
+ }
118
+ };
119
+ break;
120
+ case 'tools/call':
121
+ response = await this.handleToolCall(request);
122
+ break;
123
+ case 'resources/list':
124
+ response = {
125
+ jsonrpc: '2.0',
126
+ id: request.id,
127
+ result: {
128
+ resources: this.getAvailableResources()
129
+ }
130
+ };
131
+ break;
132
+ case 'resources/read':
133
+ response = await this.handleResourceRead(request);
134
+ break;
135
+ case 'prompts/list':
136
+ response = {
137
+ jsonrpc: '2.0',
138
+ id: request.id,
139
+ result: {
140
+ prompts: this.getAvailablePrompts()
141
+ }
142
+ };
143
+ break;
144
+ case 'ping':
145
+ response = {
146
+ jsonrpc: '2.0',
147
+ id: request.id,
148
+ result: {}
149
+ };
150
+ break;
151
+ default:
152
+ if (!('id' in request)) {
153
+ console.error(`Notification received: ${request.method}`);
154
+ return;
155
+ }
156
+ response = {
157
+ jsonrpc: '2.0',
158
+ id: request.id,
159
+ error: {
160
+ code: -32601,
161
+ message: 'Method not found'
162
+ }
163
+ };
164
+ }
165
+ this.sendResponse(response);
166
+ }
167
+ catch (error) {
168
+ const errorResponse = {
169
+ jsonrpc: '2.0',
170
+ id: request.id,
171
+ error: {
172
+ code: -32603,
173
+ message: error instanceof Error ? error.message : 'Internal error'
174
+ }
175
+ };
176
+ this.sendResponse(errorResponse);
177
+ }
178
+ }
179
+ getAvailableTools() {
180
+ return [
181
+ {
182
+ name: 'generate_text',
183
+ description: 'Generate text using Google Gemini with advanced features',
184
+ inputSchema: {
185
+ type: 'object',
186
+ properties: {
187
+ prompt: {
188
+ type: 'string',
189
+ description: 'The prompt to send to Gemini'
190
+ },
191
+ model: {
192
+ type: 'string',
193
+ description: 'Specific Gemini model to use',
194
+ enum: Object.keys(GEMINI_MODELS),
195
+ default: DEFAULT_MODEL
196
+ },
197
+ systemInstruction: {
198
+ type: 'string',
199
+ description: 'System instruction to guide model behavior'
200
+ },
201
+ temperature: {
202
+ type: 'number',
203
+ description: 'Temperature for generation (0-2)',
204
+ default: 1.0,
205
+ minimum: 0,
206
+ maximum: 2
207
+ },
208
+ maxTokens: {
209
+ type: 'number',
210
+ description: 'Maximum tokens to generate',
211
+ default: 2048
212
+ },
213
+ topK: {
214
+ type: 'number',
215
+ description: 'Top-k sampling parameter',
216
+ default: 40
217
+ },
218
+ topP: {
219
+ type: 'number',
220
+ description: 'Top-p (nucleus) sampling parameter',
221
+ default: 0.95
222
+ },
223
+ jsonMode: {
224
+ type: 'boolean',
225
+ description: 'Enable JSON mode for structured output',
226
+ default: false
227
+ },
228
+ jsonSchema: {
229
+ type: 'object',
230
+ description: 'JSON schema for structured output (when jsonMode is true)'
231
+ },
232
+ grounding: {
233
+ type: 'boolean',
234
+ description: 'Enable Google Search grounding for up-to-date information',
235
+ default: false
236
+ },
237
+ safetySettings: {
238
+ type: 'array',
239
+ description: 'Safety settings for content filtering',
240
+ items: {
241
+ type: 'object',
242
+ properties: {
243
+ category: {
244
+ type: 'string',
245
+ enum: ['HARM_CATEGORY_HARASSMENT', 'HARM_CATEGORY_HATE_SPEECH', 'HARM_CATEGORY_SEXUALLY_EXPLICIT', 'HARM_CATEGORY_DANGEROUS_CONTENT']
246
+ },
247
+ threshold: {
248
+ type: 'string',
249
+ enum: ['BLOCK_NONE', 'BLOCK_ONLY_HIGH', 'BLOCK_MEDIUM_AND_ABOVE', 'BLOCK_LOW_AND_ABOVE']
250
+ }
251
+ }
252
+ }
253
+ },
254
+ conversationId: {
255
+ type: 'string',
256
+ description: 'ID for maintaining conversation context'
257
+ },
258
+ thinkingLevel: {
259
+ type: 'string',
260
+ description: 'Thinking depth for Gemini 3 models. Pro supports low/high; Flash supports minimal/low/medium/high.',
261
+ enum: ['minimal', 'low', 'medium', 'high']
262
+ }
263
+ },
264
+ required: ['prompt']
265
+ }
266
+ },
267
+ {
268
+ name: 'analyze_image',
269
+ description: 'Analyze images using Gemini vision capabilities',
270
+ inputSchema: {
271
+ type: 'object',
272
+ properties: {
273
+ prompt: {
274
+ type: 'string',
275
+ description: 'Question or instruction about the image'
276
+ },
277
+ imageUrl: {
278
+ type: 'string',
279
+ description: 'URL of the image to analyze. Either imageUrl or imageBase64 must be provided.'
280
+ },
281
+ imageBase64: {
282
+ type: 'string',
283
+ description: 'Base64-encoded image data. Either imageUrl or imageBase64 must be provided.'
284
+ },
285
+ model: {
286
+ type: 'string',
287
+ description: 'Vision-capable Gemini model',
288
+ enum: ['gemini-3-pro-preview', 'gemini-3-flash-preview', 'gemini-2.5-pro', 'gemini-2.5-flash'],
289
+ default: DEFAULT_MODEL
290
+ },
291
+ mediaResolution: {
292
+ type: 'string',
293
+ description: 'Token allocation for image/video inputs. Higher resolution uses more tokens but provides better detail.',
294
+ enum: ['media_resolution_low', 'media_resolution_medium', 'media_resolution_high']
295
+ }
296
+ },
297
+ required: ['prompt']
298
+ }
299
+ },
300
+ {
301
+ name: 'count_tokens',
302
+ description: 'Count tokens for a given text with a specific model',
303
+ inputSchema: {
304
+ type: 'object',
305
+ properties: {
306
+ text: {
307
+ type: 'string',
308
+ description: 'Text to count tokens for'
309
+ },
310
+ model: {
311
+ type: 'string',
312
+ description: 'Model to use for token counting',
313
+ enum: Object.keys(GEMINI_MODELS),
314
+ default: DEFAULT_MODEL
315
+ }
316
+ },
317
+ required: ['text']
318
+ }
319
+ },
320
+ {
321
+ name: 'list_models',
322
+ description: 'List all available Gemini models and their capabilities',
323
+ inputSchema: {
324
+ type: 'object',
325
+ properties: {
326
+ filter: {
327
+ type: 'string',
328
+ description: 'Filter models by capability',
329
+ enum: ['all', 'thinking', 'vision', 'grounding', 'json_mode']
330
+ }
331
+ }
332
+ }
333
+ },
334
+ {
335
+ name: 'embed_text',
336
+ description: 'Generate embeddings for text using Gemini embedding models',
337
+ inputSchema: {
338
+ type: 'object',
339
+ properties: {
340
+ text: {
341
+ type: 'string',
342
+ description: 'Text to generate embeddings for'
343
+ },
344
+ model: {
345
+ type: 'string',
346
+ description: 'Embedding model to use',
347
+ enum: ['gemini-embedding-001'],
348
+ default: 'gemini-embedding-001'
349
+ }
350
+ },
351
+ required: ['text']
352
+ }
353
+ },
354
+ {
355
+ name: 'get_help',
356
+ description: 'Get help and usage information for the Gemini MCP server',
357
+ inputSchema: {
358
+ type: 'object',
359
+ properties: {
360
+ topic: {
361
+ type: 'string',
362
+ description: 'Help topic to get information about',
363
+ enum: ['overview', 'tools', 'models', 'parameters', 'examples', 'quick-start'],
364
+ default: 'overview'
365
+ }
366
+ }
367
+ }
368
+ }
369
+ ];
370
+ }
371
+ getAvailableResources() {
372
+ return [
373
+ {
374
+ uri: 'gemini://models',
375
+ name: 'Available Gemini Models',
376
+ description: 'List of all available Gemini models and their capabilities',
377
+ mimeType: 'application/json'
378
+ },
379
+ {
380
+ uri: 'gemini://capabilities',
381
+ name: 'API Capabilities',
382
+ description: 'Detailed information about Gemini API capabilities',
383
+ mimeType: 'text/markdown'
384
+ },
385
+ {
386
+ uri: 'gemini://help/usage',
387
+ name: 'Usage Guide',
388
+ description: 'Complete guide on using all tools and features',
389
+ mimeType: 'text/markdown'
390
+ },
391
+ {
392
+ uri: 'gemini://help/parameters',
393
+ name: 'Parameters Reference',
394
+ description: 'Detailed documentation of all parameters',
395
+ mimeType: 'text/markdown'
396
+ },
397
+ {
398
+ uri: 'gemini://help/examples',
399
+ name: 'Examples',
400
+ description: 'Example usage patterns for common tasks',
401
+ mimeType: 'text/markdown'
402
+ }
403
+ ];
404
+ }
405
+ getAvailablePrompts() {
406
+ return [
407
+ {
408
+ name: 'code_review',
409
+ description: 'Comprehensive code review with Gemini 3 Pro',
410
+ arguments: [
411
+ {
412
+ name: 'code',
413
+ description: 'Code to review',
414
+ required: true
415
+ },
416
+ {
417
+ name: 'language',
418
+ description: 'Programming language',
419
+ required: false
420
+ }
421
+ ]
422
+ },
423
+ {
424
+ name: 'explain_with_thinking',
425
+ description: 'Deep explanation using Gemini 3 thinking capabilities',
426
+ arguments: [
427
+ {
428
+ name: 'topic',
429
+ description: 'Topic to explain',
430
+ required: true
431
+ },
432
+ {
433
+ name: 'level',
434
+ description: 'Explanation level (beginner/intermediate/expert)',
435
+ required: false
436
+ }
437
+ ]
438
+ },
439
+ {
440
+ name: 'creative_writing',
441
+ description: 'Creative writing with style control',
442
+ arguments: [
443
+ {
444
+ name: 'prompt',
445
+ description: 'Writing prompt',
446
+ required: true
447
+ },
448
+ {
449
+ name: 'style',
450
+ description: 'Writing style',
451
+ required: false
452
+ },
453
+ {
454
+ name: 'length',
455
+ description: 'Desired length',
456
+ required: false
457
+ }
458
+ ]
459
+ }
460
+ ];
461
+ }
462
+ async handleToolCall(request) {
463
+ const { name, arguments: args } = request.params || {};
464
+ switch (name) {
465
+ case 'generate_text':
466
+ return await this.generateText(request.id, args);
467
+ case 'analyze_image':
468
+ return await this.analyzeImage(request.id, args);
469
+ case 'count_tokens':
470
+ return await this.countTokens(request.id, args);
471
+ case 'list_models':
472
+ return this.listModels(request.id, args);
473
+ case 'embed_text':
474
+ return await this.embedText(request.id, args);
475
+ case 'get_help':
476
+ return this.getHelp(request.id, args);
477
+ default:
478
+ return {
479
+ jsonrpc: '2.0',
480
+ id: request.id,
481
+ error: {
482
+ code: -32602,
483
+ message: `Unknown tool: ${name}`
484
+ }
485
+ };
486
+ }
487
+ }
488
+ async generateText(id, args) {
489
+ try {
490
+ const model = args.model || DEFAULT_MODEL;
491
+ const modelInfo = GEMINI_MODELS[model];
492
+ if (!modelInfo) {
493
+ throw new Error(`Unknown model: ${model}`);
494
+ }
495
+ // Build contents
496
+ let contents = [{
497
+ parts: [{ text: args.prompt }],
498
+ role: 'user'
499
+ }];
500
+ // Prepend conversation history if continuing a conversation
501
+ if (args.conversationId) {
502
+ const history = this.conversations.get(args.conversationId) || [];
503
+ if (history.length > 0) {
504
+ contents = [...history, ...contents];
505
+ }
506
+ }
507
+ // Build SDK config (flat structure per @google/genai SDK pattern)
508
+ const config = {
509
+ temperature: args.temperature ?? 1.0,
510
+ maxOutputTokens: args.maxTokens || 2048,
511
+ topK: args.topK || 40,
512
+ topP: args.topP || 0.95,
513
+ };
514
+ if (args.systemInstruction) {
515
+ config.systemInstruction = args.systemInstruction;
516
+ }
517
+ if (args.jsonMode) {
518
+ config.responseMimeType = 'application/json';
519
+ if (args.jsonSchema) {
520
+ config.responseSchema = args.jsonSchema;
521
+ }
522
+ }
523
+ if (args.safetySettings) {
524
+ config.safetySettings = args.safetySettings;
525
+ }
526
+ if (args.grounding && modelInfo.features.includes('grounding')) {
527
+ config.tools = [{ googleSearch: {} }];
528
+ }
529
+ // Thinking config for Gemini 3 models (SDK expects uppercase level)
530
+ if (args.thinkingLevel && modelInfo.thinking) {
531
+ config.thinkingConfig = {
532
+ thinkingLevel: args.thinkingLevel.toUpperCase()
533
+ };
534
+ }
535
+ // Call the API using SDK config pattern
536
+ const result = await this.genAI.models.generateContent({
537
+ model,
538
+ contents,
539
+ config,
540
+ });
541
+ const text = result.text || '';
542
+ // Update conversation history with only the new messages
543
+ if (args.conversationId) {
544
+ const history = this.conversations.get(args.conversationId) || [];
545
+ history.push({
546
+ parts: [{ text: args.prompt }],
547
+ role: 'user'
548
+ });
549
+ history.push({
550
+ parts: [{ text: text }],
551
+ role: 'model'
552
+ });
553
+ this.conversations.set(args.conversationId, history);
554
+ }
555
+ return {
556
+ jsonrpc: '2.0',
557
+ id,
558
+ result: {
559
+ content: [{
560
+ type: 'text',
561
+ text: text
562
+ }],
563
+ metadata: {
564
+ model,
565
+ tokensUsed: result.usageMetadata?.totalTokenCount,
566
+ candidatesCount: result.candidates?.length || 1,
567
+ finishReason: result.candidates?.[0]?.finishReason
568
+ }
569
+ }
570
+ };
571
+ }
572
+ catch (error) {
573
+ console.error('Error in generateText:', error);
574
+ return {
575
+ jsonrpc: '2.0',
576
+ id,
577
+ result: {
578
+ content: [{
579
+ type: 'text',
580
+ text: `Error: ${error instanceof Error ? error.message : 'Internal error'}`
581
+ }],
582
+ isError: true
583
+ }
584
+ };
585
+ }
586
+ }
587
+ async analyzeImage(id, args) {
588
+ try {
589
+ const model = args.model || DEFAULT_MODEL;
590
+ // Validate inputs
591
+ if (!args.imageUrl && !args.imageBase64) {
592
+ throw new Error('Either imageUrl or imageBase64 must be provided');
593
+ }
594
+ // Prepare image part
595
+ let imagePart;
596
+ if (args.imageUrl) {
597
+ // For URL, we'd need to fetch and convert to base64
598
+ // For now, we'll just pass the URL as instruction
599
+ imagePart = {
600
+ text: `[Image URL: ${args.imageUrl}]`
601
+ };
602
+ }
603
+ else if (args.imageBase64) {
604
+ // Log base64 data size for debugging
605
+ console.error(`Image base64 length: ${args.imageBase64.length}`);
606
+ // Extract MIME type and data
607
+ const matches = args.imageBase64.match(/^data:(.+);base64,(.+)$/);
608
+ if (matches) {
609
+ console.error(`MIME type: ${matches[1]}, Data length: ${matches[2].length}`);
610
+ imagePart = {
611
+ inlineData: {
612
+ mimeType: matches[1],
613
+ data: matches[2]
614
+ }
615
+ };
616
+ }
617
+ else {
618
+ // If no data URI format, assume raw base64
619
+ console.error('Raw base64 data detected');
620
+ imagePart = {
621
+ inlineData: {
622
+ mimeType: 'image/jpeg',
623
+ data: args.imageBase64
624
+ }
625
+ };
626
+ }
627
+ }
628
+ // Build SDK config
629
+ const config = {};
630
+ if (args.mediaResolution) {
631
+ config.mediaResolution = args.mediaResolution;
632
+ }
633
+ const result = await this.genAI.models.generateContent({
634
+ model,
635
+ contents: [{
636
+ parts: [
637
+ { text: args.prompt },
638
+ imagePart
639
+ ],
640
+ role: 'user'
641
+ }],
642
+ config: Object.keys(config).length > 0 ? config : undefined,
643
+ });
644
+ const text = result.text || '';
645
+ return {
646
+ jsonrpc: '2.0',
647
+ id,
648
+ result: {
649
+ content: [{
650
+ type: 'text',
651
+ text: text
652
+ }]
653
+ }
654
+ };
655
+ }
656
+ catch (error) {
657
+ console.error('Error in analyzeImage:', error);
658
+ return {
659
+ jsonrpc: '2.0',
660
+ id,
661
+ result: {
662
+ content: [{
663
+ type: 'text',
664
+ text: `Image analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`
665
+ }],
666
+ isError: true
667
+ }
668
+ };
669
+ }
670
+ }
671
+ async countTokens(id, args) {
672
+ try {
673
+ const model = args.model || DEFAULT_MODEL;
674
+ const result = await this.genAI.models.countTokens({
675
+ model,
676
+ contents: [{
677
+ parts: [{
678
+ text: args.text
679
+ }],
680
+ role: 'user'
681
+ }]
682
+ });
683
+ return {
684
+ jsonrpc: '2.0',
685
+ id,
686
+ result: {
687
+ content: [{
688
+ type: 'text',
689
+ text: `Token count: ${result.totalTokens}`
690
+ }],
691
+ metadata: {
692
+ tokenCount: result.totalTokens,
693
+ model
694
+ }
695
+ }
696
+ };
697
+ }
698
+ catch (error) {
699
+ console.error('Error in countTokens:', error);
700
+ return {
701
+ jsonrpc: '2.0',
702
+ id,
703
+ result: {
704
+ content: [{
705
+ type: 'text',
706
+ text: `Token counting failed: ${error instanceof Error ? error.message : 'Internal error'}`
707
+ }],
708
+ isError: true
709
+ }
710
+ };
711
+ }
712
+ }
713
+ listModels(id, args) {
714
+ const filter = args?.filter || 'all';
715
+ let models = Object.entries(GEMINI_MODELS);
716
+ if (filter !== 'all') {
717
+ models = models.filter(([_, info]) => {
718
+ switch (filter) {
719
+ case 'thinking':
720
+ return 'thinking' in info && info.thinking === true;
721
+ case 'vision':
722
+ return info.features.includes('function_calling'); // All current models support vision
723
+ case 'grounding':
724
+ return info.features.includes('grounding');
725
+ case 'json_mode':
726
+ return info.features.includes('json_mode');
727
+ default:
728
+ return true;
729
+ }
730
+ });
731
+ }
732
+ const modelList = models.map(([name, info]) => ({
733
+ name,
734
+ ...info
735
+ }));
736
+ return {
737
+ jsonrpc: '2.0',
738
+ id,
739
+ result: {
740
+ content: [{
741
+ type: 'text',
742
+ text: JSON.stringify(modelList, null, 2)
743
+ }],
744
+ metadata: {
745
+ count: modelList.length,
746
+ filter
747
+ }
748
+ }
749
+ };
750
+ }
751
+ async embedText(id, args) {
752
+ try {
753
+ const model = args.model || 'gemini-embedding-001';
754
+ const result = await this.genAI.models.embedContent({
755
+ model,
756
+ contents: args.text
757
+ });
758
+ return {
759
+ jsonrpc: '2.0',
760
+ id,
761
+ result: {
762
+ content: [{
763
+ type: 'text',
764
+ text: JSON.stringify({
765
+ embedding: result.embeddings?.[0]?.values || [],
766
+ model
767
+ })
768
+ }],
769
+ metadata: {
770
+ model,
771
+ dimensions: result.embeddings?.[0]?.values?.length || 0
772
+ }
773
+ }
774
+ };
775
+ }
776
+ catch (error) {
777
+ console.error('Error in embedText:', error);
778
+ return {
779
+ jsonrpc: '2.0',
780
+ id,
781
+ result: {
782
+ content: [{
783
+ type: 'text',
784
+ text: `Embedding failed: ${error instanceof Error ? error.message : 'Internal error'}`
785
+ }],
786
+ isError: true
787
+ }
788
+ };
789
+ }
790
+ }
791
+ async handleResourceRead(request) {
792
+ const uri = request.params?.uri;
793
+ if (!uri) {
794
+ return {
795
+ jsonrpc: '2.0',
796
+ id: request.id,
797
+ error: {
798
+ code: -32602,
799
+ message: 'Missing required parameter: uri'
800
+ }
801
+ };
802
+ }
803
+ let content = '';
804
+ let mimeType = 'text/plain';
805
+ switch (uri) {
806
+ case 'gemini://models':
807
+ content = JSON.stringify(GEMINI_MODELS, null, 2);
808
+ mimeType = 'application/json';
809
+ break;
810
+ case 'gemini://capabilities':
811
+ content = `# Gemini API Capabilities
812
+
813
+ ## Text Generation
814
+ - All models support advanced text generation
815
+ - System instructions for behavior control
816
+ - Temperature, topK, topP for output control
817
+ - Default temperature: 1.0 (recommended for Gemini 3)
818
+
819
+ ## Thinking Models (3.x Series)
820
+ - Step-by-step reasoning before responding
821
+ - Configurable thinking depth via thinkingLevel parameter
822
+ - Gemini 3 Pro: low, high
823
+ - Gemini 3 Flash: minimal, low, medium, high
824
+ - Better accuracy for complex problems
825
+ - Ideal for coding, analysis, and problem-solving
826
+
827
+ ## Media Resolution
828
+ - Control token allocation for image/video inputs
829
+ - Options: media_resolution_low, media_resolution_medium (default), media_resolution_high
830
+ - Higher resolution provides better detail at the cost of more tokens
831
+
832
+ ## JSON Mode
833
+ - Structured output with schema validation
834
+ - Available on all models
835
+ - Ensures consistent response format
836
+
837
+ ## Google Search Grounding
838
+ - Real-time web search integration
839
+ - Available on select models
840
+ - Perfect for current events and facts
841
+
842
+ ## Vision Capabilities
843
+ - Image analysis and understanding
844
+ - Available on most models
845
+ - Supports URLs and base64 images
846
+
847
+ ## Embeddings
848
+ - Semantic text embeddings
849
+ - Multiple models available
850
+ - Multilingual support
851
+
852
+ ## Safety Settings
853
+ - Granular content filtering
854
+ - Customizable thresholds
855
+ - Per-category control
856
+
857
+ ## Conversation Memory
858
+ - Context retention across messages
859
+ - Session-based conversations
860
+ - Ideal for multi-turn interactions`;
861
+ mimeType = 'text/markdown';
862
+ break;
863
+ case 'gemini://help/usage':
864
+ content = this.getHelpContent('overview') + '\n\n' + this.getHelpContent('tools');
865
+ mimeType = 'text/markdown';
866
+ break;
867
+ case 'gemini://help/parameters':
868
+ content = this.getHelpContent('parameters');
869
+ mimeType = 'text/markdown';
870
+ break;
871
+ case 'gemini://help/examples':
872
+ content = this.getHelpContent('examples');
873
+ mimeType = 'text/markdown';
874
+ break;
875
+ default:
876
+ return {
877
+ jsonrpc: '2.0',
878
+ id: request.id,
879
+ error: {
880
+ code: -32602,
881
+ message: `Unknown resource: ${uri}`
882
+ }
883
+ };
884
+ }
885
+ return {
886
+ jsonrpc: '2.0',
887
+ id: request.id,
888
+ result: {
889
+ contents: [{
890
+ uri,
891
+ mimeType,
892
+ text: content
893
+ }]
894
+ }
895
+ };
896
+ }
897
+ getHelpContent(topic) {
898
+ // Extract help content generation to a separate method
899
+ switch (topic) {
900
+ case 'overview':
901
+ return `# Gemini MCP Server Help
902
+
903
+ Welcome to the Gemini MCP Server v0.5.1! This server provides access to Google's Gemini AI models through Claude Desktop.
904
+
905
+ ## Available Tools
906
+ 1. **generate_text** - Generate text with advanced features
907
+ 2. **analyze_image** - Analyze images using vision models
908
+ 3. **count_tokens** - Count tokens for cost estimation
909
+ 4. **list_models** - List all available models
910
+ 5. **embed_text** - Generate text embeddings
911
+ 6. **get_help** - Get help on using this server
912
+
913
+ ## Quick Start
914
+ - "Use Gemini to explain [topic]"
915
+ - "Analyze this image with Gemini"
916
+ - "List all Gemini models"
917
+ - "Get help on parameters"
918
+
919
+ ## Key Features
920
+ - Latest Gemini 3 models with configurable thinking depth
921
+ - Thinking level control (minimal/low/medium/high)
922
+ - Media resolution control for vision tasks
923
+ - JSON mode for structured output
924
+ - Google Search grounding for current information
925
+ - System instructions for behavior control
926
+ - Conversation memory for context
927
+ - Safety settings customization
928
+
929
+ Use "get help on tools" for detailed tool information.`;
930
+ case 'tools':
931
+ return `# Available Tools
932
+
933
+ ## 1. generate_text
934
+ Generate text using Gemini models with advanced features.
935
+
936
+ **Parameters:**
937
+ - prompt (required): Your text prompt
938
+ - model: Choose from gemini-3-pro-preview, gemini-3-flash-preview, etc.
939
+ - temperature: 0-2 (default 1.0)
940
+ - maxTokens: Max output tokens (default 2048)
941
+ - systemInstruction: Guide model behavior
942
+ - jsonMode: Enable JSON output
943
+ - grounding: Enable Google Search
944
+ - conversationId: Maintain conversation context
945
+ - thinkingLevel: Thinking depth (minimal/low/medium/high) for Gemini 3 models
946
+
947
+ **Example:** "Use Gemini 3 Pro to explain quantum computing"
948
+
949
+ ## 2. analyze_image
950
+ Analyze images using vision-capable models.
951
+
952
+ **Parameters:**
953
+ - prompt (required): Question about the image
954
+ - imageUrl OR imageBase64 (required): Image source
955
+ - model: Vision-capable model (default gemini-3-pro-preview)
956
+ - mediaResolution: Token allocation for images (low/medium/high)
957
+
958
+ **Example:** "Analyze this architecture diagram"
959
+
960
+ ## 3. count_tokens
961
+ Count tokens for text with a specific model.
962
+
963
+ **Parameters:**
964
+ - text (required): Text to count
965
+ - model: Model for counting (default gemini-3-pro-preview)
966
+
967
+ **Example:** "Count tokens for this paragraph"
968
+
969
+ ## 4. list_models
970
+ List available models with optional filtering.
971
+
972
+ **Parameters:**
973
+ - filter: all, thinking, vision, grounding, json_mode
974
+
975
+ **Example:** "List models with thinking capability"
976
+
977
+ ## 5. embed_text
978
+ Generate embeddings for semantic search.
979
+
980
+ **Parameters:**
981
+ - text (required): Text to embed
982
+ - model: gemini-embedding-001 (default)
983
+
984
+ **Example:** "Generate embeddings for similarity search"
985
+
986
+ ## 6. get_help
987
+ Get help on using this server.
988
+
989
+ **Parameters:**
990
+ - topic: overview, tools, models, parameters, examples, quick-start
991
+
992
+ **Example:** "Get help on parameters"`;
993
+ case 'parameters':
994
+ return `# Parameter Reference
995
+
996
+ ## generate_text Parameters
997
+
998
+ **Required:**
999
+ - prompt (string): Your text prompt
1000
+
1001
+ **Optional:**
1002
+ - model (string): Model to use (default: gemini-3-pro-preview)
1003
+ - systemInstruction (string): System prompt for behavior
1004
+ - temperature (0-2): Creativity level (default: 1.0)
1005
+ - maxTokens (number): Max output tokens (default: 2048)
1006
+ - topK (number): Top-k sampling (default: 40)
1007
+ - topP (number): Nucleus sampling (default: 0.95)
1008
+ - jsonMode (boolean): Enable JSON output
1009
+ - jsonSchema (object): JSON schema for validation
1010
+ - grounding (boolean): Enable Google Search
1011
+ - conversationId (string): Conversation identifier
1012
+ - safetySettings (array): Content filtering settings
1013
+ - thinkingLevel (string): Thinking depth for Gemini 3 models (minimal/low/medium/high)
1014
+
1015
+ ## analyze_image Parameters
1016
+
1017
+ **Required:**
1018
+ - prompt (string): Question about the image
1019
+ - imageUrl OR imageBase64: Image source
1020
+
1021
+ **Optional:**
1022
+ - model (string): Vision model (default: gemini-3-pro-preview)
1023
+ - mediaResolution (string): Token allocation for images
1024
+ - media_resolution_low: Fewer tokens, faster processing
1025
+ - media_resolution_medium: Balanced (default)
1026
+ - media_resolution_high: More tokens, better detail
1027
+
1028
+ ## Thinking Level Guide
1029
+ - minimal: Fastest, minimal reasoning (Flash only)
1030
+ - low: Light reasoning
1031
+ - medium: Moderate reasoning (Flash only)
1032
+ - high: Deep reasoning (default for thinking models)
1033
+
1034
+ ## Temperature Guide
1035
+ - 0.1-0.3: Precise, factual
1036
+ - 0.7-1.0: Balanced (default 1.0, recommended for Gemini 3)
1037
+ - 1.0-1.5: Creative
1038
+ - 1.5-2.0: Very creative
1039
+
1040
+ ## JSON Mode Example
1041
+ Enable jsonMode and provide jsonSchema:
1042
+ {
1043
+ "type": "object",
1044
+ "properties": {
1045
+ "sentiment": {"type": "string"},
1046
+ "score": {"type": "number"}
1047
+ }
1048
+ }
1049
+
1050
+ ## Safety Settings
1051
+ Categories: HARASSMENT, HATE_SPEECH, SEXUALLY_EXPLICIT, DANGEROUS_CONTENT
1052
+ Thresholds: BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE`;
1053
+ case 'examples':
1054
+ return `# Usage Examples
1055
+
1056
+ ## Basic Text Generation
1057
+ "Use Gemini to explain machine learning"
1058
+
1059
+ ## With Specific Model
1060
+ "Use Gemini 3 Pro to write a Python sorting function"
1061
+
1062
+ ## With Thinking Level
1063
+ "Use Gemini 3 Pro with thinkingLevel high to solve this math problem"
1064
+
1065
+ ## With Temperature
1066
+ "Use Gemini with temperature 1.5 to write a creative story"
1067
+
1068
+ ## JSON Mode
1069
+ "Use Gemini in JSON mode to analyze sentiment and return {sentiment, confidence, keywords}"
1070
+
1071
+ ## With Grounding
1072
+ "Use Gemini with grounding to research latest AI developments"
1073
+
1074
+ ## System Instructions
1075
+ "Use Gemini as a Python tutor to explain decorators"
1076
+
1077
+ ## Conversation Context
1078
+ "Start conversation 'chat-001' about web development"
1079
+ "Continue chat-001 and ask about React hooks"
1080
+
1081
+ ## Image Analysis
1082
+ "Analyze this screenshot and describe the UI elements"
1083
+
1084
+ ## Image Analysis with High Resolution
1085
+ "Analyze this diagram with mediaResolution high for maximum detail"
1086
+
1087
+ ## Token Counting
1088
+ "Count tokens for this document using gemini-3-pro-preview"
1089
+
1090
+ ## Complex Example
1091
+ "Use Gemini 3 Pro to review this code with:
1092
+ - System instruction: 'You are a security expert'
1093
+ - Temperature: 0.3
1094
+ - thinkingLevel: high
1095
+ - JSON mode with schema for findings
1096
+ - Grounding for latest security practices"`;
1097
+ default:
1098
+ return 'Unknown help topic.';
1099
+ }
1100
+ }
1101
+ getHelp(id, args) {
1102
+ const topic = args?.topic || 'overview';
1103
+ let helpContent = '';
1104
+ switch (topic) {
1105
+ case 'overview':
1106
+ helpContent = this.getHelpContent('overview');
1107
+ break;
1108
+ case 'tools':
1109
+ helpContent = this.getHelpContent('tools');
1110
+ break;
1111
+ case 'models':
1112
+ helpContent = `# Available Gemini Models
1113
+
1114
+ ## Gemini 3 Series (Latest)
1115
+ **gemini-3-pro-preview** ⭐ Recommended
1116
+ - Most capable reasoning model, state-of-the-art multimodal and agentic
1117
+ - 1M token context, 64K max output
1118
+ - Thinking levels: low, high
1119
+ - Features: thinking, JSON mode, grounding, system instructions
1120
+
1121
+ **gemini-3-flash-preview**
1122
+ - Best balance of speed, scale, and frontier intelligence
1123
+ - 1M token context, 64K max output
1124
+ - Thinking levels: minimal, low, medium, high
1125
+ - Features: thinking, JSON mode, grounding, system instructions
1126
+
1127
+ ## Legacy Models (2.5 Series)
1128
+ **gemini-2.5-pro**
1129
+ - Previous generation thinking model
1130
+ - 2M token context window
1131
+ - Features: thinking, JSON mode, grounding, system instructions
1132
+
1133
+ **gemini-2.5-flash**
1134
+ - Previous generation fast thinking model
1135
+ - 1M token context window
1136
+ - Features: thinking, JSON mode, grounding, system instructions
1137
+
1138
+ **gemini-2.5-flash-lite**
1139
+ - Previous generation ultra-fast model
1140
+ - 1M token context window
1141
+ - Features: thinking, JSON mode, system instructions
1142
+
1143
+ ## Model Selection Guide
1144
+ - Complex reasoning: gemini-3-pro-preview
1145
+ - General use: gemini-3-pro-preview
1146
+ - Fast responses: gemini-3-flash-preview
1147
+ - Cost-sensitive: gemini-2.5-flash-lite
1148
+ - Maximum thinking control: gemini-3-flash-preview (4 levels)`;
1149
+ break;
1150
+ case 'parameters':
1151
+ helpContent = this.getHelpContent('parameters');
1152
+ break;
1153
+ case 'examples':
1154
+ helpContent = this.getHelpContent('examples');
1155
+ break;
1156
+ case 'quick-start':
1157
+ helpContent = `# Quick Start Guide
1158
+
1159
+ ## 1. Basic Usage
1160
+ Just ask naturally:
1161
+ - "Use Gemini to [your request]"
1162
+ - "Ask Gemini about [topic]"
1163
+
1164
+ ## 2. Common Tasks
1165
+
1166
+ **Text Generation:**
1167
+ "Use Gemini to write a function that sorts arrays"
1168
+
1169
+ **Image Analysis:**
1170
+ "What's in this image?" [attach image]
1171
+
1172
+ **Model Info:**
1173
+ "List all Gemini models"
1174
+
1175
+ **Token Counting:**
1176
+ "Count tokens for my prompt"
1177
+
1178
+ ## 3. Advanced Features
1179
+
1180
+ **JSON Output:**
1181
+ "Use Gemini in JSON mode to extract key points"
1182
+
1183
+ **Current Information:**
1184
+ "Use Gemini with grounding to get latest news"
1185
+
1186
+ **Conversations:**
1187
+ "Start a chat with Gemini about Python"
1188
+
1189
+ ## 4. Tips
1190
+ - Use gemini-3-pro-preview for most tasks
1191
+ - Lower temperature for facts, higher for creativity
1192
+ - Enable grounding for current information
1193
+ - Use conversation IDs to maintain context
1194
+
1195
+ ## Need More Help?
1196
+ - "Get help on tools" - Detailed tool information
1197
+ - "Get help on parameters" - All parameters explained
1198
+ - "Get help on models" - Model selection guide`;
1199
+ break;
1200
+ default:
1201
+ helpContent = 'Unknown help topic. Available topics: overview, tools, models, parameters, examples, quick-start';
1202
+ }
1203
+ return {
1204
+ jsonrpc: '2.0',
1205
+ id,
1206
+ result: {
1207
+ content: [{
1208
+ type: 'text',
1209
+ text: helpContent
1210
+ }]
1211
+ }
1212
+ };
1213
+ }
1214
+ sendResponse(response) {
1215
+ const responseStr = JSON.stringify(response);
1216
+ process.stdout.write(responseStr + '\n');
1217
+ }
1218
+ }
1219
+ // Start the server
1220
+ const apiKey = process.env.GEMINI_API_KEY;
1221
+ if (!apiKey) {
1222
+ console.error('GEMINI_API_KEY environment variable is required');
1223
+ process.exit(1);
1224
+ }
1225
+ new EnhancedStdioMCPServer(apiKey);
1226
+ //# sourceMappingURL=enhanced-stdio-server.js.map