Skip to content

Commit 80f3d21

Browse files
committed
Add support for adding and removing tools dynamically
1 parent 94a945d commit 80f3d21

File tree

6 files changed

+943
-2
lines changed

6 files changed

+943
-2
lines changed

README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,121 @@ class LaravelFactoriesToolkit implements Toolkit
129129

130130
***
131131

132+
## Dynamic Tool Management
133+
134+
Laravel Loop supports dynamic tool management, allowing you to add or remove MCP tools at runtime from anywhere in your Laravel application. This enables powerful features like:
135+
136+
- Enabling/disabling tools based on user roles or permissions
137+
- Managing tools through administrative interfaces
138+
- Dynamically adjusting available functionality based on application state
139+
- Providing temporary access to tools for maintenance or debugging
140+
141+
### API Reference
142+
143+
#### Adding Tools Dynamically
144+
145+
```php
146+
// Add a tool at runtime
147+
Loop::addTool(new MyCustomTool());
148+
149+
// Add multiple tools with method chaining
150+
Loop::addTool(new ToolOne())
151+
->addTool(new ToolTwo())
152+
->addTool(new ToolThree());
153+
```
154+
155+
#### Removing Tools Dynamically
156+
157+
```php
158+
// Remove a tool by name
159+
Loop::removeTool('my-custom-tool');
160+
161+
// Remove multiple tools with method chaining
162+
Loop::removeTool('tool-one')
163+
->removeTool('tool-two')
164+
->removeTool('tool-three');
165+
```
166+
167+
#### Clearing All Tools
168+
169+
```php
170+
// Remove all registered tools and toolkits
171+
Loop::clear();
172+
```
173+
174+
### Common Use Cases
175+
176+
#### Feature Toggle via HTTP Controller
177+
178+
```php
179+
// User enables integration in web UI
180+
public function enableStripeIntegration(Request $request)
181+
{
182+
// Validate user permissions
183+
$this->authorize('manage-integrations');
184+
185+
// Add Stripe tools dynamically
186+
Loop::addTool(StripeTool::make());
187+
188+
// Update user settings
189+
auth()->user()->update(['stripe_enabled' => true]);
190+
191+
return response()->json(['message' => 'Stripe integration enabled']);
192+
}
193+
```
194+
195+
#### Administrative Tool Management
196+
197+
```php
198+
// Artisan command for bulk tool management
199+
public function handle()
200+
{
201+
if ($this->option('disable-maintenance-tools')) {
202+
Loop::removeTool('database-debug')
203+
->removeTool('cache-inspector')
204+
->removeTool('log-viewer');
205+
206+
$this->info('Maintenance tools disabled');
207+
}
208+
}
209+
```
210+
211+
#### Permission-Based Tool Access
212+
213+
```php
214+
// Middleware that adjusts available tools based on user role
215+
public function handle($request, Closure $next)
216+
{
217+
if (auth()->user()->isAdmin()) {
218+
Loop::addTool(CustomTool::make('admin-debug', 'Administrative debugging tool'))
219+
->addTool(CustomTool::make('system-monitor', 'System monitoring tool'));
220+
}
221+
222+
return $next($request);
223+
}
224+
```
225+
226+
#### Conditional Tool Loading
227+
228+
```php
229+
// In a service provider or middleware
230+
public function boot()
231+
{
232+
// Add tools based on environment
233+
if (app()->environment('local', 'staging')) {
234+
Loop::addTool(CustomTool::make('debug-tool', 'Debug information tool'))
235+
->addTool(CustomTool::make('test-data-generator', 'Generate test data'));
236+
}
237+
238+
// Add tools based on feature flags
239+
if (Feature::active('advanced-analytics')) {
240+
Loop::addTool(CustomTool::make('analytics-tool', 'Advanced analytics tool'));
241+
}
242+
}
243+
```
244+
245+
***
246+
132247
## Connecting to the MCP server
133248

134249
For this to be really useful, you need to connect your MCP client (Claude Code, Claude Desktop, Cursor, Windsurf, etc) to the Laravel LoopMCP server.

src/Loop.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,36 @@ public function context(string $context): static
2222
return $this;
2323
}
2424

25+
/**
26+
* Add a tool dynamically to the registry
27+
*/
28+
public function addTool(Tool $tool): static
29+
{
30+
$this->loopTools->addTool($tool);
31+
32+
return $this;
33+
}
34+
35+
/**
36+
* Remove a tool dynamically from the registry
37+
*/
38+
public function removeTool(string $name): static
39+
{
40+
$this->loopTools->removeTool($name);
41+
42+
return $this;
43+
}
44+
45+
/**
46+
* Clear all registered tools and toolkits
47+
*/
48+
public function clear(): static
49+
{
50+
$this->loopTools->clear();
51+
52+
return $this;
53+
}
54+
2555
public function tool(Tool $tool): static
2656
{
2757
$this->loopTools->registerTool($tool);

src/LoopTools.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,48 @@ public function __construct()
1818
$this->tools = new ToolCollection;
1919
}
2020

21+
/**
22+
* Add a tool to the registry if not already present (prevents duplicates)
23+
*/
24+
public function addTool(Tool $tool): void
25+
{
26+
$toolName = $tool->getName();
27+
28+
if (! $this->tools->contains(function ($existingTool) use ($toolName) {
29+
return $existingTool->getName() === $toolName;
30+
})) {
31+
$this->tools->push($tool);
32+
}
33+
}
34+
35+
/**
36+
* Remove a tool by name and return success status
37+
*/
38+
public function removeTool(string $name): bool
39+
{
40+
$initialCount = $this->tools->count();
41+
42+
$this->tools = $this->tools->reject(function ($tool) use ($name) {
43+
return $tool->getName() === $name;
44+
});
45+
46+
return $initialCount > $this->tools->count();
47+
}
48+
49+
/**
50+
* Register a tool (alias for addTool)
51+
*/
2152
public function registerTool(Tool $tool): void
2253
{
23-
$this->tools->push($tool);
54+
$this->addTool($tool);
2455
}
2556

2657
public function registerToolkit(Toolkit $toolkit): void
2758
{
2859
$this->toolkits[] = $toolkit;
2960

3061
foreach ($toolkit->getTools() as $tool) {
31-
$this->registerTool($tool);
62+
$this->addTool($tool);
3263
}
3364
}
3465

0 commit comments

Comments
 (0)