Integrations name their own admin group (Integration::label, registry
labels()); ToolsTab no longer hard-codes ids and explains why it re-applies
withGroups. AccessTab and LogTab share AdminPostAction (guard, redirect,
terminate seam). ExposurePolicy parses option keys in one place, has one
isRequired() check and a clear $groups docblock (null vs []).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
Tools tab shows one block per integration with a group mode (inherited by its
tools) and a read-only switch that disables all non-readonly abilities of the
group. ExposurePolicy resolves tool override > group override > tool default;
lit/guide keeps its default, direct-only tools fall back to direct under a
group "indirekt". Group entries live in lit_mcp_exposure under "@group:<id>"
and "@readonly:<id>"; the old flat format stays valid. The ability->group map
comes lazily from IntegrationRegistry (Divi is not loaded at plugins_loaded).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Introduces ExposurePolicy (option lit_mcp_exposure) deciding per ability
whether it is a direct MCP tool, only reachable via mcp-adapter's
execute-ability meta-tool, or disabled entirely (not registered with the
Abilities API at all). Ability::isDirect() remains the default when no
override applies. lit/guide can never be disabled or made indirect;
lit/media-preview and lit/media-download (image/embedded-resource results)
can never be made indirect, only direct or disabled.
AbilityRegistrar and ServerRegistrar take an optional ExposurePolicy and
use it to filter registered abilities / compute the direct tool list.
IntegrationRegistry::directAbilityNames() is removed (superseded by
ExposurePolicy::directNames()). InstructionsBuilder now also takes the
policy and lists the currently direct tools by name (lit-<name>), noting
the rest are reachable via mcp-adapter-execute-ability as lit/<name>.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7