Plugin Tool Registry
Contract for accumulating plugin MCP/CLI tool definitions registered via PluginRegistrar::tool().
Overview
App\Sdk\Tools\PluginToolRegistry stores runtime records for plugin tools exposed on the Signals API MCP server and/or the signals:api Artisan CLI.
Plugins declare tools in signals.yaml (tools[]) and wire them with PluginRegistrar::tool($name, $actionClass). The bridge namespaces each tool as plugin:{package}:{name} for CLI; MCP exposes a Claude-safe hyphenated form via McpToolSchema::sanitizeToolName() (e.g. plugin-acme-hello-acme-hello-echo). Invocation always runs as the acting user and checks the declared permission via Gate.
Public surface
| Method | Purpose |
|---|---|
register() |
Warehouse one ToolDefinition |
has() |
Check whether a package/name pair is registered |
get() |
Return the definition or throw |
getByNamespacedName() |
Resolve plugin:{package}:{name} |
all() |
Map of namespaced name → ToolDefinition |
forPackage() |
Definitions for one package |
flush() |
Clear all registrations (tests / reload) |
Accepted registration shape
$registry->register(new ToolDefinition(
package: 'acme/hello',
name: 'acme.hello.echo',
title: 'Echo Hello',
description: 'Echo a message',
action: \Acme\Hello\Actions\EchoTool::class,
args: [
['name' => 'message', 'type' => 'string', 'required' => false, 'description' => 'Optional message'],
],
permission: 'acme.hello.view',
readOnly: true,
destructive: false,
surfaces: ['mcp', 'cli'],
));
Identity is (package, name). Re-registering the same pair replaces the earlier definition.
Surfaces and bridging
PluginMcpToolBridgefilters Enabled plugins, keeps tools whosesurfacesincludemcp, and buildsPluginBridgedMcpToolinstances forSignalsApiServer::additionalTools().signals:api list --plugins/signals:api call plugin:…use the same registry via the bridge, gated on theclisurface andcli.access.
Worked example
$registry->has('signals/slots-demo', 'signals.slotsdemo.echo'); // true after plugin register()
$definition = $registry->getByNamespacedName('plugin:signals/slots-demo:signals.slotsdemo.echo');
app(PluginToolInvoker::class)->invoke($definition, ['message' => 'hi'], $user);