Skip to content
Open
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
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,25 @@ concurrency:

jobs:
ci:
uses: codefuturist/shared-workflows/.github/workflows/ci-node.yml@v1
uses: codefuturist/shared-workflows/.github/workflows/ci-node.yml@b2d5cf9922522d574e8ee1116b6de1e6b7ade6d7 # v1
with:
node-version: "24"
run-integration: true
integration-artifact-pattern: "reports/integration-*"
docker-smoke-test: true
docker-image: "codefuturist/email-mcp:ci"

audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm audit --audit-level=high
15 changes: 10 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
npm:
name: Publish to npm
if: ${{ !inputs.skip-npm }}
uses: codefuturist/shared-workflows/.github/workflows/release-npm.yml@v1
uses: codefuturist/shared-workflows/.github/workflows/release-npm.yml@b2d5cf9922522d574e8ee1116b6de1e6b7ade6d7 # v1
permissions:
contents: read
id-token: write
Expand Down Expand Up @@ -50,9 +50,14 @@ jobs:
ARCH="${ARCH/aarch64/arm64}"
BASE="https://github.com/modelcontextprotocol"
BASE="${BASE}/registry/releases/latest/download"
curl -L \
"${BASE}/mcp-publisher_${OS}_${ARCH}.tar.gz" \
| tar xz mcp-publisher
ARCHIVE="mcp-publisher_${OS}_${ARCH}.tar.gz"
curl -L -o "${ARCHIVE}" "${BASE}/${ARCHIVE}"
curl -L -o checksums.txt "${BASE}/checksums.txt"
# Verify checksum before extracting
grep "${ARCHIVE}" checksums.txt | sha256sum -c --status \
|| { echo "ERROR: Checksum verification failed for ${ARCHIVE}"; exit 1; }
tar xzf "${ARCHIVE}" mcp-publisher
rm -f "${ARCHIVE}" checksums.txt

- name: Set version in server.json
run: |
Expand Down Expand Up @@ -87,7 +92,7 @@ jobs:
fetch-depth: 0

- name: Docker setup
uses: codefuturist/shared-workflows/actions/docker-setup@v1
uses: codefuturist/shared-workflows/actions/docker-setup@b2d5cf9922522d574e8ee1116b6de1e6b7ade6d7 # v1
with:
ghcr-username: ${{ github.actor }}
ghcr-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
116 changes: 116 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: Test & Sanity Check

on:
push:
branches: ["**"]
pull_request:
workflow_dispatch:

concurrency:
group: test-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: pnpm/action-setup@v4
with:
version: 9

- uses: actions/setup-node@v4
with:
node-version: "24"
cache: pnpm

- run: pnpm install --frozen-lockfile

- name: Typecheck
run: pnpm typecheck

- name: Lint (Biome + ESLint)
run: pnpm check

- name: Unit tests
run: pnpm test

- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: reports/
retention-days: 14

sanity:
name: Sanity Check
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: pnpm/action-setup@v4
with:
version: 9

- uses: actions/setup-node@v4
with:
node-version: "24"
cache: pnpm

- run: pnpm install --frozen-lockfile
- run: pnpm build

- name: Verify built artifacts exist
run: |
test -f dist/main.js || { echo "FAIL: dist/main.js missing"; exit 1; }
echo "✓ dist/main.js exists ($(wc -c < dist/main.js) bytes)"

- name: Server starts and responds to --version
run: |
VERSION=$(node dist/main.js --version)
echo "✓ email-mcp version: ${VERSION}"
[[ -n "$VERSION" ]] || { echo "FAIL: empty version"; exit 1; }

- name: Server exits cleanly on --help
run: |
node dist/main.js help | head -5
echo "✓ help output OK"

- name: Config init generates valid TOML
run: |
node -e "
import('./dist/config/loader.js').then(m => {
const tpl = m.generateTemplate();
if (!tpl.includes('[accounts]')) {
console.error('FAIL: template missing [accounts]');
process.exit(1);
}
console.log('✓ config template is valid (' + tpl.length + ' chars)');
});
"

- name: Tool registration smoke test
run: |
node -e "
import('./dist/server.js').then(({ default: createServer }) => {
const server = createServer();
if (!server) {
console.error('FAIL: createServer() returned falsy');
process.exit(1);
}
console.log('✓ MCP server instance created');
});
"

- name: Docker build
run: docker build -t email-mcp:sanity .

- name: Docker --version
run: |
VERSION=$(docker run --rm email-mcp:sanity --version)
echo "✓ Docker image version: ${VERSION}"
[[ -n "$VERSION" ]] || { echo "FAIL: empty version from Docker"; exit 1; }
42 changes: 42 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# email-mcp — Claude Code Context

## Project Overview
Email MCP server (IMAP + SMTP) with 47+ tools, IMAP IDLE push, multi-account, AI triage.
Forked from `codefuturist/email-mcp` into `Swagatar-LLC/email-mcp` for security hardening.

## Tech Stack
- **Language:** TypeScript (strict mode)
- **Runtime:** Node.js 24+ (works on 22)
- **Package Manager:** pnpm 9.15.0
- **Build:** tsc (tsconfig.build.json)
- **Test:** Vitest (unit + integration with testcontainers)
- **Lint:** Biome + ESLint (airbnb-extended)
- **Hooks:** Lefthook (pre-commit, commit-msg, pre-push)
- **CI:** GitHub Actions (shared workflows from codefuturist org)
- **Docker:** Multi-stage build, non-root user

## Key Commands
```bash
pnpm test # Unit tests (vitest)
pnpm typecheck # TypeScript type checking
pnpm check # Biome + ESLint
pnpm lint # ESLint only
pnpm format # Biome format
pnpm build # TypeScript build
```

## Architecture
- `src/tools/` — MCP tool definitions (one file per tool group)
- `src/services/` — Business logic (IMAP, SMTP, OAuth, hooks, watcher, etc.)
- `src/safety/` — Audit logging, rate limiting, input validation
- `src/config/` — TOML config loading, Zod schemas, XDG paths
- `src/connections/` — IMAP/SMTP connection pooling
- `src/prompts/` — MCP prompt definitions
- `src/resources/` — MCP resource definitions

## Conventions
- Conventional commits (enforced by cog/lefthook)
- ESLint airbnb-extended + Biome formatting
- All tool inputs validated with Zod schemas
- Write tools gated behind `readOnly` config flag
- Audit logging for all write operations
Loading