From d8e693ba58680b2b405d36457c4b4911f70f7347 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 15 Jul 2026 17:53:12 -0400 Subject: [PATCH] MCP server source --- Dockerfile | 8 ++++++ requirements.txt | 1 + server.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 Dockerfile create mode 100644 requirements.txt create mode 100644 server.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3cac503 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.13-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY server.py ./ +ENV PYTHONUNBUFFERED=1 +EXPOSE 8902 +CMD ["python3", "server.py"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..886b069 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +fastmcp>=3.0.0 diff --git a/server.py b/server.py new file mode 100644 index 0000000..d917ff1 --- /dev/null +++ b/server.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""Email MCP Server — Send and check email from Open WebUI.""" +from fastmcp import FastMCP +import smtplib, imaplib, email, os +from email.mime.text import MIMEText + +mcp = FastMCP('Email', version='1.0.0') + +SMTP_HOST = 'mail.germainebrown.com' +SMTP_PORT = 2525 +IMAP_HOST = 'mail.germainebrown.com' +IMAP_PORT = 993 + +def _get_pass(filename): + with open(f'/root/.config/himalaya/{filename}') as f: + return f.read().strip() + +@mcp.tool(description="Send an email from g@germainebrown.com") +async def send_email(to: str, subject: str, body: str) -> str: + """Send an email via SMTP.""" + pw = _get_pass('g-germainebrown.pass') + msg = MIMEText(body) + msg['From'] = 'g@germainebrown.com' + msg['To'] = to + msg['Subject'] = subject + with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=15) as s: + s.starttls() + s.login('g@germainebrown.com', pw) + s.send_message(msg) + return f'Sent email to {to}: "{subject}"' + +@mcp.tool(description="Check recent emails in shonuff@germainebrown.com inbox") +async def check_inbox(limit: int = 10) -> str: + """Read recent inbox emails.""" + pw = _get_pass('shonuff.pass') + with imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT) as imap: + imap.login('shonuff@germainebrown.com', pw) + imap.select('INBOX') + _, msgs = imap.search(None, 'ALL') + ids = msgs[0].split()[-limit:] + results = [] + for mid in reversed(ids): + _, data = imap.fetch(mid, '(RFC822)') + msg = email.message_from_bytes(data[0][1]) + results.append(f'From: {msg["From"]} | Subject: {msg["Subject"]} | Date: {msg["Date"]}') + return f'Last {len(results)} emails:\n' + '\n'.join(results) + +@mcp.tool(description="Search shonuff@ inbox by subject or sender") +async def search_email(query: str, limit: int = 10) -> str: + """Search inbox.""" + pw = _get_pass('shonuff.pass') + with imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT) as imap: + imap.login('shonuff@germainebrown.com', pw) + imap.select('INBOX') + _, msgs = imap.search(None, f'SUBJECT "{query}"') + subject_ids = msgs[0].split() + _, msgs = imap.search(None, f'FROM "{query}"') + from_ids = msgs[0].split() + all_ids = list(set(list(subject_ids) + list(from_ids)))[-limit:] + results = [] + for mid in reversed(all_ids): + _, data = imap.fetch(mid, '(RFC822)') + msg = email.message_from_bytes(data[0][1]) + results.append(f'From: {msg["From"]} | Subject: {msg["Subject"]} | Date: {msg["Date"]}') + return f'Found {len(results)} matches for "{query}":\n' + '\n'.join(results) + +if __name__ == '__main__': + mcp.run(transport='http', host='0.0.0.0', port=8902, path='/mcp')