|
|
import asyncio |
|
|
import os |
|
|
import shutil |
|
|
from pathlib import Path |
|
|
from pydantic_core import ValidationError |
|
|
from langchain_core.tools import tool |
|
|
from langchain_mcp_adapters.client import MultiServerMCPClient |
|
|
from langchain.agents import create_agent |
|
|
from langchain_openai import ChatOpenAI |
|
|
from src.mcp_servers.examples.gmail.settings import GMailSettings |
|
|
from src.prompts import get_prompt |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UV_PATH = shutil.which("uv") |
|
|
|
|
|
|
|
|
SYSTEM_PROMPT = get_prompt( |
|
|
template_name="GMail", |
|
|
latest_version=True |
|
|
) |
|
|
|
|
|
@tool |
|
|
def gmail_agent(query: str) -> str: |
|
|
""" |
|
|
A tool that acts as a Gmail agent. |
|
|
It can read, search, label, and send emails using the Gmail MCP server. |
|
|
|
|
|
Args: |
|
|
query (str): The natural language request (e.g., "Send an email to X", "Check unread emails"). |
|
|
|
|
|
Returns: |
|
|
str: The natural language response from the agent confirming the action or providing the requested information. |
|
|
|
|
|
Example output: |
|
|
"I have successfully sent the email to X with the subject 'Interview Invitation'." |
|
|
""" |
|
|
if not UV_PATH: |
|
|
return "β Error: 'uv' executable not found. Please ensure uv is installed and in the system PATH." |
|
|
|
|
|
|
|
|
creds_env = os.getenv("GMAIL_CREDS_JSON") |
|
|
token_env = os.getenv("GMAIL_TOKEN_JSON") |
|
|
if not creds_env or not token_env: |
|
|
return "β Gmail credentials not configured. Set GMAIL_CREDS_JSON and GMAIL_TOKEN_JSON environment variables." |
|
|
|
|
|
try: |
|
|
import asyncio |
|
|
async def _run_async(): |
|
|
|
|
|
try: |
|
|
|
|
|
settings = GMailSettings(creds_json=creds_env, token_json=token_env) |
|
|
except ValidationError as ve: |
|
|
return f"β Gmail settings invalid: {ve}" |
|
|
except Exception as e: |
|
|
return f"β Gmail settings error: {e}" |
|
|
creds_path, token_path = settings.materialize_files() |
|
|
|
|
|
|
|
|
model = ChatOpenAI(model="gpt-4o", temperature=0) |
|
|
|
|
|
|
|
|
client = MultiServerMCPClient( |
|
|
{ |
|
|
"gmail": { |
|
|
"command": UV_PATH, |
|
|
"args": [ |
|
|
"--directory", str(settings.gmail_mcp_dir), |
|
|
"run", "gmail", |
|
|
"--creds-file-path", str(creds_path), |
|
|
"--token-path", str(token_path), |
|
|
], |
|
|
"transport": "stdio", |
|
|
} |
|
|
} |
|
|
) |
|
|
|
|
|
|
|
|
try: |
|
|
tools = await client.get_tools() |
|
|
except Exception as e: |
|
|
return f"β Failed to connect to Gmail MCP server: {str(e)}" |
|
|
|
|
|
if not tools: |
|
|
return "β No tools available from Gmail MCP server." |
|
|
|
|
|
|
|
|
agent = create_agent(model, tools) |
|
|
|
|
|
|
|
|
result = await agent.ainvoke({ |
|
|
"messages": [ |
|
|
{ |
|
|
"role": "system", |
|
|
"content": SYSTEM_PROMPT, |
|
|
}, |
|
|
{ |
|
|
"role": "user", |
|
|
"content": query, |
|
|
}, |
|
|
] |
|
|
}) |
|
|
|
|
|
|
|
|
output = result["messages"][-1].content |
|
|
return output |
|
|
|
|
|
return asyncio.run(_run_async()) |
|
|
|
|
|
except Exception as e: |
|
|
import traceback |
|
|
return f"β Error in gmail_agent: {str(e)}\n{traceback.format_exc()}" |
|
|
|
|
|
|