Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions mcpuniverse/mcp/servers/google_sheets/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# pylint: disable=broad-exception-caught,unused-argument,redefined-builtin
import os
import json
import sys
from typing import List, Dict, Any, Optional
from dataclasses import dataclass
from contextlib import asynccontextmanager
Expand Down Expand Up @@ -50,16 +51,16 @@ async def spreadsheet_lifespan(server: FastMCP) -> AsyncIterator[SpreadsheetCont
SERVICE_ACCOUNT_PATH,
scopes=SCOPES
)
print("Using service account authentication")
print(f"Working with Google Drive folder ID: {DRIVE_FOLDER_ID or 'Not specified'}")
print("Using service account authentication", file=sys.stderr)
print(f"Working with Google Drive folder ID: {DRIVE_FOLDER_ID or 'Not specified'}", file=sys.stderr)
except Exception as e:
print(f"Error using service account authentication: {e}")
print("Falling back to OAuth flow")
print(f"Error using service account authentication: {e}", file=sys.stderr)
print("Falling back to OAuth flow", file=sys.stderr)
creds = None

# Fall back to OAuth flow if service account auth failed or not configured
if not creds:
print("Using OAuth authentication flow")
print("Using OAuth authentication flow", file=sys.stderr)
if os.path.exists(TOKEN_PATH):
with open(TOKEN_PATH, "r", encoding="utf-8") as token:
creds = Credentials.from_authorized_user_info(json.load(token), SCOPES)
Expand Down Expand Up @@ -531,7 +532,7 @@ async def create_spreadsheet(title: str, ctx: Context = None) -> Dict[str, Any]:
).execute()

spreadsheet_id = spreadsheet.get('spreadsheetId')
print(f"Spreadsheet created with ID: {spreadsheet_id}")
print(f"Spreadsheet created with ID: {spreadsheet_id}", file=sys.stderr)

# If a folder_id is specified, move the spreadsheet to that folder
if folder_id:
Expand All @@ -552,9 +553,9 @@ async def create_spreadsheet(title: str, ctx: Context = None) -> Dict[str, Any]:
fields='id, parents'
).execute()

print(f"Spreadsheet moved to folder with ID: {folder_id}")
print(f"Spreadsheet moved to folder with ID: {folder_id}", file=sys.stderr)
except Exception as e:
print(f"Warning: Could not move spreadsheet to folder: {e}")
print(f"Warning: Could not move spreadsheet to folder: {e}", file=sys.stderr)

