Skip to content

Commit 34a54f1

Browse files
committed
fix: adding generator commands
1 parent 950600b commit 34a54f1

File tree

7 files changed

+248
-0
lines changed

7 files changed

+248
-0
lines changed

docs-v2/content/en/mcp/mcp.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,26 @@ protected function discoverTools(): array
325325
}
326326
}
327327

328+
// Auto-discover tools from app/Restify/Mcp/Tools
329+
$appToolsPath = app_path('Restify/Mcp/Tools');
330+
if (is_dir($appToolsPath)) {
331+
$appToolDir = new \DirectoryIterator($appToolsPath);
332+
foreach ($appToolDir as $toolFile) {
333+
if ($toolFile->isFile() && $toolFile->getExtension() === 'php') {
334+
$fqdn = 'App\\Restify\\Mcp\\Tools\\'.$toolFile->getBasename('.php');
335+
if (class_exists($fqdn) && ! in_array($fqdn, $excludedTools, true)) {
336+
$this->addTool($fqdn);
337+
}
338+
}
339+
}
340+
}
341+
328342
return $this->registeredTools;
329343
}
330344
```
331345

346+
**Auto-Discovery from Application Directory**: The MCP server automatically discovers and registers tools from your application's `app/Restify/Mcp/Tools` directory. Any tool class placed in this directory will be automatically registered without requiring manual configuration.
347+
332348
### Configuration Options
333349

334350
You can control tool discovery through configuration:
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Commands;
4+
5+
use Illuminate\Console\ConfirmableTrait;
6+
use Illuminate\Console\GeneratorCommand;
7+
use Illuminate\Support\Str;
8+
9+
class McpResourceCommand extends GeneratorCommand
10+
{
11+
use ConfirmableTrait;
12+
13+
protected $name = 'restify:mcp-resource';
14+
15+
protected $description = 'Create a new MCP resource class';
16+
17+
protected $type = 'Resource';
18+
19+
public function handle()
20+
{
21+
if (parent::handle() === false && ! $this->option('force')) {
22+
return false;
23+
}
24+
}
25+
26+
/**
27+
* Build the class with the given name.
28+
* This method should return the file class content.
29+
*
30+
* @param string $name
31+
* @return string
32+
*
33+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
34+
*/
35+
protected function buildClass($name)
36+
{
37+
if (Str::endsWith($name, 'Resource') === false) {
38+
$name .= 'Resource';
39+
}
40+
41+
return parent::buildClass($name);
42+
}
43+
44+
protected function getStub()
45+
{
46+
return __DIR__.'/stubs/mcp-resource.stub';
47+
}
48+
49+
protected function getPath($name)
50+
{
51+
if (Str::endsWith($name, 'Resource') === false) {
52+
$name .= 'Resource';
53+
}
54+
55+
return parent::getPath($name);
56+
}
57+
58+
protected function getDefaultNamespace($rootNamespace)
59+
{
60+
return $rootNamespace.'\\Restify\\Mcp\\Resources';
61+
}
62+
}

src/Commands/ToolCommand.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Commands;
4+
5+
use Illuminate\Console\ConfirmableTrait;
6+
use Illuminate\Console\GeneratorCommand;
7+
use Illuminate\Support\Str;
8+
9+
class ToolCommand extends GeneratorCommand
10+
{
11+
use ConfirmableTrait;
12+
13+
protected $name = 'restify:mcp-tool';
14+
15+
protected $description = 'Create a new MCP tool class';
16+
17+
protected $type = 'Tool';
18+
19+
public function handle()
20+
{
21+
if (parent::handle() === false && ! $this->option('force')) {
22+
return false;
23+
}
24+
}
25+
26+
/**
27+
* Build the class with the given name.
28+
* This method should return the file class content.
29+
*
30+
* @param string $name
31+
* @return string
32+
*
33+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
34+
*/
35+
protected function buildClass($name)
36+
{
37+
if (Str::endsWith($name, 'Tool') === false) {
38+
$name .= 'Tool';
39+
}
40+
41+
$stub = parent::buildClass($name);
42+
43+
// Replace the tool name placeholder with a kebab-case version of the class name
44+
$toolName = Str::kebab(Str::beforeLast(class_basename($name), 'Tool'));
45+
$stub = str_replace('DummyToolName', $toolName, $stub);
46+
47+
return $stub;
48+
}
49+
50+
protected function getStub()
51+
{
52+
return __DIR__.'/stubs/mcp-tool.stub';
53+
}
54+
55+
protected function getPath($name)
56+
{
57+
if (Str::endsWith($name, 'Tool') === false) {
58+
$name .= 'Tool';
59+
}
60+
61+
return parent::getPath($name);
62+
}
63+
64+
protected function getDefaultNamespace($rootNamespace)
65+
{
66+
return $rootNamespace.'\\Restify\\Mcp\\Tools';
67+
}
68+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace DummyNamespace;
4+
5+
use Laravel\Mcp\Server\Contracts\Resources\Content;
6+
use Laravel\Mcp\Server\Resource;
7+
8+
class DummyClass extends Resource
9+
{
10+
public function description(): string
11+
{
12+
return 'Description of what this resource provides';
13+
}
14+
15+
public function read(): string|Content
16+
{
17+
// Return the resource content as a string or Content object
18+
// This can be JSON, text, or any other format
19+
20+
$data = [
21+
'example' => 'This is example data',
22+
'timestamp' => now()->toIso8601String(),
23+
];
24+
25+
return json_encode($data, JSON_PRETTY_PRINT);
26+
}
27+
}

src/Commands/stubs/mcp-tool.stub

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace DummyNamespace;
4+
5+
use Generator;
6+
use Laravel\Mcp\Server\Tool;
7+
use Laravel\Mcp\Server\Tools\ToolInputSchema;
8+
use Laravel\Mcp\Server\Tools\ToolResult;
9+
10+
class DummyClass extends Tool
11+
{
12+
public function name(): string
13+
{
14+
return 'DummyToolName';
15+
}
16+
17+
public function description(): string
18+
{
19+
return 'Description of what this tool does';
20+
}
21+
22+
public function schema(ToolInputSchema $schema): ToolInputSchema
23+
{
24+
// Define your tool's input parameters here
25+
// Example:
26+
// $schema->string('input')
27+
// ->description('The input parameter')
28+
// ->required();
29+
30+
return $schema;
31+
}
32+
33+
public function handle(array $arguments): ToolResult|Generator
34+
{
35+
// Implement your tool's logic here
36+
// Access input parameters via $arguments array
37+
38+
return ToolResult::json([
39+
'success' => true,
40+
'message' => 'Tool executed successfully',
41+
]);
42+
}
43+
}

src/LaravelRestifyServiceProvider.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Binaryk\LaravelRestify\Commands\DevCommand;
88
use Binaryk\LaravelRestify\Commands\FilterCommand;
99
use Binaryk\LaravelRestify\Commands\GetterCommand;
10+
use Binaryk\LaravelRestify\Commands\McpResourceCommand;
1011
use Binaryk\LaravelRestify\Commands\PolicyCommand;
1112
use Binaryk\LaravelRestify\Commands\PrepareSanctumCommand;
1213
use Binaryk\LaravelRestify\Commands\PublishAuthCommand;
@@ -17,6 +18,7 @@
1718
use Binaryk\LaravelRestify\Commands\SetupCommand;
1819
use Binaryk\LaravelRestify\Commands\StoreCommand;
1920
use Binaryk\LaravelRestify\Commands\StubCommand;
21+
use Binaryk\LaravelRestify\Commands\ToolCommand;
2022
use Binaryk\LaravelRestify\Repositories\Repository;
2123
use Spatie\LaravelPackageTools\Package;
2224
use Spatie\LaravelPackageTools\PackageServiceProvider;
@@ -46,6 +48,8 @@ public function configurePackage(Package $package): void
4648
RestifyRouteListCommand::class,
4749
PrepareSanctumCommand::class,
4850
SetupAuthCommand::class,
51+
ToolCommand::class,
52+
McpResourceCommand::class,
4953
]);
5054
}
5155

src/MCP/RestifyServer.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ protected function discoverTools(): array
6363
}
6464
}
6565

66+
// Auto-discover tools from app/Restify/Mcp/Tools
67+
$appToolsPath = app_path('Restify/Mcp/Tools');
68+
if (is_dir($appToolsPath)) {
69+
$appToolDir = new \DirectoryIterator($appToolsPath);
70+
foreach ($appToolDir as $toolFile) {
71+
if ($toolFile->isFile() && $toolFile->getExtension() === 'php') {
72+
$fqdn = 'App\\Restify\\Mcp\\Tools\\'.$toolFile->getBasename('.php');
73+
if (class_exists($fqdn) && ! in_array($fqdn, $excludedTools, true)) {
74+
$this->addTool($fqdn);
75+
}
76+
}
77+
}
78+
}
79+
6680
$extraTools = config('restify.mcp.tools.include', []);
6781
foreach ($extraTools as $toolClass) {
6882
if (class_exists($toolClass)) {
@@ -158,6 +172,20 @@ protected function discoverResources(): array
158172
}
159173
}
160174

175+
// Auto-discover resources from app/Restify/Mcp/Resources
176+
$appResourcesPath = app_path('Restify/Mcp/Resources');
177+
if (is_dir($appResourcesPath)) {
178+
$appResourceDir = new \DirectoryIterator($appResourcesPath);
179+
foreach ($appResourceDir as $resourceFile) {
180+
if ($resourceFile->isFile() && $resourceFile->getExtension() === 'php') {
181+
$fqdn = 'App\\Restify\\Mcp\\Resources\\'.$resourceFile->getBasename('.php');
182+
if (class_exists($fqdn) && ! in_array($fqdn, $excludedResources, true)) {
183+
$this->addResource($fqdn);
184+
}
185+
}
186+
}
187+
}
188+
161189
$extraResources = config('restify.mcp.resources.include', []);
162190
foreach ($extraResources as $resourceClass) {
163191
if (class_exists($resourceClass)) {

0 commit comments

Comments
 (0)