agentleFS
tecnologicachiletecnologicachile/mail-mcp/AGENTS.md

mail-mcp

AGENTS.md112 starsChanged 18 days agoMITView on GitHub

Guidance for coding agents working in mail-mcp. No repository-specific Cursor or Copilot instruction files were found: If these are added later, treat them as higher-priority local policy and merge them into this file. Run commands from repo root. Use a test name substring: Run a single test and show stdout: Run tests in one module/file scope: Before finalizing changes, run: Do not skip clippy or tests for code changes. The repository includes a minimal multi-stage Dockerfile for running the MCP…

  • Reads credentials
  • Installs packages

We split this AGENTS.md into the rules it gives an agent

51 rules. About 1 is common, 32 are distinctive, and 18 are very specific to this project.

  • ≈1

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈32

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 18

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    No repository-specific Cursor or Copilot instruction files were found:

    line 16
  2. Distinctive:

    If these are added later, treat them as higher-priority local policy and merge them into this file.

    line 22
  3. Distinctive:

    Run commands from repo root.

    line 26
  4. Very specific:

    Run all tests: cargo test

    line 44
  5. Distinctive:

    Use a test name substring:

    line 50
  6. Distinctive:

    Run a single test and show stdout:

    line 55
  7. Distinctive:

    Run tests in one module/file scope:

    line 60
  8. Distinctive:

    Before finalizing changes, run:

    line 68
  9. Distinctive:

    Do not skip clippy or tests for code changes.

    line 74
  10. Very specific:

    Run over stdio: docker run --rm -i --env-file .env mail-mcp

    line 83
  11. Very specific:

    Keep MCP transport as stdio by default.

    line 87
  12. Very specific:

    Keep runtime image minimal (current pattern: builder image + scratch).

    line 88
  13. Distinctive:

    If dependencies require a non-scratch runtime, document why in the PR/commit message.

    line 89
  14. Very specific:

    Keep .dockerignore aligned with repo layout to avoid leaking local files and reduce context size.

    line 90
  15. Very specific:

    Do not change package scope (@bradsjm) unless explicitly requested.

    line 112
  16. Very specific:

    Prefer CI-driven publishing via git tags (v*.*.*).

    line 113
  17. Distinctive:

    Prefer npm trusted publishing (GitHub OIDC + provenance) over token-based npm publish.

    line 114
  18. Distinctive:

    Keep installer generation managed by dist config.

    line 130
  19. Very specific:

    Keep Linux x64 target as x86_64-unknown-linux-gnu unless explicitly requested otherwise.

    line 131
  20. Distinctive:

    Keep package versions, dist artifacts, and release tags aligned.

    line 142
  21. Distinctive:

    If release automation changes, update README.md install commands and this file together.

    line 143
  22. Distinctive:

    Keep imports explicit; avoid wildcard imports.

    line 166
  23. Distinctive:

    Remove unused imports rather than allowing warnings.

    line 167
  24. Distinctive:

    Use rustfmt defaults; do not hand-format against rustfmt.

    line 171
  25. Distinctive:

    Keep line wrapping and chaining style consistent with existing files.

    line 172
  26. Distinctive:

    Prefer small helper functions over deeply nested expressions.

    line 173
  27. Distinctive:

    Prefer concrete types and explicit bounds over implicit conversions.

    line 177
  28. Very specific:

    Use AppResult<T> for fallible internal APIs.

    line 178
  29. Very specific:

    Use struct types in models.rs for tool input/output contracts.

    line 179
  30. Very specific:

    Keep schema-annotated types (JsonSchema) aligned with runtime behavior.

    line 181
  31. Very specific:

    Use domain names that match IMAP/MCP vocabulary (uidvalidity, mailbox, cursor).

    line 188
  32. Distinctive:

    Avoid abbreviations unless they are protocol-standard.

    line 189
  33. Very specific:

    Never use unwrap() or expect() in production code paths.

    line 193
  34. Very specific:

    Prefer specific variants (InvalidInput, NotFound, Conflict, etc.) over Internal when possible.

    line 195
  35. Distinctive:

    Keep user-facing error messages precise and bounded.

    line 196
  36. Distinctive:

    Keep pagination and cursor invariants intact.

    line 204
  37. Distinctive:

    All network/IMAP operations should be timeout-bounded.

    line 208
  38. Distinctive:

    Keep async functions cancellation-safe and side effects clear.

    line 210
  39. Very specific:

    Never log or return secrets (*_PASS, tokens, auth headers).

    line 214
  40. Distinctive:

    Keep attachment extraction bounded and failure-tolerant.

    line 217
  41. Distinctive:

    Keep tool names stable unless a breaking change is explicitly intended.

    line 221
  42. Very specific:

    Keep summary concise and useful.

    line 223
  43. Very specific:

    Ensure meta.duration_ms and meta.now_utc remain populated.

    line 224
  44. Distinctive:

    Add unit tests for pure logic changes (parsing, validation, pagination, ids).

    line 228
  45. Distinctive:

    Prefer minimal, focused diffs.

    line 234
  46. Distinctive:

    Do not introduce compatibility shims unless requested.

    line 235
  47. Distinctive:

    Do not silently alter public tool contracts.

    line 236
  48. Distinctive:

    Update docs when behavior or bounds change.

    line 237
  49. Very specific:

    If adding env vars, document them in docs/tool-contract.md and this file.

    line 238
  50. Distinctive:

    Read and write failures are logged, never fatal.

    line 257
  51. Common:

    No secrets in code/log output

    line 268

≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

AGENTS.md

Guidance for coding agents working in mail-mcp.

Project Snapshot

  • Language: Rust (edition 2024)
  • Runtime: tokio
  • Protocol framework: rmcp
  • Domain: IMAP-backed MCP server over stdio
  • Entry point: src/main.rs
  • Main server implementation: src/server.rs

Cursor/Copilot Rules

No repository-specific Cursor or Copilot instruction files were found:

  • .cursorrules: not present
  • .cursor/rules/: not present
  • .github/copilot-instructions.md: not present

If these are added later, treat them as higher-priority local policy and merge them into this file.

Build, Lint, and Test Commands

Run commands from repo root.

Build

  • Debug build: cargo build
  • Release build: cargo build --release

Format

  • Check formatting: cargo fmt -- --check
  • Apply formatting: cargo fmt

Lint

  • Strict clippy (all targets): cargo clippy --all-targets -- -D warnings

Test

  • Run all tests: cargo test
  • List tests: cargo test -- --list
  • GreenMail integration smoke test: scripts/test-greenmail.sh

Run a Single Test

Use a test name substring:

  • cargo test parses_mailbox_with_colons
  • cargo test pagination::tests::evicts_to_max_entries

Run a single test and show stdout:

  • cargo test parses_mailbox_with_colons -- --exact --nocapture
  • cargo test greenmail_imap_smoke_test -- --exact --ignored --nocapture

Run tests in one module/file scope:

  • cargo test message_id::tests
  • cargo test mime::tests
  • cargo test pagination::tests

Suggested Local Validation Sequence

Before finalizing changes, run:

  1. cargo fmt -- --check
  2. cargo clippy --all-targets -- -D warnings
  3. cargo test

Do not skip clippy or tests for code changes.

Docker

The repository includes a minimal multi-stage Dockerfile for running the MCP server.

Build and Run

  • Build image: docker build -t mail-mcp .
  • Run over stdio: docker run --rm -i --env-file .env mail-mcp

Docker Notes for Agents

  • Keep MCP transport as stdio by default. An opt-in streamable HTTP transport exists (MAIL_MCP_TRANSPORT=http, see src/http.rs and docs/advanced-configuration.md); never make it the default or enable it implicitly in Docker.
  • Keep runtime image minimal (current pattern: builder image + scratch).
  • If dependencies require a non-scratch runtime, document why in the PR/commit message.
  • Keep .dockerignore aligned with repo layout to avoid leaking local files and reduce context size.
  • Docker publish workflow: .github/workflows/publish-docker.yml.
  • Docker publish trigger: manual only (workflow_dispatch); after tagging a release, run it against the tag (e.g. gh workflow run "Publish Docker Image" --ref vX.Y.Z).
  • Published image tags include latest, vX.Y.Z, and X.Y.Z on GHCR.

