Skip to content
Merged
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
14 changes: 14 additions & 0 deletions .vscode/mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"servers": {
"GmailMCPServer": {
"command": "uv",
"args": [
"run",
"main.py"
],
"cwd": "/home/matteo/Documents/Dev/Personal/hal/MCP_and_tools/GMailMCP",
"type": "stdio"
}
},
"inputs": []
}
88 changes: 88 additions & 0 deletions CodeFirst_Libraries/PydanticAI/email_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import os
import asyncio
import smtplib
from email.message import EmailMessage
from dotenv import load_dotenv
from pydantic_ai import Agent, RunContext
import nest_asyncio

# Apply nest_asyncio to allow nested event loops if necessary
nest_asyncio.apply()

# --- Configuration ---
load_dotenv()

# --- Agent Definition ---
agent = Agent(
'openai:gpt-5-nano',
system_prompt='You are a helpful email assistant. You can send emails using the defined tools.',
deps_type=str # We can use deps to pass dependencies if needed, or simple type

)

# --- Tool Definition ---
@agent.tool
def send_email(ctx: RunContext[str], recipient: str, subject: str, body: str) -> str:
"""
Send an email using Gmail SMTP.

Args:
recipient: The email address receiving the email.
subject: The subject/title of the email.
body: The body content of the email.

Returns:
A success message or error description.
"""
sender = os.getenv("GMAIL_SENDER") or os.getenv("GMAIL_USERNAME") or "mmarcolinionline@gmail.com" # Fallback/Configuration
password = os.getenv("GMAIL_PASSWORD")

if not password:
return "Error: GMAIL_PASSWORD not set in environment variables."

print(f"DEBUG: Attempting to send email to {recipient} with subject '{subject}'")

msg = EmailMessage()
msg.set_content(body)
msg["Subject"] = subject
msg["From"] = sender
msg["To"] = recipient

try:
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(sender, password)
server.send_message(msg)
return f"Email sent successfully to {recipient}"
except Exception as e:
return f"Error sending email: {str(e)}"

# --- Execution ---
async def main():
print("Starting Email Agent...")
print("Ensure GMAIL_PASSWORD is set in your .env file.")

messages = []

while True:
try:
user_input = input("\nUser (or 'q' to quit): ")
if user_input.lower() in ["q", "quit", "exit"]:
break

# Run the agent
result = await agent.run(user_input, message_history=messages)

print(f"Agent: {result.data}")

# Update history
messages.extend(result.new_messages())

except KeyboardInterrupt:
break
except Exception as e:
print(f"Error: {e}")
break

if __name__ == "__main__":
asyncio.run(main())
4 changes: 4 additions & 0 deletions MCP_and_tools/GMailMCP/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GMAIL_PASSWORD=your_app_password_here
# If your sender email is different from the account associated with the password,
# you might need to adjust authentication or use the primary account.
# For IMAP, the email_address argument must match the account for this password.
1 change: 1 addition & 0 deletions MCP_and_tools/GMailMCP/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
49 changes: 49 additions & 0 deletions MCP_and_tools/GMailMCP/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Gmail MCP Server

This is a Model Context Protocol (MCP) server that provides Gmail integration.

## Tools

1. `send_email(sender, recipient, title, body)`: Sends an email using Gmail SMTP.
2. `get_recent_emails(email_address)`: Retrieves the titles of the last 10 emails from the inbox.

## Setup

1. Create a `.env` file based on `.env.example`:
```bash
cp .env.example .env
```
2. Add your Gmail App Password to `.env`. You can generate one in your Google Account settings (Security > 2-Step Verification > App passwords).

## Usage

Run the server using `uv`:

```bash
uv run main.py
```

## VS Code Configuration (mcp.json)

To use this server with VS Code's MCP client, add the following configuration to your MCP settings file (typically located at `~/.config/Code/User/globalStorage/mcp-servers.json` or accessible via the command palette "MCP: Configure Servers"):

```json
{
"mcpServers": {
"gmail-mcp": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/hal/MCP_and_tools/GMailMCP",
"run",
"main.py"
],
"env": {
"GMAIL_PASSWORD": "your-app-password-here"
}
}
}
}
```

> **Note:** Replace `/absolute/path/to/hal/MCP_and_tools/GMailMCP` with the actual full path to this directory on your machine. You can also move the sensitive `GMAIL_PASSWORD` env var here if you prefer not to rely on the `.env` file when running via VS Code, though the server code loads `.env` by default.
110 changes: 110 additions & 0 deletions MCP_and_tools/GMailMCP/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from fastmcp import FastMCP
import smtplib
import imaplib
import email
from email.header import decode_header
from email.message import EmailMessage
import os
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Initialize FastMCP
mcp = FastMCP("Gmail Integration")

