1
0
mirror of https://github.com/GuDaStudio/geminimcp.git synced 2026-02-05 01:50:25 +08:00

v0.2.0:移除未使用函数,改进子进程输出处理,并增强gemini函数中的错误报告功能。

This commit is contained in:
GuDaStudio
2025-12-11 16:17:05 +08:00
parent c91abd7637
commit c4144658d2

View File

@@ -18,13 +18,6 @@ import shutil
mcp = FastMCP("Gemini MCP Server-from guda.studio") mcp = FastMCP("Gemini MCP Server-from guda.studio")
def _empty_str_to_none(value: str | None) -> str | None:
"""Convert empty strings to None for optional UUID parameters."""
if isinstance(value, str) and not value.strip():
return None
return value
def run_shell_command(cmd: list[str]) -> Generator[str, None, None]: def run_shell_command(cmd: list[str]) -> Generator[str, None, None]:
"""Execute a command and stream its output line-by-line. """Execute a command and stream its output line-by-line.
@@ -45,40 +38,64 @@ def run_shell_command(cmd: list[str]) -> Generator[str, None, None]:
process = subprocess.Popen( process = subprocess.Popen(
popen_cmd, popen_cmd,
shell=False, # Safer: no shell injection shell=False,
stdin=subprocess.PIPE, # Prevent process from waiting for input stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
universal_newlines=True, universal_newlines=True,
encoding="utf-8", encoding='utf-8',
) )
output_queue: queue.Queue[str] = queue.Queue() output_queue: queue.Queue[str | None] = queue.Queue()
GRACEFUL_SHUTDOWN_DELAY = 0.3
def is_turn_completed(line: str) -> bool:
"""Check if the line indicates turn completion via JSON parsing."""
try:
data = json.loads(line)
return data.get("type") == "turn.completed"
except (json.JSONDecodeError, AttributeError, TypeError):
return False
def read_output() -> None: def read_output() -> None:
"""Read process output in a separate thread.""" """Read process output in a separate thread."""
if process.stdout: if process.stdout:
for line in iter(process.stdout.readline, ""): for line in iter(process.stdout.readline, ""):
output_queue.put(line.strip()) stripped = line.strip()
output_queue.put(stripped)
if is_turn_completed(stripped):
time.sleep(GRACEFUL_SHUTDOWN_DELAY)
process.terminate()
break
process.stdout.close() process.stdout.close()
output_queue.put(None)
thread = threading.Thread(target=read_output) thread = threading.Thread(target=read_output)
thread.daemon = True
thread.start() thread.start()
# Yield lines while process is running # Yield lines while process is running
while process.poll() is None: while True:
try: try:
yield output_queue.get(timeout=0.1) line = output_queue.get(timeout=0.5)
if line is None:
break
yield line
except queue.Empty: except queue.Empty:
continue if process.poll() is not None and not thread.is_alive():
break
process.wait() try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
thread.join(timeout=5)
# Drain remaining output from queue
while not output_queue.empty(): while not output_queue.empty():
try: try:
yield output_queue.get_nowait() line = output_queue.get_nowait()
if line is not None:
yield line
except queue.Empty: except queue.Empty:
break break
@@ -194,9 +211,11 @@ async def gemini(
# err_message = "gemini error: " + line_dict.get("message", "") # err_message = "gemini error: " + line_dict.get("message", "")
except json.JSONDecodeError as error: except json.JSONDecodeError as error:
# Improved error handling: include problematic line # Improved error handling: include problematic line
err_message = line err_message += "\n\n[json decode error] " + line
continue
except Exception as error: except Exception as error:
err_message = f"Unexpected error: {error}. Line: {line!r}" err_message += "\n\n[unexpected error] " + f"Unexpected error: {error}. Line: {line!r}"
break
if thread_id is None: if thread_id is None:
@@ -205,10 +224,10 @@ async def gemini(
"Failed to get `SESSION_ID` from the gemini session. \n\n" + err_message "Failed to get `SESSION_ID` from the gemini session. \n\n" + err_message
) )
if len(agent_messages) == 0: if success and len(agent_messages) == 0:
success = False success = False
err_message = ( err_message = (
"Failed to get `agent_messages` from the gemini session. \n\n You can try to set `return_all_messages` to `True` to get the full information. \n\n " "Failed to retrieve `agent_messages` data from the Gemini session. This might be due to Gemini performing a tool call. You can continue using the `SESSION_ID` to proceed with the conversation. \n\n "
+ err_message + err_message
) )
@@ -219,10 +238,11 @@ async def gemini(
"agent_messages": agent_messages, "agent_messages": agent_messages,
# "PROMPT": PROMPT, # "PROMPT": PROMPT,
} }
if return_all_messages:
result["all_messages"] = all_messages
else: else:
result = {"success": False, "error": err_message} result = {"success": False, "error": err_message}
if return_all_messages:
result["all_messages"] = all_messages
return result return result