NPM / NPX Distribution

The project is distributed as an npm package published by cargo-dist.

Package and Publish Source

  • Package name: @bradsjm/mail-mcp
  • Dist config source: dist-workspace.toml (installers = ["npm"], publish-jobs = ["npm"])
  • Publish workflow: .github/workflows/release.yml

Runtime Behavior

  • End users run via npx @bradsjm/mail-mcp@latest.
  • The npm package is generated by cargo-dist during release and published from CI.

Publishing Rules for Agents

  • Do not change package scope (@bradsjm) unless explicitly requested.
  • Prefer CI-driven publishing via git tags (v*.*.*).
  • Prefer npm trusted publishing (GitHub OIDC + provenance) over token-based npm publish.

Release Assets (Curl Installer)

The repository publishes GitHub Release archives/installers via cargo-dist.

Release Workflow

  • Release workflow: .github/workflows/release.yml
  • Trigger: git tags matching v*.*.*
  • Dist generates archives/checksums/installers from dist-workspace.toml target and installer settings.

Installer Behavior and Guardrails

  • Shell/Powershell installers are generated by cargo-dist and uploaded to GitHub Releases.
  • install-updater = true: those installers also install mail-mcp-update (axoupdater). The updater artifacts come from dist build; no CI change was needed.
  • Keep installer generation managed by dist config; do not hand-maintain custom installer scripts.
  • Keep Linux x64 target as x86_64-unknown-linux-gnu unless explicitly requested otherwise.

Homebrew Tap

  • Formula is published to tecnologicachile/homebrew-tap (brew install tecnologicachile/tap/mail-mcp) by the publish-homebrew-formula job in release.yml.
  • That job is copied from what dist generate emits, except the tap checkout uses ssh-key: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }} (a write deploy key on the tap repo only) instead of a HOMEBREW_TAP_TOKEN PAT. Keep that change if the job is ever regenerated.
  • Formula desc and homepage come from Cargo.toml (description, homepage).

Tag Publish Flow

  • release.yml runs on v*.*.* tags; publish-docker.yml is manual (workflow_dispatch) and must be run against the tag afterwards.
  • Keep package versions, dist artifacts, and release tags aligned.
  • If release automation changes, update README.md install commands and this file together.

Architecture and File Ownership

  • src/main.rs: process bootstrap, env loading, tracing init, stdio serving.
  • src/config.rs: env-driven account/server config parsing.
  • src/errors.rs: app-level error model and MCP error mapping.
  • src/imap.rs: IMAP transport/session operations with timeout wrappers.
  • src/server.rs: MCP tool handlers, validation, business orchestration.
  • src/models.rs: input/output DTOs and schema-bearing types.
  • src/mime.rs: message parsing, header/body extraction, sanitization.
  • src/message_id.rs: stable message id parse/encode logic.
  • src/pagination.rs: cursor storage and TTL/eviction behavior.
  • src/server/drafts.rs: draft tools and their IMAP/EWS/Graph routing.

Code Style Guidelines

Imports

  • Group imports in this order:
    1. standard library (std::...)
    2. external crates
    3. internal crate imports (crate::...)
  • Keep imports explicit; avoid wildcard imports.
  • Remove unused imports rather than allowing warnings.

Formatting

  • Use rustfmt defaults; do not hand-format against rustfmt.
  • Keep line wrapping and chaining style consistent with existing files.
  • Prefer small helper functions over deeply nested expressions.

Types and Data Modeling

  • Prefer concrete types and explicit bounds over implicit conversions.
  • Use AppResult<T> for fallible internal APIs.
  • Use struct types in models.rs for tool input/output contracts.
  • Preserve serde defaults and validation bounds when extending inputs.
  • Keep schema-annotated types (JsonSchema) aligned with runtime behavior.