return {
'spreadsheetId': spreadsheet_id,
Expand Down Expand Up @@ -628,9 +629,9 @@ async def list_spreadsheets(ctx: Context = None) -> List[Dict[str, str]]:
# If a specific folder is configured, search only in that folder
if folder_id:
query += f" and '{folder_id}' in parents"
print(f"Searching for spreadsheets in folder: {folder_id}")
print(f"Searching for spreadsheets in folder: {folder_id}", file=sys.stderr)
else:
print("Searching for spreadsheets in 'My Drive'")
print("Searching for spreadsheets in 'My Drive'", file=sys.stderr)

# List spreadsheets
results = drive_service.files().list(
Expand Down
64 changes: 34 additions & 30 deletions mcpuniverse/mcp/servers/jina_scrape_llm_summary/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import json
import os
import subprocess
import sys
from typing import Any, Dict

import click
Expand Down Expand Up @@ -81,7 +82,7 @@ async def scrape_and_extract_info(

if not scrape_result["success"]:
print(
f"Jina Scrape and Extract Info: Scraping failed: {scrape_result['error']}"
f"Jina Scrape and Extract Info: Scraping failed: {scrape_result['error']}", file=sys.stderr
)
return {
"success": False,
Expand Down Expand Up @@ -215,12 +216,13 @@ async def scrape_url_with_jina(
if attempt < len(retry_delays):
delay = retry_delays[attempt]
print(
f"Jina Scrape: Connection timeout, {delay}s before next attempt (attempt {attempt + 1})"
f"Jina Scrape: Connection timeout, {delay}s before next attempt (attempt {attempt + 1})",
file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
f"Jina Scrape: Connection retry attempts exhausted, url: {url}"
f"Jina Scrape: Connection retry attempts exhausted, url: {url}", file=sys.stderr
)
raise e

Expand All @@ -229,12 +231,12 @@ async def scrape_url_with_jina(
if attempt < len(retry_delays):
delay = retry_delays[attempt]
print(
f"Jina Scrape: Connection error: {e}, {delay}s before next attempt"
f"Jina Scrape: Connection error: {e}, {delay}s before next attempt", file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
f"Jina Scrape: Connection retry attempts exhausted, url: {url}"
f"Jina Scrape: Connection retry attempts exhausted, url: {url}", file=sys.stderr
)
raise e

Expand All @@ -243,44 +245,45 @@ async def scrape_url_with_jina(
if attempt < len(retry_delays):
delay = retry_delays[attempt]
print(
f"Jina Scrape: Read timeout, {delay}s before next attempt (attempt {attempt + 1})"
f"Jina Scrape: Read timeout, {delay}s before next attempt (attempt {attempt + 1})",
file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
f"Jina Scrape: Read timeout retry attempts exhausted, url: {url}"
f"Jina Scrape: Read timeout retry attempts exhausted, url: {url}", file=sys.stderr
)
raise e

except httpx.HTTPStatusError as e:
if attempt < len(retry_delays):
print(
f"Jina Scrape: HTTP error: {e}, response.text: {response.text}, url: {url}, "
f"{delay}s before next attempt (attempt {attempt + 1})"
f"{delay}s before next attempt (attempt {attempt + 1})", file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
f"Jina Scrape: HTTP error retry attempts exhausted, url: {url}"
f"Jina Scrape: HTTP error retry attempts exhausted, url: {url}", file=sys.stderr
)
raise e

except httpx.RequestError as e:
if attempt < len(retry_delays):
print(
f"Jina Scrape: Unknown request exception: {e}, url: {url}, "
f"{delay}s before next attempt (attempt {attempt + 1})"
f"{delay}s before next attempt (attempt {attempt + 1})", file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
f"Jina Scrape: Unknown request exception retry attempts exhausted, url: {url}"
f"Jina Scrape: Unknown request exception retry attempts exhausted, url: {url}", file=sys.stderr
)
raise e

except Exception as e:
error_msg = f"Jina Scrape: Unexpected error occurred: {str(e)}"
print(error_msg)
print(error_msg, file=sys.stderr)
return {
"success": False,
"filename": "",
Expand Down Expand Up @@ -518,7 +521,7 @@ async def extract_info_with_llm(
tail_50 = response.text[-50:]
repeat_count = response.text.count(tail_50)
if repeat_count > 5:
print("Repeat detected in extract_info_with_llm")
print("Repeat detected in extract_info_with_llm", file=sys.stderr)
continue

# Check if the request was successful
Expand All @@ -544,12 +547,12 @@ async def extract_info_with_llm(
delay = connect_retry_delays[attempt]
print(
f"Jina Scrape and Extract Info: Connection timeout, {delay}s before next attempt "
f"(attempt {attempt + 1})"
f"(attempt {attempt + 1})", file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
"Jina Scrape and Extract Info: Connection retry attempts exhausted"
"Jina Scrape and Extract Info: Connection retry attempts exhausted", file=sys.stderr
)
raise e

Expand All @@ -559,32 +562,33 @@ async def extract_info_with_llm(
delay = connect_retry_delays[attempt]
print(
f"Jina Scrape and Extract Info: Connection error: {e}, "
f"{delay}s before next attempt"
f"{delay}s before next attempt", file=sys.stderr
)
await asyncio.sleep(delay)
continue
print(
"Jina Scrape and Extract Info: Connection retry attempts exhausted"
"Jina Scrape and Extract Info: Connection retry attempts exhausted", file=sys.stderr
)
raise e

except httpx.ReadTimeout as e:
# read timeout, LLM API is too slow, no need to retry
if attempt < len(connect_retry_delays):
print(
f"Jina Scrape and Extract Info: LLM API attempt {attempt} read timeout"
f"Jina Scrape and Extract Info: LLM API attempt {attempt} read timeout", file=sys.stderr
)
continue
print(
f"Jina Scrape and Extract Info: LLM API read timeout retry attempts exhausted, "
f"please check the request complexity, information to extract: {info_to_extract}, "
f"length of content: {len(content)}, url: {url}"
f"length of content: {len(content)}, url: {url}", file=sys.stderr
)
raise e

except httpx.HTTPStatusError as e:
print(
f"Jina Scrape and Extract Info: HTTP error for LLM API: {e}, response.text: {response.text}"
f"Jina Scrape and Extract Info: HTTP error for LLM API: {e}, response.text: {response.text}",
file=sys.stderr
)
raise httpx.HTTPStatusError(
f"response.text: {response.text}",
Expand All @@ -594,13 +598,13 @@ async def extract_info_with_llm(

except httpx.RequestError as e:
print(
f"Jina Scrape and Extract Info: Unknown request exception: {e}"
f"Jina Scrape and Extract Info: Unknown request exception: {e}", file=sys.stderr
)
raise e

except Exception as e:
error_msg = f"Jina Scrape and Extract Info: Unexpected error during LLM API call: {str(e)}"
print(error_msg)
print(error_msg, file=sys.stderr)
return {
"success": False,
"extracted_info": "",
Expand All @@ -617,8 +621,8 @@ async def extract_info_with_llm(
error_msg = (
f"Jina Scrape and Extract Info: Failed to parse LLM API response: {str(e)}"
)
print(error_msg)
print(f"Raw response: {response.text}")
print(error_msg, file=sys.stderr)
print(f"Raw response: {response.text}", file=sys.stderr)
return {
"success": False,
"extracted_info": "",
Expand All @@ -629,7 +633,7 @@ async def extract_info_with_llm(

print(
f"Jina Scrape and Extract Info: Info to extract: {info_to_extract}, "
f"LLM Response data: {response_data}"
f"LLM Response data: {response_data}", file=sys.stderr
)

# Extract summary from response
Expand All @@ -638,7 +642,7 @@ async def extract_info_with_llm(
summary = response_data["choices"][0]["message"]["content"]
except Exception as e:
error_msg = f"Jina Scrape and Extract Info: Failed to get summary from LLM API response: {str(e)}"
print(error_msg)
print(error_msg, file=sys.stderr)
return {
"success": False,
"extracted_info": "",
Expand All @@ -664,7 +668,7 @@ async def extract_info_with_llm(
summary = response_data["candidates"][0]["content"]["parts"][0]["text"]
except Exception as e:
error_msg = f"Jina Scrape and Extract Info: Failed to get summary from LLM API response: {str(e)}"
print(error_msg)
print(error_msg, file=sys.stderr)
return {
"success": False,
"extracted_info": "",
Expand All @@ -684,7 +688,7 @@ async def extract_info_with_llm(
error_msg = (
f"Jina Scrape and Extract Info: LLM API error: {response_data['error']}"
)
print(error_msg)
print(error_msg, file=sys.stderr)
return {
"success": False,
"extracted_info": "",
Expand All @@ -696,7 +700,7 @@ async def extract_info_with_llm(
f"Jina Scrape and Extract Info: No valid response from LLM API, "
f"response data: {response_data}"
)
print(error_msg)
print(error_msg, file=sys.stderr)
return {
"success": False,
"extracted_info": "",
Expand All @@ -723,7 +727,7 @@ def main(transport: str, port: str):
:param port: Port for SSE.
:param transport: The transport type, e.g., `stdio` or `sse`.
"""
print(f"Starting the MCP server on port {port} with transport {transport}")
print(f"Starting the MCP server on port {port} with transport {transport}", file=sys.stderr)
assert transport.lower() in ["stdio", "sse"], "Transport should be stdio or sse"
logger = get_logger("Service:jina_scrape_llm_summary")
logger.info("Starting the MCP server")
Expand Down
5 changes: 3 additions & 2 deletions mcpuniverse/mcp/servers/serper_search/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import os
import sys
from typing import Any, Dict

import click
Expand Down Expand Up @@ -170,7 +171,7 @@ async def perform_search(search_query: str) -> tuple[list, dict]:
if query_without_quotes: # Make sure we still have a valid query
print(
f"No results found for query with quotes: '{original_query}'. "
f"Retrying with query without quotes: '{query_without_quotes}'"
f"Retrying with query without quotes: '{query_without_quotes}'", file=sys.stderr
)
organic_results, search_params = await perform_search(
query_without_quotes
Expand Down Expand Up @@ -210,7 +211,7 @@ def main(transport: str, port: str):
:param port: Port for SSE.
:param transport: The transport type, e.g., `stdio` or `sse`.
"""
print(f"Starting the MCP server on port {port} with transport {transport}")
print(f"Starting the MCP server on port {port} with transport {transport}", file=sys.stderr)
assert transport.lower() in ["stdio", "sse"], \
"Transport should be `stdio` or `sse`"
logger = get_logger("Service:serper_search")
Expand Down
Loading