Unified Notifications MCP Server — Phase 1: Gmail
Send email alerts from any AI agent (Claude, LangGraph, GPT) via the Model Context Protocol.
This MCP server exposes a mail_send tool that any MCP-compatible AI agent can call to send emails via Gmail.
Use case: A factory machine stops working → your AI monitoring agent calls mail_send → manager, technician, and staff all receive an alert email instantly.
Machine stops → AI Agent → mail_send tool → Gmail → Manager + Technician notified
MCP endpoint: http://localhost:8100/mcp
notifications-mcp/
├── src/
│ ├── server.py ← Entrypoint (Streamable HTTP + OAuth routes)
│ ├── config.py ← Loads config.yaml
│ ├── registry.py ← Dynamically loads channel tools
│ └── channels/
│ ├── mail/ ← Gmail channel (Phase 1)
│ ├── teams/ ← Microsoft Teams (Phase 2 placeholder)
│ └── sms/ ← SMS via Twilio (Phase 3 placeholder)
To add a new channel: create channels/<name>/tools.py with a register(mcp, cfg) function, add the channel name to enabled_channels in config.yaml. No other files change.
- Python 3.11+
- A Google Cloud project with the Gmail API enabled
- Go to Google Cloud Console
- Enable the Gmail API for your project
- Go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID
- Application type: Web application
- Add Authorized redirect URI:
http://localhost:8100/auth/gmail/callback - Download the JSON → save as
credentials/google_credentials.json
pip install -r requirements.txt
# or for development:
pip install -e ".[dev]"python -m src.serverYou'll see:
{"level": "INFO", "message": "Starting notifications-mcp | host=0.0.0.0 | port=8100"}
{"level": "INFO", "message": "MCP endpoint → http://localhost:8100/mcp"}
{"level": "INFO", "message": "Gmail OAuth → http://localhost:8100/auth/gmail/start"}
Open your browser and visit:
http://localhost:8100/auth/gmail/start
- You'll be redirected to Google's consent page
- Log in with the Gmail account you want to send FROM
- Grant the "Send email" permission
- You'll see ✅ Gmail Authenticated! — close the tab
- The token is saved to
credentials/gmail_token.jsonand auto-refreshes silently from now on
npx @modelcontextprotocol/inspector http://localhost:8100/mcpCall mail_send with:
{
"to": ["manager@yourcompany.com", "technician@yourcompany.com"],
"subject": "ALERT: Machine #3 stopped",
"body": "Machine #3 on Floor B stopped at 18:02.\nError code: E-404.\nPlease investigate immediately."
}The agent sees this tool description:
mail_send — Send an email via Gmail to one or more recipients. For factory machine downtime alerts, include the machine name, location, stop time, and error code.
The agent calls it as:
result = await client.call_tool("mail_send", {
"to": ["manager@factory.com", "tech@factory.com"],
"subject": "ALERT: Machine #3 stopped",
"body": "Machine #3 stopped at 18:02. Error: E-404. Location: Floor B, Line 2."
})Add to your MCP config:
{
"mcpServers": {
"notifications": {
"url": "http://localhost:8100/mcp"
}
}
}Send an email to one or more recipients via Gmail.
| Parameter | Type | Required | Description |
|---|---|---|---|
to |
list[str] |
✅ | List of recipient email addresses |
subject |
str |
✅ | Email subject line |
body |
str |
✅ | Email body (plain text) |
cc |
list[str] |
❌ | CC recipients |
bcc |
list[str] |
❌ | BCC recipients |
Returns on success:
{"status": "sent", "message_id": "18b3c...", "recipients": ["manager@co.com"]}Returns on failure:
{"status": "failed", "error": "rate_limited", "message": "Gmail rate limit hit. Wait 60s."}Edit config.yaml to change settings:
server:
host: "0.0.0.0"
port: 8100 # Change port here
enabled_channels:
- mail # Add 'teams' or 'sms' here in Phase 2/3
channels:
mail:
credentials_path: "credentials/google_credentials.json"
token_path: "credentials/gmail_token.json"
scopes:
- "https://www.googleapis.com/auth/gmail.send"
oauth_redirect_uri: "http://localhost:8100/auth/gmail/callback"pytest tests/ -vExpected output:
tests/channels/mail/test_tools.py::test_mail_send_success PASSED
tests/channels/mail/test_tools.py::test_mail_send_not_authenticated PASSED
tests/channels/mail/test_tools.py::test_mail_send_rate_limited PASSED
tests/channels/mail/test_tools.py::test_mail_send_missing_to_field PASSED
tests/channels/mail/test_tools.py::test_mail_send_missing_subject PASSED
tests/channels/mail/test_tools.py::test_mail_send_multiple_recipients PASSED
tests/channels/mail/test_tools.py::test_mail_send_with_cc_bcc PASSED
- Create the channel folder:
src/channels/teams/__init__.py src/channels/teams/auth.py src/channels/teams/client.py src/channels/teams/schemas.py src/channels/teams/tools.py ← must have def register(mcp, cfg) - Add to
config.yaml:enabled_channels: - mail - teams ← add this channels: teams: tenant_id: "..." client_id: "..."
- Done.
server.pyandregistry.pyneed zero changes.
credentials/is gitignored — never commit Google credentials- OAuth token auto-refreshes silently — you only consent once
- The server runs on localhost — not exposed to the internet by default
- No API key required for localhost use
Phase 1: Gmail ✅ | Phase 2: Teams 🔜 | Phase 3: SMS 🔜