Naming

  • Types: UpperCamelCase.
  • Functions/methods: snake_case.
  • Constants: UPPER_SNAKE_CASE.
  • Use domain names that match IMAP/MCP vocabulary (uidvalidity, mailbox, cursor).
  • Avoid abbreviations unless they are protocol-standard.

Error Handling

  • Never use unwrap() or expect() in production code paths.
  • Convert external errors into AppError with actionable context.
  • Prefer specific variants (InvalidInput, NotFound, Conflict, etc.) over Internal when possible.
  • Keep user-facing error messages precise and bounded.
  • Preserve mapping from AppError to ErrorData in errors.rs.

Validation and Bounds

  • Validate all user input before IMAP operations.
  • Enforce existing numeric/string bounds (limit, chars, dates, bytes).
  • Reject conflicting parameter combinations explicitly.
  • Keep pagination and cursor invariants intact.

Async and Timeouts

  • All network/IMAP operations should be timeout-bounded.
  • Reuse server-configured timeout settings; do not hardcode new timeout values.
  • Keep async functions cancellation-safe and side effects clear.

Security and Privacy

  • Never log or return secrets (*_PASS, tokens, auth headers).
  • Preserve TLS-only behavior unless a deliberate security design change is requested.
  • Maintain HTML sanitization for message HTML (ammonia).
  • Keep attachment extraction bounded and failure-tolerant.

MCP Tool Behavior

  • Keep tool names stable unless a breaking change is explicitly intended.
  • Maintain ToolEnvelope shape (summary, data, meta).
  • Keep summary concise and useful.
  • Ensure meta.duration_ms and meta.now_utc remain populated.

Testing Expectations

  • Add unit tests for pure logic changes (parsing, validation, pagination, ids).
  • Extend existing test modules near changed code.
  • For bug fixes, add regression tests reproducing prior failure mode.

Change Discipline for Agents

  • Prefer minimal, focused diffs.
  • Do not introduce compatibility shims unless requested.
  • Do not silently alter public tool contracts.
  • Update docs when behavior or bounds change.
  • If adding env vars, document them in docs/tool-contract.md and this file.
  • MAIL_SMTP_<ID>_FROM_EMAIL: optional sender address override. When the SMTP auth username (_USER) differs from the desired From address (e.g. shared/group mailboxes where auth uses a personal account but the From should be the group address), set this to the group address. When unset, the From address defaults to _USER. Affects send, reply, and forward.
  • MAIL_IMAP_MAX_MAILBOXES: cap on how many mailboxes imap_list_mailboxes returns (default 200, clamped to 1..=10000). The response always carries total and truncated, so a client can tell a capped list from a complete one.
  • MAIL_DRAFTS_ENABLED: enables the draft_* tools (default false). Independent of MAIL_IMAP_WRITE_ENABLED by design: drafts-only must not grant move/delete/flag on other mail, so every draft operation on an existing draft_id checks the target is a draft (IMAP Drafts folder, EWS IsDraft, Graph isDraft). draft_send also requires MAIL_SMTP_WRITE_ENABLED. Backend per account: EWS config, else Graph config (MAIL_GRAPH_* only, never the generic MAIL_OAUTH2_*), else IMAP.
  • MAIL_OAUTH2_TOKEN_STORE: optional file where rotated OAuth2 refresh tokens are persisted (unset = in-memory rotation only). Entries carry a fingerprint of the env token they came from, so a changed env token wins. Read and write failures are logged, never fatal.
  • MAIL_IMAP_SEARCH_CONCURRENCY: parallel IMAP connections used by imap_search_all_mailboxes (default 4, clamped to 1..=8). Each connection walks its share of the mailboxes with EXAMINE + UID SEARCH; providers cap concurrent connections per account, so stay well below their limit.

Quick Pre-Commit Checklist

  • Code formatted
  • Clippy clean with warnings denied
  • Tests passing
  • No secrets in code/log output
  • Contract and validation invariants preserved

Download now (ZIP)

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 28,693 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository2 other files it gives its agents.

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.