Add SSH MCP server and Gmail attachment download
Features: - SSH MCP server with two tools: * ssh_execute: Run commands on remote hosts via SSH * ssh_file_upload: Upload files via SFTP - Support for both password and SSH key authentication - Auto-accept SSH host keys (AutoAddPolicy) for homelab use - Gmail attachment download functionality - Added download_attachment tool for Gmail API Technical changes: - Created mcp_servers/mcp_ssh.py with MCP-compliant text output - Updated llm_interface.py to load SSH MCP server - Added paramiko>=3.4.0 to requirements.txt - Updated .env.example with SSH configuration template - Enhanced gmail_client.py with download_attachment() method - Added download_attachment tool handler in tools.py SSH credentials configured via environment variables: - PROXMOX_SSH_HOST, PROXMOX_SSH_USER, PROXMOX_SSH_PORT - PROXMOX_SSH_PASSWORD (or) PROXMOX_SSH_KEY_FILE Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
69
tools.py
69
tools.py
@@ -190,6 +190,33 @@ TOOL_DEFINITIONS = [
|
||||
"required": ["message_id"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "download_attachment",
|
||||
"description": "Download an email attachment from Gmail. Use get_email first to get attachment IDs.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message_id": {
|
||||
"type": "string",
|
||||
"description": "Gmail message ID containing the attachment",
|
||||
},
|
||||
"attachment_id": {
|
||||
"type": "string",
|
||||
"description": "Attachment ID from the email (obtained from get_email)",
|
||||
},
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Original filename of the attachment",
|
||||
},
|
||||
"output_dir": {
|
||||
"type": "string",
|
||||
"description": "Directory to save the file (default: 'downloads')",
|
||||
"default": "downloads",
|
||||
},
|
||||
},
|
||||
"required": ["message_id", "attachment_id", "filename"],
|
||||
},
|
||||
},
|
||||
# Calendar tools
|
||||
{
|
||||
"name": "read_calendar",
|
||||
@@ -411,6 +438,13 @@ def execute_tool(tool_name: str, tool_input: Dict[str, Any], healing_system: Any
|
||||
message_id=tool_input["message_id"],
|
||||
format_type=tool_input.get("format", "text"),
|
||||
)
|
||||
elif tool_name == "download_attachment":
|
||||
result_str = _download_attachment(
|
||||
message_id=tool_input["message_id"],
|
||||
attachment_id=tool_input["attachment_id"],
|
||||
filename=tool_input["filename"],
|
||||
output_dir=tool_input.get("output_dir", "downloads"),
|
||||
)
|
||||
elif tool_name == "read_calendar":
|
||||
result_str = _read_calendar(
|
||||
days_ahead=tool_input.get("days_ahead", 7),
|
||||
@@ -844,7 +878,10 @@ def _get_email(message_id: str, format_type: str = "text") -> str:
|
||||
output.append(f"\n{email_data.get('body', '')}")
|
||||
|
||||
if email_data.get("attachments"):
|
||||
output.append(f"\nAttachments: {', '.join(email_data['attachments'])}")
|
||||
output.append("\nAttachments:")
|
||||
for att in email_data["attachments"]:
|
||||
att_info = f" - {att['filename']} ({att.get('size', 0)} bytes, ID: {att.get('attachment_id', 'N/A')})"
|
||||
output.append(att_info)
|
||||
|
||||
full_output = "\n".join(output)
|
||||
if len(full_output) > _MAX_TOOL_OUTPUT:
|
||||
@@ -855,6 +892,36 @@ def _get_email(message_id: str, format_type: str = "text") -> str:
|
||||
return f"Error getting email: {result.get('error', 'Unknown error')}"
|
||||
|
||||
|
||||
def _download_attachment(
|
||||
message_id: str,
|
||||
attachment_id: str,
|
||||
filename: str,
|
||||
output_dir: str = "downloads",
|
||||
) -> str:
|
||||
"""Download an email attachment."""
|
||||
gmail_client, _, _ = _initialize_google_clients()
|
||||
|
||||
if not gmail_client:
|
||||
return "Error: Google not authorized. Run: python bot_runner.py --setup-google"
|
||||
|
||||
result = gmail_client.download_attachment(
|
||||
message_id=message_id,
|
||||
attachment_id=attachment_id,
|
||||
filename=filename,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
|
||||
if result["success"]:
|
||||
return (
|
||||
f"Downloaded attachment successfully:\n"
|
||||
f" File: {result['filename']}\n"
|
||||
f" Path: {result['file_path']}\n"
|
||||
f" Size: {result['size']:,} bytes"
|
||||
)
|
||||
else:
|
||||
return f"Error downloading attachment: {result.get('error', 'Unknown error')}"
|
||||
|
||||
|
||||
def _read_calendar(
|
||||
days_ahead: int = 7,
|
||||
calendar_id: str = "primary",
|
||||
|
||||
Reference in New Issue
Block a user