Skip to content

feat: capability-scope permission model + install-docs restructure - #200

Closed
lucagattoni wants to merge 6 commits into
Wh1isper:mainfrom
lucagattoni:20260713_1504-permission-scopes-and-docs
Closed

feat: capability-scope permission model + install-docs restructure#200
lucagattoni wants to merge 6 commits into
Wh1isper:mainfrom
lucagattoni:20260713_1504-permission-scopes-and-docs

Conversation

@lucagattoni

Copy link
Copy Markdown
Contributor

What this delivers

A capability-scope permission model (read-only by default) plus a restructured installation guide, rebased cleanly onto current main (post-#199).

1. Capability-scope permission model (read-only default)

Every MCP tool is gated behind a capability scope, set via permissions in the config or MCP_EMAIL_SERVER_PERMISSIONS. A fresh install is read-only — it can list/read mail but cannot modify, delete, or send until scopes are granted. Out-of-scope tools are hidden from the tool list and rejected at call time.

Scope Grants
read Always granted: list/read mail, mailboxes, attachments
draft save_to_mailbox (drafts-type folders unless organize also granted)
organize move_emails, archive_emails, mark_emails_as_read
delete delete_emails
send send_email
manage add_email_account
full Everything

Upgrading from a pre-scopes version? Set permissions = ["full"] to restore prior behavior.

2. Docs restructure → docs/installation.md

README's long config reference moved into a dedicated Installation & Configuration guide (uv/pip/Docker/Claude Code install, Updating, env vars, credential storage, HTTP transport security, attachment downloads, allowlists). README keeps a quickstart + the new Permissions section + a pointer.

3. Chore

Ignore .DS_Store everywhere.

Reconciliation notes (why this isn't a plain cherry-pick)

This work was authored before #194/#199 landed, so integrating onto current main required resolving real semantic conflicts — surfaced honestly here:

Test plan

  • uv run pytest -q558 passed
  • uv run ruff check / ruff format --check — clean
  • prettier --check README.md docs/installation.md — clean
  • Verified every env var from the old README is still documented; no config content lost

Opened as draft — the reconciliation decisions above (esp. save_to_mailbox gating) warrant a review before marking ready.

🤖 Generated with Claude Code

https://claude.ai/code/session_013pd8meRq4jSiqaLq715nSD

lucagattoni and others added 6 commits July 13, 2026 15:14
Gate every MCP tool behind a capability scope (read, draft, organize,
delete, send, manage, full) configured via `permissions` in the TOML or
MCP_EMAIL_SERVER_PERMISSIONS (env override held in a PrivateAttr so
store() never persists a temporary grant). The server is now read-only
by default — a breaking change; `permissions = ["full"]` restores the
old behavior.

Enforcement is two-layer: visible_if predicates hide out-of-scope tools
from list_tools(), and every scoped tool re-checks at call time.
Closes two mutation leaks the tool list alone wouldn't catch:
get_emails_content's mark_as_read parameter now requires the organize
scope, and with only the draft scope save_to_mailbox may target only
drafts-type folders (organize lifts the restriction).

Also relocate the README's installation/configuration detail into a
dedicated docs/installation.md (added to the mkdocs nav) with the
scope documentation, leaving the README a quick start plus pointers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHu48yxodNvMb8vsuU5NSu
- Lead installation with uv (uv tool install / uvx) instead of pip; keep
  pip as an alternative.
- Add a Claude Code (CLI) section using `claude mcp add ... --scope user
  -- mcp-email-server stdio`, with uvx and env-var variants.
- Add an Updating section covering uv/uvx/pip/Docker/Claude Code.
- README: add the Claude Code one-liner and point to the fuller guide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHu48yxodNvMb8vsuU5NSu
The permission-scopes section listed the scopes and the two mechanisms
but didn't show how to actually apply or change them in a real setup.
Add a "Setting and changing scopes" subsection: config-file vs env-var
(with precedence), concrete per-client instructions (Claude Code CLI
add/remove-re-add, JSON mcpServers env block, Docker), the empty-string
reset, and an "after you change scopes" note (restart the client; verify
via which tools appear).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHu48yxodNvMb8vsuU5NSu
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013pd8meRq4jSiqaLq715nSD
…oupling

The permission model predated Wh1isper#194 (save_to_mailbox decoupled from SMTP).
save_to_mailbox is now gated on the draft scope alone — a pure IMAP APPEND
that stays available without a send-capable account. Update the test that
asserted the old SMTP-gated behavior.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013pd8meRq4jSiqaLq715nSD
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@lucagattoni
lucagattoni marked this pull request as ready for review July 13, 2026 14:26
@lucagattoni
lucagattoni marked this pull request as draft July 13, 2026 14:28
@lucagattoni
lucagattoni marked this pull request as ready for review July 13, 2026 14:29
@lucagattoni

Copy link
Copy Markdown
Contributor Author

Superseded by #209, which rebases this feature cleanly onto current main (post-#204 tooling and #205 docs reorganization) and harmonizes the docs into the new multi-file docs/ structure. Closing in favor of that PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant