Skip to content

Commit 14b9841

Browse files
committed
fix: refactoring
1 parent 2f68e74 commit 14b9841

File tree

12 files changed

+551
-477
lines changed

12 files changed

+551
-477
lines changed

src/MCP/Bootstrap/BootMcpTools.php

Lines changed: 60 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
use Binaryk\LaravelRestify\Actions\Action;
66
use Binaryk\LaravelRestify\Getters\Getter;
7+
use Binaryk\LaravelRestify\MCP\Collections\ToolsCollection;
78
use Binaryk\LaravelRestify\MCP\Concerns\HasMcpTools;
9+
use Binaryk\LaravelRestify\MCP\Enums\OperationTypeEnum;
10+
use Binaryk\LaravelRestify\MCP\Enums\ToolsCategoryEnum;
811
use Binaryk\LaravelRestify\MCP\Requests\McpActionRequest;
912
use Binaryk\LaravelRestify\MCP\Requests\McpGetterRequest;
1013
use Binaryk\LaravelRestify\MCP\Tools\Operations\ActionTool;
@@ -18,6 +21,7 @@
1821
use Binaryk\LaravelRestify\Repositories\Repository;
1922
use Binaryk\LaravelRestify\Restify;
2023
use Illuminate\Support\Collection;
24+
use Illuminate\Support\Facades\App;
2125
use Illuminate\Support\Facades\Cache;
2226

2327
/**
@@ -44,6 +48,14 @@ public function boot(): array
4448
$mode = config('restify.mcp.mode', 'direct');
4549
$cacheKey = "restify.mcp.all_tools_metadata.{$mode}";
4650

51+
if (App::hasDebugModeEnabled()) {
52+
return collect()
53+
->merge($this->discoverCustomTools())
54+
->merge($this->discoverRepositoryTools())
55+
->values()
56+
->toArray();
57+
}
58+
4759
$tools = Cache::remember($cacheKey, 3600, function (): array {
4860
return collect()
4961
->merge($this->discoverCustomTools())
@@ -71,13 +83,13 @@ protected function discoverCustomTools(): Collection
7183
if (class_exists($fqdn) && ! in_array($fqdn, $excludedTools, true)) {
7284
$instance = app($fqdn);
7385
$tools->push([
74-
'type' => 'custom',
86+
'type' => OperationTypeEnum::custom,
7587
'name' => $instance->name(),
7688
'title' => $instance->title(),
7789
'description' => $instance->description(),
7890
'class' => $fqdn,
7991
'instance' => $instance,
80-
'category' => 'Custom Tools',
92+
'category' => ToolsCategoryEnum::CUSTOM_TOOLS->value,
8193
]);
8294
}
8395
}
@@ -93,13 +105,13 @@ protected function discoverCustomTools(): Collection
93105
if (class_exists($fqdn) && ! in_array($fqdn, $excludedTools, true)) {
94106
$instance = app($fqdn);
95107
$tools->push([
96-
'type' => 'wrapper',
108+
'type' => OperationTypeEnum::wrapper,
97109
'name' => $instance->name(),
98110
'title' => $instance->title(),
99111
'description' => $instance->description(),
100112
'class' => $fqdn,
101113
'instance' => $instance,
102-
'category' => 'Wrapper Tools',
114+
'category' => ToolsCategoryEnum::WRAPPER_TOOLS->value,
103115
]);
104116
}
105117
}
@@ -116,13 +128,13 @@ protected function discoverCustomTools(): Collection
116128
if (class_exists($fqdn) && ! in_array($fqdn, $excludedTools, true)) {
117129
$instance = app($fqdn);
118130
$tools->push([
119-
'type' => 'custom',
131+
'type' => OperationTypeEnum::custom,
120132
'name' => $instance->name(),
121133
'title' => $instance->title(),
122134
'description' => $instance->description(),
123135
'class' => $fqdn,
124136
'instance' => $instance,
125-
'category' => 'Custom Tools',
137+
'category' => ToolsCategoryEnum::CUSTOM_TOOLS->value,
126138
]);
127139
}
128140
}
@@ -135,13 +147,13 @@ protected function discoverCustomTools(): Collection
135147
if (class_exists($toolClass)) {
136148
$instance = app($toolClass);
137149
$tools->push([
138-
'type' => 'custom',
150+
'type' => OperationTypeEnum::custom,
139151
'name' => $instance->name(),
140152
'title' => $instance->title(),
141153
'description' => $instance->description(),
142154
'class' => $toolClass,
143155
'instance' => $instance,
144-
'category' => 'Custom Tools',
156+
'category' => ToolsCategoryEnum::CUSTOM_TOOLS->value,
145157
]);
146158
}
147159
}
@@ -155,146 +167,93 @@ protected function discoverCustomTools(): Collection
155167
protected function discoverRepositoryTools(): Collection
156168
{
157169
return collect(Restify::$repositories)
158-
->filter(fn (string $repo): bool => in_array(HasMcpTools::class, class_uses_recursive($repo)))
159-
->flatMap(fn (string $repoClass): Collection => $this->discoverRepositoryOperations($repoClass))
170+
->filter(fn(string $repo): bool => in_array(HasMcpTools::class, class_uses_recursive($repo)))
171+
->flatMap(fn(string $repoClass): Collection => $this->discoverRepositoryOperations($repoClass))
160172
->values();
161173
}
162174

163175
/**
164176
* Discover all operations (CRUD, actions, getters) for a specific repository.
165177
*/
166-
protected function discoverRepositoryOperations(string $repositoryClass): Collection
178+
protected function discoverRepositoryOperations(string $repositoryClass): ToolsCollection
167179
{
168180
$repository = app($repositoryClass);
169-
$tools = collect();
181+
$tools = ToolsCollection::make();
170182

171-
// Profile tool (only for users repository)
172183
if ($repository::uriKey() === 'users') {
173-
$instance = new ProfileTool($repositoryClass);
174-
$tools->push([
175-
'type' => 'profile',
176-
'name' => $instance->name(),
177-
'title' => $instance->title(),
178-
'description' => $instance->description(),
179-
'class' => ProfileTool::class,
180-
'instance' => $instance,
181-
'repository' => $repository::uriKey(),
182-
'category' => 'Profile',
183-
]);
184+
$tools->pushTool(
185+
new ProfileTool($repositoryClass),
186+
$repository::uriKey()
187+
);
184188
}
185189

186-
// Index operation
187190
if (method_exists($repository, 'mcpAllowsIndex') && $repository->mcpAllowsIndex()) {
188-
$instance = new IndexTool($repositoryClass);
189-
$tools->push([
190-
'type' => 'index',
191-
'name' => $instance->name(),
192-
'title' => $instance->title(),
193-
'description' => $instance->description(),
194-
'class' => IndexTool::class,
195-
'instance' => $instance,
196-
'repository' => $repository::uriKey(),
197-
'category' => 'CRUD Operations',
198-
]);
191+
$tools->pushTool(
192+
new IndexTool($repositoryClass),
193+
$repository::uriKey()
194+
);
199195
}
200196

201-
// Show operation
202197
if (method_exists($repository, 'mcpAllowsShow') && $repository->mcpAllowsShow()) {
203-
$instance = new ShowTool($repositoryClass);
204-
$tools->push([
205-
'type' => 'show',
206-
'name' => $instance->name(),
207-
'title' => $instance->title(),
208-
'description' => $instance->description(),
209-
'class' => ShowTool::class,
210-
'instance' => $instance,
211-
'repository' => $repository::uriKey(),
212-
'category' => 'CRUD Operations',
213-
]);
198+
$tools->pushTool(
199+
new ShowTool($repositoryClass),
200+
$repository::uriKey()
201+
);
214202
}
215203

216-
// Store operation
217204
if (method_exists($repository, 'mcpAllowsStore') && $repository->mcpAllowsStore()) {
218-
$instance = new StoreTool($repositoryClass);
219-
$tools->push([
220-
'type' => 'store',
221-
'name' => $instance->name(),
222-
'title' => $instance->title(),
223-
'description' => $instance->description(),
224-
'class' => StoreTool::class,
225-
'instance' => $instance,
226-
'repository' => $repository::uriKey(),
227-
'category' => 'CRUD Operations',
228-
]);
205+
$tools->pushTool(
206+
new StoreTool($repositoryClass),
207+
$repository::uriKey()
208+
);
229209
}
230210

231-
// Update operation
232211
if (method_exists($repository, 'mcpAllowsUpdate') && $repository->mcpAllowsUpdate()) {
233-
$instance = new UpdateTool($repositoryClass);
234-
$tools->push([
235-
'type' => 'update',
236-
'name' => $instance->name(),
237-
'title' => $instance->title(),
238-
'description' => $instance->description(),
239-
'class' => UpdateTool::class,
240-
'instance' => $instance,
241-
'repository' => $repository::uriKey(),
242-
'category' => 'CRUD Operations',
243-
]);
212+
$tools->pushTool(
213+
new UpdateTool($repositoryClass),
214+
$repository::uriKey()
215+
);
244216
}
245217

246-
// Delete operation
247218
if (method_exists($repository, 'mcpAllowsDelete') && $repository->mcpAllowsDelete()) {
248-
$instance = new DeleteTool($repositoryClass);
249-
$tools->push([
250-
'type' => 'delete',
251-
'name' => $instance->name(),
252-
'title' => $instance->title(),
253-
'description' => $instance->description(),
254-
'class' => DeleteTool::class,
255-
'instance' => $instance,
256-
'repository' => $repository::uriKey(),
257-
'category' => 'CRUD Operations',
258-
]);
219+
$tools->pushTool(
220+
new DeleteTool($repositoryClass),
221+
$repository::uriKey()
222+
);
259223
}
260224

261-
// Actions
262225
if (method_exists($repository, 'mcpAllowsActions') && $repository->mcpAllowsActions()) {
263226
$tools = $tools->merge($this->discoverActions($repositoryClass, $repository));
264227
}
265228

266-
// Getters
267229
if (method_exists($repository, 'mcpAllowsGetters') && $repository->mcpAllowsGetters()) {
268230
$tools = $tools->merge($this->discoverGetters($repositoryClass, $repository));
269231
}
270232

271233
return $tools;
272234
}
273235

