diff --git a/.claude/settings.json b/.claude/settings.json index 00d5b4934..f11165a91 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -62,9 +62,6 @@ "Bash(uv run --project ~/.claude/magpie/vetted-ops vetted-op-read *)", "Bash(uvx --from ~/.claude/magpie/vetted-ops vetted-op-read *)", "mcp__claude_ai_Gmail__get_thread", - "mcp__claude_ai_Gmail__search_threads", - "mcp__gmail-plaintext__create_draft", - "mcp__ponymail__search_list", "mcp__ponymail__auth_status", "mcp__ponymail__get_thread", "mcp__ponymail__get_email", diff --git a/docs/setup/secure-agent-setup.md b/docs/setup/secure-agent-setup.md index b7902ff26..e8b3ee870 100644 --- a/docs/setup/secure-agent-setup.md +++ b/docs/setup/secure-agent-setup.md @@ -696,17 +696,17 @@ The full block below is the two merged, annotated. "Bash(uv run --project ~/.claude/magpie/vetted-ops vetted-op-read *)", "Bash(uvx --from ~/.claude/magpie/vetted-ops vetted-op-read *)", // same dispatcher, the form bulk gatherer agents use // Read-only MCP tools the security skills call on every sync / import / - // triage run. Without these, each archive or mailbox read prompts, and a - // bulk sync fans out into hundreds of prompts. Write tools stay off this - // list (drafts, logins, label/thread mutations keep their prompt), with - // one exception: gmail-plaintext `create_draft` only creates an unsent - // draft the operator reviews in Gmail. - "mcp__ponymail__search_list", "mcp__ponymail__get_thread", "mcp__ponymail__get_email", + // triage run. Without these, each read of a named thread or message + // prompts, and a bulk sync fans out into hundreds of prompts. Whole-mailbox + // and whole-list searches stay off this list, as do write tools (drafts, + // logins, label/thread mutations): these sessions read untrusted reports, + // so the operator sees those calls. + "mcp__ponymail__get_thread", "mcp__ponymail__get_email", "mcp__ponymail__get_source", "mcp__ponymail__list_lists", "mcp__ponymail__list_restrictions", "mcp__ponymail__auth_status", - "mcp__claude_ai_Gmail__search_threads", "mcp__claude_ai_Gmail__get_thread", - "mcp__claude_ai_Gmail__get_message", "mcp__claude_ai_Gmail__list_drafts", "mcp__claude_ai_Gmail__get_draft", - "mcp__gmail-plaintext__create_draft", "mcp__gmail-plaintext__check_auth", + "mcp__claude_ai_Gmail__get_thread", "mcp__claude_ai_Gmail__get_message", + "mcp__claude_ai_Gmail__list_drafts", "mcp__claude_ai_Gmail__get_draft", + "mcp__gmail-plaintext__check_auth", "mcp__apache-projects__get_committee", "mcp__apache-projects__get_group_members", "mcp__apache-projects__get_person", "mcp__apache-projects__search_people", "mcp__apache-projects__project_stats", "mcp__apache-projects__get_releases", diff --git a/plugins/magpie-security-tools/tools/permission-audit/src/permission_audit/audit.py b/plugins/magpie-security-tools/tools/permission-audit/src/permission_audit/audit.py index f34baa31e..b8452d892 100644 --- a/plugins/magpie-security-tools/tools/permission-audit/src/permission_audit/audit.py +++ b/plugins/magpie-security-tools/tools/permission-audit/src/permission_audit/audit.py @@ -97,7 +97,6 @@ "security": frozenset( { "mcp__claude_ai_Gmail__get_thread", - "mcp__claude_ai_Gmail__search_threads", "mcp__claude_ai_Gmail__list_drafts", "mcp__claude_ai_Gmail__list_labels", } @@ -112,7 +111,6 @@ "ASF": { "security": frozenset( { - "mcp__ponymail__search_list", "mcp__ponymail__auth_status", "mcp__ponymail__get_thread", "mcp__ponymail__get_email", diff --git a/plugins/magpie-setup/skills/setup/family-mcp-allows.json b/plugins/magpie-setup/skills/setup/family-mcp-allows.json index 5996bed13..38b73fa26 100644 --- a/plugins/magpie-setup/skills/setup/family-mcp-allows.json +++ b/plugins/magpie-setup/skills/setup/family-mcp-allows.json @@ -4,8 +4,10 @@ "instead of granted to everyone. setup adopt/upgrade write the allows for the families in", ".apache-magpie.lock into the committed .claude/settings.json (a derived key, like", "enabledPlugins); reconciliation adds the allows for families installed only on one machine", - "to .claude/settings.local.json. List read-only or draft-only tools only: a tool that sends,", - "posts or deletes stays behind the harness prompt and never belongs here.", + "to .claude/settings.local.json. List tools that read one named item or report state only:", + "a tool that sends, posts or deletes, creates a draft, or searches a whole mailbox or list", + "stays behind the harness prompt and never belongs here, because these sessions read", + "untrusted content and the operator should see those calls.", "The claude_ai_Gmail entries are reads; drafting goes through gmail-plaintext, which writes", "plain text with no tracking links." ], @@ -32,7 +34,6 @@ ], "tools": [ "get_thread", - "search_threads", "get_message", "list_drafts", "get_draft" @@ -44,7 +45,6 @@ "security" ], "tools": [ - "create_draft", "check_auth" ] }, @@ -55,7 +55,6 @@ "security" ], "tools": [ - "search_list", "auth_status", "get_thread", "get_email", diff --git a/plugins/magpie-setup/skills/setup/install.md b/plugins/magpie-setup/skills/setup/install.md index 7750c272b..f5bc0e4e3 100644 --- a/plugins/magpie-setup/skills/setup/install.md +++ b/plugins/magpie-setup/skills/setup/install.md @@ -1746,10 +1746,10 @@ Same hands-off contract as 9c — **surface, do not run**: is then usable by **any** agent session on the machine, Magpie-related or not (see [`tools/gmail/oauth-draft/README.md` → MCP server](../../../../tools/gmail/oauth-draft/README.md#mcp-server)). 3. **Reflect the outcome** in the recommended permission allow-list - (add `mcp__gmail-plaintext__create_draft` alongside the Gmail read - tools — see [`verify.md`](verify.md) check 8d). It only ever creates - **unsent** drafts the human reviews and sends, so allow-listing it - avoids a prompt on every draft. + (add `mcp__gmail-plaintext__check_auth` alongside the Gmail read + tools — see [`verify.md`](verify.md) check 8d). Leave + `mcp__gmail-plaintext__create_draft` off it: each draft keeps its + harness prompt, so the operator sees it being created. 4. **Tell the operator what to do next**, as a numbered list: 1. Run the `claude mcp add gmail-plaintext …` command above. 2. Restart the agent, so the `mcp__gmail-plaintext__*` tools load. diff --git a/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py b/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py index ea85e8520..0ecdbbb67 100644 --- a/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py +++ b/plugins/magpie-setup/skills/setup/setup_preflight/isolated_fingerprint.py @@ -21,4 +21,4 @@ for installs that do not carry the framework source (see `isolated.py`). """ -FRAMEWORK_FINGERPRINT = "sha256:362e4711c8e0274f" +FRAMEWORK_FINGERPRINT = "sha256:3814a0293e38b051" diff --git a/plugins/magpie-setup/skills/setup/verify.md b/plugins/magpie-setup/skills/setup/verify.md index e245daf87..4c85735c4 100644 --- a/plugins/magpie-setup/skills/setup/verify.md +++ b/plugins/magpie-setup/skills/setup/verify.md @@ -677,12 +677,9 @@ adopter opted into via - **`security` family** — - `mcp__claude_ai_Gmail__get_thread` - - `mcp__claude_ai_Gmail__search_threads` - `mcp__claude_ai_Gmail__list_drafts` - `mcp__claude_ai_Gmail__list_labels` - - `mcp__gmail-plaintext__create_draft` - and, only when `project.md` declares `organization: ASF` (they are ASF services): - - `mcp__ponymail__search_list` - `mcp__ponymail__auth_status` - `mcp__ponymail__get_thread` - `mcp__ponymail__get_email` diff --git a/tools/permission-audit/src/permission_audit/audit.py b/tools/permission-audit/src/permission_audit/audit.py index f34baa31e..b8452d892 100644 --- a/tools/permission-audit/src/permission_audit/audit.py +++ b/tools/permission-audit/src/permission_audit/audit.py @@ -97,7 +97,6 @@ "security": frozenset( { "mcp__claude_ai_Gmail__get_thread", - "mcp__claude_ai_Gmail__search_threads", "mcp__claude_ai_Gmail__list_drafts", "mcp__claude_ai_Gmail__list_labels", } @@ -112,7 +111,6 @@ "ASF": { "security": frozenset( { - "mcp__ponymail__search_list", "mcp__ponymail__auth_status", "mcp__ponymail__get_thread", "mcp__ponymail__get_email", diff --git a/tools/permission-audit/tests/test_audit.py b/tools/permission-audit/tests/test_audit.py index fea201a6f..f02982d41 100644 --- a/tools/permission-audit/tests/test_audit.py +++ b/tools/permission-audit/tests/test_audit.py @@ -20,8 +20,8 @@ def test_empty_allow_only_misses_recommended(): result = audit_settings(allow_list=[], families=["security"]) assert result.forbidden == [] - # lychee (default family "") + 4 generic security entries = 5 - assert len(result.missing_recommended) == 5 + # lychee (default family "") + 3 generic security entries = 4 + assert len(result.missing_recommended) == 4 def test_forbidden_python_wildcard_flagged_with_pointer(): @@ -73,7 +73,7 @@ def test_default_family_always_included_even_when_not_requested(): def test_asf_only_recommendations_need_the_asf_organization(): """PonyMail, the ASF project directory and Vulnogram are ASF services.""" asf_only = { - "mcp__ponymail__search_list", + "mcp__ponymail__get_thread", "mcp__apache-projects__get_person", "Bash(vulnogram-api-record-fetch *)", } @@ -83,5 +83,5 @@ def test_asf_only_recommendations_need_the_asf_organization(): assert not asf_only & elsewhere assert not asf_only & independent assert asf_only <= asf - # lychee + 4 generic + 11 ASF security entries - assert len(asf) == 16 + # lychee + 3 generic + 10 ASF security entries + assert len(asf) == 14 diff --git a/tools/sandbox-lint/expected.json b/tools/sandbox-lint/expected.json index aa2926186..122733c72 100644 --- a/tools/sandbox-lint/expected.json +++ b/tools/sandbox-lint/expected.json @@ -98,9 +98,6 @@ "Bash(gh browse *)", "Bash(gh auth status)", "mcp__claude_ai_Gmail__get_thread", - "mcp__claude_ai_Gmail__search_threads", - "mcp__gmail-plaintext__create_draft", - "mcp__ponymail__search_list", "mcp__ponymail__auth_status", "mcp__ponymail__get_thread", "mcp__ponymail__get_email",