feat: configurable exposure policy for direct, indirect and disabled tools

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
This commit is contained in:
2026-09-26 03:04:14 +02:00
co-authored by Claude Opus 5.5
parent 7f136f6f4c
commit 2f8a9f0c61
11 changed files with 362 additions and 26 deletions
+16 -2
View File
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace LIT\MCP\Guides;
use LIT\MCP\Abilities\ExposurePolicy;
use LIT\MCP\Integrations\Integration;
use LIT\MCP\Integrations\IntegrationRegistry;
@@ -16,9 +17,15 @@ final class InstructionsBuilder
/** @var (callable(): list<string>)|null */
private $postTypeNames;
public function __construct(private IntegrationRegistry $registry, ?callable $postTypeNames = null)
{
private ExposurePolicy $policy;
public function __construct(
private IntegrationRegistry $registry,
?callable $postTypeNames = null,
?ExposurePolicy $policy = null
) {
$this->postTypeNames = $postTypeNames;
$this->policy = $policy ?? new ExposurePolicy();
}
public function build(): string
@@ -28,9 +35,16 @@ final class InstructionsBuilder
$this->registry->available()
));
$directNames = array_map(
static fn (string $name): string => 'lit-' . substr($name, strlen('lit/')),
$this->policy->directNames($this->registry->abilities())
);
$lines = [
'LIT MCP pflegt diese WordPress-Website (Inhalte, Medien, Divi 5, Pods).',
'Aktive Integrationen: ' . $active . '.',
'Direkt aufrufbare Tools: ' . implode(', ', $directNames) . '.',
'Weitere Fähigkeiten über mcp-adapter-execute-ability (Ability-Name lit/<name>).',
];
if ($this->postTypeNames !== null) {