274-
/**
275-
* Discover all actions for a repository.
276-
*/
277236
protected function discoverActions(string $repositoryClass, Repository $repository): Collection
278237
{
279238
$actionRequest = app(McpActionRequest::class);
280239

281240
return $repository->resolveActions($actionRequest)
282-
->filter(fn ($action): bool => $action instanceof Action)
283-
->filter(fn (Action $action): bool => $action->isShownOnMcp($actionRequest, $repository))
284-
->filter(fn (Action $action): bool => $action->authorizedToSee($actionRequest))
285-
->unique(fn (Action $action): string => $action->uriKey())
241+
->filter(fn($action): bool => $action instanceof Action)
242+
->filter(fn(Action $action): bool => $action->isShownOnMcp($actionRequest, $repository))
243+
->filter(fn(Action $action): bool => $action->authorizedToSee($actionRequest))
244+
->unique(fn(Action $action): string => $action->uriKey())
286245
->map(function (Action $action) use ($repositoryClass, $repository): array {
287246
$instance = new ActionTool($repositoryClass, $action);
288247

289248
return [
290-
'type' => 'action',
249+
'type' => OperationTypeEnum::action,
291250
'name' => $instance->name(),
292251
'title' => $instance->title(),
293252
'description' => $instance->description(),
294253
'class' => ActionTool::class,
295254
'instance' => $instance,
296255
'repository' => $repository::uriKey(),
297-
'category' => 'Actions',
256+
'category' => ToolsCategoryEnum::ACTIONS->value,
298257
'action' => $action,
299258
];
300259
})
@@ -309,22 +268,22 @@ protected function discoverGetters(string $repositoryClass, Repository $reposito
309268
$getterRequest = app(McpGetterRequest::class);
310269

311270
return $repository->resolveGetters($getterRequest)
312-
->filter(fn ($getter): bool => $getter instanceof Getter)
313-
->filter(fn (Getter $getter): bool => $getter->isShownOnMcp($getterRequest, $repository))
314-
->filter(fn (Getter $getter): bool => $getter->authorizedToSee($getterRequest))
315-
->unique(fn (Getter $getter): string => $getter->uriKey())
271+
->filter(fn($getter): bool => $getter instanceof Getter)
272+
->filter(fn(Getter $getter): bool => $getter->isShownOnMcp($getterRequest, $repository))
273+
->filter(fn(Getter $getter): bool => $getter->authorizedToSee($getterRequest))
274+
->unique(fn(Getter $getter): string => $getter->uriKey())
316275
->map(function (Getter $getter) use ($repositoryClass, $repository): array {
317276
$instance = new GetterTool($repositoryClass, $getter);
318277

319278
return [
320-
'type' => 'getter',
279+
'type' => OperationTypeEnum::getter,
321280
'name' => $instance->name(),
322281
'title' => $instance->title(),
323282
'description' => $instance->description(),
324283
'class' => GetterTool::class,
325284
'instance' => $instance,
326285
'repository' => $repository::uriKey(),
327-
'category' => 'Getters',
286+
'category' => ToolsCategoryEnum::GETTERS->value,
328287
'getter' => $getter,
329288
];
330289
})
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\MCP\Collections;
4+
5+
use Binaryk\LaravelRestify\MCP\Enums\OperationTypeEnum;
6+
use Binaryk\LaravelRestify\MCP\Enums\ToolsCategoryEnum;
7+
use Binaryk\LaravelRestify\MCP\Tools\Operations\StoreTool;
8+
use Illuminate\Support\Collection;
9+
use Laravel\Mcp\Server\Tool;
10+
11+
class ToolsCollection extends Collection
12+
{
13+
public function toUi(): self
14+
{
15+
return $this->map(fn (array $tool): array => [
16+
'name' => $tool['name'],
17+
'title' => $tool['title'],
18+
'description' => $tool['description'],
19+
'category' => $tool['category'],
20+
'type' => $tool['type'],
21+
]);
22+
}
23+
24+
public function pushTool(Tool $tool, string $repositoryKey, array $extra = []): self
25+
{
26+
return $this->push(array_merge([
27+
'type' => OperationTypeEnum::fromTool($tool),
28+
'name' => $tool->name(),
29+
'title' => $tool->title(),
30+
'description' => $tool->description(),
31+
'class' => get_class($tool),
32+
'instance' => $tool,
33+
'repository' => $repositoryKey,
34+
'category' => ToolsCategoryEnum::fromTool($tool)->value,
35+
], $extra));
36+
}
37+
38+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\MCP\Enums;
4+
5+
use Binaryk\LaravelRestify\MCP\Tools\Operations\ActionTool;
6+
use Binaryk\LaravelRestify\MCP\Tools\Operations\DeleteTool;
7+
use Binaryk\LaravelRestify\MCP\Tools\Operations\GetterTool;
8+
use Binaryk\LaravelRestify\MCP\Tools\Operations\IndexTool;
9+
use Binaryk\LaravelRestify\MCP\Tools\Operations\ProfileTool;
10+
use Binaryk\LaravelRestify\MCP\Tools\Operations\ShowTool;
11+
use Binaryk\LaravelRestify\MCP\Tools\Operations\StoreTool;
12+
use Binaryk\LaravelRestify\MCP\Tools\Operations\UpdateTool;
13+
use Binaryk\LaravelRestify\MCP\Tools\Wrapper\DiscoverRepositoriesTool;
14+
use Binaryk\LaravelRestify\MCP\Tools\Wrapper\ExecuteOperationTool;
15+
use Binaryk\LaravelRestify\MCP\Tools\Wrapper\GetOperationDetailsTool;
16+
use Binaryk\LaravelRestify\MCP\Tools\Wrapper\GetRepositoryOperationsTool;
17+
use Laravel\Mcp\Server\Tool;
18+
19+
enum OperationTypeEnum
20+
{
21+
case index;
22+
case show;
23+
case store;
24+
case update;
25+
case delete;
26+
case profile;
27+
case action;
28+
case getter;
29+
case custom;
30+
case wrapper;
31+
32+
public static function fromTool(Tool $tool): self
33+
{
34+
return match (true) {
35+
$tool instanceof IndexTool => self::index,
36+
$tool instanceof ShowTool => self::show,
37+
$tool instanceof StoreTool => self::store,
38+
$tool instanceof UpdateTool => self::update,
39+
$tool instanceof DeleteTool => self::delete,
40+
$tool instanceof ProfileTool => self::profile,
41+
$tool instanceof ActionTool => self::action,
42+
$tool instanceof GetterTool => self::getter,
43+
$tool instanceof GetOperationDetailsTool,
44+
$tool instanceof ExecuteOperationTool,
45+
$tool instanceof DiscoverRepositoriesTool,
46+
$tool instanceof GetRepositoryOperationsTool => self::wrapper,
47+
default => self::custom,
48+
};
49+
}
50+
}

0 commit comments

Comments
 (0)