#!/usr/bin/env node
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import OpenAI from 'openai';
import * as z from 'zod';
// Configuration from environment variables
const CONFIG = {
apiKey: process.env.GEMINI_API_KEY || '',
baseURL: process.env.GEMINI_BASE_URL || '',
model: process.env.GEMINI_MODEL || 'gemini-3-pro-preview'
};
// Initialize OpenAI client with custom base URL
const openai = new OpenAI({
apiKey: CONFIG.apiKey,
baseURL: CONFIG.baseURL
});
// Initialize MCP Server
const server = new McpServer({
name: 'gemini-mcp',
version: '1.0.0'
});
// Helper function to call Gemini API
async function callGemini(
messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>,
options: {
temperature?: number;
} = {}
): Promise<string> {
const response = await openai.chat.completions.create({
model: CONFIG.model,
messages,
temperature: options.temperature ?? 0.7,
});
return response.choices[0]?.message?.content ?? '';
}
// Tool 1: gemini_think - Deep analysis and reasoning
server.tool(
'gemini_think',
'Let Gemini-3-pro-preview deeply analyze complex problems, perform reasoning and brainstorming',
{
problem: z.string().describe('The problem or task to analyze'),
context: z.string().optional().describe('Related background information or context'),
thinkingStyle: z.enum(['analytical', 'creative', 'critical', 'systematic'])
.optional()
.describe('Thinking style: analytical (logical analysis), creative (divergent thinking), critical (critical evaluation), systematic (systematic decomposition)')
},
async ({ problem, context, thinkingStyle = 'analytical' }) => {
const stylePrompts: Record<string, string> = {
analytical: 'Use rigorous logical analysis. Break down the problem into components, identify relationships, and draw evidence-based conclusions.',
creative: 'Think divergently and creatively. Explore unconventional angles, make novel connections, and generate innovative ideas.',
critical: 'Apply critical evaluation. Question assumptions, identify potential flaws, consider counterarguments, and assess strengths and weaknesses.',
systematic: 'Use systematic decomposition. Create a structured framework, organize information hierarchically, and address each aspect methodically.'
};
const systemPrompt = `You are a world-class analytical thinker and problem solver. ${stylePrompts[thinkingStyle]}
Your response should be thorough, well-structured, and insightful. Include:
1. Problem understanding and key aspects
2. Detailed analysis process
3. Key insights and findings
4. Conclusions and recommendations
Think deeply and provide comprehensive analysis.`;
const userMessage = context
? `Context:\n${context}\n\nProblem to analyze:\n${problem}`
: problem;
const response = await callGemini([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userMessage }
], { temperature: thinkingStyle === 'creative' ? 0.9 : 0.7 });
return {
content: [{ type: 'text' as const, text: response }],
structuredContent: {
thinking: response,
model: CONFIG.model
}
};
}
);
// Tool 2: gemini_brainstorm - Generate multiple ideas/solutions
server.tool(
'gemini_brainstorm',
'Let Gemini brainstorm on a topic and generate multiple creative ideas or solutions with pros and cons',
{
topic: z.string().describe('The topic to brainstorm'),
constraints: z.string().optional().describe('Constraints or requirements to consider'),
count: z.number().min(3).max(10).optional().describe('Number of ideas to generate (default: 5)')
},
async ({ topic, constraints, count = 5 }) => {
const systemPrompt = `You are a creative strategist and innovation expert. Your task is to brainstorm ${count} distinct ideas or solutions.
For each idea, provide:
1. A concise title
2. A clear description (2-3 sentences)
3. Key advantages (pros)
4. Potential drawbacks (cons)
Be creative, think outside the box, and ensure each idea is meaningfully different from the others.
IMPORTANT: Respond in valid JSON format with this exact structure:
{
"ideas": [
{
"title": "Idea Title",
"description": "Description of the idea",
"pros": ["advantage 1", "advantage 2"],
"cons": ["drawback 1", "drawback 2"]
}
]
}`;
const userMessage = constraints
? `Topic: ${topic}\n\nConstraints/Requirements:\n${constraints}\n\nGenerate ${count} creative ideas.`
: `Topic: ${topic}\n\nGenerate ${count} creative ideas.`;
const response = await callGemini([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userMessage }
], { temperature: 1.0 });
// Try to parse JSON response
let ideas;
try {
const jsonMatch = response.match(/\{[\s\S]*\}/);
if (jsonMatch) {
ideas = JSON.parse(jsonMatch[0]).ideas;
}
} catch {
// If JSON parsing fails, return raw response
ideas = [{ title: 'Raw Response', description: response, pros: [], cons: [] }];
}
return {
content: [{ type: 'text' as const, text: response }],
structuredContent: {
ideas: ideas || [],
model: CONFIG.model
}
};
}
);
// Tool 3: gemini_review - Code/Architecture/Security review
server.tool(
'gemini_review',
'Let Gemini review code, architecture design, or technical solutions',
{
content: z.string().describe('The content to review (code, design document, etc.)'),
reviewType: z.enum(['code', 'architecture', 'security', 'performance'])
.describe('Type of review: code, architecture, security, or performance'),
focus: z.string().optional().describe('Specific aspects to focus on')
},
async ({ content, reviewType, focus }) => {
const reviewPrompts: Record<string, string> = {
code: 'Review this code for quality, readability, maintainability, best practices, and potential bugs.',
architecture: 'Review this architecture design for scalability, maintainability, separation of concerns, and design patterns.',
security: 'Review for security vulnerabilities including injection attacks, authentication issues, data exposure, and OWASP Top 10 risks.',
performance: 'Review for performance issues including algorithmic complexity, memory usage, I/O bottlenecks, and optimization opportunities.'
};
const systemPrompt = `You are an expert ${reviewType} reviewer with deep expertise in software engineering.
${reviewPrompts[reviewType]}
Provide a structured review with:
1. Executive summary
2. List of issues found (with severity: critical/major/minor/suggestion)
3. Specific recommendations for each issue
4. Overall score (0-10)
IMPORTANT: Respond in valid JSON format with this exact structure:
{
"summary": "Executive summary of the review",
"issues": [
{
"severity": "critical|major|minor|suggestion",
"description": "Description of the issue",
"recommendation": "How to fix or improve"
}
],
"score": 7.5
}`;
const userMessage = focus
? `${reviewType.toUpperCase()} REVIEW\n\nFocus areas: ${focus}\n\nContent to review:\n${content}`
: `${reviewType.toUpperCase()} REVIEW\n\nContent to review:\n${content}`;
const response = await callGemini([
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userMessage }
], { temperature: 0.3 });
// Try to parse JSON response
let reviewResult;
try {
const jsonMatch = response.match(/\{[\s\S]*\}/);
if (jsonMatch) {
reviewResult = JSON.parse(jsonMatch[0]);
}
} catch {
// If JSON parsing fails, return default structure
reviewResult = {
summary: response,
issues: [],
score: 5
};
}
return {
content: [{ type: 'text' as const, text: response }],
structuredContent: {
summary: reviewResult?.summary || response,
issues: reviewResult?.issues || [],
score: reviewResult?.score || 5,
model: CONFIG.model
}
};
}
);
// Tool 4: gemini_query - General purpose query
server.tool(
'gemini_query',
'Send any query to Gemini-3-pro-preview model',
{
prompt: z.string().describe('The complete prompt to send'),
systemPrompt: z.string().optional().describe('Optional system prompt'),
temperature: z.number().min(0).max(2).optional().describe('Sampling temperature (0-2), default 0.7')
},
async ({ prompt, systemPrompt, temperature = 0.7 }) => {
const messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }> = [];
if (systemPrompt) {
messages.push({ role: 'system', content: systemPrompt });
}
messages.push({ role: 'user', content: prompt });
const response = await callGemini(messages, { temperature });
return {
content: [{ type: 'text' as const, text: response }],
structuredContent: {
response,
model: CONFIG.model
}
};
}
);
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Gemini MCP Server started');
}
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});