@@ -1201,6 +1201,311 @@ class ProductRepository extends Repository
12011201}
12021202```
12031203
1204+ ## Actions and Getters Integration
1205+
1206+ Laravel Restify's MCP integration automatically discovers and exposes repository ** Actions** and ** Getters** as MCP tools, providing AI agents with access to custom business logic and data operations.
1207+
1208+ ### Auto-Discovery System
1209+
1210+ The MCP server automatically discovers actions and getters attached to your repositories during the boot process:
1211+
1212+ ``` php
1213+ protected function discoverRepositoryTools(): void
1214+ {
1215+ collect(Restify::$repositories)
1216+ ->filter(function (string $repository) {
1217+ return in_array(McpTools::class, class_uses_recursive($repository));
1218+ })
1219+ ->each(function (string $repository) {
1220+ $repositoryInstance = app($repository);
1221+
1222+ // Discover and register action tools
1223+ $repositoryInstance->resolveActions(app(McpRequest::class))
1224+ ->each(function (Action $action) use ($repository) {
1225+ $this->addTool(new ActionTool($repository, $action));
1226+ });
1227+
1228+ // Discover and register getter tools
1229+ $repositoryInstance->resolveGetters(app(McpRequest::class))
1230+ ->each(function (Getter $getter) use ($repository) {
1231+ $this->addTool(new GetterTool($repository, $getter));
1232+ });
1233+ });
1234+ }
1235+ ```
1236+
1237+ ### Enabling Actions and Getters
1238+
1239+ To enable actions and getters for MCP, simply add them to your repository as usual:
1240+
1241+ ``` php
1242+ use Binaryk\LaravelRestify\MCP\Concerns\McpTools;
1243+
1244+ class PostRepository extends Repository
1245+ {
1246+ use McpTools;
1247+
1248+ public function actions(RestifyRequest $request): array
1249+ {
1250+ return [
1251+ PublishPostAction::make(),
1252+ ArchivePostAction::make(),
1253+ BulkUpdateStatusAction::make(),
1254+ ];
1255+ }
1256+
1257+ public function getters(RestifyRequest $request): array
1258+ {
1259+ return [
1260+ PostAnalyticsGetter::make(),
1261+ PopularPostsGetter::make(),
1262+ RecentCommentsGetter::make(),
1263+ ];
1264+ }
1265+ }
1266+ ```
1267+
1268+ These will be automatically discovered and exposed as MCP tools:
1269+ - ` posts-publish-post-action-tool `
1270+ - ` posts-archive-post-action-tool `
1271+ - ` posts-bulk-update-status-action-tool `
1272+ - ` posts-post-analytics-getter-tool `
1273+ - ` posts-popular-posts-getter-tool `
1274+ - ` posts-recent-comments-getter-tool `
1275+
1276+ ### Validation Rules for Actions and Getters
1277+
1278+ ** IMPORTANT** : For the MCP system to properly identify and validate parameters, your actions and getters should define validation rules using the ` rules() ` method:
1279+
1280+ #### Action Rules Example
1281+
1282+ ``` php
1283+ <?php
1284+
1285+ use Binaryk\LaravelRestify\Actions\Action;
1286+
1287+ class PublishPostAction extends Action
1288+ {
1289+ public function rules(): array
1290+ {
1291+ return [
1292+ 'publish_date' => ['required', 'date', 'after:now'],
1293+ 'notify_subscribers' => ['boolean'],
1294+ 'featured' => ['boolean'],
1295+ 'category_id' => ['integer', 'exists:categories,id'],
1296+ 'tags' => ['array'],
1297+ 'tags.*' => ['string', 'max:50'],
1298+ ];
1299+ }
1300+
1301+ public function handle(RestifyRequest $request, $models): mixed
1302+ {
1303+ foreach ($models as $post) {
1304+ $post->update([
1305+ 'status' => 'published',
1306+ 'published_at' => $request->input('publish_date'),
1307+ 'featured' => $request->boolean('featured'),
1308+ 'category_id' => $request->input('category_id'),
1309+ ]);
1310+
1311+ if ($request->boolean('notify_subscribers')) {
1312+ dispatch(new NotifySubscribersJob($post));
1313+ }
1314+ }
1315+
1316+ return response()->json(['message' => 'Posts published successfully']);
1317+ }
1318+ }
1319+ ```
1320+
1321+ #### Getter Rules Example
1322+
1323+ ``` php
1324+ <?php
1325+
1326+ use Binaryk\LaravelRestify\Getters\Getter;
1327+
1328+ class PostAnalyticsGetter extends Getter
1329+ {
1330+ public function rules(): array
1331+ {
1332+ return [
1333+ 'date_from' => ['required', 'date'],
1334+ 'date_to' => ['required', 'date', 'after:date_from'],
1335+ 'group_by' => ['string', 'in:day,week,month'],
1336+ 'include_drafts' => ['boolean'],
1337+ 'categories' => ['array'],
1338+ 'categories.*' => ['integer', 'exists:categories,id'],
1339+ ];
1340+ }
1341+
1342+ public function handle(RestifyRequest $request): mixed
1343+ {
1344+ $query = Post::whereBetween('created_at', [
1345+ $request->input('date_from'),
1346+ $request->input('date_to')
1347+ ]);
1348+
1349+ if (!$request->boolean('include_drafts')) {
1350+ $query->where('status', 'published');
1351+ }
1352+
1353+ if ($request->filled('categories')) {
1354+ $query->whereIn('category_id', $request->input('categories'));
1355+ }
1356+
1357+ return $query->selectRaw('
1358+ DATE(created_at) as date,
1359+ COUNT(*) as post_count,
1360+ AVG(view_count) as avg_views,
1361+ SUM(like_count) as total_likes
1362+ ')
1363+ ->groupBy('date')
1364+ ->orderBy('date')
1365+ ->get();
1366+ }
1367+ }
1368+ ```
1369+
1370+ ### Schema Generation from Rules
1371+
1372+ The MCP system uses the ` rules() ` method to automatically generate proper tool schemas with appropriate field types and validation:
1373+
1374+ ``` php
1375+ // Action with rules
1376+ public function rules(): array
1377+ {
1378+ return [
1379+ 'title' => ['required', 'string', 'max:255'],
1380+ 'priority' => ['integer', 'min:1', 'max:5'],
1381+ 'due_date' => ['date', 'after:today'],
1382+ 'notify_assignees' => ['boolean'],
1383+ 'attachments' => ['array'],
1384+ ];
1385+ }
1386+
1387+ // Results in MCP tool schema:
1388+ // - title: required string field
1389+ // - priority: number field (integer)
1390+ // - due_date: string field (date format)
1391+ // - notify_assignees: boolean field
1392+ // - attachments: array field
1393+ ```
1394+
1395+ ### Rules Method Requirements
1396+
1397+ #### For Actions
1398+ - ** REQUIRED** : Actions must implement ` rules() ` method for proper MCP schema generation
1399+ - ** Field Types** : The system maps Laravel validation rules to appropriate MCP field types
1400+ - ** Validation** : Rules are enforced when AI agents call the action tools
1401+
1402+ #### For Getters
1403+ - ** OPTIONAL** : Getters can implement ` rules() ` method for parameter validation
1404+ - ** Flexibility** : If no ` rules() ` method exists, basic schema is generated
1405+ - ** Best Practice** : Define rules for getters that accept parameters
1406+
1407+ ### Rule-to-Schema Mapping
1408+
1409+ | Laravel Rule | MCP Field Type | Description |
1410+ | --------------| ----------------| -------------|
1411+ | ` boolean ` | ` boolean ` | True/false values |
1412+ | ` integer ` , ` numeric ` | ` number ` | Numeric values |
1413+ | ` array ` | ` array ` | Array of values |
1414+ | ` required ` | Required field | Field marked as required |
1415+ | All others | ` string ` | Default string field |
1416+
1417+ ### Advanced Rule Examples
1418+
1419+ #### Complex Action Rules
1420+
1421+ ``` php
1422+ class BulkProcessPostsAction extends Action
1423+ {
1424+ public function rules(): array
1425+ {
1426+ return [
1427+ 'action_type' => ['required', 'string', 'in:publish,draft,archive,delete'],
1428+ 'post_ids' => ['required', 'array', 'min:1'],
1429+ 'post_ids.*' => ['integer', 'exists:posts,id'],
1430+ 'scheduled_at' => ['nullable', 'date', 'after:now'],
1431+ 'reason' => ['required_if:action_type,archive,delete', 'string', 'max:500'],
1432+ 'send_notification' => ['boolean'],
1433+ 'backup_before_delete' => ['required_if:action_type,delete', 'boolean'],
1434+ ];
1435+ }
1436+ }
1437+ ```
1438+
1439+ #### Parameterized Getter Rules
1440+
1441+ ``` php
1442+ class CustomReportGetter extends Getter
1443+ {
1444+ public function rules(): array
1445+ {
1446+ return [
1447+ 'report_type' => ['required', 'string', 'in:sales,traffic,engagement'],
1448+ 'date_range' => ['required', 'string', 'in:today,week,month,quarter,year,custom'],
1449+ 'start_date' => ['required_if:date_range,custom', 'date'],
1450+ 'end_date' => ['required_if:date_range,custom', 'date', 'after:start_date'],
1451+ 'format' => ['string', 'in:json,csv,pdf'],
1452+ 'include_metadata' => ['boolean'],
1453+ 'filters' => ['array'],
1454+ 'filters.*.field' => ['required', 'string'],
1455+ 'filters.*.operator' => ['required', 'string', 'in:equals,contains,greater_than,less_than'],
1456+ 'filters.*.value' => ['required'],
1457+ ];
1458+ }
1459+ }
1460+ ```
1461+
1462+ ### Best Practices for Rules
1463+
1464+ #### 1. Always Define Rules for Actions
1465+ ``` php
1466+ // ✅ Good: Clear validation rules
1467+ public function rules(): array
1468+ {
1469+ return [
1470+ 'email' => ['required', 'email'],
1471+ 'role' => ['required', 'in:admin,user,moderator'],
1472+ 'active' => ['boolean'],
1473+ ];
1474+ }
1475+
1476+ // ❌ Bad: No rules defined
1477+ public function rules(): array
1478+ {
1479+ return []; // MCP can't generate proper schema
1480+ }
1481+ ```
1482+
1483+ #### 2. Use Descriptive Rule Combinations
1484+ ``` php
1485+ public function rules(): array
1486+ {
1487+ return [
1488+ 'priority' => ['required', 'integer', 'min:1', 'max:10'],
1489+ 'tags' => ['array', 'max:5'],
1490+ 'tags.*' => ['string', 'max:50', 'alpha_dash'],
1491+ 'deadline' => ['nullable', 'date', 'after:today'],
1492+ ];
1493+ }
1494+ ```
1495+
1496+ #### 3. Handle Conditional Requirements
1497+ ``` php
1498+ public function rules(): array
1499+ {
1500+ return [
1501+ 'notification_type' => ['required', 'in:email,sms,push'],
1502+ 'email' => ['required_if:notification_type,email', 'email'],
1503+ 'phone' => ['required_if:notification_type,sms', 'regex:/^\+?[1-9]\d{1,14}$/'],
1504+ 'device_token' => ['required_if:notification_type,push', 'string'],
1505+ ];
1506+ }
1507+ ```
1508+
12041509### Integration with Field Visibility Controls
12051510
12061511MCP field methods work seamlessly with Laravel Restify's existing field visibility system:
0 commit comments