gemini-bridge 1.0.3__tar.gz → 1.0.5__tar.gz
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.
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/PKG-INFO +2 -75
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/README.md +1 -74
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/gemini_bridge.egg-info/PKG-INFO +2 -75
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/pyproject.toml +1 -1
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/src/__init__.py +1 -1
- gemini_bridge-1.0.5/src/mcp_server.py +241 -0
- gemini_bridge-1.0.3/src/mcp_server.py +0 -406
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/LICENSE +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/gemini_bridge.egg-info/SOURCES.txt +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/gemini_bridge.egg-info/dependency_links.txt +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/gemini_bridge.egg-info/entry_points.txt +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/gemini_bridge.egg-info/requires.txt +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/gemini_bridge.egg-info/top_level.txt +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/setup.cfg +0 -0
- {gemini_bridge-1.0.3 → gemini_bridge-1.0.5}/src/__main__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gemini-bridge
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.5
|
4
4
|
Summary: Lightweight MCP server bridging Claude Code to Google's Gemini AI via official CLI
|
5
5
|
Author-email: Shelakh <info@shelakh.com>
|
6
6
|
License-Expression: MIT
|
@@ -537,83 +537,10 @@ gemini --version
|
|
537
537
|
- Ensure Claude Code MCP configuration is correct
|
538
538
|
- Check that the `gemini` command is in your PATH
|
539
539
|
|
540
|
-
### Timeout Issues 🔥
|
541
|
-
|
542
|
-
Gemini Bridge now includes comprehensive timeout debugging. If you're experiencing timeout issues:
|
543
|
-
|
544
|
-
**1. Use the Debug Tool**
|
545
|
-
```python
|
546
|
-
# Get detailed diagnostics about your configuration
|
547
|
-
get_debug_info()
|
548
|
-
```
|
549
|
-
|
550
|
-
This will show:
|
551
|
-
- Current timeout configuration
|
552
|
-
- Gemini CLI status and version
|
553
|
-
- Authentication status
|
554
|
-
- Environment variables
|
555
|
-
- System information
|
556
|
-
|
557
|
-
**2. Configure Appropriate Timeout**
|
558
|
-
|
559
|
-
For different operation types, recommended timeouts:
|
560
|
-
|
561
|
-
- **Default operations**: 60 seconds (default)
|
562
|
-
- **Large file analysis**: 240 seconds
|
563
|
-
- **Complex multi-file operations**: 300+ seconds
|
564
|
-
|
565
|
-
**Configuration Examples:**
|
566
|
-
|
567
|
-
```bash
|
568
|
-
# Claude Code with 4-minute timeout for large operations
|
569
|
-
claude mcp add gemini-bridge -s user --env GEMINI_BRIDGE_TIMEOUT=240 -- uvx gemini-bridge
|
570
|
-
|
571
|
-
# Environment variable (if running manually)
|
572
|
-
export GEMINI_BRIDGE_TIMEOUT=240
|
573
|
-
```
|
574
|
-
|
575
|
-
**3. Common Timeout Scenarios**
|
576
|
-
|
577
|
-
| Scenario | Recommended Timeout | Reason |
|
578
|
-
|----------|-------------------|---------|
|
579
|
-
| Single file < 10KB | 60s (default) | Fast processing |
|
580
|
-
| Multiple files or large files | 240s | More content to process |
|
581
|
-
| Complex code analysis | 300s | Deep reasoning required |
|
582
|
-
| Very large files (>100KB) | 300-600s | Processing overhead |
|
583
|
-
|
584
|
-
**4. Debugging Steps**
|
585
|
-
|
586
|
-
1. **Check your configuration**:
|
587
|
-
```bash
|
588
|
-
# Run the debug tool to see current timeout
|
589
|
-
# Look for "Actual timeout used" in the output
|
590
|
-
```
|
591
|
-
|
592
|
-
2. **Monitor logs**: The server now logs detailed timing information
|
593
|
-
|
594
|
-
3. **Test with smaller queries**: If large queries timeout, break them into smaller parts
|
595
|
-
|
596
|
-
4. **Verify Gemini CLI performance**: Test `gemini` directly with similar queries
|
597
|
-
|
598
|
-
**5. Advanced Troubleshooting**
|
599
|
-
|
600
|
-
If timeouts persist even with high timeout values:
|
601
|
-
|
602
|
-
- **Network issues**: Check your internet connection
|
603
|
-
- **Gemini CLI version**: Update with `npm install -g @google/gemini-cli@latest`
|
604
|
-
- **Authentication**: Re-authenticate with `gemini auth login`
|
605
|
-
- **System resources**: Check if your system is under high load
|
606
|
-
- **File encoding**: Ensure files are UTF-8 encoded
|
607
|
-
- **MCP client timeout**: Some clients have their own timeout settings
|
608
|
-
|
609
540
|
### Common Error Messages
|
610
541
|
- **"CLI not available"**: Gemini CLI is not installed or not in PATH
|
611
542
|
- **"Authentication required"**: Run `gemini auth login`
|
612
|
-
- **"Timeout after
|
613
|
-
- Solution: Increase `GEMINI_BRIDGE_TIMEOUT` environment variable
|
614
|
-
- For immediate testing: Use smaller files or simpler queries
|
615
|
-
- **"Large content size warning"**: Files total >100KB, may need longer timeout
|
616
|
-
- **"Very high timeout configured"**: Timeout >300s, failed operations will wait long
|
543
|
+
- **"Timeout after 60 seconds"**: Query took too long, try breaking it into smaller parts
|
617
544
|
|
618
545
|
## 🤝 Contributing
|
619
546
|
|
@@ -513,83 +513,10 @@ gemini --version
|
|
513
513
|
- Ensure Claude Code MCP configuration is correct
|
514
514
|
- Check that the `gemini` command is in your PATH
|
515
515
|
|
516
|
-
### Timeout Issues 🔥
|
517
|
-
|
518
|
-
Gemini Bridge now includes comprehensive timeout debugging. If you're experiencing timeout issues:
|
519
|
-
|
520
|
-
**1. Use the Debug Tool**
|
521
|
-
```python
|
522
|
-
# Get detailed diagnostics about your configuration
|
523
|
-
get_debug_info()
|
524
|
-
```
|
525
|
-
|
526
|
-
This will show:
|
527
|
-
- Current timeout configuration
|
528
|
-
- Gemini CLI status and version
|
529
|
-
- Authentication status
|
530
|
-
- Environment variables
|
531
|
-
- System information
|
532
|
-
|
533
|
-
**2. Configure Appropriate Timeout**
|
534
|
-
|
535
|
-
For different operation types, recommended timeouts:
|
536
|
-
|
537
|
-
- **Default operations**: 60 seconds (default)
|
538
|
-
- **Large file analysis**: 240 seconds
|
539
|
-
- **Complex multi-file operations**: 300+ seconds
|
540
|
-
|
541
|
-
**Configuration Examples:**
|
542
|
-
|
543
|
-
```bash
|
544
|
-
# Claude Code with 4-minute timeout for large operations
|
545
|
-
claude mcp add gemini-bridge -s user --env GEMINI_BRIDGE_TIMEOUT=240 -- uvx gemini-bridge
|
546
|
-
|
547
|
-
# Environment variable (if running manually)
|
548
|
-
export GEMINI_BRIDGE_TIMEOUT=240
|
549
|
-
```
|
550
|
-
|
551
|
-
**3. Common Timeout Scenarios**
|
552
|
-
|
553
|
-
| Scenario | Recommended Timeout | Reason |
|
554
|
-
|----------|-------------------|---------|
|
555
|
-
| Single file < 10KB | 60s (default) | Fast processing |
|
556
|
-
| Multiple files or large files | 240s | More content to process |
|
557
|
-
| Complex code analysis | 300s | Deep reasoning required |
|
558
|
-
| Very large files (>100KB) | 300-600s | Processing overhead |
|
559
|
-
|
560
|
-
**4. Debugging Steps**
|
561
|
-
|
562
|
-
1. **Check your configuration**:
|
563
|
-
```bash
|
564
|
-
# Run the debug tool to see current timeout
|
565
|
-
# Look for "Actual timeout used" in the output
|
566
|
-
```
|
567
|
-
|
568
|
-
2. **Monitor logs**: The server now logs detailed timing information
|
569
|
-
|
570
|
-
3. **Test with smaller queries**: If large queries timeout, break them into smaller parts
|
571
|
-
|
572
|
-
4. **Verify Gemini CLI performance**: Test `gemini` directly with similar queries
|
573
|
-
|
574
|
-
**5. Advanced Troubleshooting**
|
575
|
-
|
576
|
-
If timeouts persist even with high timeout values:
|
577
|
-
|
578
|
-
- **Network issues**: Check your internet connection
|
579
|
-
- **Gemini CLI version**: Update with `npm install -g @google/gemini-cli@latest`
|
580
|
-
- **Authentication**: Re-authenticate with `gemini auth login`
|
581
|
-
- **System resources**: Check if your system is under high load
|
582
|
-
- **File encoding**: Ensure files are UTF-8 encoded
|
583
|
-
- **MCP client timeout**: Some clients have their own timeout settings
|
584
|
-
|
585
516
|
### Common Error Messages
|
586
517
|
- **"CLI not available"**: Gemini CLI is not installed or not in PATH
|
587
518
|
- **"Authentication required"**: Run `gemini auth login`
|
588
|
-
- **"Timeout after
|
589
|
-
- Solution: Increase `GEMINI_BRIDGE_TIMEOUT` environment variable
|
590
|
-
- For immediate testing: Use smaller files or simpler queries
|
591
|
-
- **"Large content size warning"**: Files total >100KB, may need longer timeout
|
592
|
-
- **"Very high timeout configured"**: Timeout >300s, failed operations will wait long
|
519
|
+
- **"Timeout after 60 seconds"**: Query took too long, try breaking it into smaller parts
|
593
520
|
|
594
521
|
## 🤝 Contributing
|
595
522
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: gemini-bridge
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.5
|
4
4
|
Summary: Lightweight MCP server bridging Claude Code to Google's Gemini AI via official CLI
|
5
5
|
Author-email: Shelakh <info@shelakh.com>
|
6
6
|
License-Expression: MIT
|
@@ -537,83 +537,10 @@ gemini --version
|
|
537
537
|
- Ensure Claude Code MCP configuration is correct
|
538
538
|
- Check that the `gemini` command is in your PATH
|
539
539
|
|
540
|
-
### Timeout Issues 🔥
|
541
|
-
|
542
|
-
Gemini Bridge now includes comprehensive timeout debugging. If you're experiencing timeout issues:
|
543
|
-
|
544
|
-
**1. Use the Debug Tool**
|
545
|
-
```python
|
546
|
-
# Get detailed diagnostics about your configuration
|
547
|
-
get_debug_info()
|
548
|
-
```
|
549
|
-
|
550
|
-
This will show:
|
551
|
-
- Current timeout configuration
|
552
|
-
- Gemini CLI status and version
|
553
|
-
- Authentication status
|
554
|
-
- Environment variables
|
555
|
-
- System information
|
556
|
-
|
557
|
-
**2. Configure Appropriate Timeout**
|
558
|
-
|
559
|
-
For different operation types, recommended timeouts:
|
560
|
-
|
561
|
-
- **Default operations**: 60 seconds (default)
|
562
|
-
- **Large file analysis**: 240 seconds
|
563
|
-
- **Complex multi-file operations**: 300+ seconds
|
564
|
-
|
565
|
-
**Configuration Examples:**
|
566
|
-
|
567
|
-
```bash
|
568
|
-
# Claude Code with 4-minute timeout for large operations
|
569
|
-
claude mcp add gemini-bridge -s user --env GEMINI_BRIDGE_TIMEOUT=240 -- uvx gemini-bridge
|
570
|
-
|
571
|
-
# Environment variable (if running manually)
|
572
|
-
export GEMINI_BRIDGE_TIMEOUT=240
|
573
|
-
```
|
574
|
-
|
575
|
-
**3. Common Timeout Scenarios**
|
576
|
-
|
577
|
-
| Scenario | Recommended Timeout | Reason |
|
578
|
-
|----------|-------------------|---------|
|
579
|
-
| Single file < 10KB | 60s (default) | Fast processing |
|
580
|
-
| Multiple files or large files | 240s | More content to process |
|
581
|
-
| Complex code analysis | 300s | Deep reasoning required |
|
582
|
-
| Very large files (>100KB) | 300-600s | Processing overhead |
|
583
|
-
|
584
|
-
**4. Debugging Steps**
|
585
|
-
|
586
|
-
1. **Check your configuration**:
|
587
|
-
```bash
|
588
|
-
# Run the debug tool to see current timeout
|
589
|
-
# Look for "Actual timeout used" in the output
|
590
|
-
```
|
591
|
-
|
592
|
-
2. **Monitor logs**: The server now logs detailed timing information
|
593
|
-
|
594
|
-
3. **Test with smaller queries**: If large queries timeout, break them into smaller parts
|
595
|
-
|
596
|
-
4. **Verify Gemini CLI performance**: Test `gemini` directly with similar queries
|
597
|
-
|
598
|
-
**5. Advanced Troubleshooting**
|
599
|
-
|
600
|
-
If timeouts persist even with high timeout values:
|
601
|
-
|
602
|
-
- **Network issues**: Check your internet connection
|
603
|
-
- **Gemini CLI version**: Update with `npm install -g @google/gemini-cli@latest`
|
604
|
-
- **Authentication**: Re-authenticate with `gemini auth login`
|
605
|
-
- **System resources**: Check if your system is under high load
|
606
|
-
- **File encoding**: Ensure files are UTF-8 encoded
|
607
|
-
- **MCP client timeout**: Some clients have their own timeout settings
|
608
|
-
|
609
540
|
### Common Error Messages
|
610
541
|
- **"CLI not available"**: Gemini CLI is not installed or not in PATH
|
611
542
|
- **"Authentication required"**: Run `gemini auth login`
|
612
|
-
- **"Timeout after
|
613
|
-
- Solution: Increase `GEMINI_BRIDGE_TIMEOUT` environment variable
|
614
|
-
- For immediate testing: Use smaller files or simpler queries
|
615
|
-
- **"Large content size warning"**: Files total >100KB, may need longer timeout
|
616
|
-
- **"Very high timeout configured"**: Timeout >300s, failed operations will wait long
|
543
|
+
- **"Timeout after 60 seconds"**: Query took too long, try breaking it into smaller parts
|
617
544
|
|
618
545
|
## 🤝 Contributing
|
619
546
|
|
@@ -0,0 +1,241 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Gemini MCP Server - Simple CLI Bridge
|
4
|
+
Version 1.0.5
|
5
|
+
A minimal MCP server to interface with Gemini AI via the gemini CLI.
|
6
|
+
Created by @shelakh/elyin
|
7
|
+
"""
|
8
|
+
|
9
|
+
import logging
|
10
|
+
import os
|
11
|
+
import shutil
|
12
|
+
import subprocess
|
13
|
+
from typing import List, Optional
|
14
|
+
|
15
|
+
from mcp.server.fastmcp import FastMCP
|
16
|
+
|
17
|
+
mcp = FastMCP("gemini-assistant")
|
18
|
+
|
19
|
+
|
20
|
+
def _normalize_model_name(model: Optional[str]) -> str:
|
21
|
+
"""
|
22
|
+
Normalize user-provided model identifiers to canonical Gemini CLI model names.
|
23
|
+
Defaults to gemini-2.5-flash when not provided or unrecognized.
|
24
|
+
|
25
|
+
Accepted forms:
|
26
|
+
- "flash", "2.5-flash", "gemini-2.5-flash"
|
27
|
+
- "pro", "2.5-pro", "gemini-2.5-pro"
|
28
|
+
"""
|
29
|
+
if not model:
|
30
|
+
return "gemini-2.5-flash"
|
31
|
+
value = model.strip().lower()
|
32
|
+
# Common short aliases
|
33
|
+
if value in {"flash", "2.5-flash", "gemini-2.5-flash"}:
|
34
|
+
return "gemini-2.5-flash"
|
35
|
+
if value in {"pro", "2.5-pro", "gemini-2.5-pro"}:
|
36
|
+
return "gemini-2.5-pro"
|
37
|
+
# If the caller passed a full model name, keep it
|
38
|
+
if value.startswith("gemini-"):
|
39
|
+
return value
|
40
|
+
# Fallback to flash for anything else
|
41
|
+
return "gemini-2.5-flash"
|
42
|
+
|
43
|
+
|
44
|
+
def _get_timeout() -> int:
|
45
|
+
"""
|
46
|
+
Get the timeout value from environment variable GEMINI_BRIDGE_TIMEOUT.
|
47
|
+
Defaults to 60 seconds if not set or invalid.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
Timeout value in seconds (positive integer)
|
51
|
+
"""
|
52
|
+
timeout_str = os.getenv("GEMINI_BRIDGE_TIMEOUT")
|
53
|
+
if not timeout_str:
|
54
|
+
return 60
|
55
|
+
|
56
|
+
try:
|
57
|
+
timeout = int(timeout_str)
|
58
|
+
if timeout <= 0:
|
59
|
+
logging.warning("Invalid GEMINI_BRIDGE_TIMEOUT value '%s' (must be positive). Using default 60 seconds.", timeout_str)
|
60
|
+
return 60
|
61
|
+
return timeout
|
62
|
+
except ValueError:
|
63
|
+
logging.warning("Invalid GEMINI_BRIDGE_TIMEOUT value '%s' (must be integer). Using default 60 seconds.", timeout_str)
|
64
|
+
return 60
|
65
|
+
|
66
|
+
|
67
|
+
def execute_gemini_simple(query: str, directory: str = ".", model: Optional[str] = None) -> str:
|
68
|
+
"""
|
69
|
+
Execute gemini CLI command for simple queries without file attachments.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
query: The prompt to send to Gemini
|
73
|
+
directory: Working directory for the command
|
74
|
+
model: Optional model name (flash, pro, etc.)
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
CLI output or error message
|
78
|
+
"""
|
79
|
+
# Check if gemini CLI is available
|
80
|
+
if not shutil.which("gemini"):
|
81
|
+
return "Error: Gemini CLI not found. Install with: npm install -g @google/gemini-cli"
|
82
|
+
|
83
|
+
# Validate directory
|
84
|
+
if not os.path.isdir(directory):
|
85
|
+
return f"Error: Directory does not exist: {directory}"
|
86
|
+
|
87
|
+
# Build command - use stdin for input to avoid hanging
|
88
|
+
selected_model = _normalize_model_name(model)
|
89
|
+
cmd = ["gemini", "-m", selected_model]
|
90
|
+
|
91
|
+
# Execute CLI command - simple timeout, no retries
|
92
|
+
timeout = _get_timeout()
|
93
|
+
try:
|
94
|
+
result = subprocess.run(
|
95
|
+
cmd,
|
96
|
+
cwd=directory,
|
97
|
+
capture_output=True,
|
98
|
+
text=True,
|
99
|
+
timeout=timeout,
|
100
|
+
input=query
|
101
|
+
)
|
102
|
+
|
103
|
+
if result.returncode == 0:
|
104
|
+
return result.stdout.strip() if result.stdout.strip() else "No output from Gemini CLI"
|
105
|
+
else:
|
106
|
+
return f"Gemini CLI Error: {result.stderr.strip()}"
|
107
|
+
|
108
|
+
except subprocess.TimeoutExpired:
|
109
|
+
return f"Error: Gemini CLI command timed out after {timeout} seconds"
|
110
|
+
except Exception as e:
|
111
|
+
return f"Error executing Gemini CLI: {str(e)}"
|
112
|
+
|
113
|
+
|
114
|
+
def execute_gemini_with_files(query: str, directory: str = ".", files: Optional[List[str]] = None, model: Optional[str] = None) -> str:
|
115
|
+
"""
|
116
|
+
Execute gemini CLI command with file attachments.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
query: The prompt to send to Gemini
|
120
|
+
directory: Working directory for the command
|
121
|
+
files: List of file paths to attach (relative to directory)
|
122
|
+
model: Optional model name (flash, pro, etc.)
|
123
|
+
|
124
|
+
Returns:
|
125
|
+
CLI output or error message
|
126
|
+
"""
|
127
|
+
# Check if gemini CLI is available
|
128
|
+
if not shutil.which("gemini"):
|
129
|
+
return "Error: Gemini CLI not found. Install with: npm install -g @google/gemini-cli"
|
130
|
+
|
131
|
+
# Validate directory
|
132
|
+
if not os.path.isdir(directory):
|
133
|
+
return f"Error: Directory does not exist: {directory}"
|
134
|
+
|
135
|
+
# Validate files parameter
|
136
|
+
if not files:
|
137
|
+
return "Error: No files provided for file attachment mode"
|
138
|
+
|
139
|
+
# Build command - use stdin for input to avoid hanging
|
140
|
+
selected_model = _normalize_model_name(model)
|
141
|
+
cmd = ["gemini", "-m", selected_model]
|
142
|
+
|
143
|
+
# Read and concatenate file contents
|
144
|
+
file_contents = []
|
145
|
+
for file_path in files:
|
146
|
+
try:
|
147
|
+
# Convert relative paths to absolute based on directory
|
148
|
+
if not os.path.isabs(file_path):
|
149
|
+
file_path = os.path.join(directory, file_path)
|
150
|
+
|
151
|
+
if os.path.isfile(file_path):
|
152
|
+
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
153
|
+
content = f.read()
|
154
|
+
file_contents.append(f"=== {os.path.basename(file_path)} ===\n{content}")
|
155
|
+
else:
|
156
|
+
file_contents.append(f"=== {os.path.basename(file_path)} ===\n[File not found]")
|
157
|
+
except Exception as e:
|
158
|
+
file_contents.append(f"=== {os.path.basename(file_path)} ===\n[Error reading file: {str(e)}]")
|
159
|
+
|
160
|
+
# Combine file contents with query
|
161
|
+
stdin_content = "\n\n".join(file_contents) + "\n\n" + query
|
162
|
+
|
163
|
+
# Execute CLI command - simple timeout, no retries
|
164
|
+
timeout = _get_timeout()
|
165
|
+
try:
|
166
|
+
result = subprocess.run(
|
167
|
+
cmd,
|
168
|
+
cwd=directory,
|
169
|
+
capture_output=True,
|
170
|
+
text=True,
|
171
|
+
timeout=timeout,
|
172
|
+
input=stdin_content
|
173
|
+
)
|
174
|
+
|
175
|
+
if result.returncode == 0:
|
176
|
+
return result.stdout.strip() if result.stdout.strip() else "No output from Gemini CLI"
|
177
|
+
else:
|
178
|
+
return f"Gemini CLI Error: {result.stderr.strip()}"
|
179
|
+
|
180
|
+
except subprocess.TimeoutExpired:
|
181
|
+
return f"Error: Gemini CLI command timed out after {timeout} seconds"
|
182
|
+
except Exception as e:
|
183
|
+
return f"Error executing Gemini CLI: {str(e)}"
|
184
|
+
|
185
|
+
|
186
|
+
@mcp.tool()
|
187
|
+
def consult_gemini(
|
188
|
+
query: str,
|
189
|
+
directory: str,
|
190
|
+
model: Optional[str] = None
|
191
|
+
) -> str:
|
192
|
+
"""
|
193
|
+
Send a query directly to Gemini CLI.
|
194
|
+
|
195
|
+
This is the core function - a direct bridge between Claude and Gemini.
|
196
|
+
No caching, no sessions, no complexity. Just execute and return.
|
197
|
+
|
198
|
+
Args:
|
199
|
+
query: The question or prompt to send to Gemini
|
200
|
+
directory: Working directory (required)
|
201
|
+
model: Optional model name (flash, pro, etc.)
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
Gemini's response
|
205
|
+
"""
|
206
|
+
return execute_gemini_simple(query, directory, model)
|
207
|
+
|
208
|
+
|
209
|
+
@mcp.tool()
|
210
|
+
def consult_gemini_with_files(
|
211
|
+
query: str,
|
212
|
+
directory: str,
|
213
|
+
files: Optional[List[str]] = None,
|
214
|
+
model: Optional[str] = None
|
215
|
+
) -> str:
|
216
|
+
"""
|
217
|
+
Send a query to Gemini CLI with file attachments.
|
218
|
+
|
219
|
+
Files are read and concatenated into the prompt. Simple and direct.
|
220
|
+
|
221
|
+
Args:
|
222
|
+
query: The question or prompt to send to Gemini
|
223
|
+
directory: Working directory (required)
|
224
|
+
files: List of file paths to attach (relative to directory)
|
225
|
+
model: Optional model name (flash, pro, etc.)
|
226
|
+
|
227
|
+
Returns:
|
228
|
+
Gemini's response with file context
|
229
|
+
"""
|
230
|
+
if not files:
|
231
|
+
return "Error: files parameter is required for consult_gemini_with_files"
|
232
|
+
return execute_gemini_with_files(query, directory, files, model)
|
233
|
+
|
234
|
+
|
235
|
+
def main():
|
236
|
+
"""Entry point for the MCP server."""
|
237
|
+
mcp.run()
|
238
|
+
|
239
|
+
|
240
|
+
if __name__ == "__main__":
|
241
|
+
main()
|
@@ -1,406 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Gemini MCP Server - Simple CLI Bridge
|
4
|
-
Version 1.0.2
|
5
|
-
A minimal MCP server to interface with Gemini AI via the gemini CLI.
|
6
|
-
Created by @shelakh/elyin
|
7
|
-
"""
|
8
|
-
|
9
|
-
import logging
|
10
|
-
import os
|
11
|
-
import shutil
|
12
|
-
import subprocess
|
13
|
-
import sys
|
14
|
-
from typing import List, Optional
|
15
|
-
|
16
|
-
from mcp.server.fastmcp import FastMCP
|
17
|
-
|
18
|
-
# Configure logging for debugging timeout issues
|
19
|
-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
20
|
-
logger = logging.getLogger(__name__)
|
21
|
-
|
22
|
-
mcp = FastMCP("gemini-assistant")
|
23
|
-
|
24
|
-
|
25
|
-
def _normalize_model_name(model: Optional[str]) -> str:
|
26
|
-
"""
|
27
|
-
Normalize user-provided model identifiers to canonical Gemini CLI model names.
|
28
|
-
Defaults to gemini-2.5-flash when not provided or unrecognized.
|
29
|
-
|
30
|
-
Accepted forms:
|
31
|
-
- "flash", "2.5-flash", "gemini-2.5-flash"
|
32
|
-
- "pro", "2.5-pro", "gemini-2.5-pro"
|
33
|
-
"""
|
34
|
-
if not model:
|
35
|
-
return "gemini-2.5-flash"
|
36
|
-
value = model.strip().lower()
|
37
|
-
# Common short aliases
|
38
|
-
if value in {"flash", "2.5-flash", "gemini-2.5-flash"}:
|
39
|
-
return "gemini-2.5-flash"
|
40
|
-
if value in {"pro", "2.5-pro", "gemini-2.5-pro"}:
|
41
|
-
return "gemini-2.5-pro"
|
42
|
-
# If the caller passed a full model name, keep it
|
43
|
-
if value.startswith("gemini-"):
|
44
|
-
return value
|
45
|
-
# Fallback to flash for anything else
|
46
|
-
return "gemini-2.5-flash"
|
47
|
-
|
48
|
-
|
49
|
-
def _get_timeout() -> int:
|
50
|
-
"""
|
51
|
-
Get the timeout value from environment variable GEMINI_BRIDGE_TIMEOUT.
|
52
|
-
Defaults to 60 seconds if not set or invalid.
|
53
|
-
|
54
|
-
Returns:
|
55
|
-
Timeout value in seconds (positive integer)
|
56
|
-
"""
|
57
|
-
timeout_str = os.getenv("GEMINI_BRIDGE_TIMEOUT")
|
58
|
-
logger.debug(
|
59
|
-
"Reading timeout from environment: GEMINI_BRIDGE_TIMEOUT=%s", timeout_str
|
60
|
-
)
|
61
|
-
|
62
|
-
if not timeout_str:
|
63
|
-
logger.info("GEMINI_BRIDGE_TIMEOUT not set, using default 60 seconds")
|
64
|
-
return 60
|
65
|
-
|
66
|
-
try:
|
67
|
-
timeout = int(timeout_str)
|
68
|
-
except ValueError:
|
69
|
-
logger.warning(
|
70
|
-
"Invalid GEMINI_BRIDGE_TIMEOUT value '%s' (must be integer). Using default 60 seconds.",
|
71
|
-
timeout_str,
|
72
|
-
)
|
73
|
-
return 60
|
74
|
-
|
75
|
-
if timeout <= 0:
|
76
|
-
logger.warning(
|
77
|
-
"Invalid GEMINI_BRIDGE_TIMEOUT value '%s' (must be positive). Using default 60 seconds.",
|
78
|
-
timeout_str,
|
79
|
-
)
|
80
|
-
return 60
|
81
|
-
|
82
|
-
logger.info("Using configured timeout: %s seconds", timeout)
|
83
|
-
if timeout > 300:
|
84
|
-
logger.warning(
|
85
|
-
"Large timeout configured (%ss). This may cause long waits for failed operations.",
|
86
|
-
timeout,
|
87
|
-
)
|
88
|
-
return timeout
|
89
|
-
|
90
|
-
def execute_gemini_simple(query: str, directory: str = ".", model: Optional[str] = None) -> str:
|
91
|
-
"""
|
92
|
-
Execute gemini CLI command for simple queries without file attachments.
|
93
|
-
|
94
|
-
Args:
|
95
|
-
query: The prompt to send to Gemini
|
96
|
-
directory: Working directory for the command
|
97
|
-
model: Optional model name (flash, pro, etc.)
|
98
|
-
|
99
|
-
Returns:
|
100
|
-
CLI output or error message
|
101
|
-
"""
|
102
|
-
# Check if gemini CLI is available
|
103
|
-
if not shutil.which("gemini"):
|
104
|
-
return "Error: Gemini CLI not found. Install with: npm install -g @google/gemini-cli"
|
105
|
-
|
106
|
-
# Validate directory
|
107
|
-
if not os.path.isdir(directory):
|
108
|
-
return f"Error: Directory does not exist: {directory}"
|
109
|
-
|
110
|
-
# Build command - use stdin for input to avoid hanging
|
111
|
-
selected_model = _normalize_model_name(model)
|
112
|
-
cmd = ["gemini", "-m", selected_model]
|
113
|
-
|
114
|
-
# Execute CLI command - simple timeout, no retries
|
115
|
-
timeout = _get_timeout()
|
116
|
-
logger.info(f"Executing Gemini CLI with timeout: {timeout}s, model: {selected_model}, directory: {directory}")
|
117
|
-
logger.debug(f"Query length: {len(query)} characters")
|
118
|
-
|
119
|
-
try:
|
120
|
-
result = subprocess.run(
|
121
|
-
cmd,
|
122
|
-
cwd=directory,
|
123
|
-
capture_output=True,
|
124
|
-
text=True,
|
125
|
-
timeout=timeout,
|
126
|
-
input=query
|
127
|
-
)
|
128
|
-
|
129
|
-
logger.debug(f"Gemini CLI completed with return code: {result.returncode}")
|
130
|
-
|
131
|
-
if result.returncode == 0:
|
132
|
-
output = result.stdout.strip() if result.stdout.strip() else "No output from Gemini CLI"
|
133
|
-
logger.info(f"Gemini CLI successful, output length: {len(output)} characters")
|
134
|
-
return output
|
135
|
-
else:
|
136
|
-
error_msg = f"Gemini CLI Error: {result.stderr.strip()}"
|
137
|
-
logger.error(error_msg)
|
138
|
-
return error_msg
|
139
|
-
|
140
|
-
except subprocess.TimeoutExpired:
|
141
|
-
timeout_msg = f"Error: Gemini CLI command timed out after {timeout} seconds. Try increasing GEMINI_BRIDGE_TIMEOUT environment variable for large operations."
|
142
|
-
logger.error(timeout_msg)
|
143
|
-
return timeout_msg
|
144
|
-
except Exception as e:
|
145
|
-
error_msg = f"Error executing Gemini CLI: {str(e)}"
|
146
|
-
logger.error(error_msg)
|
147
|
-
return error_msg
|
148
|
-
|
149
|
-
|
150
|
-
def execute_gemini_with_files(query: str, directory: str = ".", files: Optional[List[str]] = None, model: Optional[str] = None) -> str:
|
151
|
-
"""
|
152
|
-
Execute gemini CLI command with file attachments.
|
153
|
-
|
154
|
-
Args:
|
155
|
-
query: The prompt to send to Gemini
|
156
|
-
directory: Working directory for the command
|
157
|
-
files: List of file paths to attach (relative to directory)
|
158
|
-
model: Optional model name (flash, pro, etc.)
|
159
|
-
|
160
|
-
Returns:
|
161
|
-
CLI output or error message
|
162
|
-
"""
|
163
|
-
# Check if gemini CLI is available
|
164
|
-
if not shutil.which("gemini"):
|
165
|
-
return "Error: Gemini CLI not found. Install with: npm install -g @google/gemini-cli"
|
166
|
-
|
167
|
-
# Validate directory
|
168
|
-
if not os.path.isdir(directory):
|
169
|
-
return f"Error: Directory does not exist: {directory}"
|
170
|
-
|
171
|
-
# Validate files parameter
|
172
|
-
if not files:
|
173
|
-
return "Error: No files provided for file attachment mode"
|
174
|
-
|
175
|
-
# Build command - use stdin for input to avoid hanging
|
176
|
-
selected_model = _normalize_model_name(model)
|
177
|
-
cmd = ["gemini", "-m", selected_model]
|
178
|
-
|
179
|
-
# Read and concatenate file contents
|
180
|
-
file_contents = []
|
181
|
-
for file_path in files:
|
182
|
-
try:
|
183
|
-
# Convert relative paths to absolute based on directory
|
184
|
-
if not os.path.isabs(file_path):
|
185
|
-
file_path = os.path.join(directory, file_path)
|
186
|
-
|
187
|
-
if os.path.isfile(file_path):
|
188
|
-
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
189
|
-
content = f.read()
|
190
|
-
file_contents.append(f"=== {os.path.basename(file_path)} ===\n{content}")
|
191
|
-
else:
|
192
|
-
file_contents.append(f"=== {os.path.basename(file_path)} ===\n[File not found]")
|
193
|
-
except Exception as e:
|
194
|
-
file_contents.append(f"=== {os.path.basename(file_path)} ===\n[Error reading file: {str(e)}]")
|
195
|
-
|
196
|
-
# Combine file contents with query
|
197
|
-
stdin_content = "\n\n".join(file_contents) + "\n\n" + query
|
198
|
-
|
199
|
-
# Execute CLI command - simple timeout, no retries
|
200
|
-
timeout = _get_timeout()
|
201
|
-
total_content_size = len(stdin_content)
|
202
|
-
logger.info(f"Executing Gemini CLI with files, timeout: {timeout}s, model: {selected_model}, directory: {directory}")
|
203
|
-
logger.info(f"File count: {len(files)}, total content size: {total_content_size} characters")
|
204
|
-
|
205
|
-
# Warn about large content that might timeout
|
206
|
-
if total_content_size > 100000: # 100KB threshold
|
207
|
-
logger.warning(f"Large content size ({total_content_size} chars). Consider increasing timeout if you experience timeouts.")
|
208
|
-
|
209
|
-
try:
|
210
|
-
result = subprocess.run(
|
211
|
-
cmd,
|
212
|
-
cwd=directory,
|
213
|
-
capture_output=True,
|
214
|
-
text=True,
|
215
|
-
timeout=timeout,
|
216
|
-
input=stdin_content
|
217
|
-
)
|
218
|
-
|
219
|
-
logger.debug(f"Gemini CLI completed with return code: {result.returncode}")
|
220
|
-
|
221
|
-
if result.returncode == 0:
|
222
|
-
output = result.stdout.strip() if result.stdout.strip() else "No output from Gemini CLI"
|
223
|
-
logger.info(f"Gemini CLI successful, output length: {len(output)} characters")
|
224
|
-
return output
|
225
|
-
else:
|
226
|
-
error_msg = f"Gemini CLI Error: {result.stderr.strip()}"
|
227
|
-
logger.error(error_msg)
|
228
|
-
return error_msg
|
229
|
-
|
230
|
-
except subprocess.TimeoutExpired:
|
231
|
-
timeout_msg = f"Error: Gemini CLI command timed out after {timeout} seconds with {len(files)} files ({total_content_size} chars). Try increasing GEMINI_BRIDGE_TIMEOUT environment variable (current: {os.getenv('GEMINI_BRIDGE_TIMEOUT', 'not set')})."
|
232
|
-
logger.error(timeout_msg)
|
233
|
-
return timeout_msg
|
234
|
-
except Exception as e:
|
235
|
-
error_msg = f"Error executing Gemini CLI: {str(e)}"
|
236
|
-
logger.error(error_msg)
|
237
|
-
return error_msg
|
238
|
-
|
239
|
-
|
240
|
-
@mcp.tool()
|
241
|
-
def consult_gemini(
|
242
|
-
query: str,
|
243
|
-
directory: str,
|
244
|
-
model: Optional[str] = None
|
245
|
-
) -> str:
|
246
|
-
"""
|
247
|
-
Send a query directly to Gemini CLI.
|
248
|
-
|
249
|
-
This is the core function - a direct bridge between Claude and Gemini.
|
250
|
-
No caching, no sessions, no complexity. Just execute and return.
|
251
|
-
|
252
|
-
Args:
|
253
|
-
query: The question or prompt to send to Gemini
|
254
|
-
directory: Working directory (required)
|
255
|
-
model: Optional model name (flash, pro, etc.)
|
256
|
-
|
257
|
-
Returns:
|
258
|
-
Gemini's response
|
259
|
-
"""
|
260
|
-
return execute_gemini_simple(query, directory, model)
|
261
|
-
|
262
|
-
|
263
|
-
@mcp.tool()
|
264
|
-
def consult_gemini_with_files(
|
265
|
-
query: str,
|
266
|
-
directory: str,
|
267
|
-
files: Optional[List[str]] = None,
|
268
|
-
model: Optional[str] = None
|
269
|
-
) -> str:
|
270
|
-
"""
|
271
|
-
Send a query to Gemini CLI with file attachments.
|
272
|
-
|
273
|
-
Files are read and concatenated into the prompt. Simple and direct.
|
274
|
-
|
275
|
-
Args:
|
276
|
-
query: The question or prompt to send to Gemini
|
277
|
-
directory: Working directory (required)
|
278
|
-
files: List of file paths to attach (relative to directory)
|
279
|
-
model: Optional model name (flash, pro, etc.)
|
280
|
-
|
281
|
-
Returns:
|
282
|
-
Gemini's response with file context
|
283
|
-
"""
|
284
|
-
if not files:
|
285
|
-
return "Error: files parameter is required for consult_gemini_with_files"
|
286
|
-
return execute_gemini_with_files(query, directory, files, model)
|
287
|
-
|
288
|
-
|
289
|
-
@mcp.tool()
|
290
|
-
def get_debug_info() -> str:
|
291
|
-
"""
|
292
|
-
Get diagnostic information about the Gemini Bridge configuration.
|
293
|
-
|
294
|
-
Useful for troubleshooting timeout issues and verifying setup.
|
295
|
-
|
296
|
-
Returns:
|
297
|
-
Formatted debug information including timeout configuration,
|
298
|
-
environment variables, and system status
|
299
|
-
"""
|
300
|
-
debug_info = []
|
301
|
-
debug_info.append("=== Gemini Bridge Debug Information ===\n")
|
302
|
-
|
303
|
-
# Timeout configuration
|
304
|
-
timeout_env = os.getenv("GEMINI_BRIDGE_TIMEOUT")
|
305
|
-
actual_timeout = _get_timeout()
|
306
|
-
debug_info.append("Timeout Configuration:")
|
307
|
-
debug_info.append(f" GEMINI_BRIDGE_TIMEOUT env var: {timeout_env or 'not set'}")
|
308
|
-
debug_info.append(f" Actual timeout used: {actual_timeout} seconds")
|
309
|
-
|
310
|
-
if actual_timeout == 60 and not timeout_env:
|
311
|
-
debug_info.append(" ⚠️ Using default timeout. Set GEMINI_BRIDGE_TIMEOUT=240 for large operations.")
|
312
|
-
elif actual_timeout < 120:
|
313
|
-
debug_info.append(" ⚠️ Timeout may be too low for large files or complex queries.")
|
314
|
-
elif actual_timeout > 300:
|
315
|
-
debug_info.append(f" ⚠️ Very high timeout configured. Failed operations will wait {actual_timeout}s.")
|
316
|
-
else:
|
317
|
-
debug_info.append(" ✓ Timeout looks reasonable for most operations.")
|
318
|
-
|
319
|
-
debug_info.append("")
|
320
|
-
|
321
|
-
# Gemini CLI status
|
322
|
-
gemini_path = shutil.which("gemini")
|
323
|
-
debug_info.append("Gemini CLI Status:")
|
324
|
-
debug_info.append(f" CLI available: {'✓ Yes' if gemini_path else '✗ No'}")
|
325
|
-
if gemini_path:
|
326
|
-
debug_info.append(f" CLI path: {gemini_path}")
|
327
|
-
try:
|
328
|
-
# Try to get version
|
329
|
-
result = subprocess.run(
|
330
|
-
["gemini", "--version"],
|
331
|
-
capture_output=True,
|
332
|
-
text=True,
|
333
|
-
timeout=5
|
334
|
-
)
|
335
|
-
if result.returncode == 0:
|
336
|
-
version = result.stdout.strip()
|
337
|
-
debug_info.append(f" CLI version: {version}")
|
338
|
-
else:
|
339
|
-
debug_info.append(f" CLI version check failed: {result.stderr.strip()}")
|
340
|
-
except Exception as e:
|
341
|
-
debug_info.append(f" CLI version check error: {str(e)}")
|
342
|
-
else:
|
343
|
-
debug_info.append(" ✗ Install with: npm install -g @google/gemini-cli")
|
344
|
-
|
345
|
-
debug_info.append("")
|
346
|
-
# Environment details
|
347
|
-
debug_info.append("Environment:")
|
348
|
-
debug_info.append(f" Python version: {sys.version.split()[0]}")
|
349
|
-
debug_info.append(f" Current working directory: {os.getcwd()}")
|
350
|
-
debug_info.append(f" PORT: {os.getenv('PORT', '8080')}")
|
351
|
-
|
352
|
-
# Check authentication status
|
353
|
-
try:
|
354
|
-
result = subprocess.run(
|
355
|
-
["gemini", "auth", "status"],
|
356
|
-
capture_output=True,
|
357
|
-
text=True,
|
358
|
-
timeout=10,
|
359
|
-
cwd="."
|
360
|
-
)
|
361
|
-
if result.returncode == 0:
|
362
|
-
debug_info.append(" Authentication: ✓ Logged in")
|
363
|
-
else:
|
364
|
-
debug_info.append(" Authentication: ✗ Not logged in - run 'gemini auth login'")
|
365
|
-
except Exception as e:
|
366
|
-
debug_info.append(f" Authentication status check failed: {str(e)}")
|
367
|
-
|
368
|
-
debug_info.append("")
|
369
|
-
|
370
|
-
# Recent environment variables that might affect operation
|
371
|
-
relevant_env_vars = [
|
372
|
-
"GEMINI_BRIDGE_TIMEOUT", "NODE_PATH", "PATH", "HOME",
|
373
|
-
"GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_CLOUD_PROJECT"
|
374
|
-
]
|
375
|
-
|
376
|
-
debug_info.append("Relevant Environment Variables:")
|
377
|
-
for var in relevant_env_vars:
|
378
|
-
value = os.getenv(var)
|
379
|
-
if value:
|
380
|
-
# Truncate very long values
|
381
|
-
display_value = value[:100] + "..." if len(value) > 100 else value
|
382
|
-
debug_info.append(f" {var}: {display_value}")
|
383
|
-
else:
|
384
|
-
debug_info.append(f" {var}: not set")
|
385
|
-
|
386
|
-
debug_info.append("")
|
387
|
-
debug_info.append("=== End Debug Information ===")
|
388
|
-
|
389
|
-
return "\n".join(debug_info)
|
390
|
-
|
391
|
-
|
392
|
-
def main():
|
393
|
-
"""Entry point for the MCP server."""
|
394
|
-
port = int(os.getenv("PORT", "8080"))
|
395
|
-
timeout = _get_timeout() # Log timeout configuration at startup
|
396
|
-
|
397
|
-
logger.info(f"Starting Gemini Bridge MCP Server on port {port}")
|
398
|
-
logger.info(f"Configured timeout: {timeout} seconds")
|
399
|
-
logger.info(f"Gemini CLI available: {shutil.which('gemini') is not None}")
|
400
|
-
|
401
|
-
# Run the MCP server with SSE transport (port is managed by the library)
|
402
|
-
mcp.run(transport="sse")
|
403
|
-
|
404
|
-
|
405
|
-
if __name__ == "__main__":
|
406
|
-
main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|