Remove specific account references from public documentation
- Replace FETCHERPAY with generic CUSTOM account examples - Update README.md, .env.example, and DEPLOY.md with generic configurations - Remove hardcoded IPs, email addresses, and domain names - Update package.json description to be more generic 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
17
.env.example
17
.env.example
@@ -3,15 +3,14 @@
|
||||
YAHOO_EMAIL=you@yahoo.com
|
||||
YAHOO_APP_PASSWORD=xxxx xxxx xxxx xxxx
|
||||
|
||||
# ── FetcherPay self-hosted mail (Dovecot / Poste.io) ─────────────────────────
|
||||
# IMAP/SMTP are exposed as Kubernetes NodePorts on the server.
|
||||
# Use the direct server IP (not hostname) to avoid K8s internal DNS flakiness.
|
||||
FETCHERPAY_EMAIL=you@fetcherpay.com
|
||||
FETCHERPAY_PASSWORD=yourpassword
|
||||
FETCHERPAY_IMAP_HOST=23.120.207.35 # direct IP avoids EAI_AGAIN; or: mail.fetcherpay.com
|
||||
FETCHERPAY_IMAP_PORT=30993 # K8s NodePort — IMAPS (TLS, self-signed cert)
|
||||
FETCHERPAY_SMTP_HOST=23.120.207.35
|
||||
FETCHERPAY_SMTP_PORT=30587 # K8s NodePort — SMTP + STARTTLS
|
||||
# ── Optional: Custom IMAP/SMTP Server ────────────────────────────────────────
|
||||
# Uncomment and configure these if you want to use a second email account
|
||||
# CUSTOM_EMAIL=you@yourdomain.com
|
||||
# CUSTOM_PASSWORD=yourpassword
|
||||
# CUSTOM_IMAP_HOST=mail.yourdomain.com
|
||||
# CUSTOM_IMAP_PORT=993
|
||||
# CUSTOM_SMTP_HOST=mail.yourdomain.com
|
||||
# CUSTOM_SMTP_PORT=587
|
||||
|
||||
# ── Server ───────────────────────────────────────────────────────────────────
|
||||
PORT=3456
|
||||
|
||||
97
DEPLOY.md
97
DEPLOY.md
@@ -1,7 +1,7 @@
|
||||
# Hermes MCP — Setup & Deployment
|
||||
|
||||
Hermes is a multi-account email MCP server for Claude AI.
|
||||
It supports **Yahoo Mail** (IMAP App Password) and any **self-hosted mail server** (Dovecot / Poste.io).
|
||||
It supports **Yahoo Mail** (IMAP App Password) and any **custom IMAP/SMTP server**.
|
||||
|
||||
---
|
||||
|
||||
@@ -25,51 +25,51 @@ curl http://localhost:3456/health
|
||||
|
||||
---
|
||||
|
||||
## Production deployment (MicroK8s — current setup)
|
||||
## Production deployment (Kubernetes example)
|
||||
|
||||
The server runs as a Kubernetes Deployment on `23.120.207.35` (MicroK8s single-node cluster).
|
||||
SSL is handled by `cert-manager` with a Let's Encrypt cert for `hermes.fetcherpay.com`.
|
||||
Example deployment using MicroK8s single-node cluster.
|
||||
SSL is handled by `cert-manager` with a Let's Encrypt certificate.
|
||||
|
||||
### Prerequisites on the server
|
||||
- MicroK8s with addons: `dns`, `ingress`, `registry`, `cert-manager`
|
||||
- Local registry at `localhost:32000`
|
||||
- A `ClusterIssuer` named `letsencrypt-prod` already configured
|
||||
|
||||
### One-time: create K8s namespace secret
|
||||
### One-time: create K8s namespace and secret
|
||||
```bash
|
||||
microk8s kubectl create namespace fetcherpay # if it doesn't exist
|
||||
microk8s kubectl create namespace hermes-mcp # if it doesn't exist
|
||||
|
||||
microk8s kubectl create secret generic hermes-mcp-env -n fetcherpay \
|
||||
--from-literal=YAHOO_EMAIL=gheron01@yahoo.com \
|
||||
--from-literal=YAHOO_APP_PASSWORD=lzlleytmslxocxae \
|
||||
--from-literal=FETCHERPAY_EMAIL=garfield.heron@fetcherpay.com \
|
||||
--from-literal=FETCHERPAY_PASSWORD=onelove \
|
||||
--from-literal=FETCHERPAY_IMAP_HOST=23.120.207.35 \
|
||||
--from-literal=FETCHERPAY_IMAP_PORT=30993 \
|
||||
--from-literal=FETCHERPAY_SMTP_HOST=23.120.207.35 \
|
||||
--from-literal=FETCHERPAY_SMTP_PORT=30587 \
|
||||
microk8s kubectl create secret generic hermes-mcp-env -n hermes-mcp \
|
||||
--from-literal=YAHOO_EMAIL=your@yahoo.com \
|
||||
--from-literal=YAHOO_APP_PASSWORD=your-app-password \
|
||||
--from-literal=CUSTOM_EMAIL=your@domain.com \
|
||||
--from-literal=CUSTOM_PASSWORD=your-password \
|
||||
--from-literal=CUSTOM_IMAP_HOST=mail.yourdomain.com \
|
||||
--from-literal=CUSTOM_IMAP_PORT=993 \
|
||||
--from-literal=CUSTOM_SMTP_HOST=mail.yourdomain.com \
|
||||
--from-literal=CUSTOM_SMTP_PORT=587 \
|
||||
--from-literal=PORT=3456
|
||||
```
|
||||
|
||||
### Build & push image
|
||||
```bash
|
||||
# From your local machine — SCP src to server first, then SSH in:
|
||||
scp -P 2222 -r src/ package*.json tsconfig.json Dockerfile garfield@23.120.207.35:~/hermes-mcp/
|
||||
|
||||
ssh -p 2222 garfield@23.120.207.35
|
||||
cd ~/hermes-mcp
|
||||
# Option 1: Build locally and push to your registry
|
||||
docker build -t localhost:32000/hermes-mcp:latest .
|
||||
docker push localhost:32000/hermes-mcp:latest
|
||||
|
||||
# Option 2: Copy to server and build there
|
||||
scp -r src/ package*.json tsconfig.json Dockerfile user@your-server:~/hermes-mcp/
|
||||
ssh user@your-server "cd ~/hermes-mcp && docker build -t localhost:32000/hermes-mcp:latest . && docker push localhost:32000/hermes-mcp:latest"
|
||||
```
|
||||
|
||||
### Apply K8s manifests (hermes-k8s.yaml on the server)
|
||||
### Apply K8s manifests
|
||||
```yaml
|
||||
# ~/hermes-mcp/hermes-k8s.yaml (already applied — shown for reference)
|
||||
# hermes-k8s.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hermes-mcp
|
||||
namespace: fetcherpay
|
||||
namespace: hermes-mcp
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
@@ -99,7 +99,7 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: hermes-mcp
|
||||
namespace: fetcherpay
|
||||
namespace: hermes-mcp
|
||||
spec:
|
||||
selector:
|
||||
app: hermes-mcp
|
||||
@@ -111,7 +111,7 @@ apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: hermes-ingress
|
||||
namespace: fetcherpay
|
||||
namespace: hermes-mcp
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
||||
@@ -120,7 +120,7 @@ metadata:
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: hermes.fetcherpay.com
|
||||
- host: hermes.yourdomain.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
@@ -132,23 +132,24 @@ spec:
|
||||
number: 3456
|
||||
tls:
|
||||
- hosts:
|
||||
- hermes.fetcherpay.com
|
||||
secretName: hermes-fetcherpay-tls
|
||||
- hermes.yourdomain.com
|
||||
secretName: hermes-tls
|
||||
```
|
||||
|
||||
Apply the manifests:
|
||||
```bash
|
||||
microk8s kubectl apply -f hermes-k8s.yaml
|
||||
```
|
||||
|
||||
### Redeploy after code changes
|
||||
```bash
|
||||
# On your local machine:
|
||||
scp -P 2222 src/imap.ts src/smtp.ts src/tools.ts src/index.ts \
|
||||
garfield@23.120.207.35:~/hermes-mcp/src/
|
||||
# Rebuild and push the image
|
||||
docker build -t localhost:32000/hermes-mcp:latest .
|
||||
docker push localhost:32000/hermes-mcp:latest
|
||||
|
||||
ssh -p 2222 garfield@23.120.207.35 "
|
||||
cd ~/hermes-mcp &&
|
||||
docker build -t localhost:32000/hermes-mcp:latest . &&
|
||||
docker push localhost:32000/hermes-mcp:latest &&
|
||||
microk8s kubectl rollout restart deployment/hermes-mcp -n fetcherpay &&
|
||||
microk8s kubectl rollout status deployment/hermes-mcp -n fetcherpay
|
||||
"
|
||||
# Restart the deployment
|
||||
microk8s kubectl rollout restart deployment/hermes-mcp -n hermes-mcp
|
||||
microk8s kubectl rollout status deployment/hermes-mcp -n hermes-mcp
|
||||
```
|
||||
|
||||
---
|
||||
@@ -157,17 +158,17 @@ ssh -p 2222 garfield@23.120.207.35 "
|
||||
|
||||
```bash
|
||||
# Logs
|
||||
microk8s kubectl logs -n fetcherpay -l app=hermes-mcp --tail=100 -f
|
||||
microk8s kubectl logs -n hermes-mcp -l app=hermes-mcp --tail=100 -f
|
||||
|
||||
# Pod status
|
||||
microk8s kubectl get pods -n fetcherpay -l app=hermes-mcp
|
||||
microk8s kubectl get pods -n hermes-mcp -l app=hermes-mcp
|
||||
|
||||
# Update a single env var without rebuild (takes effect on next rollout)
|
||||
microk8s kubectl set env deployment/hermes-mcp -n fetcherpay KEY=value
|
||||
microk8s kubectl rollout restart deployment/hermes-mcp -n fetcherpay
|
||||
microk8s kubectl set env deployment/hermes-mcp -n hermes-mcp KEY=value
|
||||
microk8s kubectl rollout restart deployment/hermes-mcp -n hermes-mcp
|
||||
|
||||
# Health check
|
||||
curl https://hermes.fetcherpay.com/health
|
||||
curl https://hermes.yourdomain.com/health
|
||||
```
|
||||
|
||||
---
|
||||
@@ -175,7 +176,7 @@ curl https://hermes.fetcherpay.com/health
|
||||
## Add to Claude.ai
|
||||
|
||||
1. Go to **Claude.ai → Settings → Connectors → Add custom connector**
|
||||
2. Enter URL: `https://hermes.fetcherpay.com/mcp`
|
||||
2. Enter URL: `https://hermes.yourdomain.com/mcp` (or your server's URL)
|
||||
3. Click Connect
|
||||
|
||||
### Available tools
|
||||
@@ -189,7 +190,7 @@ curl https://hermes.fetcherpay.com/health
|
||||
| `create_draft` | Save a draft to the Drafts folder | `to`, `subject`, `body`, `account` |
|
||||
| `send_email` | Send an email | `to`, `subject`, `body`, `account` |
|
||||
|
||||
`account` is always optional — defaults to `"yahoo"`. Set to `"fetcherpay"` for the FetcherPay mailbox.
|
||||
`account` is always optional and defaults to `"yahoo"`. Configure your second account in the code if needed.
|
||||
|
||||
---
|
||||
|
||||
@@ -197,7 +198,7 @@ curl https://hermes.fetcherpay.com/health
|
||||
|
||||
| Issue | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| `yahoo_read_message` 5-min timeout | `source: true` downloads full raw RFC822 | Use `bodyParts: ['TEXT']` |
|
||||
| `read_message` timeout | `source: true` downloads full raw RFC822 | Use `bodyParts: ['TEXT']` instead |
|
||||
| `messageFlagsAdd` deadlock | Called inside `for await` loop while FETCH active | Moved to after the loop |
|
||||
| Stale session after pod restart | `!sessionId` guard blocked re-initialize | Accept initialize regardless of session ID |
|
||||
| FetcherPay `EAI_AGAIN` DNS | K8s internal DNS cold-start for hostname | Use direct IP `23.120.207.35` |
|
||||
| Stale session after pod restart | Session ID guard blocked re-initialize | Accept initialize regardless of session ID |
|
||||
| `EAI_AGAIN` DNS errors | K8s internal DNS resolution issues | Use direct IP instead of hostname |
|
||||
|
||||
30
README.md
30
README.md
@@ -1,17 +1,17 @@
|
||||
# Hermes MCP
|
||||
|
||||
A multi-account email MCP server for [Claude AI](https://claude.ai).
|
||||
Supports **Yahoo Mail** (IMAP App Password) and any **self-hosted mail server** (Dovecot / Poste.io).
|
||||
Supports **Yahoo Mail** (IMAP App Password) and any **self-hosted mail server** (IMAP/SMTP).
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- Read, search, and send email from Claude via MCP
|
||||
- Multi-account: connect Yahoo and a custom IMAP/SMTP server simultaneously
|
||||
- Multi-account support: Yahoo Mail and custom IMAP/SMTP servers
|
||||
- Streamable HTTP transport (MCP 1.x) + legacy SSE endpoint
|
||||
- Automatic session recovery after server restarts
|
||||
- Deployable to Kubernetes (MicroK8s example included)
|
||||
- Docker and Kubernetes deployment ready
|
||||
|
||||
---
|
||||
|
||||
@@ -26,7 +26,7 @@ Supports **Yahoo Mail** (IMAP App Password) and any **self-hosted mail server**
|
||||
| `create_draft` | Save a draft to the Drafts folder | `to`, `subject`, `body`, `account` |
|
||||
| `send_email` | Send an email | `to`, `subject`, `body`, `account` |
|
||||
|
||||
`account` defaults to `"yahoo"`. Set to `"fetcherpay"` (or whatever you name your second account) for the custom mailbox.
|
||||
`account` parameter allows you to specify which configured mailbox to use (defaults to `"yahoo"`).
|
||||
|
||||
---
|
||||
|
||||
@@ -60,19 +60,17 @@ Copy `.env.example` to `.env` and fill in your values:
|
||||
YAHOO_EMAIL=you@yahoo.com
|
||||
YAHOO_APP_PASSWORD=xxxx xxxx xxxx xxxx
|
||||
|
||||
# Self-hosted mail (Dovecot / Poste.io / any IMAP server)
|
||||
FETCHERPAY_EMAIL=you@yourdomain.com
|
||||
FETCHERPAY_PASSWORD=yourpassword
|
||||
FETCHERPAY_IMAP_HOST=your-mail-server-ip
|
||||
FETCHERPAY_IMAP_PORT=993
|
||||
FETCHERPAY_SMTP_HOST=your-mail-server-ip
|
||||
FETCHERPAY_SMTP_PORT=587
|
||||
# Optional: Self-hosted mail server (any IMAP/SMTP server)
|
||||
# CUSTOM_EMAIL=you@yourdomain.com
|
||||
# CUSTOM_PASSWORD=yourpassword
|
||||
# CUSTOM_IMAP_HOST=mail.yourdomain.com
|
||||
# CUSTOM_IMAP_PORT=993
|
||||
# CUSTOM_SMTP_HOST=mail.yourdomain.com
|
||||
# CUSTOM_SMTP_PORT=587
|
||||
|
||||
PORT=3456
|
||||
```
|
||||
|
||||
> **Tip:** Use the server's direct IP for `FETCHERPAY_IMAP_HOST` / `FETCHERPAY_SMTP_HOST` to avoid DNS resolution issues in Kubernetes.
|
||||
|
||||
---
|
||||
|
||||
## Connecting to Claude.ai
|
||||
@@ -107,9 +105,9 @@ Claude.ai ──POST /mcp──► StreamableHTTPServerTransport
|
||||
imapflow (IMAP) nodemailer (SMTP)
|
||||
│ │
|
||||
┌────────▼───┐ ┌───────▼───────┐
|
||||
│ Yahoo Mail │ │ Self-hosted │
|
||||
│ imap.mail │ │ Dovecot / │
|
||||
│ .yahoo.com │ │ Poste.io │
|
||||
│ Yahoo Mail │ │ Custom IMAP/ │
|
||||
│ │ │ SMTP Server │
|
||||
│ │ │ (optional) │
|
||||
└────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "hermes-mcp",
|
||||
"version": "1.0.0",
|
||||
"description": "Yahoo Mail MCP server for Claude AI",
|
||||
"description": "Multi-account email MCP server for Claude AI",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user