@mcp.tool()
def send_email(sender: str, recipient: str, title: str, body: str) -> str:
"""
Send an email using Gmail SMTP.

Args:
sender: The email address sending the email.
recipient: The email address receiving the email.
title: The subject/title of the email.
body: The body content of the email.
"""
password = os.getenv("GMAIL_PASSWORD")
if not password:
raise ValueError("GMAIL_PASSWORD not set in environment variables.")

# Create the email
msg = EmailMessage()
msg.set_content(body)
msg["Subject"] = title
msg["From"] = sender
msg["To"] = recipient

try:
# Connect to Gmail SMTP server
# Note: This requires an App Password if 2FA is enabled
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(sender, password)
server.send_message(msg)
return f"Email sent successfully to {recipient}"
except Exception as e:
return f"Error sending email: {str(e)}"

@mcp.tool()
def get_recent_emails(email_address: str) -> list[str]:
"""
Retrieve the titles of the last 10 emails from the inbox.

Args:
email_address: The email address to check (must match GMAIL_PASSWORD account).
"""
password = os.getenv("GMAIL_PASSWORD")
if not password:
raise ValueError("GMAIL_PASSWORD not set in environment variables.")

try:
# Connect to Gmail IMAP server
mail = imaplib.IMAP4_SSL("imap.gmail.com")
mail.login(email_address, password)

# Select the 'inbox'
mail.select("inbox")

# Search for all emails
status, messages = mail.search(None, "ALL")
if status != "OK":
return ["Error retrieving emails"]

# Get the list of email IDs
email_ids = messages[0].split()

# Get the last 10 email IDs (or fewer if less than 10 exist)
last_10_ids = email_ids[-10:] if len(email_ids) >= 10 else email_ids

titles = []
# Fetch in reverse order (newest first)
for e_id in reversed(last_10_ids):
status, msg_data = mail.fetch(e_id, "(RFC822)")
if status != "OK":
continue

for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
subject = msg["Subject"]
if subject:
decoded_list = decode_header(subject)
subject_str = ""
for decoded_part, encoding in decoded_list:
if isinstance(decoded_part, bytes):
subject_str += decoded_part.decode(encoding if encoding else "utf-8", errors="ignore")
else:
subject_str += decoded_part
titles.append(subject_str)
else:
titles.append("(No Subject)")

mail.logout()
return titles
except Exception as e:
return [f"Error retrieving emails: {str(e)}"]

if __name__ == "__main__":
mcp.run()

10 changes: 10 additions & 0 deletions MCP_and_tools/GMailMCP/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[project]
name = "gmail-mcp"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastmcp>=2.14.4",
"python-dotenv>=1.2.1",
]
1 change: 1 addition & 0 deletions MCP_and_tools/SendEmailWithComposio/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
Empty file.
16 changes: 16 additions & 0 deletions MCP_and_tools/SendEmailWithComposio/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[project]
name = "sendemailwithcomposio"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"composio>=0.10.10",
"composio-langchain>=0.10.10",
"composio-openai-agents>=0.10.10",
"dotenv>=0.9.9",
"langchain>=1.2.7",
"langchain-community>=0.4.1",
"langchain-openai>=1.1.7",
"openai-agents>=0.7.0",
]
55 changes: 55 additions & 0 deletions MCP_and_tools/SendEmailWithComposio/sendMail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import os

from dotenv import load_dotenv
import asyncio
from composio import Composio
from agents import Agent, Runner
from composio_openai_agents import OpenAIAgentsProvider

# Load environment variables
load_dotenv()

if not os.environ.get("OPENAI_API_KEY"):
print("WARNING: OPENAI_API_KEY not found in environment variables.")

composio = Composio(api_key=os.environ.get("COMPOSIO_API_KEY"), provider=OpenAIAgentsProvider())

# Id of the user in your system
externalUserId = "c3e00703-0478-4974-8873-bb6b6586f8bf"

# Create an auth config for gmail from the dashboard or programmatically
auth_config_id = os.environ.get("AUTH_CONFIG_ID")
connection_request = composio.connected_accounts.link(
user_id=externalUserId,
auth_config_id=auth_config_id,
)

# Redirect user to the OAuth flow
redirect_url = connection_request.redirect_url

print(
f"Please authorize the app by visiting this URL: {redirect_url}"
) # Print the redirect url to the user

# Wait for the connection to be established
connected_account = connection_request.wait_for_connection()
print(
f"Connection established successfully! Connected account id: {connected_account.id}"
)

# Get Gmail tools that are pre-configured
tools = composio.tools.get(user_id=externalUserId, tools=["GMAIL_SEND_EMAIL"])

agent = Agent(
name="Email Manager", instructions="You are a helpful assistant", tools=tools
)

# Run the agent
async def main():
result = await Runner.run(
starting_agent=agent,
input="Send an email to mmarcolinishop@gmail.com with the subject 'Hello from composio 👋🏻' and the body 'Congratulations on sending your first email using AI Agents and Composio!'",
)
print(result.final_output)

asyncio.run(main())
Loading