Skip to content

feat: capability-scope permission model (read-only default) - #209

Draft
lucagattoni wants to merge 3 commits into
Wh1isper:mainfrom
lucagattoni:20260720_1808-permission-scopes-code
Draft

feat: capability-scope permission model (read-only default)#209
lucagattoni wants to merge 3 commits into
Wh1isper:mainfrom
lucagattoni:20260720_1808-permission-scopes-code

Conversation

@lucagattoni

Copy link
Copy Markdown
Contributor

What this delivers

A capability-scope permission model for the email tools, rebased cleanly onto current main and with docs harmonized into the new multi-file docs/ structure (post-#205).

This supersedes #200, which was branched a week ago and now conflicts with the docs reorganization (#205) and tooling changes (#204). Same feature, cleanly re-homed.

The feature

The server is read-only by default. Every mutating tool is gated behind a capability scope, set via the permissions config field or MCP_EMAIL_SERVER_PERMISSIONS. 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.

Rebase notes (adopts upstream's current shape)

  • Uses upstream's typed CredentialStorage and its refactored DEFAULT_CONFIG_PATH; adds only _VALID_PERMISSION_SCOPES and _permissions_override.
  • Docs distributed the idiomatic way: security.md gets the substantive Permission scopes section; configuration.md gets the setting + env-var rows; tools.md notes scope-gating in "Conditional tools"; getting-started.md gets a read-only note.
  • Fixed three now-stale passages the read-only default invalidated: getting-started verify step, the send_email is missing troubleshooting entry, and the guides.md "IMAP mutation tools always available" claim.

Test plan

Security hardening (the former #201) will follow as a separate rebased PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_013pd8meRq4jSiqaLq715nSD

lucagattoni and others added 2 commits July 20, 2026 18:11
…only)

Code-only slice of PR Wh1isper#200, rebased onto current main (post-docs-reorg Wh1isper#205).
Every MCP tool is gated behind a capability scope; a fresh install is read-only
until scopes are granted via the permissions config field or
MCP_EMAIL_SERVER_PERMISSIONS. Out-of-scope tools are hidden from list_tools and
rejected at call time.

Docs are intentionally omitted here — they need re-homing into the new
multi-file docs/ structure (configuration.md / security.md), handled separately.

Adopts upstream's typed CredentialStorage and DEFAULT_CONFIG_PATH; adds only
_VALID_PERMISSION_SCOPES and _permissions_override.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013pd8meRq4jSiqaLq715nSD
…#205 structure)

Homes the permission-scope documentation into upstream's multi-file docs:
- security.md: new 'Permission scopes' section (scope table, read-only posture,
  config + env examples)
- configuration.md: permissions setting + MCP_EMAIL_SERVER_PERMISSIONS env rows;
  note scope-gating on IMAP-only mutation tools
- tools.md: scope-gating note in 'Conditional tools'
- getting-started.md: read-only-by-default note + next-steps link
- troubleshooting.md / guides.md: correct now-stale 'send_email'/'IMAP mutation
  tools always available' claims for the read-only default

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

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.7%. Comparing base (81dd623) to head (b561faa).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##            main    #209     +/-   ##
=======================================
+ Coverage   92.5%   92.7%   +0.1%     
=======================================
  Files         10      10             
  Lines       2013    2059     +46     
  Branches     310     316      +6     
=======================================
+ Hits        1863    1909     +46     
  Misses       107     107             
  Partials      43      43             

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The permission model makes the server read-only by default, so the mutating
tools (send_email, save_to_mailbox, move/archive/delete/mark) are hidden unless
scoped. The GreenMail E2E exercises the full tool surface, so it must opt in:
set MCP_EMAIL_SERVER_PERMISSIONS=full for the spawned stdio server.

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

Wh1isper commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Update after deeper review: my original conclusion in this comment was incorrect. Current main still lacks the specified deny-by-default mutation-class authorization, and an empty recipient policy is currently treated as unrestricted despite the accepted spec and documentation requiring it to disable send/append.

PR #209 has therefore been reopened for rework. The existing implementation still needs redesign for the post-#212 architecture; full requirements are in the follow-up comment: #209 (comment)

Thank you again for raising the authorization concern.

@Wh1isper Wh1isper closed this Jul 25, 2026
@Wh1isper Wh1isper reopened this Jul 25, 2026
@Wh1isper

Copy link
Copy Markdown
Owner

Correction after a deeper review of current main: the underlying authorization problem is not fully resolved, so I am reopening this PR and asking for a rework rather than leaving it closed.

Two gaps remain in the post-#212 implementation:

  • the accepted policy model specifies deny-by-default allowed mutation classes, but the managed catalog, ManagedPolicy, MutationAccountSnapshot, and mutation services currently carry no such authorization;
  • an empty allowed-recipient collection is specified and documented to disable send_email and save_to_mailbox, but the current application check treats it as unrestricted.

The existing branch still cannot be rebased as-is: its dynamic tool visibility, global Settings checks, and manage/add_email_account scope conflict with the accepted architecture. Please rework it on current main so that:

  • the MCP catalog remains static;
  • account and credential management remains outside MCP;
  • allowed mutation classes are persisted in managed policy and checked in the application layer using fresh authority before each independent provider effect;
  • empty recipients fail closed for send/append, with compatible migration behavior considered explicitly;
  • the exact catalog, application/adapter tests, managed persistence tests, docs, specs, and GreenMail coverage are updated.

Thank you again for raising this area. Your original scope model needs redesign, but the security concern itself remains valid and should stay open for rework.

@Wh1isper
Wh1isper marked this pull request as draft August 28, 2026 05:46
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.

2 participants