Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4b2d7695f | ||
|
|
82498b9189 | ||
|
|
949a9230c5 | ||
|
|
f6da6705db | ||
|
|
686b41e406 | ||
|
|
24c53368a7 | ||
|
|
29b854fd44 |
No files matched your search
@@ -247,6 +247,5 @@ MIT License - See LICENSE file for details
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check the [documentation site](local)
|
||||
- Review [FiveM docs](https://docs.fivem.net/)
|
||||
- Open an issue on GitHub
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mcp\Servers\FiveMServer;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use ReflectionClass;
|
||||
|
||||
class DocsController extends Controller
|
||||
{
|
||||
@@ -27,6 +31,64 @@ class DocsController extends Controller
|
||||
*/
|
||||
public function documentation(): View
|
||||
{
|
||||
return view('docs.documentation');
|
||||
$serverReflection = new ReflectionClass(FiveMServer::class);
|
||||
|
||||
$toolsProperty = $serverReflection->getProperty('tools');
|
||||
$resourcesProperty = $serverReflection->getProperty('resources');
|
||||
$promptsProperty = $serverReflection->getProperty('prompts');
|
||||
|
||||
$toolsProperty->setAccessible(true);
|
||||
$resourcesProperty->setAccessible(true);
|
||||
$promptsProperty->setAccessible(true);
|
||||
|
||||
$defaultProperties = $serverReflection->getDefaultProperties();
|
||||
|
||||
$tools = $this->extractComponentDetails($defaultProperties['tools'] ?? [], 'tool');
|
||||
$resources = $this->extractComponentDetails($defaultProperties['resources'] ?? [], 'resource');
|
||||
$prompts = $this->extractComponentDetails($defaultProperties['prompts'] ?? [], 'prompt');
|
||||
|
||||
return view('docs.documentation', [
|
||||
'tools' => $tools,
|
||||
'resources' => $resources,
|
||||
'prompts' => $prompts,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract details from MCP components.
|
||||
*/
|
||||
protected function extractComponentDetails(array $components, string $type): array
|
||||
{
|
||||
return collect($components)->map(function ($componentClass) use ($type) {
|
||||
$reflection = new ReflectionClass($componentClass);
|
||||
$descriptionAttr = $reflection->getAttributes(Description::class)[0] ?? null;
|
||||
$description = $descriptionAttr ? $descriptionAttr->getArguments()[0] : 'No description available';
|
||||
|
||||
// Get the simple class name and convert it to a readable format
|
||||
$className = $reflection->getShortName();
|
||||
$name = $this->formatClassName($className);
|
||||
|
||||
// Get category from namespace
|
||||
$namespace = $reflection->getNamespaceName();
|
||||
$parts = explode('\\', $namespace);
|
||||
$category = $parts[count($parts) - 1] ?? 'General';
|
||||
|
||||
return [
|
||||
'name' => $name,
|
||||
'class' => $className,
|
||||
'description' => $description,
|
||||
'category' => $category,
|
||||
'type' => $type,
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format class name to readable format.
|
||||
*/
|
||||
protected function formatClassName(string $className): string
|
||||
{
|
||||
// Convert PascalCase to Title Case with spaces
|
||||
return Str::of($className)->kebab()->replace('-', ' ')->title();
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,16 @@ use App\Mcp\Resources\BestPractices;
|
||||
use App\Mcp\Resources\CodeSnippets;
|
||||
use App\Mcp\Resources\DatabaseQueries;
|
||||
use App\Mcp\Resources\FrameworkComparison;
|
||||
use App\Mcp\Tools\COX\Doorlock\Client\GetOxDoorlockClientFunction;
|
||||
use App\Mcp\Tools\COX\Doorlock\Server\GetOxDoorlockServerEvent;
|
||||
use App\Mcp\Tools\COX\Doorlock\Server\GetOxDoorlockServerFunction;
|
||||
use App\Mcp\Tools\COX\Fuel\Client\GetOxFuelClientFunction;
|
||||
use App\Mcp\Tools\COX\Fuel\Server\GetOxFuelServerFunction;
|
||||
use App\Mcp\Tools\COX\Inventory\Client\GetInventoryClientFunction;
|
||||
use App\Mcp\Tools\COX\Inventory\Server\GetInventoryServerFunction;
|
||||
use App\Mcp\Tools\COX\MySQL\GetCOXEventReference;
|
||||
use App\Mcp\Tools\COX\MySQL\GetCOXFunction;
|
||||
use App\Mcp\Tools\COX\Target\Client\GetOxTargetClientFunction;
|
||||
use App\Mcp\Tools\FiveM\Client\GetEventClientReference;
|
||||
use App\Mcp\Tools\FiveM\Client\GetNativeClientFunction;
|
||||
use App\Mcp\Tools\FiveM\GenerateManifest;
|
||||
@@ -26,6 +32,8 @@ use App\Mcp\Tools\QBCore\Client\GetQBCoreClientEventReference;
|
||||
use App\Mcp\Tools\QBCore\Client\GetQBCoreClientFunction;
|
||||
use App\Mcp\Tools\QBCore\GetQBCoreConfig;
|
||||
use App\Mcp\Tools\QBCore\GetQBCorePlayers;
|
||||
use App\Mcp\Tools\QBCore\GetQBCoreResourceList;
|
||||
use App\Mcp\Tools\QBCore\GetQBCoreResourceReference;
|
||||
use App\Mcp\Tools\QBCore\GetQBCoreSharedData;
|
||||
use App\Mcp\Tools\QBCore\Server\GetQBCoreServerEventReference;
|
||||
use App\Mcp\Tools\QBCore\Server\GetQBCoreServerFunction;
|
||||
@@ -66,10 +74,18 @@ class FiveMServer extends Server
|
||||
GetQBCoreSharedData::class,
|
||||
GetQBCoreConfig::class,
|
||||
GetQBCorePlayers::class,
|
||||
GetQBCoreResourceList::class,
|
||||
GetQBCoreResourceReference::class,
|
||||
GetCOXEventReference::class,
|
||||
GetCOXFunction::class,
|
||||
GetInventoryServerFunction::class,
|
||||
GetInventoryClientFunction::class,
|
||||
GetOxTargetClientFunction::class,
|
||||
GetOxFuelClientFunction::class,
|
||||
GetOxFuelServerFunction::class,
|
||||
GetOxDoorlockClientFunction::class,
|
||||
GetOxDoorlockServerFunction::class,
|
||||
GetOxDoorlockServerEvent::class,
|
||||
];
|
||||
|
||||
protected array $resources = [
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\COX\Doorlock\Client;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Look up ox_doorlock client functions by name. Returns function signature, parameters, return type, and usage examples for client-side door management.')]
|
||||
class GetOxDoorlockClientFunction extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$functionName = $request->get('function_name');
|
||||
$language = $request->get('language', 'lua');
|
||||
|
||||
$function = $this->findFunction($functionName);
|
||||
|
||||
if (! $function) {
|
||||
return Response::text(sprintf("ox_doorlock client function '%s' not found. Check ox_doorlock documentation at https://coxdocs.dev/ox_doorlock", $functionName));
|
||||
}
|
||||
|
||||
$output = $this->formatFunctionInfo($function, $language);
|
||||
|
||||
return Response::text($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an ox_doorlock client function.
|
||||
*/
|
||||
protected function findFunction(string $name): ?array
|
||||
{
|
||||
$functions = [
|
||||
'pickClosestDoor' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Attempt to lockpick the closest door',
|
||||
'side' => 'client',
|
||||
'parameters' => [],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => 'exports.ox_doorlock:pickClosestDoor()',
|
||||
'js_example' => 'exports.ox_doorlock.pickClosestDoor();',
|
||||
],
|
||||
'useClosestDoor' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Toggle the lock state of the closest door',
|
||||
'side' => 'client',
|
||||
'parameters' => [],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => 'exports.ox_doorlock:useClosestDoor()',
|
||||
'js_example' => 'exports.ox_doorlock.useClosestDoor();',
|
||||
],
|
||||
'getClosestDoor' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Get data for the closest door',
|
||||
'side' => 'client',
|
||||
'parameters' => [],
|
||||
'returns' => ['type' => 'table|nil', 'description' => 'Door data or nil if no door nearby'],
|
||||
'lua_example' => "local door = exports.ox_doorlock:getClosestDoor()\nif door then\n print('Closest door ID: '..door.id)\n print('Door is locked: '..tostring(door.state == 1))\nend",
|
||||
'js_example' => "const door = exports.ox_doorlock.getClosestDoor();\nif (door) {\n console.log('Closest door ID: ' + door.id);\n console.log('Door is locked: ' + (door.state === 1));\n}",
|
||||
],
|
||||
];
|
||||
|
||||
$nameLower = strtolower($name);
|
||||
|
||||
foreach ($functions as $functionName => $functionData) {
|
||||
if (strtolower($functionName) === $nameLower) {
|
||||
return array_merge(['name' => $functionName], $functionData);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format function info.
|
||||
*/
|
||||
protected function formatFunctionInfo(array $function, string $language): string
|
||||
{
|
||||
return view('mcp.cox.cox-function', [
|
||||
'function' => $function,
|
||||
'language' => $language,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'function_name' => $schema
|
||||
->string()
|
||||
->description('The name of the ox_doorlock client function to look up (e.g., "pickClosestDoor", "useClosestDoor", "getClosestDoor")')
|
||||
->required(),
|
||||
'language' => $schema
|
||||
->string()
|
||||
->enum(['lua', 'js'])
|
||||
->description('The scripting language for code examples')
|
||||
->default('lua'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\COX\Doorlock\Server;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Look up ox_doorlock server events by name. Returns event signature, parameters, and usage examples for server-side door events.')]
|
||||
class GetOxDoorlockServerEvent extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$eventName = $request->get('event_name');
|
||||
$language = $request->get('language', 'lua');
|
||||
|
||||
$event = $this->findEvent($eventName);
|
||||
|
||||
if (! $event) {
|
||||
return Response::text(sprintf("ox_doorlock server event '%s' not found. Check ox_doorlock documentation at https://coxdocs.dev/ox_doorlock", $eventName));
|
||||
}
|
||||
|
||||
$output = $this->formatEventInfo($event, $language);
|
||||
|
||||
return Response::text($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an ox_doorlock server event.
|
||||
*/
|
||||
protected function findEvent(string $name): ?array
|
||||
{
|
||||
$events = [
|
||||
'ox_doorlock:stateChanged' => [
|
||||
'type' => 'doorlock',
|
||||
'namespace' => 'Server',
|
||||
'description' => 'Triggered when a door lock state changes',
|
||||
'side' => 'server',
|
||||
'parameters' => [
|
||||
['name' => 'doorId', 'type' => 'number', 'description' => 'The door ID'],
|
||||
['name' => 'state', 'type' => 'number', 'description' => 'New door state (0 = unlocked, 1 = locked)'],
|
||||
],
|
||||
'lua_example' => "AddEventHandler('ox_doorlock:stateChanged', function(doorId, state)\n local doorName = exports.ox_doorlock:getDoor(doorId)?.name or 'Unknown'\n local stateText = state == 1 and 'locked' or 'unlocked'\n print(('Door %s (ID: %s) is now %s'):format(doorName, doorId, stateText))\nend)",
|
||||
'js_example' => "on('ox_doorlock:stateChanged', (doorId, state) => {\n const door = exports.ox_doorlock.getDoor(doorId);\n const doorName = door?.name || 'Unknown';\n const stateText = state === 1 ? 'locked' : 'unlocked';\n console.log(`Door \${doorName} (ID: \${doorId}) is now \${stateText}`);\n});",
|
||||
],
|
||||
];
|
||||
|
||||
$nameLower = strtolower($name);
|
||||
|
||||
foreach ($events as $eventName => $eventData) {
|
||||
if (strtolower($eventName) === $nameLower) {
|
||||
return array_merge(['name' => $eventName], $eventData);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format event info.
|
||||
*/
|
||||
protected function formatEventInfo(array $event, string $language): string
|
||||
{
|
||||
return view('mcp.cox.cox-event-reference', [
|
||||
'event' => $event,
|
||||
'language' => $language,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'event_name' => $schema
|
||||
->string()
|
||||
->description('The name of the ox_doorlock server event to look up (e.g., "ox_doorlock:stateChanged")')
|
||||
->required(),
|
||||
'language' => $schema
|
||||
->string()
|
||||
->enum(['lua', 'js'])
|
||||
->description('The scripting language for code examples')
|
||||
->default('lua'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\COX\Doorlock\Server;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Look up ox_doorlock server functions by name. Returns function signature, parameters, return type, and usage examples for server-side door management.')]
|
||||
class GetOxDoorlockServerFunction extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$functionName = $request->get('function_name');
|
||||
$language = $request->get('language', 'lua');
|
||||
|
||||
$function = $this->findFunction($functionName);
|
||||
|
||||
if (! $function) {
|
||||
return Response::text(sprintf("ox_doorlock server function '%s' not found. Check ox_doorlock documentation at https://coxdocs.dev/ox_doorlock", $functionName));
|
||||
}
|
||||
|
||||
$output = $this->formatFunctionInfo($function, $language);
|
||||
|
||||
return Response::text($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an ox_doorlock server function.
|
||||
*/
|
||||
protected function findFunction(string $name): ?array
|
||||
{
|
||||
$functions = [
|
||||
'getDoor' => [
|
||||
'namespace' => 'Server',
|
||||
'description' => 'Get door data by door ID',
|
||||
'side' => 'server',
|
||||
'parameters' => [
|
||||
['name' => 'doorId', 'type' => 'number', 'description' => 'The door ID'],
|
||||
],
|
||||
'returns' => ['type' => 'table|nil', 'description' => 'Door data or nil if not found'],
|
||||
'lua_example' => "local door = exports.ox_doorlock:getDoor(1)\nif door then\n print('Door name: '..door.name)\n print('Door state: '..door.state)\nend",
|
||||
'js_example' => "const door = exports.ox_doorlock.getDoor(1);\nif (door) {\n console.log('Door name: ' + door.name);\n console.log('Door state: ' + door.state);\n}",
|
||||
],
|
||||
'getDoorFromName' => [
|
||||
'namespace' => 'Server',
|
||||
'description' => 'Get door data by door name',
|
||||
'side' => 'server',
|
||||
'parameters' => [
|
||||
['name' => 'doorName', 'type' => 'string', 'description' => 'The door name'],
|
||||
],
|
||||
'returns' => ['type' => 'table|nil', 'description' => 'Door data or nil if not found'],
|
||||
'lua_example' => "local door = exports.ox_doorlock:getDoorFromName('mrpd_main')\nif door then\n print('Door ID: '..door.id)\n print('Door is locked: '..tostring(door.state == 1))\nend",
|
||||
'js_example' => "const door = exports.ox_doorlock.getDoorFromName('mrpd_main');\nif (door) {\n console.log('Door ID: ' + door.id);\n console.log('Door is locked: ' + (door.state === 1));\n}",
|
||||
],
|
||||
'editDoor' => [
|
||||
'namespace' => 'Server',
|
||||
'description' => 'Edit door properties by door ID',
|
||||
'side' => 'server',
|
||||
'parameters' => [
|
||||
['name' => 'doorId', 'type' => 'number', 'description' => 'The door ID'],
|
||||
['name' => 'data', 'type' => 'table', 'description' => 'Table with properties to update (state, groups, etc.)'],
|
||||
['name' => 'playerId', 'type' => 'number|nil', 'description' => 'Optional player ID who triggered the edit'],
|
||||
],
|
||||
'returns' => ['type' => 'boolean', 'description' => 'True if door was successfully edited'],
|
||||
'lua_example' => "local success = exports.ox_doorlock:editDoor(1, {\n state = 0, -- Unlocked\n groups = {police = 0} -- Police can use\n})\nif success then\n print('Door edited successfully')\nend",
|
||||
'js_example' => "const success = exports.ox_doorlock.editDoor(1, {\n state: 0, // Unlocked\n groups: {police: 0} // Police can use\n});\nif (success) {\n console.log('Door edited successfully');\n}",
|
||||
],
|
||||
'setDoorState' => [
|
||||
'namespace' => 'Server',
|
||||
'description' => 'Set the lock state of a door',
|
||||
'side' => 'server',
|
||||
'parameters' => [
|
||||
['name' => 'doorId', 'type' => 'number', 'description' => 'The door ID'],
|
||||
['name' => 'state', 'type' => 'number', 'description' => '0 = unlocked, 1 = locked'],
|
||||
['name' => 'playerId', 'type' => 'number|nil', 'description' => 'Optional player ID who triggered the state change'],
|
||||
],
|
||||
'returns' => ['type' => 'boolean', 'description' => 'True if state was successfully changed'],
|
||||
'lua_example' => "local success = exports.ox_doorlock:setDoorState(1, 1) -- Lock door ID 1\nif success then\n print('Door locked successfully')\nend",
|
||||
'js_example' => "const success = exports.ox_doorlock.setDoorState(1, 1); // Lock door ID 1\nif (success) {\n console.log('Door locked successfully');\n}",
|
||||
],
|
||||
];
|
||||
|
||||
$nameLower = strtolower($name);
|
||||
|
||||
foreach ($functions as $functionName => $functionData) {
|
||||
if (strtolower($functionName) === $nameLower) {
|
||||
return array_merge(['name' => $functionName], $functionData);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format function info.
|
||||
*/
|
||||
protected function formatFunctionInfo(array $function, string $language): string
|
||||
{
|
||||
return view('mcp.cox.cox-function', [
|
||||
'function' => $function,
|
||||
'language' => $language,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'function_name' => $schema
|
||||
->string()
|
||||
->description('The name of the ox_doorlock server function to look up (e.g., "getDoor", "getDoorFromName", "editDoor", "setDoorState")')
|
||||
->required(),
|
||||
'language' => $schema
|
||||
->string()
|
||||
->enum(['lua', 'js'])
|
||||
->description('The scripting language for code examples')
|
||||
->default('lua'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\COX\Fuel\Client;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Look up ox_fuel client functions by name. Returns function signature, parameters, return type, and usage examples for vehicle fuel management.')]
|
||||
class GetOxFuelClientFunction extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$functionName = $request->get('function_name');
|
||||
$language = $request->get('language', 'lua');
|
||||
|
||||
$function = $this->findFunction($functionName);
|
||||
|
||||
if (! $function) {
|
||||
return Response::text(sprintf("ox_fuel client function '%s' not found. Check ox_fuel documentation at https://coxdocs.dev/ox_fuel", $functionName));
|
||||
}
|
||||
|
||||
$output = $this->formatFunctionInfo($function, $language);
|
||||
|
||||
return Response::text($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an ox_fuel client function.
|
||||
*/
|
||||
protected function findFunction(string $name): ?array
|
||||
{
|
||||
$functions = [
|
||||
'setMoneyCheck' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Set a custom function to check if a player has enough money to pay for fuel',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'callback', 'type' => 'function', 'description' => 'Function(amount: number) -> boolean that returns true if player can afford fuel'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => "exports.ox_fuel:setMoneyCheck(function(amount)\n local playerMoney = exports.framework:GetPlayerMoney()\n return playerMoney >= amount\nend)",
|
||||
'js_example' => "exports.ox_fuel.setMoneyCheck((amount) => {\n const playerMoney = exports.framework.GetPlayerMoney();\n return playerMoney >= amount;\n});",
|
||||
],
|
||||
];
|
||||
|
||||
$nameLower = strtolower($name);
|
||||
|
||||
foreach ($functions as $functionName => $functionData) {
|
||||
if (strtolower($functionName) === $nameLower) {
|
||||
return array_merge(['name' => $functionName], $functionData);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format function info.
|
||||
*/
|
||||
protected function formatFunctionInfo(array $function, string $language): string
|
||||
{
|
||||
return view('mcp.cox.cox-function', [
|
||||
'function' => $function,
|
||||
'language' => $language,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'function_name' => $schema
|
||||
->string()
|
||||
->description('The name of the ox_fuel client function to look up (e.g., "setMoneyCheck")')
|
||||
->required(),
|
||||
'language' => $schema
|
||||
->string()
|
||||
->enum(['lua', 'js'])
|
||||
->description('The scripting language for code examples')
|
||||
->default('lua'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\COX\Fuel\Server;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Look up ox_fuel server functions by name. Returns function signature, parameters, return type, and usage examples for server-side fuel management.')]
|
||||
class GetOxFuelServerFunction extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$functionName = $request->get('function_name');
|
||||
$language = $request->get('language', 'lua');
|
||||
|
||||
$function = $this->findFunction($functionName);
|
||||
|
||||
if (! $function) {
|
||||
return Response::text(sprintf("ox_fuel server function '%s' not found. Check ox_fuel documentation at https://coxdocs.dev/ox_fuel", $functionName));
|
||||
}
|
||||
|
||||
$output = $this->formatFunctionInfo($function, $language);
|
||||
|
||||
return Response::text($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an ox_fuel server function.
|
||||
*/
|
||||
protected function findFunction(string $name): ?array
|
||||
{
|
||||
$functions = [
|
||||
'setPaymentMethod' => [
|
||||
'namespace' => 'Server',
|
||||
'description' => 'Set a custom payment method for fuel purchases',
|
||||
'side' => 'server',
|
||||
'parameters' => [
|
||||
['name' => 'callback', 'type' => 'function', 'description' => 'Function(source: number, amount: number) -> boolean that handles payment and returns true if successful'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => "exports.ox_fuel:setPaymentMethod(function(source, amount)\n local success = exports.framework:RemovePlayerMoney(source, amount)\n if success then\n print('Player '..source..' paid $'..amount..' for fuel')\n end\n return success\nend)",
|
||||
'js_example' => "exports.ox_fuel.setPaymentMethod((source, amount) => {\n const success = exports.framework.RemovePlayerMoney(source, amount);\n if (success) {\n console.log(`Player \${source} paid $\${amount} for fuel`);\n }\n return success;\n});",
|
||||
],
|
||||
];
|
||||
|
||||
$nameLower = strtolower($name);
|
||||
|
||||
foreach ($functions as $functionName => $functionData) {
|
||||
if (strtolower($functionName) === $nameLower) {
|
||||
return array_merge(['name' => $functionName], $functionData);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format function info.
|
||||
*/
|
||||
protected function formatFunctionInfo(array $function, string $language): string
|
||||
{
|
||||
return view('mcp.cox.cox-function', [
|
||||
'function' => $function,
|
||||
'language' => $language,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'function_name' => $schema
|
||||
->string()
|
||||
->description('The name of the ox_fuel server function to look up (e.g., "setPaymentMethod")')
|
||||
->required(),
|
||||
'language' => $schema
|
||||
->string()
|
||||
->enum(['lua', 'js'])
|
||||
->description('The scripting language for code examples')
|
||||
->default('lua'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\COX\Target\Client;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Look up ox_target client functions by name. Returns function signature, parameters, return type, and usage examples for targeting/third-eye interaction system.')]
|
||||
class GetOxTargetClientFunction extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$functionName = $request->get('function_name');
|
||||
$language = $request->get('language', 'lua');
|
||||
|
||||
$function = $this->findFunction($functionName);
|
||||
|
||||
if (! $function) {
|
||||
return Response::text(sprintf("ox_target client function '%s' not found. Check ox_target documentation at https://coxdocs.dev/ox_target", $functionName));
|
||||
}
|
||||
|
||||
$output = $this->formatFunctionInfo($function, $language);
|
||||
|
||||
return Response::text($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an ox_target client function.
|
||||
*/
|
||||
protected function findFunction(string $name): ?array
|
||||
{
|
||||
$functions = [
|
||||
'disableTargeting' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Disables or enables the targeting system',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'disabled', 'type' => 'boolean', 'description' => 'true to disable, false to enable'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => 'exports.ox_target:disableTargeting(true) -- Disable targeting',
|
||||
'js_example' => 'exports.ox_target.disableTargeting(true); // Disable targeting',
|
||||
],
|
||||
'isActive' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Check if the targeting system is currently active',
|
||||
'side' => 'client',
|
||||
'parameters' => [],
|
||||
'returns' => ['type' => 'boolean', 'description' => 'true if targeting is active'],
|
||||
'lua_example' => "local active = exports.ox_target:isActive()\nif active then\n print('Targeting is active')\nend",
|
||||
'js_example' => "const active = exports.ox_target.isActive();\nif (active) {\n console.log('Targeting is active');\n}",
|
||||
],
|
||||
'addGlobalOption' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add a global target option that appears on all entities',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Target option configuration'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => "exports.ox_target:addGlobalOption({\n name = 'greet',\n icon = 'fas fa-hand-wave',\n label = 'Wave',\n onSelect = function()\n print('You waved!')\n end\n})",
|
||||
'js_example' => "exports.ox_target.addGlobalOption({\n name: 'greet',\n icon: 'fas fa-hand-wave',\n label: 'Wave',\n onSelect: () => {\n console.log('You waved!');\n }\n});",
|
||||
],
|
||||
'addGlobalPed' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to all peds',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Option ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addGlobalPed({\n {\n name = 'talk',\n icon = 'fas fa-comment',\n label = 'Talk',\n onSelect = function(data)\n print('Talking to ped: '..data.entity)\n end\n }\n})",
|
||||
'js_example' => "const id = exports.ox_target.addGlobalPed([\n {\n name: 'talk',\n icon: 'fas fa-comment',\n label: 'Talk',\n onSelect: (data) => {\n console.log('Talking to ped: ' + data.entity);\n }\n }\n]);",
|
||||
],
|
||||
'addGlobalVehicle' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to all vehicles',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Option ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addGlobalVehicle({\n {\n name = 'lockpick',\n icon = 'fas fa-lock',\n label = 'Lockpick Vehicle',\n canInteract = function(entity)\n return GetVehicleDoorLockStatus(entity) == 2\n end,\n onSelect = function(data)\n -- Lockpick logic\n end\n }\n})",
|
||||
'js_example' => "const id = exports.ox_target.addGlobalVehicle([\n {\n name: 'lockpick',\n icon: 'fas fa-lock',\n label: 'Lockpick Vehicle',\n canInteract: (entity) => {\n return GetVehicleDoorLockStatus(entity) === 2;\n },\n onSelect: (data) => {\n // Lockpick logic\n }\n }\n]);",
|
||||
],
|
||||
'addGlobalObject' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to all objects',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Option ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addGlobalObject({\n {\n name = 'examine',\n icon = 'fas fa-search',\n label = 'Examine',\n onSelect = function(data)\n print('Examining object')\n end\n }\n})",
|
||||
'js_example' => "const id = exports.ox_target.addGlobalObject([\n {\n name: 'examine',\n icon: 'fas fa-search',\n label: 'Examine',\n onSelect: (data) => {\n console.log('Examining object');\n }\n }\n]);",
|
||||
],
|
||||
'addGlobalPlayer' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to all players',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Option ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addGlobalPlayer({\n {\n name = 'givemoney',\n icon = 'fas fa-dollar-sign',\n label = 'Give Money',\n onSelect = function(data)\n -- Give money logic\n end\n }\n})",
|
||||
'js_example' => "const id = exports.ox_target.addGlobalPlayer([\n {\n name: 'givemoney',\n icon: 'fas fa-dollar-sign',\n label: 'Give Money',\n onSelect: (data) => {\n // Give money logic\n }\n }\n]);",
|
||||
],
|
||||
'addModel' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to specific entity models',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'models', 'type' => 'string|table', 'description' => 'Model hash or array of model hashes'],
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Option ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addModel('prop_atm_01', {\n {\n name = 'atm',\n icon = 'fas fa-credit-card',\n label = 'Use ATM',\n onSelect = function()\n -- Open ATM interface\n end\n }\n})",
|
||||
'js_example' => "const id = exports.ox_target.addModel('prop_atm_01', [\n {\n name: 'atm',\n icon: 'fas fa-credit-card',\n label: 'Use ATM',\n onSelect: () => {\n // Open ATM interface\n }\n }\n]);",
|
||||
],
|
||||
'addEntity' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to a specific entity',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'entity', 'type' => 'number', 'description' => 'Entity handle'],
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => "local ped = PlayerPedId()\nexports.ox_target:addEntity(ped, {\n {\n name = 'selfie',\n icon = 'fas fa-camera',\n label = 'Take Selfie',\n onSelect = function()\n print('Taking selfie')\n end\n }\n})",
|
||||
'js_example' => "const ped = PlayerPedId();\nexports.ox_target.addEntity(ped, [\n {\n name: 'selfie',\n icon: 'fas fa-camera',\n label: 'Take Selfie',\n onSelect: () => {\n console.log('Taking selfie');\n }\n }\n]);",
|
||||
],
|
||||
'addLocalEntity' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add target options to a networked entity (client-side only)',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'netId', 'type' => 'number', 'description' => 'Network ID'],
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => "local netId = NetworkGetNetworkIdFromEntity(entity)\nexports.ox_target:addLocalEntity(netId, {\n {\n name = 'interact',\n icon = 'fas fa-hand',\n label = 'Interact',\n onSelect = function()\n print('Interacting')\n end\n }\n})",
|
||||
'js_example' => "const netId = NetworkGetNetworkIdFromEntity(entity);\nexports.ox_target.addLocalEntity(netId, [\n {\n name: 'interact',\n icon: 'fas fa-hand',\n label: 'Interact',\n onSelect: () => {\n console.log('Interacting');\n }\n }\n]);",
|
||||
],
|
||||
'addSphereZone' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add a sphere zone with target options',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'name', 'type' => 'string', 'description' => 'Unique zone name'],
|
||||
['name' => 'coords', 'type' => 'vector3', 'description' => 'Zone center coordinates'],
|
||||
['name' => 'radius', 'type' => 'number', 'description' => 'Zone radius'],
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
['name' => 'zoneOptions', 'type' => 'table', 'description' => 'Zone configuration'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Zone ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addSphereZone('bank_atm', vector3(150.0, -1040.0, 29.5), 2.0, {\n {\n name = 'atm',\n icon = 'fas fa-credit-card',\n label = 'Use ATM',\n onSelect = function()\n print('Opening ATM')\n end\n }\n}, {})",
|
||||
'js_example' => "const id = exports.ox_target.addSphereZone('bank_atm', [150.0, -1040.0, 29.5], 2.0, [\n {\n name: 'atm',\n icon: 'fas fa-credit-card',\n label: 'Use ATM',\n onSelect: () => {\n console.log('Opening ATM');\n }\n }\n], {});",
|
||||
],
|
||||
'addBoxZone' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add a box zone with target options',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'name', 'type' => 'string', 'description' => 'Unique zone name'],
|
||||
['name' => 'coords', 'type' => 'vector3', 'description' => 'Zone center coordinates'],
|
||||
['name' => 'size', 'type' => 'vector3', 'description' => 'Zone size (length, width, height)'],
|
||||
['name' => 'rotation', 'type' => 'number', 'description' => 'Zone rotation'],
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
['name' => 'zoneOptions', 'type' => 'table', 'description' => 'Zone configuration'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Zone ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addBoxZone('garage', vector3(215.0, -809.0, 30.7), vector3(5.0, 10.0, 3.0), 0, {\n {\n name = 'vehicles',\n icon = 'fas fa-car',\n label = 'Garage',\n onSelect = function()\n print('Opening garage')\n end\n }\n}, {})",
|
||||
'js_example' => "const id = exports.ox_target.addBoxZone('garage', [215.0, -809.0, 30.7], [5.0, 10.0, 3.0], 0, [\n {\n name: 'vehicles',\n icon: 'fas fa-car',\n label: 'Garage',\n onSelect: () => {\n console.log('Opening garage');\n }\n }\n], {});",
|
||||
],
|
||||
'addPolyZone' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Add a polygon zone with target options',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'name', 'type' => 'string', 'description' => 'Unique zone name'],
|
||||
['name' => 'points', 'type' => 'table', 'description' => 'Array of vector2 points'],
|
||||
['name' => 'options', 'type' => 'table', 'description' => 'Array of target options'],
|
||||
['name' => 'zoneOptions', 'type' => 'table', 'description' => 'Zone configuration'],
|
||||
],
|
||||
'returns' => ['type' => 'number', 'description' => 'Zone ID'],
|
||||
'lua_example' => "local id = exports.ox_target:addPolyZone('parking', {\n vector2(200.0, -800.0),\n vector2(220.0, -800.0),\n vector2(220.0, -820.0),\n vector2(200.0, -820.0)\n}, {\n {\n name = 'park',\n icon = 'fas fa-parking',\n label = 'Park Vehicle',\n onSelect = function()\n print('Parking vehicle')\n end\n }\n}, {})",
|
||||
'js_example' => "const id = exports.ox_target.addPolyZone('parking', [\n [200.0, -800.0],\n [220.0, -800.0],\n [220.0, -820.0],\n [200.0, -820.0]\n], [\n {\n name: 'park',\n icon: 'fas fa-parking',\n label: 'Park Vehicle',\n onSelect: () => {\n console.log('Parking vehicle');\n }\n }\n], {});",
|
||||
],
|
||||
'removeZone' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Remove a zone by ID',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'id', 'type' => 'number', 'description' => 'Zone ID to remove'],
|
||||
],
|
||||
'returns' => ['type' => 'void', 'description' => 'No return value'],
|
||||
'lua_example' => 'exports.ox_target:removeZone(zoneId)',
|
||||
'js_example' => 'exports.ox_target.removeZone(zoneId);',
|
||||
],
|
||||
'zoneExists' => [
|
||||
'namespace' => 'Client',
|
||||
'description' => 'Check if a zone exists by name',
|
||||
'side' => 'client',
|
||||
'parameters' => [
|
||||
['name' => 'name', 'type' => 'string', 'description' => 'Zone name'],
|
||||
],
|
||||
'returns' => ['type' => 'boolean', 'description' => 'true if zone exists'],
|
||||
'lua_example' => "local exists = exports.ox_target:zoneExists('bank_atm')\nif exists then\n print('Zone exists')\nend",
|
||||
'js_example' => "const exists = exports.ox_target.zoneExists('bank_atm');\nif (exists) {\n console.log('Zone exists');\n}",
|
||||
],
|
||||
];
|
||||
|
||||
$nameLower = strtolower($name);
|
||||
|
||||
foreach ($functions as $functionName => $functionData) {
|
||||
if (strtolower($functionName) === $nameLower) {
|
||||
return array_merge(['name' => $functionName], $functionData);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format function info.
|
||||
*/
|
||||
protected function formatFunctionInfo(array $function, string $language): string
|
||||
{
|
||||
return view('mcp.cox.cox-function', [
|
||||
'function' => $function,
|
||||
'language' => $language,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'function_name' => $schema
|
||||
->string()
|
||||
->description('The name of the ox_target client function to look up (e.g., "addSphereZone", "addGlobalVehicle", "addModel")')
|
||||
->required(),
|
||||
'language' => $schema
|
||||
->string()
|
||||
->enum(['lua', 'js'])
|
||||
->description('The scripting language for code examples')
|
||||
->default('lua'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\QBCore;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Get a complete list of all 58 documented QBCore resources with brief descriptions and categories.')]
|
||||
class GetQBCoreResourceList extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$category = $request->get('category');
|
||||
$resources = $this->getAllResources($category);
|
||||
|
||||
return Response::text($this->formatResourceList($resources));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all QBCore resources, optionally filtered by category.
|
||||
*/
|
||||
protected function getAllResources(?string $category = null): array
|
||||
{
|
||||
$allResources = [
|
||||
// Admin & Management
|
||||
'qb-adminmenu' => [
|
||||
'name' => 'qb-adminmenu',
|
||||
'title' => 'Admin Menu',
|
||||
'category' => 'Admin & Management',
|
||||
'description' => 'Admin panel for server management with player controls, moderation, warnings, and coordinate tools',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-adminmenu',
|
||||
],
|
||||
|
||||
// Jobs
|
||||
'qb-ambulancejob' => [
|
||||
'name' => 'qb-ambulancejob',
|
||||
'title' => 'Ambulance Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Medical job with hospital check-in, damage/bleeding system, and patient revival mechanics',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-ambulancejob',
|
||||
],
|
||||
'qb-busjob' => [
|
||||
'name' => 'qb-busjob',
|
||||
'title' => 'Bus Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Public transportation job for bus drivers with route and payment system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-busjob',
|
||||
],
|
||||
'qb-garbagejob' => [
|
||||
'name' => 'qb-garbagejob',
|
||||
'title' => 'Garbage Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Garbage collection job with pickup routes and payment system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-garbagejob',
|
||||
],
|
||||
'qb-hotdogjob' => [
|
||||
'name' => 'qb-hotdogjob',
|
||||
'title' => 'Hot Dog Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Hot dog stand vendor job with payment system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-hotdogjob',
|
||||
],
|
||||
'qb-mechanicjob' => [
|
||||
'name' => 'qb-mechanicjob',
|
||||
'title' => 'Mechanic Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Vehicle repair and customization job with parts system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-mechanicjob',
|
||||
],
|
||||
'qb-newsjob' => [
|
||||
'name' => 'qb-newsjob',
|
||||
'title' => 'News Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'News reporter job with interviews and broadcast system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-newsjob',
|
||||
],
|
||||
'qb-policejob' => [
|
||||
'name' => 'qb-policejob',
|
||||
'title' => 'Police Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Law enforcement job with dispatch, arrest, jailing, and evidence system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-policejob',
|
||||
],
|
||||
'qb-recyclejob' => [
|
||||
'name' => 'qb-recyclejob',
|
||||
'title' => 'Recycle Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Recycling center worker job with item pickup and crafting',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-recyclejob',
|
||||
],
|
||||
'qb-taxijob' => [
|
||||
'name' => 'qb-taxijob',
|
||||
'title' => 'Taxi Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Taxi driver job with passenger pickup and payment system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-taxijob',
|
||||
],
|
||||
'qb-towjob' => [
|
||||
'name' => 'qb-towjob',
|
||||
'title' => 'Tow Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Vehicle towing service with impound and payment system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-towjob',
|
||||
],
|
||||
'qb-truckerjob' => [
|
||||
'name' => 'qb-truckerjob',
|
||||
'title' => 'Trucker Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Long-haul trucking job with delivery routes and payment',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-truckerjob',
|
||||
],
|
||||
|
||||
// Crime & Robberies
|
||||
'qb-bankrobbery' => [
|
||||
'name' => 'qb-bankrobbery',
|
||||
'title' => 'Bank Robbery',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Heist job with thermal drill, hacking, and loot system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-bankrobbery',
|
||||
],
|
||||
'qb-drugs' => [
|
||||
'name' => 'qb-drugs',
|
||||
'title' => 'Drug Dealing',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Drug production and dealing system with supply and demand',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-drugs',
|
||||
],
|
||||
'qb-houserobbery' => [
|
||||
'name' => 'qb-houserobbery',
|
||||
'title' => 'House Robbery',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Residential burglary system with lockpicking and loot',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-houserobbery',
|
||||
],
|
||||
'qb-jewelry' => [
|
||||
'name' => 'qb-jewelry',
|
||||
'title' => 'Jewelry Store Robbery',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Jewelry store heist with thermite drill and loot system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-jewelry',
|
||||
],
|
||||
'qb-storerobbery' => [
|
||||
'name' => 'qb-storerobbery',
|
||||
'title' => 'Store Robbery',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Convenience store robbery with holdup mechanics',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-storerobbery',
|
||||
],
|
||||
'qb-truckrobbery' => [
|
||||
'name' => 'qb-truckrobbery',
|
||||
'title' => 'Truck Robbery',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Armored truck heist with combat and loot mechanics',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-truckrobbery',
|
||||
],
|
||||
'qb-weed' => [
|
||||
'name' => 'qb-weed',
|
||||
'title' => 'Weed Growing',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Marijuana cultivation and harvesting system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-weed',
|
||||
],
|
||||
'qb-vineyard' => [
|
||||
'name' => 'qb-vineyard',
|
||||
'title' => 'Vineyard',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Grape harvesting and wine production system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-vineyard',
|
||||
],
|
||||
|
||||
// Housing & Interiors
|
||||
'qb-apartments' => [
|
||||
'name' => 'qb-apartments',
|
||||
'title' => 'Apartments',
|
||||
'category' => 'Housing & Interiors',
|
||||
'description' => 'Player apartment rental and management system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-apartments',
|
||||
],
|
||||
'qb-houses' => [
|
||||
'name' => 'qb-houses',
|
||||
'title' => 'Houses',
|
||||
'category' => 'Housing & Interiors',
|
||||
'description' => 'Player house ownership with storage and customization',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-houses',
|
||||
],
|
||||
'qb-interior' => [
|
||||
'name' => 'qb-interior',
|
||||
'title' => 'Interior',
|
||||
'category' => 'Housing & Interiors',
|
||||
'description' => 'Interior world system for building custom rooms',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-interior',
|
||||
],
|
||||
|
||||
// Vehicles & Transportation
|
||||
'qb-garages' => [
|
||||
'name' => 'qb-garages',
|
||||
'title' => 'Garages',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Vehicle parking and retrieval system with multiple garages',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-garages',
|
||||
],
|
||||
'qb-vehiclekeys' => [
|
||||
'name' => 'qb-vehiclekeys',
|
||||
'title' => 'Vehicle Keys',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Vehicle ownership and key distribution system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-vehiclekeys',
|
||||
],
|
||||
'qb-vehiclesales' => [
|
||||
'name' => 'qb-vehiclesales',
|
||||
'title' => 'Vehicle Sales',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Vehicle dealership system for buying and trading vehicles',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-vehiclesales',
|
||||
],
|
||||
'qb-vehicleshop' => [
|
||||
'name' => 'qb-vehicleshop',
|
||||
'title' => 'Vehicle Shop',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Show room for purchasing new vehicles',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-vehicleshop',
|
||||
],
|
||||
'qb-fuel' => [
|
||||
'name' => 'qb-fuel',
|
||||
'title' => 'Fuel System',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Vehicle fueling system with gas stations',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-fuel',
|
||||
],
|
||||
|
||||
// Commerce & Markets
|
||||
'qb-banking' => [
|
||||
'name' => 'qb-banking',
|
||||
'title' => 'Banking',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Bank account system with deposits, withdrawals, and transfers',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-banking',
|
||||
],
|
||||
'qb-cityhall' => [
|
||||
'name' => 'qb-cityhall',
|
||||
'title' => 'City Hall',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Government records and ID system for players',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-cityhall',
|
||||
],
|
||||
'qb-clothing' => [
|
||||
'name' => 'qb-clothing',
|
||||
'title' => 'Clothing Shop',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Clothing store system for outfit customization',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-clothing',
|
||||
],
|
||||
'qb-crypto' => [
|
||||
'name' => 'qb-crypto',
|
||||
'title' => 'Cryptocurrency',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Cryptocurrency trading platform system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-crypto',
|
||||
],
|
||||
'qb-pawnshop' => [
|
||||
'name' => 'qb-pawnshop',
|
||||
'title' => 'Pawn Shop',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Pawn shop for selling and buying items',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-pawnshop',
|
||||
],
|
||||
'qb-shops' => [
|
||||
'name' => 'qb-shops',
|
||||
'title' => 'Shops',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'General-purpose shop system for generic stores',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-shops',
|
||||
],
|
||||
|
||||
// Player Systems
|
||||
'qb-inventory' => [
|
||||
'name' => 'qb-inventory',
|
||||
'title' => 'Inventory',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Player item inventory management system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-inventory',
|
||||
],
|
||||
'qb-management' => [
|
||||
'name' => 'qb-management',
|
||||
'title' => 'Management',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Org/faction/job management system for player hierarchies',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-management',
|
||||
],
|
||||
'qb-multicharacter' => [
|
||||
'name' => 'qb-multicharacter',
|
||||
'title' => 'Multi-Character',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Multiple character selection and management on login',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-multicharacter',
|
||||
],
|
||||
'qb-phone' => [
|
||||
'name' => 'qb-phone',
|
||||
'title' => 'Phone',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'In-game phone system with apps, messages, and calls',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-phone',
|
||||
],
|
||||
'qb-prison' => [
|
||||
'name' => 'qb-prison',
|
||||
'title' => 'Prison',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Prison system for jailed players with tasks and release',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-prison',
|
||||
],
|
||||
'qb-spawn' => [
|
||||
'name' => 'qb-spawn',
|
||||
'title' => 'Spawn',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Initial spawn location selector for new players',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-spawn',
|
||||
],
|
||||
'qb-fitbit' => [
|
||||
'name' => 'qb-fitbit',
|
||||
'title' => 'Fitbit',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Health and fitness tracking wearable device',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-fitbit',
|
||||
],
|
||||
|
||||
// UI & Interface
|
||||
'qb-hud' => [
|
||||
'name' => 'qb-hud',
|
||||
'title' => 'HUD',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Main heads-up display for player information',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-hud',
|
||||
],
|
||||
'qb-input' => [
|
||||
'name' => 'qb-input',
|
||||
'title' => 'Input',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Generic input dialog system for NUI popups',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-input',
|
||||
],
|
||||
'qb-loading' => [
|
||||
'name' => 'qb-loading',
|
||||
'title' => 'Loading Screen',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Animated loading screen on server startup',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-loading',
|
||||
],
|
||||
'qb-menu' => [
|
||||
'name' => 'qb-menu',
|
||||
'title' => 'Menu',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Simple menu UI system for player interactions',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-menu',
|
||||
],
|
||||
'qb-radialmenu' => [
|
||||
'name' => 'qb-radialmenu',
|
||||
'title' => 'Radial Menu',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Radial/circular menu interface for quick selections',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-radialmenu',
|
||||
],
|
||||
'qb-scoreboard' => [
|
||||
'name' => 'qb-scoreboard',
|
||||
'title' => 'Scoreboard',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Server player list and information scoreboard',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-scoreboard',
|
||||
],
|
||||
'qb-target' => [
|
||||
'name' => 'qb-target',
|
||||
'title' => 'Target System',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'NPC and object targeting system for interactions',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-target',
|
||||
],
|
||||
|
||||
// Entertainment & Activities
|
||||
'qb-diving' => [
|
||||
'name' => 'qb-diving',
|
||||
'title' => 'Diving',
|
||||
'category' => 'Entertainment & Activities',
|
||||
'description' => 'Underwater treasure hunting activity',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-diving',
|
||||
],
|
||||
'qb-lapraces' => [
|
||||
'name' => 'qb-lapraces',
|
||||
'title' => 'Lap Races',
|
||||
'category' => 'Entertainment & Activities',
|
||||
'description' => 'Racing competition system with lap tracking',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-lapraces',
|
||||
],
|
||||
'qb-minigames' => [
|
||||
'name' => 'qb-minigames',
|
||||
'title' => 'Minigames',
|
||||
'category' => 'Entertainment & Activities',
|
||||
'description' => 'Collection of minigames for lockpicking, hacking, etc.',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-minigames',
|
||||
],
|
||||
'qb-radio' => [
|
||||
'name' => 'qb-radio',
|
||||
'title' => 'Radio',
|
||||
'category' => 'Entertainment & Activities',
|
||||
'description' => 'In-vehicle or ambient radio station system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-radio',
|
||||
],
|
||||
'qb-streetraces' => [
|
||||
'name' => 'qb-streetraces',
|
||||
'title' => 'Street Races',
|
||||
'category' => 'Entertainment & Activities',
|
||||
'description' => 'Street racing event system with records',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-streetraces',
|
||||
],
|
||||
|
||||
// Utilities & Miscellaneous
|
||||
'qb-doorlock' => [
|
||||
'name' => 'qb-doorlock',
|
||||
'title' => 'Door Lock',
|
||||
'category' => 'Utilities & Miscellaneous',
|
||||
'description' => 'Door locking system with access control',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-doorlock',
|
||||
],
|
||||
'qb-scrapyard' => [
|
||||
'name' => 'qb-scrapyard',
|
||||
'title' => 'Scrap Yard',
|
||||
'category' => 'Utilities & Miscellaneous',
|
||||
'description' => 'Vehicle scrapping system for parts and money',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-scrapyard',
|
||||
],
|
||||
'qb-smallresources' => [
|
||||
'name' => 'qb-smallresources',
|
||||
'title' => 'Small Resources',
|
||||
'category' => 'Utilities & Miscellaneous',
|
||||
'description' => 'Bundle of small utility resources for various features',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-smallresources',
|
||||
],
|
||||
'qb-weapons' => [
|
||||
'name' => 'qb-weapons',
|
||||
'title' => 'Weapons',
|
||||
'category' => 'Utilities & Miscellaneous',
|
||||
'description' => 'Weapon shop and ammo purchasing system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-weapons',
|
||||
],
|
||||
'qb-weathersync' => [
|
||||
'name' => 'qb-weathersync',
|
||||
'title' => 'Weather Sync',
|
||||
'category' => 'Utilities & Miscellaneous',
|
||||
'description' => 'Server-wide weather synchronization system',
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-weathersync',
|
||||
],
|
||||
];
|
||||
|
||||
if ($category) {
|
||||
return array_filter($allResources, fn ($r) => strtolower($r['category']) === strtolower($category));
|
||||
}
|
||||
|
||||
return $allResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the resource list.
|
||||
*/
|
||||
protected function formatResourceList(array $resources): string
|
||||
{
|
||||
return view('mcp.qbcore.qbcore-resource-list', [
|
||||
'resources' => $resources,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'category' => $schema
|
||||
->string()
|
||||
->description('Optional: Filter resources by category (Admin & Management, Jobs, Crime & Robberies, Housing & Interiors, Vehicles & Transportation, Commerce & Markets, Player Systems, UI & Interface, Entertainment & Activities, Utilities & Miscellaneous)')
|
||||
->enum([
|
||||
'Admin & Management',
|
||||
'Jobs',
|
||||
'Crime & Robberies',
|
||||
'Housing & Interiors',
|
||||
'Vehicles & Transportation',
|
||||
'Commerce & Markets',
|
||||
'Player Systems',
|
||||
'UI & Interface',
|
||||
'Entertainment & Activities',
|
||||
'Utilities & Miscellaneous',
|
||||
]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mcp\Tools\QBCore;
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
#[Description('Get detailed documentation for a specific QBCore resource. Returns information about configuration, commands, events, callbacks, and usage examples.')]
|
||||
class GetQBCoreResourceReference extends Tool
|
||||
{
|
||||
/**
|
||||
* Handle the tool request.
|
||||
*/
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
$resourceName = $request->get('resource_name');
|
||||
|
||||
$resource = $this->findResource($resourceName);
|
||||
|
||||
if (! $resource) {
|
||||
return Response::text(sprintf("QBCore resource '%s' not found. Use GetQBCoreResourceList to see all available resources.", $resourceName));
|
||||
}
|
||||
|
||||
return Response::text($this->formatResourceReference($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a QBCore resource by name.
|
||||
*/
|
||||
protected function findResource(string $name): ?array
|
||||
{
|
||||
$resources = [
|
||||
'qb-adminmenu' => [
|
||||
'name' => 'qb-adminmenu',
|
||||
'title' => 'Admin Menu',
|
||||
'category' => 'Admin & Management',
|
||||
'description' => 'Admin panel for server management and player moderation.',
|
||||
'features' => ['Player Management', 'Moderation', 'Coordinate Tools', 'Announcements', 'Reports', 'Warnings'],
|
||||
'commands' => [
|
||||
'/admin' => 'Opens the admin menu',
|
||||
'/blips' => 'Toggles player blips',
|
||||
'/names' => 'Toggles player names display',
|
||||
'/coords' => 'Shows your current coordinates',
|
||||
'/maxmods' => 'Sets vehicle to max mods',
|
||||
'/noclip' => 'Toggles noclip mode',
|
||||
'/admincar' => 'Adds current vehicle to garage',
|
||||
'/announce [message]' => 'Creates an announcement',
|
||||
'/report [message]' => 'Create a report to staff',
|
||||
'/reportr [message]' => 'Replies to a user report',
|
||||
'/reporttoggle' => 'Opt in/out of receiving player reports',
|
||||
'/staffchat [message]' => 'Sends a staff-only message',
|
||||
'/warn [id] [reason]' => 'Warn a player',
|
||||
'/checkwarns [id] [opt: number]' => 'View warnings for a player',
|
||||
'/delwarn [id] [number]' => 'Delete a warning from a player',
|
||||
'/givenuifocus [id] [hasFocus] [hasCursor]' => 'Sets nuifocus state for player',
|
||||
'/setmodel [model] [id]' => 'Changes the players ped model',
|
||||
'/setspeed [opt: speed]' => 'Sets players foot speed',
|
||||
'/kickall' => 'Kick all players from server',
|
||||
'/setammo [amount] [opt: weapon]' => 'Set weapon ammo',
|
||||
'/vector2' => 'Copies vector2 to clipboard',
|
||||
'/vector3' => 'Copies vector3 to clipboard',
|
||||
'/vector4' => 'Copies vector4 to clipboard',
|
||||
'/heading' => 'Copies heading to clipboard',
|
||||
],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-adminmenu',
|
||||
],
|
||||
|
||||
'qb-ambulancejob' => [
|
||||
'name' => 'qb-ambulancejob',
|
||||
'title' => 'Ambulance Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Medical job with hospital check-in system, damage/bleeding mechanics, and patient revival.',
|
||||
'features' => ['Hospital Check-in System', 'Damage Tracking', 'Bleeding System', 'Patient Revival', 'Job Shop', 'Vehicle Spawner'],
|
||||
'commands' => [
|
||||
'/911e [message]' => 'Sends a message to EMS',
|
||||
'/status' => 'Check the status of the nearest player',
|
||||
'/heal' => 'Heals the nearest player',
|
||||
'/revivep' => 'Revives the nearest player',
|
||||
'/revive' => 'Revive yourself',
|
||||
'/setpain [opt: id]' => 'Sets the pain level',
|
||||
'/kill [opt: id]' => 'Kills the player',
|
||||
'/aheal [opt: id]' => 'Heals a player',
|
||||
],
|
||||
'items' => [
|
||||
'ifaks' => 'Relieves player stress and heals them by +10',
|
||||
'bandage' => 'Heals player by +10 and has 50% chance of removing 1 level of bleeding',
|
||||
'firstaid' => 'Completely heals closest player as long as they are in last-stand',
|
||||
'painkillers' => 'Stops bleeding temporarily but wears off over time',
|
||||
],
|
||||
'events' => [
|
||||
'hospital:server:SetDeathStatus' => 'Modify the players isdead metadata',
|
||||
'hospital:server:SetLaststandStatus' => 'Modify the players inlaststand metadata',
|
||||
'hospital:server:ambulanceAlert' => 'Send a notification to all EMTs',
|
||||
'hospital:server:RevivePlayer' => 'Revive a player for free or a fee',
|
||||
],
|
||||
'callbacks' => [
|
||||
'hospital:GetDoctors' => 'Returns the number of players online with the ambulance job',
|
||||
],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-ambulancejob',
|
||||
],
|
||||
|
||||
'qb-banking' => [
|
||||
'name' => 'qb-banking',
|
||||
'title' => 'Banking',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Bank account system with deposits, withdrawals, and transfers between players.',
|
||||
'features' => ['Account Management', 'Money Transfer', 'Transaction History', 'ATM Withdrawals'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-banking',
|
||||
],
|
||||
|
||||
'qb-inventory' => [
|
||||
'name' => 'qb-inventory',
|
||||
'title' => 'Inventory',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Player item inventory management system with weight-based limits.',
|
||||
'features' => ['Item Management', 'Weight Limits', 'Inventory UI', 'Drop Items', 'Trade Items'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-inventory',
|
||||
],
|
||||
|
||||
'qb-phone' => [
|
||||
'name' => 'qb-phone',
|
||||
'title' => 'Phone',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'In-game phone system with apps, messages, calls, and notifications.',
|
||||
'features' => ['Messaging', 'Phone Calls', 'Apps System', 'Contacts', 'Photos', 'Radio'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-phone',
|
||||
],
|
||||
|
||||
'qb-policejob' => [
|
||||
'name' => 'qb-policejob',
|
||||
'title' => 'Police Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Law enforcement job with dispatch, arrest, jailing, and evidence system.',
|
||||
'features' => ['Dispatch System', 'Arrests', 'Jail Management', 'Evidence Collection', 'Vehicle Impound'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-policejob',
|
||||
],
|
||||
|
||||
'qb-garages' => [
|
||||
'name' => 'qb-garages',
|
||||
'title' => 'Garages',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Vehicle parking and retrieval system with multiple garage locations.',
|
||||
'features' => ['Multiple Garages', 'Vehicle Storage', 'Quick Parking', 'Vehicle Retrieval'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-garages',
|
||||
],
|
||||
|
||||
'qb-shops' => [
|
||||
'name' => 'qb-shops',
|
||||
'title' => 'Shops',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'General-purpose shop system for creating generic stores.',
|
||||
'features' => ['Shop Creation', 'Item Pricing', 'Purchase System', 'Multiple Locations'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-shops',
|
||||
],
|
||||
|
||||
'qb-target' => [
|
||||
'name' => 'qb-target',
|
||||
'title' => 'Target System',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'NPC and object targeting system for player interactions.',
|
||||
'features' => ['Click Targeting', 'NPC Interaction', 'Object Targeting', 'Distance Based'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-target',
|
||||
],
|
||||
|
||||
'qb-hud' => [
|
||||
'name' => 'qb-hud',
|
||||
'title' => 'HUD',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Main heads-up display showing player information and status.',
|
||||
'features' => ['Health Display', 'Armor Display', 'Hunger/Thirst', 'Stress Level', 'Mini Map'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-hud',
|
||||
],
|
||||
|
||||
'qb-doorlock' => [
|
||||
'name' => 'qb-doorlock',
|
||||
'title' => 'Door Lock',
|
||||
'category' => 'Utilities & Miscellaneous',
|
||||
'description' => 'Door locking system with access control and permissions.',
|
||||
'features' => ['Door Locking', 'Access Control', 'Job Locks', 'Gang Locks'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-doorlock',
|
||||
],
|
||||
|
||||
'qb-mechanicjob' => [
|
||||
'name' => 'qb-mechanicjob',
|
||||
'title' => 'Mechanic Job',
|
||||
'category' => 'Jobs',
|
||||
'description' => 'Vehicle repair and customization job with parts system.',
|
||||
'features' => ['Vehicle Repair', 'Vehicle Customization', 'Parts Management', 'Customer Jobs'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-mechanicjob',
|
||||
],
|
||||
|
||||
'qb-housing' => [
|
||||
'name' => 'qb-houses',
|
||||
'title' => 'Houses',
|
||||
'category' => 'Housing & Interiors',
|
||||
'description' => 'Player house ownership with storage and customization.',
|
||||
'features' => ['House Purchase', 'House Storage', 'Furniture Customization', 'Multi-Garage'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-houses',
|
||||
],
|
||||
|
||||
'qb-prison' => [
|
||||
'name' => 'qb-prison',
|
||||
'title' => 'Prison',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Prison system for jailed players with tasks and release.',
|
||||
'features' => ['Jailing System', 'Prison Jobs', 'Release System', 'Time Tracking'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-prison',
|
||||
],
|
||||
|
||||
'qb-bankrobbery' => [
|
||||
'name' => 'qb-bankrobbery',
|
||||
'title' => 'Bank Robbery',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Heist job with thermal drill, hacking, and loot system.',
|
||||
'features' => ['Thermal Drill', 'Hacking Minigame', 'Loot System', 'Police Alerts'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-bankrobbery',
|
||||
],
|
||||
|
||||
'qb-drugs' => [
|
||||
'name' => 'qb-drugs',
|
||||
'title' => 'Drug Dealing',
|
||||
'category' => 'Crime & Robberies',
|
||||
'description' => 'Drug production and dealing system with supply and demand.',
|
||||
'features' => ['Drug Production', 'Dealing Mechanics', 'Supply/Demand', 'Dealer Routes'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-drugs',
|
||||
],
|
||||
|
||||
'qb-fuel' => [
|
||||
'name' => 'qb-fuel',
|
||||
'title' => 'Fuel System',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Vehicle fueling system with gas stations.',
|
||||
'features' => ['Gas Stations', 'Fuel Usage', 'Cost Calculation', 'Player Jobs'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-fuel',
|
||||
],
|
||||
|
||||
'qb-multicharacter' => [
|
||||
'name' => 'qb-multicharacter',
|
||||
'title' => 'Multi-Character',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Multiple character selection and management on login.',
|
||||
'features' => ['Character Creation', 'Character Selection', 'Character Deletion'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-multicharacter',
|
||||
],
|
||||
|
||||
'qb-clothing' => [
|
||||
'name' => 'qb-clothing',
|
||||
'title' => 'Clothing Shop',
|
||||
'category' => 'Commerce & Markets',
|
||||
'description' => 'Clothing store system for outfit customization.',
|
||||
'features' => ['Outfit Customization', 'Clothing Purchase', 'Clothing Categories'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-clothing',
|
||||
],
|
||||
|
||||
'qb-vehicleshop' => [
|
||||
'name' => 'qb-vehicleshop',
|
||||
'title' => 'Vehicle Shop',
|
||||
'category' => 'Vehicles & Transportation',
|
||||
'description' => 'Show room for purchasing new vehicles.',
|
||||
'features' => ['Vehicle Showcase', 'Vehicle Purchase', 'Test Drive'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-vehicleshop',
|
||||
],
|
||||
|
||||
'qb-input' => [
|
||||
'name' => 'qb-input',
|
||||
'title' => 'Input',
|
||||
'category' => 'UI & Interface',
|
||||
'description' => 'Generic input dialog system for NUI popups.',
|
||||
'features' => ['Text Input', 'Number Input', 'Validation', 'Custom Styling'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-input',
|
||||
],
|
||||
|
||||
'qb-manage' => [
|
||||
'name' => 'qb-management',
|
||||
'title' => 'Management',
|
||||
'category' => 'Player Systems',
|
||||
'description' => 'Org/faction/job management for player hierarchies.',
|
||||
'features' => ['Rank Management', 'Member Management', 'Permission Control'],
|
||||
'url' => 'https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-management',
|
||||
],
|
||||
];
|
||||
|
||||
// Normalize the resource name for matching
|
||||
$normalized = strtolower(str_replace(['_', ' '], '-', $name));
|
||||
// Remove any prefix variations and ensure qb- prefix
|
||||
$normalized = preg_replace('/^(qbcore[-_]?)?/i', '', $normalized);
|
||||
$normalized = 'qb-'.ltrim($normalized, 'qb-');
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
if (strtolower($resource['name']) === $normalized) {
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the resource reference.
|
||||
*/
|
||||
protected function formatResourceReference(array $resource): string
|
||||
{
|
||||
return view('mcp.qbcore.qbcore-resource-reference', [
|
||||
'resource' => $resource,
|
||||
])->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool's input schema.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\JsonSchema\JsonSchema>
|
||||
*/
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'resource_name' => $schema
|
||||
->string()
|
||||
->description('The name of the QBCore resource to look up (e.g., qb-ambulancejob, qb-adminmenu, qb-inventory)')
|
||||
->required(),
|
||||
];
|
||||
}
|
||||
}
|
||||
+101
-47
@@ -8,64 +8,118 @@
|
||||
@theme {
|
||||
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
--color-gta-dark: #1a1a1a;
|
||||
--color-gta-light: #f8fafc;
|
||||
--color-gta-orange: #f57c00;
|
||||
--color-gta-cyan: #1de9b6;
|
||||
--color-gta-gray: #334155;
|
||||
--color-gta-indigo: #3b82f6;
|
||||
|
||||
.tab-content {
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
--color-gray-50: #f8fafc;
|
||||
--color-gray-100: #f1f5f9;
|
||||
--color-gray-200: #e2e8f0;
|
||||
--color-gray-300: #cbd5e1;
|
||||
--color-gray-400: #94a3b8;
|
||||
--color-gray-500: #64748b;
|
||||
--color-gray-600: #475569;
|
||||
--color-gray-700: #334155;
|
||||
--color-gray-800: #1e293b;
|
||||
--color-gray-900: #0f172a;
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
--color-indigo-50: #fff7ed;
|
||||
--color-indigo-100: #ffedd5;
|
||||
--color-indigo-200: #fed7aa;
|
||||
--color-indigo-300: #fdba74;
|
||||
--color-indigo-400: #fb923c;
|
||||
--color-indigo-500: #f57c00;
|
||||
--color-indigo-600: #ea580c;
|
||||
--color-indigo-700: #c2410c;
|
||||
--color-indigo-800: #9a3412;
|
||||
--color-indigo-900: #7c2d12;
|
||||
|
||||
--animate-fade-in: fade-in 0.3s ease-in-out;
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.code-block-wrapper {
|
||||
position: relative;
|
||||
@layer base {
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-gray-50 text-gray-900 dark:bg-gray-900 dark:text-gray-100;
|
||||
}
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
background-color: rgba(55, 65, 81, 0.8);
|
||||
color: white;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: all 0.2s ease-in-out;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
@layer utilities {
|
||||
.text-gta-neon {
|
||||
color: var(--color-gta-cyan);
|
||||
}
|
||||
|
||||
.text-gta-orange {
|
||||
color: var(--color-gta-orange);
|
||||
}
|
||||
|
||||
.bg-gta-neon {
|
||||
background-color: var(--color-gta-cyan);
|
||||
}
|
||||
|
||||
.bg-gta-orange {
|
||||
background-color: var(--color-gta-orange);
|
||||
}
|
||||
|
||||
.border-gta-neon {
|
||||
border-color: var(--color-gta-cyan);
|
||||
}
|
||||
|
||||
.border-gta-orange {
|
||||
border-color: var(--color-gta-orange);
|
||||
}
|
||||
}
|
||||
|
||||
.code-block-wrapper:hover .copy-button {
|
||||
opacity: 1;
|
||||
}
|
||||
@layer components {
|
||||
.link-gta {
|
||||
color: var(--color-gta-cyan);
|
||||
transition: color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background-color: rgba(55, 65, 81, 1);
|
||||
}
|
||||
.link-gta:hover {
|
||||
color: #6ee7b7;
|
||||
}
|
||||
|
||||
.copy-button.copied {
|
||||
background-color: rgba(16, 185, 129, 0.9);
|
||||
border-color: rgba(16, 185, 129, 1);
|
||||
}
|
||||
.btn-gta-primary {
|
||||
background-color: var(--color-gta-orange);
|
||||
color: #ffffff;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.copy-button svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
.btn-gta-primary:hover {
|
||||
background-color: #ea580c;
|
||||
}
|
||||
|
||||
.btn-gta-secondary {
|
||||
background-color: transparent;
|
||||
color: var(--color-gta-cyan);
|
||||
border: 1px solid var(--color-gta-cyan);
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.btn-gta-secondary:hover {
|
||||
background-color: color-mix(in oklab, var(--color-gta-cyan) 16%, transparent);
|
||||
}
|
||||
}
|
||||
+42
-7
@@ -4,16 +4,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const codeBlocks = document.querySelectorAll('pre');
|
||||
|
||||
codeBlocks.forEach((pre) => {
|
||||
if (!pre.parentElement.classList.contains('code-block-wrapper')) {
|
||||
if (!pre.parentElement.classList.contains('relative')) {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'code-block-wrapper';
|
||||
wrapper.className = 'relative group';
|
||||
pre.parentNode.insertBefore(wrapper, pre);
|
||||
wrapper.appendChild(pre);
|
||||
}
|
||||
|
||||
const wrapper = pre.parentElement;
|
||||
const copyButton = document.createElement('button');
|
||||
copyButton.className = 'copy-button';
|
||||
copyButton.className = 'absolute top-2 right-2 px-3 py-1.5 bg-gray-700/80 text-white border border-white/20 rounded-md text-xs font-medium cursor-pointer opacity-0 group-hover:opacity-100 transition-all duration-200 ease-in-out flex items-center gap-1 hover:bg-gray-700';
|
||||
copyButton.innerHTML = `<svg class="copy-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg> <span class="copy-text">Copy</span>`;
|
||||
|
||||
copyButton.addEventListener('click', () => {
|
||||
@@ -21,12 +21,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const text = code ? code.textContent : pre.textContent;
|
||||
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
copyButton.classList.add('copied');
|
||||
copyButton.innerHTML = `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> <span>Copied!</span>`;
|
||||
copyButton.classList.remove('bg-gray-700/80', 'border-white/20', 'hover:bg-gray-700');
|
||||
copyButton.classList.add('!bg-emerald-500/90', 'border-emerald-500');
|
||||
copyButton.innerHTML = `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> <span>Copied!</span>`;
|
||||
|
||||
setTimeout(() => {
|
||||
copyButton.classList.remove('copied');
|
||||
copyButton.innerHTML = `<svg class="copy-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg><span class="copy-text">Copy</span>`;
|
||||
copyButton.classList.add('bg-gray-700/80', 'border-white/20', 'hover:bg-gray-700');
|
||||
copyButton.classList.remove('!bg-emerald-500/90', 'border-emerald-500');
|
||||
copyButton.innerHTML = `<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg><span class="copy-text">Copy</span>`;
|
||||
}, 2000);
|
||||
}).catch((err) => {
|
||||
console.error('Failed to copy:', err);
|
||||
@@ -35,4 +37,37 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
wrapper.appendChild(copyButton);
|
||||
});
|
||||
|
||||
// Tab switching functionality
|
||||
const tabButtons = document.querySelectorAll('[data-tab]');
|
||||
const tabContents = document.querySelectorAll('[data-tab-content]');
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
const targetTab = this.dataset.tab;
|
||||
|
||||
// Remove active class from all buttons
|
||||
tabButtons.forEach(btn => {
|
||||
btn.classList.remove('active', 'border-gta-orange', 'text-gta-orange');
|
||||
btn.classList.add('border-transparent', 'text-gray-500', 'dark:text-gray-400');
|
||||
});
|
||||
|
||||
// Add active class to clicked button
|
||||
this.classList.remove('border-transparent', 'text-gray-500', 'dark:text-gray-400');
|
||||
this.classList.add('active', 'border-gta-orange', 'text-gta-orange');
|
||||
|
||||
// Hide all tab contents
|
||||
tabContents.forEach(content => {
|
||||
content.classList.add('hidden');
|
||||
content.classList.remove('active');
|
||||
});
|
||||
|
||||
// Show target tab content
|
||||
const targetContent = document.querySelector(`[data-tab-content="${targetTab}"]`);
|
||||
if (targetContent) {
|
||||
targetContent.classList.remove('hidden');
|
||||
targetContent.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,591 +1,366 @@
|
||||
@extends('docs.layout')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Full Documentation - FiveM MCP Server')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-5xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-white shadow rounded-lg p-8">
|
||||
<h1 class="text-3xl font-extrabold text-gray-900 mb-6">FiveM Development MCP Server</h1>
|
||||
<div class="max-w-5xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-8">
|
||||
<h1 class="text-3xl font-extrabold text-gray-900 dark:text-white mb-6">FiveM Development MCP Server</h1>
|
||||
|
||||
<p class="text-lg text-gray-700 mb-8">
|
||||
A comprehensive Model Context Protocol (MCP) server for FiveM (GTA5) development, built with Laravel MCP.
|
||||
This server provides AI assistants with powerful tools to help you develop FiveM resources more efficiently.
|
||||
</p>
|
||||
<p class="text-lg text-gray-700 dark:text-gray-300 mb-8">
|
||||
A comprehensive Model Context Protocol (MCP) server for FiveM (GTA5) development, built with Laravel MCP.
|
||||
This server provides AI assistants with powerful tools to help you develop FiveM resources more efficiently.
|
||||
</p>
|
||||
|
||||
<!-- Installation -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Installation & Connection</h2>
|
||||
<p class="text-gray-700 mb-6">Choose how you want to connect to the FiveM MCP server:</p>
|
||||
<!-- Installation -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Installation & Connection</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-6">Choose how you want to connect to the FiveM MCP server:</p>
|
||||
|
||||
<!-- Tab Buttons -->
|
||||
<div class="border-b border-gray-200 mb-6">
|
||||
<nav class="-mb-px flex space-x-8">
|
||||
<button
|
||||
data-tab="remote"
|
||||
class="tab-button active border-b-2 border-indigo-500 py-4 px-1 text-center text-sm font-medium text-indigo-600"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">🌐</span>
|
||||
Remote Server
|
||||
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">
|
||||
Recommended
|
||||
</span>
|
||||
<!-- Tab Buttons -->
|
||||
<div class="border-b border-gray-200 dark:border-gray-700 mb-6">
|
||||
<nav class="-mb-px flex space-x-8">
|
||||
<button data-tab="remote"
|
||||
class="transition-all duration-200 ease-in-out active border-b-2 border-gta-orange py-4 px-1 text-center text-sm font-medium text-gta-orange">
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">🌐</span>
|
||||
Remote Server
|
||||
<span
|
||||
class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-700 border border-gta-orange text-gta-orange">
|
||||
Recommended
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
data-tab="local"
|
||||
class="tab-button border-b-2 border-transparent py-4 px-1 text-center text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💻</span>
|
||||
Local Installation
|
||||
</span>
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
<button data-tab="local"
|
||||
class="transition-all duration-200 ease-in-out border-b-2 border-transparent py-4 px-1 text-center text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-600">
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💻</span>
|
||||
Local Installation
|
||||
</span>
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content Container -->
|
||||
<div class="tab-content-container">
|
||||
<!-- Remote Server Option -->
|
||||
<div data-tab-content="remote" class="tab-content active">
|
||||
<div class="bg-indigo-50 border-l-4 border-indigo-500 p-6">
|
||||
<p class="text-gray-700 mb-4">
|
||||
<strong>Easy setup!</strong> Connect to a hosted MCP server. This is the easiest option and works from anywhere without any local setup.
|
||||
</p>
|
||||
<!-- Tab Content Container -->
|
||||
<div class="tab-content-container">
|
||||
<!-- Remote Server Option -->
|
||||
<div data-tab-content="remote" class="animate-fade-in active">
|
||||
<div class="bg-gray-100 dark:bg-gray-700/30 border-l-4 border-gta-orange p-6">
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">
|
||||
<strong>Easy setup!</strong> Connect to a hosted MCP server. This is the easiest option and
|
||||
works from anywhere without any local setup.
|
||||
</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Claude Desktop Configuration:</h4>
|
||||
<p class="text-gray-700 mb-3">Edit your configuration file:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-3 ml-4">
|
||||
<li><strong>macOS:</strong> <code class="bg-gray-100 px-2 py-1 rounded text-sm">~/Library/Application Support/Claude/claude_desktop_config.json</code></li>
|
||||
<li><strong>Windows:</strong> <code class="bg-gray-100 px-2 py-1 rounded text-sm">%APPDATA%\Claude\claude_desktop_config.json</code></li>
|
||||
</ul>
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Claude Desktop Configuration:</h4>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Edit your configuration file:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 mb-3 ml-4">
|
||||
<li><strong>macOS:</strong> <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">~/Library/Application Support/Claude/claude_desktop_config.json</code>
|
||||
</li>
|
||||
<li><strong>Windows:</strong> <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">%APPDATA%\Claude\claude_desktop_config.json</code>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="text-gray-700 mb-3">Add this configuration (replace with your actual server URL):</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<h4 class="font-semibold text-gray-900 mb-2">VSCode Configuration (Cline Extension):</h4>
|
||||
<p class="text-gray-700 mb-3">If using VSCode with the Cline extension, edit your settings:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-3 ml-4">
|
||||
<li>Open VSCode Settings (JSON)</li>
|
||||
<li>Add to your global or workspace <code class="bg-gray-100 px-2 py-1 rounded text-sm">settings.json</code></li>
|
||||
</ul>
|
||||
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Add this configuration (replace with your
|
||||
actual
|
||||
server URL):</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Local Installation Option -->
|
||||
<div data-tab-content="local" class="tab-content hidden">
|
||||
<div class="bg-gray-50 border-l-4 border-gray-400 p-6">
|
||||
<p class="text-gray-700 mb-4">
|
||||
<strong>Advanced setup.</strong> Run the MCP server on your own machine. Requires PHP and Laravel setup.
|
||||
</p>
|
||||
<div class="mt-6">
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">VSCode Configuration (Cline
|
||||
Extension):
|
||||
</h4>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">If using VSCode with the Cline extension, edit
|
||||
your
|
||||
settings:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 mb-3 ml-4">
|
||||
<li>Open VSCode Settings (JSON)</li>
|
||||
<li>Add to your global or workspace <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">settings.json</code>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Claude Desktop Configuration:</h4>
|
||||
<p class="text-gray-700 mb-3">Edit your configuration file and add:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>{
|
||||
"mcpServers": {
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": [
|
||||
"/path/to/fivem-mcp/artisan",
|
||||
"mcp:start",
|
||||
"fivem"
|
||||
]
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Command Line Usage:</h4>
|
||||
<p class="text-gray-700 mb-3">For any MCP-compatible client:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>php artisan mcp:start fivem</code></pre>
|
||||
<!-- Local Installation Option -->
|
||||
<div data-tab-content="local" class="animate-fade-in hidden">
|
||||
<div class="bg-gray-50 dark:bg-gray-700/20 border-l-4 border-gray-400 dark:border-gray-500 p-6">
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">
|
||||
<strong>Advanced setup.</strong> Run the MCP server on your own machine. Requires PHP and
|
||||
Laravel setup.
|
||||
</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2 mt-6">VSCode Configuration (Cline Extension):</h4>
|
||||
<p class="text-gray-700 mb-3">If using VSCode with the Cline extension, add to <code class="bg-gray-100 px-2 py-1 rounded text-sm">settings.json</code>:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Claude Desktop Configuration:</h4>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Edit your configuration file and add:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>@verbatim{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": [
|
||||
"/path/to/fivem-mcp/artisan",
|
||||
"mcp:start",
|
||||
"fivem"
|
||||
]
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Command Line Usage:</h4>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">For any MCP-compatible client:</p>
|
||||
<pre
|
||||
class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>php artisan mcp:start fivem</code></pre>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2 mt-6">VSCode Configuration (Cline
|
||||
Extension):</h4>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">If using VSCode with the Cline extension, add
|
||||
to
|
||||
<code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">settings.json</code>:
|
||||
</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "php",
|
||||
"args": ["artisan", "mcp:start", "fivem"],
|
||||
"cwd": "/path/to/fivem-mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
|
||||
<p class="text-gray-700 mb-3 mt-4"><strong>Or use the full PHP path:</strong></p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3 mt-4"><strong>Or use the full PHP path:</strong>
|
||||
</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": ["/path/to/fivem-mcp/artisan", "mcp:start", "fivem"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-blue-50 dark:bg-blue-900/20 border-l-4 border-blue-500 p-4 mt-6">
|
||||
<p class="text-sm text-blue-800 dark:text-blue-200">
|
||||
<strong>💡 Tip:</strong> After configuring Claude Desktop, completely quit and restart the
|
||||
application
|
||||
for
|
||||
changes to take effect.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Available Tools -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Available Tools</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
||||
The FiveM MCP Server provides {{ count($tools) }} tools organized by category.
|
||||
These tools allow AI assistants to search documentation, generate code, and lookup framework functions.
|
||||
</p>
|
||||
|
||||
@php
|
||||
$groupedTools = collect($tools)->groupBy('category');
|
||||
@endphp
|
||||
|
||||
@foreach ($groupedTools as $category => $categoryTools)
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-bold text-gray-800 dark:text-gray-200 mb-4 flex items-center">
|
||||
<span class="inline-block w-1 h-6 bg-gta-orange mr-3"></span>
|
||||
{{ $category }} Tools
|
||||
<span
|
||||
class="ml-3 text-sm font-normal text-gray-500 dark:text-gray-400">({{ count($categoryTools) }})</span>
|
||||
</h3>
|
||||
|
||||
@foreach ($categoryTools as $index => $tool)
|
||||
<div class="mb-6 border-l-4 border-gta-orange pl-6">
|
||||
<h4 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">{{ $tool['name'] }}</h4>
|
||||
<p class="text-gray-700 dark:text-gray-300">{{ $tool['description'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</section>
|
||||
|
||||
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 mt-6">
|
||||
<p class="text-sm text-blue-800">
|
||||
<strong>💡 Tip:</strong> After configuring Claude Desktop, completely quit and restart the application for changes to take effect.
|
||||
</p>
|
||||
<!-- Available Resources -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Available Resources</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
||||
MCP Resources provide read-only reference documentation that AI assistants can access.
|
||||
Currently available: {{ count($resources) }} resources.
|
||||
</p>
|
||||
|
||||
@forelse ($resources as $index => $resource)
|
||||
<div class="mb-6 border-l-4 border-green-500 pl-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">{{ $index + 1 }}.
|
||||
{{ $resource['name'] }}
|
||||
</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">{{ $resource['description'] }}</p>
|
||||
</div>
|
||||
</section>
|
||||
@empty
|
||||
<p class="text-gray-500 dark:text-gray-400 italic">No resources configured.</p>
|
||||
@endforelse
|
||||
</section>
|
||||
|
||||
<!-- Available Tools -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Available Tools</h2>
|
||||
<!-- Available Prompts -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Available Prompts</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
||||
MCP Prompts are pre-built prompt templates for common tasks.
|
||||
Currently available: {{ count($prompts) }} prompts.
|
||||
</p>
|
||||
|
||||
<!-- Tool 1: SearchFiveMDocs -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">1. SearchFiveMDocs</h3>
|
||||
<p class="text-gray-700 mb-4">Search FiveM, QBCore, and COX MySQL documentation for specific topics.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">query</code> (required): Search query (e.g., "events",
|
||||
"natives", "mysql", "database")</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">category</code> (optional): Filter by category (all,
|
||||
scripting, natives, networking, resources, qbcore, coxdocs)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Examples:</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>Search for QBCore callbacks and exports</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>How do I query the database with COX MySQL?</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Tool 2: GetNativeFunction -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">2. GetNativeFunction</h3>
|
||||
<p class="text-gray-700 mb-4">Look up GTA5/FiveM native functions.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">function_name</code> (required): Native function name
|
||||
(e.g., "GetPlayerPed", "SetEntityCoords")</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">language</code> (optional): Code example language (lua
|
||||
or js)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Common Native Examples:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li>Common natives: <code class="bg-gray-100 px-2 py-1 rounded text-sm">GetPlayerPed</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">SetEntityCoords</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">GetEntityCoords</code></li>
|
||||
<li>CFX natives: <code class="bg-gray-100 px-2 py-1 rounded text-sm">RegisterNetEvent</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">TriggerServerEvent</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">TriggerClientEvent</code></li>
|
||||
<li>ESX: <code class="bg-gray-100 px-2 py-1 rounded text-sm">ESX.GetPlayerFromId</code></li>
|
||||
<li>QBCore: <code class="bg-gray-100 px-2 py-1 rounded text-sm">QBCore.Functions.GetPlayer</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Tool 3: GenerateManifest -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">3. GenerateManifest</h3>
|
||||
<p class="text-gray-700 mb-4">Generate a fxmanifest.lua file.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">resource_name</code> (required): Resource name</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">author</code> (optional): Author name</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">description</code> (optional): Resource description</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">version</code> (optional): Version number (default:
|
||||
"1.0.0")</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">script_type</code> (optional): lua or js (default: lua)
|
||||
</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">include_client</code> (optional): Include client scripts
|
||||
(default: true)</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">include_server</code> (optional): Include server scripts
|
||||
(default: true)</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">framework</code> (optional): standalone, esx, or qbcore
|
||||
(default: standalone)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example:</h4>
|
||||
<pre
|
||||
class="bg-gray-100 rounded p-3 text-sm"><code>Generate a manifest for an ESX resource called "my-shop"</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Tool 4: GetEventReference -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">4. GetEventReference</h3>
|
||||
<p class="text-gray-700 mb-4">Get information about FiveM, ESX, and QBCore events.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">event_name</code> (optional): Specific event name to
|
||||
look up</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">event_type</code> (optional): Filter by type (all, core,
|
||||
esx, qbcore)</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">language</code> (optional): Code example language (lua
|
||||
or js)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Examples:</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>Show me all core FiveM events</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>Look up the QBCore:Client:OnPlayerLoaded event</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>List all ESX events</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Tool 5: GenerateResourceBoilerplate -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">5. GenerateResourceBoilerplate</h3>
|
||||
<p class="text-gray-700 mb-4">Generate complete resource boilerplate code.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">resource_name</code> (required): Resource name</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">framework</code> (optional): standalone, esx, or qbcore
|
||||
(default: standalone)</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">script_type</code> (optional): lua or js (default: lua)
|
||||
</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">include_nui</code> (optional): Include NUI files
|
||||
(default: false)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example:</h4>
|
||||
<pre
|
||||
class="bg-gray-100 rounded p-3 text-sm"><code>Generate boilerplate for a QBCore resource with NUI called "admin-panel"</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Tool 6: GetQBCoreEventReference -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">6. GetQBCoreEventReference</h3>
|
||||
<p class="text-gray-700 mb-4">Get information about QBCore framework events.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">event_name</code> (optional): Specific event name to
|
||||
look up</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">event_category</code> (optional): Filter by category
|
||||
(all, player, job, inventory, vehicle, money)</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">language</code> (optional): Code example language (lua
|
||||
or js)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Examples:</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>What's the QBCore:Client:OnPlayerLoaded event?</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>Show me all QBCore player events</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>List all QBCore inventory events</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Tool 7: GetQBCoreFunction -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">7. GetQBCoreFunction</h3>
|
||||
<p class="text-gray-700 mb-4">Look up QBCore functions and exports.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">function_name</code> (required): QBCore function name
|
||||
(e.g., "QBCore.Functions.GetPlayer", "AddMoney")</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">language</code> (optional): Code example language (lua
|
||||
or js)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Common QBCore Functions:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li>Player: <code class="bg-gray-100 px-2 py-1 rounded text-sm">QBCore.Functions.GetPlayer</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">QBCore.Functions.GetPlayerData</code></li>
|
||||
<li>Items: <code class="bg-gray-100 px-2 py-1 rounded text-sm">AddItem</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">RemoveItem</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">GetItemByName</code></li>
|
||||
<li>Money: <code class="bg-gray-100 px-2 py-1 rounded text-sm">AddMoney</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">RemoveMoney</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">GetMoney</code></li>
|
||||
<li>Jobs: <code class="bg-gray-100 px-2 py-1 rounded text-sm">SetJob</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">GetJob</code></li>
|
||||
<li>Vehicles: <code class="bg-gray-100 px-2 py-1 rounded text-sm">AddVehicle</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">DeleteVehicle</code></li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example:</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>How do I use the AddMoney function in QBCore?</code></pre>
|
||||
</div>
|
||||
<!-- Tool 8: GetCOXEventReference -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">8. GetCOXEventReference</h3>
|
||||
<p class="text-gray-700 mb-4">Get information about COX MySQL events and callbacks.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">event_name</code> (optional): Specific event name to
|
||||
look up</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">event_type</code> (optional): Filter by type (all,
|
||||
query, connection, transaction, error)</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">language</code> (optional): Code example language (lua
|
||||
or js)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Examples:</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>What are the COX MySQL connection events?</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm mb-2"><code>Show me all COX transaction events</code></pre>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>How do I handle query errors in COX?</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Tool 9: GetCOXFunction -->
|
||||
<div class="mb-8 border-l-4 border-indigo-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">9. GetCOXFunction</h3>
|
||||
<p class="text-gray-700 mb-4">Look up COX MySQL functions and methods.</p>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Parameters:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">function_name</code> (required): COX function name
|
||||
(e.g., "MySQL.query", "MySQL.insert")</li>
|
||||
<li><code class="bg-gray-100 px-2 py-1 rounded text-sm">language</code> (optional): Code example language (lua
|
||||
or js)</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Common COX Methods:</h4>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-4 ml-4">
|
||||
<li>Query: <code class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.query</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.single</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.scalar</code></li>
|
||||
<li>Modify: <code class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.insert</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.update</code></li>
|
||||
<li>Transactions: <code class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.transaction.begin</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.transaction.commit</code></li>
|
||||
<li>Connection: <code class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.ready</code>, <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.getStatus</code></li>
|
||||
<li>Security: <code class="bg-gray-100 px-2 py-1 rounded text-sm">MySQL.prepare</code> (prepared statements)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example:</h4>
|
||||
<pre
|
||||
class="bg-gray-100 rounded p-3 text-sm"><code>How do I query the database safely with prepared statements?</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Available Resources -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Available Resources</h2>
|
||||
<p class="text-gray-700 mb-6">MCP Resources provide read-only reference documentation that AI assistants can access:</p>
|
||||
|
||||
<!-- Resource 1: Code Snippets -->
|
||||
<div class="mb-8 border-l-4 border-green-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">1. Code Snippets</h3>
|
||||
<p class="text-gray-700 mb-4">Common FiveM code patterns and snippets for quick reference.</p>
|
||||
<p class="text-gray-600 text-sm">URI: <code class="bg-gray-100 px-2 py-1 rounded text-sm">fivem://snippets/common</code></p>
|
||||
<p class="text-gray-700 mt-2">Includes patterns for distance checks, event handlers, threads with cleanup, database queries, and NUI callbacks in both Lua and JavaScript.</p>
|
||||
@forelse ($prompts as $index => $prompt)
|
||||
<div class="mb-6 border-l-4 border-purple-500 pl-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">{{ $index + 1 }}.
|
||||
{{ $prompt['name'] }}
|
||||
</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">{{ $prompt['description'] }}</p>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-gray-500 dark:text-gray-400 italic">No prompts configured.</p>
|
||||
@endforelse
|
||||
</section>
|
||||
|
||||
<!-- Resource 2: Best Practices -->
|
||||
<div class="mb-8 border-l-4 border-green-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">2. Best Practices</h3>
|
||||
<p class="text-gray-700 mb-4">FiveM development best practices and optimization tips.</p>
|
||||
<p class="text-gray-600 text-sm">URI: <code class="bg-gray-100 px-2 py-1 rounded text-sm">fivem://guides/best-practices</code></p>
|
||||
<p class="text-gray-700 mt-2">Covers performance optimization, security best practices, code organization, resource management, testing, and common pitfalls.</p>
|
||||
</div>
|
||||
<!-- Testing -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Testing the Server</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">You can test the MCP server locally using the inspector:
|
||||
</p>
|
||||
<pre
|
||||
class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>php artisan mcp:inspector fivem</code></pre>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm mt-2">This will open the MCP Inspector in your browser
|
||||
where
|
||||
you
|
||||
can test all the tools interactively.</p>
|
||||
</section>
|
||||
|
||||
<!-- Resource 4: Database Queries -->
|
||||
<div class="mb-8 border-l-4 border-green-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">4. Database Queries</h3>
|
||||
<p class="text-gray-700 mb-4">FiveM database query examples and common patterns for COX MySQL.</p>
|
||||
<p class="text-gray-600 text-sm">URI: <code
|
||||
class="bg-gray-100 px-2 py-1 rounded text-sm">fivem://guides/database-queries</code></p>
|
||||
<p class="text-gray-700 mt-2">Covers CRUD operations, prepared statements, transactions, async queries, error handling,
|
||||
performance tips, and common database patterns (SELECT, INSERT, UPDATE, DELETE).</p>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Development -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Development</h2>
|
||||
|
||||
<!-- Available Prompts -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Available Prompts</h2>
|
||||
<p class="text-gray-700 mb-6">MCP Prompts are pre-built prompt templates for common tasks:</p>
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">Adding New Tools</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">1. Create a new tool class in <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">app/Mcp/Tools/</code>:
|
||||
</p>
|
||||
|
||||
<!-- Prompt 1: Create New Resource -->
|
||||
<div class="mb-8 border-l-4 border-purple-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">1. Create New Resource</h3>
|
||||
<p class="text-gray-700 mb-4">Create a new FiveM resource with framework and language selection.</p>
|
||||
<p class="text-gray-600 text-sm">Parameters: resource_name, framework (standalone/esx/qbcore), language (lua/js)</p>
|
||||
</div>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>@verbatim<?php
|
||||
|
||||
<!-- Prompt 2: Debug Issues -->
|
||||
<div class="mb-8 border-l-4 border-purple-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">2. Debug Issues</h3>
|
||||
<p class="text-gray-700 mb-4">Debug common FiveM issues and errors with detailed analysis.</p>
|
||||
<p class="text-gray-600 text-sm">Parameters: issue (description), error_message (from console)</p>
|
||||
</div>
|
||||
namespace App\Mcp\Tools;
|
||||
|
||||
<!-- Prompt 3: Optimize Performance -->
|
||||
<div class="mb-8 border-l-4 border-purple-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">3. Optimize Performance</h3>
|
||||
<p class="text-gray-700 mb-4">Optimize FiveM script performance with detailed suggestions.</p>
|
||||
<p class="text-gray-600 text-sm">Parameters: code (script to optimize), script_type (client/server/shared)</p>
|
||||
</div>
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
|
||||
<!-- Prompt 4: Convert Language -->
|
||||
<div class="mb-8 border-l-4 border-purple-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">4. Convert Language</h3>
|
||||
<p class="text-gray-700 mb-4">Convert code between Lua and JavaScript with proper syntax.</p>
|
||||
<p class="text-gray-600 text-sm">Parameters: code, from (lua/js), to (lua/js)</p>
|
||||
</div>
|
||||
#[Description('Your tool description')]
|
||||
class YourTool extends Tool
|
||||
{
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
// Tool logic here
|
||||
return Response::text('Result');
|
||||
}
|
||||
|
||||
<!-- Prompt 5: Add Framework Integration -->
|
||||
<div class="mb-8 border-l-4 border-purple-500 pl-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">5. Add Framework Integration</h3>
|
||||
<p class="text-gray-700 mb-4">Add ESX or QBCore framework integration to existing resource.</p>
|
||||
<p class="text-gray-600 text-sm">Parameters: code (current resource), current_framework, target_framework (esx/qbcore)</p>
|
||||
</div>
|
||||
</section>
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'param' => $schema->string()->required(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@endverbatim</code></pre>
|
||||
|
||||
<!-- Testing -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Testing the Server</h2>
|
||||
<p class="text-gray-700 mb-4">You can test the MCP server locally using the inspector:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>php artisan mcp:inspector fivem</code></pre>
|
||||
<p class="text-gray-600 text-sm mt-2">This will open the MCP Inspector in your browser where you can test all the tools interactively.</p>
|
||||
</section>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">2. Register the tool in <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">app/Mcp/Servers/FiveMServer.php</code>:
|
||||
</p>
|
||||
|
||||
<!-- Development -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Development</h2>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>@verbatimprotected array $tools = [
|
||||
// ... existing tools
|
||||
\App\Mcp\Tools\YourTool::class,
|
||||
];@endverbatim</code></pre>
|
||||
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Adding New Tools</h3>
|
||||
<p class="text-gray-700 mb-4">1. Create a new tool class in <code class="bg-gray-100 px-2 py-1 rounded text-sm">app/Mcp/Tools/</code>:</p>
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3 mt-6">Code Formatting</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">Format code with Laravel Pint:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>vendor/bin/pint</code></pre>
|
||||
</section>
|
||||
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code><?php
|
||||
<!-- Frameworks & Languages -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Supported Frameworks</h2>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4">
|
||||
<li><strong>Standalone:</strong> Basic FiveM resources without framework dependencies</li>
|
||||
<li><strong>ESX:</strong> ESX Framework (es_extended)</li>
|
||||
<li><strong>QBCore:</strong> QBCore Framework (qb-core)</li>
|
||||
</ul>
|
||||
|
||||
namespace App\Mcp\Tools;
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4 mt-6">Scripting Languages</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300">Both Lua and JavaScript are fully supported across all tools and
|
||||
generators.</p>
|
||||
</section>
|
||||
|
||||
use Illuminate\Contracts\JsonSchema\JsonSchema;
|
||||
use Laravel\Mcp\Request;
|
||||
use Laravel\Mcp\Response;
|
||||
use Laravel\Mcp\Server\Attributes\Description;
|
||||
use Laravel\Mcp\Server\Tool;
|
||||
<!-- Resources -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Resources</h2>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4">
|
||||
<li><a href="https://docs.fivem.net/docs/" class="link-gta">FiveM
|
||||
Documentation</a></li>
|
||||
<li><a href="https://docs.fivem.net/natives/" class="link-gta">FiveM
|
||||
Natives Reference</a></li>
|
||||
<li><a href="https://coxdocs.dev/" class="link-gta">COX
|
||||
MySQL
|
||||
Documentation</a> - Required
|
||||
for database operations</li>
|
||||
<li><a href="https://docs.qbcore.org/" class="link-gta">QBCore
|
||||
Documentation</a></li>
|
||||
<li><a href="https://laravel.com/docs/mcp" class="link-gta">Laravel
|
||||
MCP Documentation</a></li>
|
||||
<li><a href="https://modelcontextprotocol.io/" class="link-gta">Model
|
||||
Context Protocol</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
#[Description('Your tool description')]
|
||||
class YourTool extends Tool
|
||||
{
|
||||
public function handle(Request $request): Response
|
||||
{
|
||||
// Tool logic here
|
||||
return Response::text('Result');
|
||||
}
|
||||
<!-- Contributing -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Contributing</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">Contributions are welcome! Areas for expansion:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4">
|
||||
<li>More native functions in the database</li>
|
||||
<li>Additional framework support (vRP, etc.)</li>
|
||||
<li>More event types</li>
|
||||
<li>Advanced code generators</li>
|
||||
<li>Database query builders</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
public function schema(JsonSchema $schema): array
|
||||
{
|
||||
return [
|
||||
'param' => $schema->string()->required(),
|
||||
];
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p class="text-gray-700 mb-4">2. Register the tool in <code class="bg-gray-100 px-2 py-1 rounded text-sm">app/Mcp/Servers/FiveMServer.php</code>:</p>
|
||||
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>protected array $tools = [
|
||||
// ... existing tools
|
||||
\App\Mcp\Tools\YourTool::class,
|
||||
];</code></pre>
|
||||
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3 mt-6">Code Formatting</h3>
|
||||
<p class="text-gray-700 mb-4">Format code with Laravel Pint:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>vendor/bin/pint</code></pre>
|
||||
</section>
|
||||
|
||||
<!-- Frameworks & Languages -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Supported Frameworks</h2>
|
||||
<ul class="list-disc list-inside text-gray-700 space-y-2 ml-4">
|
||||
<li><strong>Standalone:</strong> Basic FiveM resources without framework dependencies</li>
|
||||
<li><strong>ESX:</strong> ESX Framework (es_extended)</li>
|
||||
<li><strong>QBCore:</strong> QBCore Framework (qb-core)</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4 mt-6">Scripting Languages</h2>
|
||||
<p class="text-gray-700">Both Lua and JavaScript are fully supported across all tools and generators.</p>
|
||||
</section>
|
||||
|
||||
<!-- Resources -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Resources</h2>
|
||||
<ul class="list-disc list-inside text-gray-700 space-y-2 ml-4">
|
||||
<li><a href="https://docs.fivem.net/docs/" class="text-indigo-600 hover:text-indigo-500">FiveM Documentation</a></li>
|
||||
<li><a href="https://docs.fivem.net/natives/" class="text-indigo-600 hover:text-indigo-500">FiveM Natives Reference</a></li>
|
||||
<li><a href="https://coxdocs.dev/" class="text-indigo-600 hover:text-indigo-500">COX MySQL Documentation</a> - Required
|
||||
for database operations</li>
|
||||
<li><a href="https://docs.qbcore.org/" class="text-indigo-600 hover:text-indigo-500">QBCore Documentation</a></li>
|
||||
<li><a href="https://laravel.com/docs/mcp" class="text-indigo-600 hover:text-indigo-500">Laravel MCP Documentation</a></li>
|
||||
<li><a href="https://modelcontextprotocol.io/" class="text-indigo-600 hover:text-indigo-500">Model Context Protocol</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- Contributing -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Contributing</h2>
|
||||
<p class="text-gray-700 mb-4">Contributions are welcome! Areas for expansion:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 space-y-2 ml-4">
|
||||
<li>More native functions in the database</li>
|
||||
<li>Additional framework support (vRP, etc.)</li>
|
||||
<li>More event types</li>
|
||||
<li>Advanced code generators</li>
|
||||
<li>Database query builders</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- License -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">License</h2>
|
||||
<p class="text-gray-700">MIT License</p>
|
||||
</section>
|
||||
</div>
|
||||
<!-- License -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">License</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300">MIT License</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tabButtons = document.querySelectorAll('.tab-button');
|
||||
const tabContents = document.querySelectorAll('.tab-content');
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const targetTab = this.dataset.tab;
|
||||
|
||||
// Remove active class from all buttons
|
||||
tabButtons.forEach(btn => {
|
||||
btn.classList.remove('active', 'border-indigo-500', 'text-indigo-600');
|
||||
btn.classList.add('border-transparent', 'text-gray-500');
|
||||
});
|
||||
|
||||
// Add active class to clicked button
|
||||
this.classList.remove('border-transparent', 'text-gray-500');
|
||||
this.classList.add('active', 'border-indigo-500', 'text-indigo-600');
|
||||
|
||||
// Hide all tab contents
|
||||
tabContents.forEach(content => {
|
||||
content.classList.add('hidden');
|
||||
content.classList.remove('active');
|
||||
});
|
||||
|
||||
// Show target tab content
|
||||
const targetContent = document.querySelector(`[data-tab-content="${targetTab}"]`);
|
||||
if (targetContent) {
|
||||
targetContent.classList.remove('hidden');
|
||||
targetContent.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,213 +1,239 @@
|
||||
@extends('docs.layout')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'FiveM MCP Server')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||||
<!-- Hero Section -->
|
||||
<div class="text-center mb-12">
|
||||
<h1 class="text-4xl font-extrabold text-gray-900 sm:text-5xl sm:tracking-tight lg:text-6xl">
|
||||
FiveM Development MCP Server
|
||||
</h1>
|
||||
<p class="mt-5 max-w-xl mx-auto text-xl text-gray-500">
|
||||
A comprehensive Model Context Protocol server for FiveM development with 5 tools, 3 resources, and 5 prompts.
|
||||
</p>
|
||||
</div>
|
||||
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||||
<!-- Hero Section -->
|
||||
<div class="text-center mb-12">
|
||||
<h1 class="text-4xl font-extrabold text-gray-900 dark:text-white sm:text-5xl sm:tracking-tight lg:text-6xl">
|
||||
FiveM Development MCP Server
|
||||
</h1>
|
||||
<p class="mt-5 max-w-xl mx-auto text-xl text-gray-500 dark:text-gray-400">
|
||||
A comprehensive Model Context Protocol server for FiveM development with 5 tools, 3 resources, and 5
|
||||
prompts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Features Grid -->
|
||||
<div class="mt-12">
|
||||
<h2 class="text-3xl font-extrabold text-gray-900 mb-8">Features</h2>
|
||||
<div class="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<!-- Documentation Search -->
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-indigo-500 rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
<!-- Features Grid -->
|
||||
<div class="mt-12">
|
||||
<h2 class="text-3xl font-extrabold text-gray-900 dark:text-white mb-8">Features</h2>
|
||||
<div class="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<!-- Documentation Search -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-gta-orange rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Documentation Search</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900">Documentation Search</h3>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Search FiveM documentation by topic and category. Get direct links to relevant
|
||||
documentation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Search FiveM documentation by topic and category. Get direct links to relevant documentation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Native Functions -->
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-indigo-500 rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
|
||||
</svg>
|
||||
<!-- Native Functions -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-gta-orange rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Native Functions</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900">Native Functions</h3>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Look up GTA5/FiveM native functions with signatures, parameters, and code examples.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Look up GTA5/FiveM native functions with signatures, parameters, and code examples.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manifest Generator -->
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-indigo-500 rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<!-- Manifest Generator -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-gta-orange rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Manifest Generator</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900">Manifest Generator</h3>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Generate fxmanifest.lua files automatically for any framework and scripting language.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Generate fxmanifest.lua files automatically for any framework and scripting language.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Event Reference -->
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-indigo-500 rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
<!-- Event Reference -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-gta-orange rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Event Reference</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900">Event Reference</h3>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Complete database of FiveM events including core, ESX, and QBCore events with examples.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Complete database of FiveM events including core, ESX, and QBCore events with examples.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Boilerplate Generator -->
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-indigo-500 rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
||||
</svg>
|
||||
<!-- Boilerplate Generator -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-gta-orange rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Boilerplate Generator</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900">Boilerplate Generator</h3>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Generate complete resource structures with client, server, config, and optional NUI files.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Generate complete resource structures with client, server, config, and optional NUI files.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Framework Support -->
|
||||
<div class="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-indigo-500 rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"></path>
|
||||
</svg>
|
||||
<!-- Framework Support -->
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="flex items-center">
|
||||
<div class="shrink-0 bg-gta-orange rounded-md p-3">
|
||||
<svg class="h-6 w-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Framework Support</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-5">
|
||||
<h3 class="text-lg font-medium text-gray-900">Framework Support</h3>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Full support for Standalone, ESX, and QBCore frameworks in both Lua and JavaScript.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Full support for Standalone, ESX, and QBCore frameworks in both Lua and JavaScript.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="mt-16 bg-indigo-700 rounded-lg shadow-xl overflow-hidden">
|
||||
<div class="px-6 py-12 sm:px-12">
|
||||
<div class="text-center">
|
||||
<h2 class="text-3xl font-extrabold text-white">Ready to get started?</h2>
|
||||
<p class="mt-4 text-lg text-indigo-100">
|
||||
Set up the MCP server in just 5 minutes with our quick start guide.
|
||||
</p>
|
||||
<div class="mt-8 flex justify-center space-x-4">
|
||||
<a href="{{ route('docs.quickstart') }}" class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-indigo-700 bg-white hover:bg-indigo-50">
|
||||
Quick Start Guide
|
||||
</a>
|
||||
<a href="{{ route('docs.documentation') }}" class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-500 hover:bg-indigo-600">
|
||||
Full Documentation
|
||||
</a>
|
||||
<!-- Quick Actions -->
|
||||
<div class="mt-16 bg-gray-900 dark:bg-black border border-gta-orange rounded-lg shadow-xl overflow-hidden">
|
||||
<div class="px-6 py-12 sm:px-12">
|
||||
<div class="text-center">
|
||||
<h2 class="text-3xl font-extrabold text-white">Ready to get started?</h2>
|
||||
<p class="mt-4 text-lg text-gray-200 dark:text-gray-300">
|
||||
Set up the MCP server in just 5 minutes with our quick start guide.
|
||||
</p>
|
||||
<div class="mt-8 flex justify-center space-x-4">
|
||||
<a href="{{ route('docs.quickstart') }}"
|
||||
class="btn-gta-secondary inline-flex items-center px-6 py-3 text-base">
|
||||
Quick Start Guide
|
||||
</a>
|
||||
<a href="{{ route('docs.documentation') }}"
|
||||
class="btn-gta-primary inline-flex items-center px-6 py-3 text-base">
|
||||
Full Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resources -->
|
||||
<div class="mt-16">
|
||||
<h2 class="text-3xl font-extrabold text-gray-900 mb-8">Resources</h2>
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div class="bg-white shadow rounded-lg p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-4">MCP Server Configuration</h3>
|
||||
<p class="text-sm text-gray-500 mb-4">
|
||||
To connect to the FiveM MCP server, use the following configuration in your MCP client:
|
||||
</p>
|
||||
<pre class="bg-gray-50 rounded p-4 text-sm overflow-x-auto"><code>{
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"url": "{{ route('fivem') }}",
|
||||
"type": "http"
|
||||
<!-- Resources -->
|
||||
<div class="mt-16">
|
||||
<h2 class="text-3xl font-extrabold text-gray-900 dark:text-white mb-8">Resources</h2>
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">MCP Server Configuration</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mb-4">
|
||||
To connect to the FiveM MCP server, use the following configuration in your MCP client:
|
||||
</p>
|
||||
<pre
|
||||
class="bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-4 text-sm overflow-x-auto"><code>@verbatim{
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"url": "{{ route('fivem') }}",
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
<div class="bg-white shadow rounded-lg p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-4">External Links</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li>
|
||||
<a href="https://docs.fivem.net/docs/" class="text-indigo-600 hover:text-indigo-500">FiveM Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.fivem.net/natives/" class="text-indigo-600 hover:text-indigo-500">FiveM Natives Reference</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.qbcore.org/" class="text-indigo-600 hover:text-indigo-500">QBCore Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://coxdocs.dev/" class="text-indigo-600 hover:text-indigo-500">COX MySQL Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://laravel.com/docs/mcp" class="text-indigo-600 hover:text-indigo-500">Laravel MCP Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://modelcontextprotocol.io/" class="text-indigo-600 hover:text-indigo-500">Model Context Protocol</a>
|
||||
</li>
|
||||
</ul>
|
||||
}@endverbatim</code></pre>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white mb-4">External Links</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li>
|
||||
<a href="https://docs.fivem.net/docs/"
|
||||
class="link-gta">FiveM
|
||||
Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.fivem.net/natives/"
|
||||
class="link-gta">FiveM
|
||||
Natives Reference</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.qbcore.org/"
|
||||
class="link-gta">QBCore
|
||||
Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://coxdocs.dev/"
|
||||
class="link-gta">COX
|
||||
MySQL Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://laravel.com/docs/mcp"
|
||||
class="link-gta">Laravel
|
||||
MCP Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://modelcontextprotocol.io/"
|
||||
class="link-gta">Model
|
||||
Context Protocol</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,50 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@yield('title', 'FiveM MCP Server Documentation')</title>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body class="h-full bg-gray-50">
|
||||
<div class="min-h-full">
|
||||
<!-- Navigation -->
|
||||
<nav class="bg-white shadow-sm">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between h-16">
|
||||
<div class="flex">
|
||||
<div class="shrink-0 flex items-center">
|
||||
<h1 class="text-xl font-bold text-gray-900">FiveM MCP Server</h1>
|
||||
</div>
|
||||
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
|
||||
<a href="{{ route('docs.index') }}" class="{{ request()->routeIs('docs.index') ? 'border-indigo-500 text-gray-900' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700' }} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
|
||||
Home
|
||||
</a>
|
||||
<a href="{{ route('docs.quickstart') }}" class="{{ request()->routeIs('docs.quickstart') ? 'border-indigo-500 text-gray-900' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700' }} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
|
||||
Quick Start
|
||||
</a>
|
||||
<a href="{{ route('docs.documentation') }}" class="{{ request()->routeIs('docs.documentation') ? 'border-indigo-500 text-gray-900' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700' }} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main>
|
||||
@yield('content')
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-white border-t border-gray-200 mt-12">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<p class="text-center text-sm text-gray-500">
|
||||
Built with <a href="https://laravel.com/docs/mcp" class="text-indigo-600 hover:text-indigo-500">Laravel MCP</a> for <a href="https://docs.fivem.net" class="text-indigo-600 hover:text-indigo-500">FiveM</a> development
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,380 +1,388 @@
|
||||
@extends('docs.layout')
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Quick Start Guide - FiveM MCP Server')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-4xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-white shadow rounded-lg p-8">
|
||||
<h1 class="text-3xl font-extrabold text-gray-900 mb-6">FiveM MCP Quick Start Guide</h1>
|
||||
<div class="max-w-4xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-8">
|
||||
<h1 class="text-3xl font-extrabold text-gray-900 dark:text-white mb-6">FiveM MCP Quick Start Guide</h1>
|
||||
|
||||
<!-- What is this -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">What is this?</h2>
|
||||
<p class="text-gray-700 mb-4">
|
||||
This MCP server gives AI assistants (like Claude) access to FiveM development tools including:
|
||||
</p>
|
||||
<ul class="list-disc list-inside text-gray-700 space-y-2 ml-4">
|
||||
<li>Documentation search</li>
|
||||
<li>Native function lookups</li>
|
||||
<li>Manifest generation</li>
|
||||
<li>Event references</li>
|
||||
<li>Resource boilerplate generation</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- Choose Setup Type -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Choose Your Setup</h2>
|
||||
|
||||
<!-- Tab Buttons -->
|
||||
<div class="border-b border-gray-200 mb-6">
|
||||
<nav class="-mb-px flex space-x-8">
|
||||
<button
|
||||
data-tab="remote"
|
||||
class="tab-button active border-b-2 border-indigo-500 py-4 px-1 text-center text-sm font-medium text-indigo-600"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">🌐</span>
|
||||
Remote Server
|
||||
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">
|
||||
Recommended
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
data-tab="local"
|
||||
class="tab-button border-b-2 border-transparent py-4 px-1 text-center text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💻</span>
|
||||
Local Installation
|
||||
</span>
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Tab Content Container -->
|
||||
<div class="tab-content-container">
|
||||
<!-- Remote Setup Tab -->
|
||||
<div data-tab-content="remote" class="tab-content active">
|
||||
<div class="bg-indigo-50 border-l-4 border-indigo-500 p-4 mb-6">
|
||||
<p class="text-sm text-indigo-800">
|
||||
<strong>Easy setup!</strong> Connect to a hosted MCP server. Works from anywhere without any local installation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-700 mb-6">
|
||||
If someone is hosting the FiveM MCP server for you, follow these steps to connect:
|
||||
</p>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">1. Get the Server URL</h3>
|
||||
<p class="text-gray-700 mb-3">
|
||||
Ask your server administrator for the MCP server URL. It will look like:
|
||||
</p>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>https://your-domain.com/fivem</code></pre>
|
||||
<p class="text-gray-700 mb-3 mt-4">
|
||||
If you're using the official hosted server, use this URL:
|
||||
</p>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>{{ route('fivem') }}</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">2. Configure Claude Desktop</h3>
|
||||
<p class="text-gray-700 mb-3">Edit your Claude Desktop configuration file:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-3 ml-4">
|
||||
<li><strong>macOS:</strong> <code class="bg-gray-100 px-2 py-1 rounded text-sm">~/Library/Application Support/Claude/claude_desktop_config.json</code></li>
|
||||
<li><strong>Windows:</strong> <code class="bg-gray-100 px-2 py-1 rounded text-sm">%APPDATA%\Claude\claude_desktop_config.json</code></li>
|
||||
</ul>
|
||||
|
||||
<p class="text-gray-700 mb-3">Add this configuration (replace the URL with your actual server URL):</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p class="text-gray-700 mb-3 mt-6"><strong>For VSCode (Cline Extension):</strong></p>
|
||||
<p class="text-gray-700 mb-3">Edit your VSCode <code class="bg-gray-100 px-2 py-1 rounded text-sm">settings.json</code>:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">3. Restart Claude Desktop</h3>
|
||||
<p class="text-gray-700">
|
||||
Completely quit and restart Claude Desktop for changes to take effect.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">4. Verify Connection</h3>
|
||||
<p class="text-gray-700">
|
||||
In Claude Desktop, you should see a small 🔌 icon or indication that the FiveM MCP server is connected.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-green-50 border-l-4 border-green-500 p-4">
|
||||
<p class="text-sm text-green-800">
|
||||
<strong>That's it!</strong> You're now connected to the remote MCP server and can start using FiveM development tools with Claude.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Local Setup Tab -->
|
||||
<div data-tab-content="local" class="tab-content hidden">
|
||||
<div class="bg-gray-50 border-l-4 border-gray-400 p-4 mb-6">
|
||||
<p class="text-sm text-gray-700">
|
||||
<strong>Advanced setup.</strong> Run the MCP server on your own machine. Requires PHP and Laravel installation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-700 mb-6">
|
||||
If you want to run the MCP server on your own machine:
|
||||
</p>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">1. Test the Server</h3>
|
||||
<p class="text-gray-700 mb-3">First, verify the server works:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>cd /path/to/fivem-mcp
|
||||
php artisan mcp:inspector fivem</code></pre>
|
||||
<p class="text-gray-600 text-sm mt-2">This opens a web inspector where you can test all tools.</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">2. Configure Claude Desktop</h3>
|
||||
<p class="text-gray-700 mb-3">Edit your Claude Desktop configuration file:</p>
|
||||
<ul class="list-disc list-inside text-gray-700 mb-3 ml-4">
|
||||
<li><strong>macOS:</strong> <code class="bg-gray-100 px-2 py-1 rounded text-sm">~/Library/Application Support/Claude/claude_desktop_config.json</code></li>
|
||||
<li><strong>Windows:</strong> <code class="bg-gray-100 px-2 py-1 rounded text-sm">%APPDATA%\Claude\claude_desktop_config.json</code></li>
|
||||
</ul>
|
||||
|
||||
<p class="text-gray-700 mb-3">Add this configuration:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"command": "php",
|
||||
"args": [
|
||||
"artisan",
|
||||
"mcp:start",
|
||||
"fivem"
|
||||
],
|
||||
"cwd": "/path/to/fivem-mcp"
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p class="text-gray-700 mb-3"><strong>Or use the full PHP path (e.g., for Herd):</strong></p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": [
|
||||
"/path/to/fivem-mcp/artisan",
|
||||
"mcp:start",
|
||||
"fivem"
|
||||
]
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p class="text-gray-700 mb-3 mt-6"><strong>For VSCode (Cline Extension):</strong></p>
|
||||
<p class="text-gray-700 mb-3">Edit your VSCode <code class="bg-gray-100 px-2 py-1 rounded text-sm">settings.json</code>:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "php",
|
||||
"args": ["artisan", "mcp:start", "fivem"],
|
||||
"cwd": "/path/to/fivem-mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
|
||||
<p class="text-gray-700 mb-3"><strong>Or with full paths:</strong></p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": ["/path/to/fivem-mcp/artisan", "mcp:start", "fivem"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">3. Restart Claude Desktop</h3>
|
||||
<p class="text-gray-700">
|
||||
Completely quit and restart Claude Desktop for changes to take effect.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">4. Verify Connection</h3>
|
||||
<p class="text-gray-700">
|
||||
In Claude Desktop, you should see a small 🔌 icon or indication that the FiveM MCP server is connected.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Quick Examples -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Quick Examples</h2>
|
||||
<p class="text-gray-700 mb-4">Once connected, try these prompts in Claude:</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="border-l-4 border-indigo-500 pl-4">
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example 1: Search Documentation</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>Search FiveM docs for "state bags"</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-indigo-500 pl-4">
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example 2: Look Up a Native</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>What does the GetPlayerPed native function do? Show me an example.</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-indigo-500 pl-4">
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example 3: Generate a Manifest</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>Generate a fxmanifest.lua for my resource called "vehicle-shop" using ESX framework</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-indigo-500 pl-4">
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example 4: List Events</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>Show me all FiveM core server events</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-indigo-500 pl-4">
|
||||
<h4 class="font-semibold text-gray-900 mb-2">Example 5: Create Boilerplate</h4>
|
||||
<pre class="bg-gray-100 rounded p-3 text-sm"><code>Create a complete resource structure for a QBCore script called "bank-heist" with NUI</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Troubleshooting -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Troubleshooting</h2>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Server Not Connecting</h3>
|
||||
<ol class="list-decimal list-inside text-gray-700 space-y-3 ml-4">
|
||||
<li>
|
||||
<strong>Check PHP Path:</strong> Make sure the PHP path in your config is correct
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-3 mt-2 overflow-x-auto"><code>which php
|
||||
# or for Herd:
|
||||
ls -la "~/Library/Application Support/Herd/bin/"</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Test Manually:</strong> Run the server command directly
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-3 mt-2 overflow-x-auto"><code>cd /path/to/fivem-mcp
|
||||
php artisan mcp:start fivem</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Check Logs:</strong> Look at Claude Desktop logs
|
||||
<ul class="list-disc list-inside ml-6 mt-2">
|
||||
<li>macOS: <code class="bg-gray-100 px-2 py-1 rounded text-sm">~/Library/Logs/Claude/</code></li>
|
||||
<li>Windows: Check Event Viewer or app logs</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Permission Issues</h3>
|
||||
<p class="text-gray-700 mb-3">If you get permission errors:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>cd /path/to/fivem-mcp
|
||||
chmod +x artisan</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-3">Path Issues</h3>
|
||||
<p class="text-gray-700">
|
||||
Make sure to use <strong>absolute paths</strong> in your config, not relative paths.
|
||||
<!-- What is this -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">What is this?</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">
|
||||
This MCP server gives AI assistants (like Claude) access to FiveM development tools including:
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4">
|
||||
<li>Documentation search</li>
|
||||
<li>Native function lookups</li>
|
||||
<li>Manifest generation</li>
|
||||
<li>Event references</li>
|
||||
<li>Resource boilerplate generation</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- Next Steps -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Next Steps</h2>
|
||||
<ul class="list-disc list-inside text-gray-700 space-y-2 ml-4">
|
||||
<li><a href="{{ route('docs.documentation') }}" class="text-indigo-600 hover:text-indigo-500">Read the full documentation</a></li>
|
||||
<li>Explore all 5 tools in the MCP Inspector</li>
|
||||
<li>Try creating a complete FiveM resource with AI assistance</li>
|
||||
<li>Contribute new tools or improve existing ones</li>
|
||||
</ul>
|
||||
</section>
|
||||
<!-- Choose Setup Type -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Choose Your Setup</h2>
|
||||
|
||||
<!-- Support -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-4">Support</h2>
|
||||
<p class="text-gray-700 mb-3">For issues:</p>
|
||||
<ol class="list-decimal list-inside text-gray-700 space-y-2 ml-4">
|
||||
<li>Check <a href="https://laravel.com/docs/mcp" class="text-indigo-600 hover:text-indigo-500">Laravel MCP Documentation</a></li>
|
||||
<li>Check <a href="https://docs.fivem.net/" class="text-indigo-600 hover:text-indigo-500">FiveM Documentation</a></li>
|
||||
<li>Review server logs</li>
|
||||
<li>Open a GitHub issue</li>
|
||||
</ol>
|
||||
<p class="text-gray-700 mt-6 text-lg font-semibold">Happy coding! 🎮</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tab Buttons -->
|
||||
<div class="border-b border-gray-200 dark:border-gray-700 mb-6">
|
||||
<nav class="-mb-px flex space-x-8">
|
||||
<button data-tab="remote"
|
||||
class="transition-all duration-200 ease-in-out active border-b-2 border-gta-orange py-4 px-1 text-center text-sm font-medium text-gta-orange">
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">🌐</span>
|
||||
Remote Server
|
||||
<span
|
||||
class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-700 border border-gta-orange text-gta-orange">
|
||||
Recommended
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button data-tab="local"
|
||||
class="transition-all duration-200 ease-in-out border-b-2 border-transparent py-4 px-1 text-center text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-300 dark:hover:border-gray-600">
|
||||
<span class="flex items-center">
|
||||
<span class="mr-2">💻</span>
|
||||
Local Installation
|
||||
</span>
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tabButtons = document.querySelectorAll('.tab-button');
|
||||
const tabContents = document.querySelectorAll('.tab-content');
|
||||
<!-- Tab Content Container -->
|
||||
<div class="tab-content-container">
|
||||
<!-- Remote Setup Tab -->
|
||||
<div data-tab-content="remote" class="animate-fade-in active">
|
||||
<div class="bg-gray-100 dark:bg-gray-700/30 border-l-4 border-gta-orange p-4 mb-6">
|
||||
<p class="text-sm text-gray-800 dark:text-gray-200">
|
||||
<strong>Easy setup!</strong> Connect to a hosted MCP server. Works from anywhere without any
|
||||
local
|
||||
installation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const targetTab = this.dataset.tab;
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
||||
If someone is hosting the FiveM MCP server for you, follow these steps to connect:
|
||||
</p>
|
||||
|
||||
// Remove active class from all buttons
|
||||
tabButtons.forEach(btn => {
|
||||
btn.classList.remove('active', 'border-indigo-500', 'text-indigo-600');
|
||||
btn.classList.add('border-transparent', 'text-gray-500');
|
||||
});
|
||||
<!-- Step 1 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. Get the Server URL</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">
|
||||
Ask your server administrator for the MCP server URL. It will look like:
|
||||
</p>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>https://your-domain.com/fivem</code></pre>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3 mt-4">
|
||||
If you're using the official hosted server, use this URL:
|
||||
</p>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>{{ route('fivem') }}</code></pre>
|
||||
</div>
|
||||
|
||||
// Add active class to clicked button
|
||||
this.classList.remove('border-transparent', 'text-gray-500');
|
||||
this.classList.add('active', 'border-indigo-500', 'text-indigo-600');
|
||||
<!-- Step 2 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Configure Claude Desktop
|
||||
</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Edit your Claude Desktop configuration file:
|
||||
</p>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 mb-3 ml-4">
|
||||
<li><strong>macOS:</strong> <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">~/Library/Application Support/Claude/claude_desktop_config.json</code>
|
||||
</li>
|
||||
<li><strong>Windows:</strong> <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">%APPDATA%\Claude\claude_desktop_config.json</code>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
// Hide all tab contents
|
||||
tabContents.forEach(content => {
|
||||
content.classList.add('hidden');
|
||||
content.classList.remove('active');
|
||||
});
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Add this configuration (replace the URL with
|
||||
your actual server URL):
|
||||
</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
|
||||
// Show target tab content
|
||||
const targetContent = document.querySelector(`[data-tab-content="${targetTab}"]`);
|
||||
if (targetContent) {
|
||||
targetContent.classList.remove('hidden');
|
||||
targetContent.classList.add('active');
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3 mt-6"><strong>For VSCode (Cline Extension):</strong></p>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Edit your VSCode <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">settings.json</code>:
|
||||
</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"url": "https://your-domain.com/fivem"
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Restart Claude Desktop</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
Completely quit and restart Claude Desktop for changes to take effect.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">4. Verify Connection</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
In Claude Desktop, you should see a small 🔌 icon or indication that the FiveM MCP server is
|
||||
connected.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-green-50 dark:bg-green-900/20 border-l-4 border-green-500 p-4">
|
||||
<p class="text-sm text-green-800 dark:text-green-200">
|
||||
<strong>That's it!</strong> You're now connected to the remote MCP server and can start
|
||||
using FiveM development
|
||||
tools with Claude.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Local Setup Tab -->
|
||||
<div data-tab-content="local" class="animate-fade-in hidden">
|
||||
<div
|
||||
class="bg-gray-50 dark:bg-gray-700/20 border-l-4 border-gray-400 dark:border-gray-500 p-4 mb-6">
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">
|
||||
<strong>Advanced setup.</strong> Run the MCP server on your own machine. Requires PHP and
|
||||
Laravel
|
||||
installation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-6">
|
||||
If you want to run the MCP server on your own machine:
|
||||
</p>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">1. Test the Server</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">First, verify the server works:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>cd /path/to/fivem-mcp
|
||||
php artisan mcp:inspector fivem</code></pre>
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm mt-2">This opens a web inspector where you
|
||||
can test all tools.</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">2. Configure Claude Desktop
|
||||
</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Edit your Claude Desktop configuration file:
|
||||
</p>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 mb-3 ml-4">
|
||||
<li><strong>macOS:</strong> <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">~/Library/Application Support/Claude/claude_desktop_config.json</code>
|
||||
</li>
|
||||
<li><strong>Windows:</strong> <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">%APPDATA%\Claude\claude_desktop_config.json</code>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Add this configuration:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>@verbatim{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"command": "php",
|
||||
"args": [
|
||||
"artisan",
|
||||
"mcp:start",
|
||||
"fivem"
|
||||
],
|
||||
"cwd": "/path/to/fivem-mcp"
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3"><strong>Or use the full PHP path (e.g., for
|
||||
Herd):</strong></p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcpServers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": [
|
||||
"/path/to/fivem-mcp/artisan",
|
||||
"mcp:start",
|
||||
"fivem"
|
||||
]
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3 mt-6"><strong>For VSCode (Cline
|
||||
Extension):</strong></p>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">Edit your VSCode <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">settings.json</code>:
|
||||
</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto mb-4"><code>@verbatim{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "php",
|
||||
"args": ["artisan", "mcp:start", "fivem"],
|
||||
"cwd": "/path/to/fivem-mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3"><strong>Or with full paths:</strong></p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatim{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"fivem": {
|
||||
"command": "/path/to/php",
|
||||
"args": ["/path/to/fivem-mcp/artisan", "mcp:start", "fivem"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}@endverbatim</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">3. Restart Claude Desktop
|
||||
</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
Completely quit and restart Claude Desktop for changes to take effect.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">4. Verify Connection</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
In Claude Desktop, you should see a small 🔌 icon or indication that the FiveM MCP server is
|
||||
connected.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Quick Examples -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Quick Examples</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-4">Once connected, try these prompts in Claude:</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="border-l-4 border-gta-orange pl-4">
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Example 1: Search Documentation</h4>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>Search FiveM docs for "state bags"</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-gta-orange pl-4">
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Example 2: Look Up a Native</h4>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>What does the GetPlayerPed native function do? Show me an example.</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-gta-orange pl-4">
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Example 3: Generate a Manifest</h4>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>Generate a fxmanifest.lua for my resource called "vehicle-shop" using ESX framework</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-gta-orange pl-4">
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Example 4: List Events</h4>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>Show me all FiveM core server events</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="border-l-4 border-gta-orange pl-4">
|
||||
<h4 class="font-semibold text-gray-900 dark:text-white mb-2">Example 5: Create Boilerplate</h4>
|
||||
<pre
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded p-3 text-sm"><code>Create a complete resource structure for a QBCore script called "bank-heist" with NUI</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Troubleshooting -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Troubleshooting</h2>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">Server Not Connecting</h3>
|
||||
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-3 ml-4">
|
||||
<li>
|
||||
<strong>Check PHP Path:</strong> Make sure the PHP path in your config is correct
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-3 mt-2 overflow-x-auto"><code>@verbatimwhich php
|
||||
# or for Herd:
|
||||
ls -la "~/Library/Application Support/Herd/bin/"@endverbatim</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Test Manually:</strong> Run the server command directly
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-3 mt-2 overflow-x-auto"><code>@verbatimcd /path/to/fivem-mcp
|
||||
php artisan mcp:start fivem@endverbatim</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Check Logs:</strong> Look at Claude Desktop logs
|
||||
<ul class="list-disc list-inside ml-6 mt-2">
|
||||
<li>macOS: <code
|
||||
class="bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 px-2 py-1 rounded text-sm">~/Library/Logs/Claude/</code>
|
||||
</li>
|
||||
<li>Windows: Check Event Viewer or app logs</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">Permission Issues</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">If you get permission errors:</p>
|
||||
<pre class="bg-gray-900 text-gray-100 rounded p-4 overflow-x-auto"><code>@verbatimcd /path/to/fivem-mcp
|
||||
chmod +x artisan@endverbatim</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-3">Path Issues</h3>
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
Make sure to use <strong>absolute paths</strong> in your config, not relative paths.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Next Steps -->
|
||||
<section class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Next Steps</h2>
|
||||
<ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4">
|
||||
<li><a href="{{ route('docs.documentation') }}"
|
||||
class="link-gta">Read
|
||||
the full
|
||||
documentation</a></li>
|
||||
<li>Explore all 5 tools in the MCP Inspector</li>
|
||||
<li>Try creating a complete FiveM resource with AI assistance</li>
|
||||
<li>Contribute new tools or improve existing ones</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- Support -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">Support</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 mb-3">For issues:</p>
|
||||
<ol class="list-decimal list-inside text-gray-700 dark:text-gray-300 space-y-2 ml-4">
|
||||
<li>Check <a href="https://laravel.com/docs/mcp"
|
||||
class="link-gta">Laravel
|
||||
MCP
|
||||
Documentation</a></li>
|
||||
<li>Check <a href="https://docs.fivem.net/"
|
||||
class="link-gta">FiveM
|
||||
Documentation</a></li>
|
||||
<li>Review server logs</li>
|
||||
<li>Open a GitHub issue</li>
|
||||
</ol>
|
||||
<p class="text-gray-700 dark:text-gray-300 mt-6 text-lg font-semibold">Happy coding! 🎮</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="h-full">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>@yield('title', 'FiveM MCP Server Documentation')</title>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
|
||||
<body class="h-full bg-gray-50 dark:bg-gray-900">
|
||||
<div class="min-h-full">
|
||||
<!-- Navigation -->
|
||||
@include('layouts.partials.navigation')
|
||||
|
||||
<!-- Main Content -->
|
||||
<main>
|
||||
@yield('content')
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
@include('layouts.partials.footer')
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<footer class="bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 mt-12">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
<p class="text-center text-sm text-gray-500 dark:text-gray-400">
|
||||
Built with <a href="https://laravel.com/docs/mcp"
|
||||
class="link-gta">Laravel
|
||||
MCP</a>
|
||||
for <a href="https://docs.fivem.net"
|
||||
class="link-gta">FiveM</a>
|
||||
development
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,35 @@
|
||||
<nav class="bg-white dark:bg-gray-800 shadow-sm">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between h-16">
|
||||
<div class="flex">
|
||||
<div class="shrink-0 flex items-center">
|
||||
<h1 class="text-xl font-bold text-gray-900 dark:text-white">FiveM MCP Server</h1>
|
||||
</div>
|
||||
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
|
||||
<a href="{{ route('docs.index') }}"
|
||||
class="{{ request()->routeIs('docs.index') ? 'border-gta-orange text-gray-900 dark:text-white' : 'border-transparent text-gray-500 dark:text-gray-400 hover:border-gray-300 dark:hover:border-gray-600 hover:text-gray-700 dark:hover:text-gray-300' }} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
|
||||
Home
|
||||
</a>
|
||||
<a href="{{ route('docs.quickstart') }}"
|
||||
class="{{ request()->routeIs('docs.quickstart') ? 'border-gta-orange text-gray-900 dark:text-white' : 'border-transparent text-gray-500 dark:text-gray-400 hover:border-gray-300 dark:hover:border-gray-600 hover:text-gray-700 dark:hover:text-gray-300' }} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
|
||||
Quick Start
|
||||
</a>
|
||||
<a href="{{ route('docs.documentation') }}"
|
||||
class="{{ request()->routeIs('docs.documentation') ? 'border-gta-orange text-gray-900 dark:text-white' : 'border-transparent text-gray-500 dark:text-gray-400 hover:border-gray-300 dark:hover:border-gray-600 hover:text-gray-700 dark:hover:text-gray-300' }} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a href="https://github.com/adrianmejias/fivem-mcp" target="_blank" rel="noopener noreferrer"
|
||||
class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 inline-flex items-center px-3 py-2 text-sm font-medium">
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v 3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
||||
</svg>
|
||||
<span class="ml-2">GitHub</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,25 @@
|
||||
## QBCore Resources Directory
|
||||
|
||||
Complete list of all {{ count($resources) }} official QBCore resources. Use `GetQBCoreResourceReference` to get detailed information about specific resources.
|
||||
|
||||
@php
|
||||
$grouped = collect($resources)->groupBy('category');
|
||||
@endphp
|
||||
|
||||
@foreach($grouped as $category => $categoryResources)
|
||||
### {{ $category }}
|
||||
|
||||
| Resource | Description | Documentation |
|
||||
|----------|-------------|-----------------|
|
||||
@foreach($categoryResources as $resource)
|
||||
| **{{ $resource['title'] }}** (`{{ $resource['name'] }}`) | {{ $resource['description'] }} | [View Docs]({{ $resource['url'] }}) |
|
||||
@endforeach
|
||||
|
||||
@endforeach
|
||||
|
||||
### Quick Links
|
||||
- [QBCore Framework GitHub](https://github.com/qbcore-framework)
|
||||
- [QBCore Documentation](https://docs.qbcore.org)
|
||||
- [QBCore Discord Community](https://discord.gg/qbcore)
|
||||
|
||||
**Total Resources:** {{ count($resources) }}
|
||||
@@ -0,0 +1,64 @@
|
||||
## {{ $resource['title'] }} (`{{ $resource['name'] }}`)
|
||||
|
||||
**Category:** {!! $resource['category'] !!}
|
||||
|
||||
{{ $resource['description'] }}
|
||||
|
||||
### Overview
|
||||
|
||||
{{ $resource['description'] }}
|
||||
|
||||
@if(isset($resource['features']) && !empty($resource['features']))
|
||||
#### Key Features
|
||||
@foreach($resource['features'] as $feature)
|
||||
- {{ $feature }}
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if(isset($resource['commands']) && !empty($resource['commands']))
|
||||
### Commands
|
||||
|
||||
@foreach($resource['commands'] as $command => $description)
|
||||
#### `{{ $command }}`
|
||||
{{ $description }}
|
||||
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if(isset($resource['events']) && !empty($resource['events']))
|
||||
### Events
|
||||
|
||||
@foreach($resource['events'] as $event => $description)
|
||||
#### `{{ $event }}`
|
||||
{{ $description }}
|
||||
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if(isset($resource['callbacks']) && !empty($resource['callbacks']))
|
||||
### Callbacks
|
||||
|
||||
@foreach($resource['callbacks'] as $callback => $description)
|
||||
#### `{{ $callback }}`
|
||||
{{ $description }}
|
||||
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if(isset($resource['items']) && !empty($resource['items']))
|
||||
### Items
|
||||
|
||||
| Item | Description |
|
||||
|------|-------------|
|
||||
@foreach($resource['items'] as $item => $description)
|
||||
| `{{ $item }}` | {{ $description }} |
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
### Documentation
|
||||
- [Resource Documentation]({{ $resource['url'] }})
|
||||
- [QBCore Framework](https://docs.qbcore.org)
|
||||
- [GitHub Repository](https://github.com/qbcore-framework)
|
||||
|
||||
**Learn More:**
|
||||
To get detailed configuration options and advanced usage, visit the [full documentation]({{ $resource['url'] }}) for this resource.
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\COX\Doorlock\Client\GetOxDoorlockClientFunction;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
it('get ox_doorlock client function returns response with content', function () {
|
||||
$tool = new GetOxDoorlockClientFunction;
|
||||
$request = new Request(['function_name' => 'getClosestDoor']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock client function handles unknown function', function () {
|
||||
$tool = new GetOxDoorlockClientFunction;
|
||||
$request = new Request(['function_name' => 'NonExistentFunction123']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
});
|
||||
|
||||
it('get ox_doorlock client function works with pickClosestDoor', function () {
|
||||
$tool = new GetOxDoorlockClientFunction;
|
||||
$request = new Request(['function_name' => 'pickClosestDoor']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock client function works with useClosestDoor', function () {
|
||||
$tool = new GetOxDoorlockClientFunction;
|
||||
$request = new Request(['function_name' => 'useClosestDoor']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock client function supports javascript examples', function () {
|
||||
$tool = new GetOxDoorlockClientFunction;
|
||||
$request = new Request(['function_name' => 'getClosestDoor', 'language' => 'js']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\COX\Doorlock\Server\GetOxDoorlockServerEvent;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
it('get ox_doorlock server event returns response with content', function () {
|
||||
$tool = new GetOxDoorlockServerEvent;
|
||||
$request = new Request(['event_name' => 'ox_doorlock:stateChanged']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock server event handles unknown event', function () {
|
||||
$tool = new GetOxDoorlockServerEvent;
|
||||
$request = new Request(['event_name' => 'NonExistentEvent123']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
});
|
||||
|
||||
it('get ox_doorlock server event supports javascript examples', function () {
|
||||
$tool = new GetOxDoorlockServerEvent;
|
||||
$request = new Request(['event_name' => 'ox_doorlock:stateChanged', 'language' => 'js']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\COX\Doorlock\Server\GetOxDoorlockServerFunction;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
it('get ox_doorlock server function returns response with content', function () {
|
||||
$tool = new GetOxDoorlockServerFunction;
|
||||
$request = new Request(['function_name' => 'getDoor']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock server function handles unknown function', function () {
|
||||
$tool = new GetOxDoorlockServerFunction;
|
||||
$request = new Request(['function_name' => 'NonExistentFunction123']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
});
|
||||
|
||||
it('get ox_doorlock server function works with getDoorFromName', function () {
|
||||
$tool = new GetOxDoorlockServerFunction;
|
||||
$request = new Request(['function_name' => 'getDoorFromName']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock server function works with editDoor', function () {
|
||||
$tool = new GetOxDoorlockServerFunction;
|
||||
$request = new Request(['function_name' => 'editDoor']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock server function works with setDoorState', function () {
|
||||
$tool = new GetOxDoorlockServerFunction;
|
||||
$request = new Request(['function_name' => 'setDoorState']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_doorlock server function supports javascript examples', function () {
|
||||
$tool = new GetOxDoorlockServerFunction;
|
||||
$request = new Request(['function_name' => 'getDoor', 'language' => 'js']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\COX\Fuel\Client\GetOxFuelClientFunction;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
it('get ox_fuel client function returns response with content', function () {
|
||||
$tool = new GetOxFuelClientFunction;
|
||||
$request = new Request(['function_name' => 'setMoneyCheck']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_fuel client function handles unknown function', function () {
|
||||
$tool = new GetOxFuelClientFunction;
|
||||
$request = new Request(['function_name' => 'NonExistentFunction123']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
});
|
||||
|
||||
it('get ox_fuel client function supports javascript examples', function () {
|
||||
$tool = new GetOxFuelClientFunction;
|
||||
$request = new Request(['function_name' => 'setMoneyCheck', 'language' => 'js']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\COX\Fuel\Server\GetOxFuelServerFunction;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
it('get ox_fuel server function returns response with content', function () {
|
||||
$tool = new GetOxFuelServerFunction;
|
||||
$request = new Request(['function_name' => 'setPaymentMethod']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_fuel server function handles unknown function', function () {
|
||||
$tool = new GetOxFuelServerFunction;
|
||||
$request = new Request(['function_name' => 'NonExistentFunction123']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
});
|
||||
|
||||
it('get ox_fuel server function supports javascript examples', function () {
|
||||
$tool = new GetOxFuelServerFunction;
|
||||
$request = new Request(['function_name' => 'setPaymentMethod', 'language' => 'js']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\COX\Target\Client\GetOxTargetClientFunction;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
it('get ox_target client function returns response with content', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'addSphereZone']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_target client function handles unknown function', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'NonExistentFunction123']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
});
|
||||
|
||||
it('get ox_target client function works with addGlobalVehicle', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'addGlobalVehicle']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_target client function works with addModel', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'addModel']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_target client function works with addBoxZone', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'addBoxZone']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_target client function works with addPolyZone', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'addPolyZone']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_target client function works with isActive', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'isActive']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('get ox_target client function supports javascript examples', function () {
|
||||
$tool = new GetOxTargetClientFunction;
|
||||
$request = new Request(['function_name' => 'addEntity', 'language' => 'js']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
|
||||
expect($response)->not()->toBeNull();
|
||||
expect($response->content())->not()->toBeNull();
|
||||
});
|
||||
@@ -42,6 +42,20 @@ it('documentation renders correct view', function () {
|
||||
$response->assertViewIs('docs.documentation');
|
||||
});
|
||||
|
||||
it('documentation page includes dynamic tools data', function () {
|
||||
$response = $this->get('/documentation');
|
||||
|
||||
$response->assertViewHas('tools');
|
||||
$response->assertViewHas('resources');
|
||||
$response->assertViewHas('prompts');
|
||||
|
||||
expect($response->viewData('tools'))->toBeArray();
|
||||
expect($response->viewData('resources'))->toBeArray();
|
||||
expect($response->viewData('prompts'))->toBeArray();
|
||||
|
||||
expect($response->viewData('tools'))->not()->toBeEmpty();
|
||||
});
|
||||
|
||||
it('nonexistent route returns 404', function () {
|
||||
$response = $this->get('/nonexistent-page-xyz');
|
||||
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\QBCore\GetQBCoreResourceList;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
test('GetQBCoreResourceList returns all resources', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request([]);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('QBCore Resources Directory');
|
||||
expect($content)->toContain('qb-ambulancejob');
|
||||
expect($content)->toContain('qb-adminmenu');
|
||||
expect($content)->toContain('qb-policejob');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList contains all 58 resources', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request([]);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
// Count resource names in the response
|
||||
$resources = [
|
||||
'qb-adminmenu', 'qb-ambulancejob', 'qb-apartments', 'qb-banking', 'qb-bankrobbery',
|
||||
'qb-busjob', 'qb-cityhall', 'qb-clothing', 'qb-crypto', 'qb-diving',
|
||||
'qb-doorlock', 'qb-drugs', 'qb-fitbit', 'qb-fuel', 'qb-garages',
|
||||
'qb-garbagejob', 'qb-hotdogjob', 'qb-houserobbery', 'qb-houses', 'qb-hud',
|
||||
'qb-input', 'qb-interior', 'qb-inventory', 'qb-jewelry', 'qb-lapraces',
|
||||
'qb-loading', 'qb-management', 'qb-mechanicjob', 'qb-menu', 'qb-minigames',
|
||||
'qb-multicharacter', 'qb-newsjob', 'qb-pawnshop', 'qb-phone', 'qb-policejob',
|
||||
'qb-prison', 'qb-radialmenu', 'qb-radio', 'qb-recyclejob', 'qb-scoreboard',
|
||||
'qb-scrapyard', 'qb-shops', 'qb-smallresources', 'qb-spawn', 'qb-storerobbery',
|
||||
'qb-streetraces', 'qb-taxijob', 'qb-towjob', 'qb-target', 'qb-truckerjob',
|
||||
'qb-truckrobbery', 'qb-vehiclekeys', 'qb-vehiclesales', 'qb-vehicleshop', 'qb-vineyard',
|
||||
'qb-weapons', 'qb-weathersync', 'qb-weed',
|
||||
];
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
expect($content)->toContain($resource);
|
||||
}
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList filters by category - Jobs', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request(['category' => 'Jobs']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
// Should contain job resources
|
||||
expect($content)->toContain('qb-ambulancejob');
|
||||
expect($content)->toContain('qb-policejob');
|
||||
expect($content)->toContain('qb-mechanicjob');
|
||||
|
||||
// Should not contain non-job resources
|
||||
expect($content)->not->toContain('## Admin & Management');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList filters by category - Crime & Robberies', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request(['category' => 'Crime & Robberies']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('qb-bankrobbery');
|
||||
expect($content)->toContain('qb-drugs');
|
||||
expect($content)->toContain('qb-weed');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList filters by category - Admin & Management', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request(['category' => 'Admin & Management']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('qb-adminmenu');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList filters by category - UI & Interface', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request(['category' => 'UI & Interface']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('qb-hud');
|
||||
expect($content)->toContain('qb-menu');
|
||||
expect($content)->toContain('qb-target');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList filters by category - Housing & Interiors', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request(['category' => 'Housing & Interiors']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('qb-apartments');
|
||||
expect($content)->toContain('qb-houses');
|
||||
expect($content)->toContain('qb-interior');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList contains documentation links', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request([]);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('https://docs.qbcore.org/qbcore-documentation/qbcore-resources/');
|
||||
expect($content)->toContain('View Docs');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceList has grouped categories', function () {
|
||||
$tool = new GetQBCoreResourceList;
|
||||
$request = new Request([]);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('### Admin');
|
||||
expect($content)->toContain('### Jobs');
|
||||
expect($content)->toContain('### Crime');
|
||||
expect($content)->toContain('### Housing');
|
||||
expect($content)->toContain('### Vehicles');
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
use App\Mcp\Tools\QBCore\GetQBCoreResourceReference;
|
||||
use Laravel\Mcp\Request;
|
||||
|
||||
test('GetQBCoreResourceReference returns ambulance job details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-ambulancejob']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Ambulance Job');
|
||||
expect($content)->toContain('Hospital Check-in System');
|
||||
expect($content)->toContain('/heal');
|
||||
expect($content)->toContain('ifaks');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns admin menu details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-adminmenu']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Admin Menu');
|
||||
expect($content)->toContain('/admin');
|
||||
expect($content)->toContain('/blips');
|
||||
expect($content)->toContain('Player Management');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns hud details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-hud']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('HUD');
|
||||
expect($content)->toContain('Health Display');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns inventory details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-inventory']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Inventory');
|
||||
expect($content)->toContain('Player Systems');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns phone details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-phone']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Phone');
|
||||
expect($content)->toContain('Messaging');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns police job details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-policejob']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Police Job');
|
||||
expect($content)->toContain('Dispatch System');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference includes documentation URL', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-adminmenu']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('https://docs.qbcore.org/qbcore-documentation/qbcore-resources/qb-adminmenu');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference not found returns helpful message', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-nonexistent']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('not found');
|
||||
expect($content)->toContain('GetQBCoreResourceList');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference handles case variations', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'QBCore-Ambulancejob']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Ambulance Job');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns garages details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-garages']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Garages');
|
||||
expect($content)->toContain('Transportation');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference returns shops details', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-shops']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('Shops');
|
||||
expect($content)->toContain('Commerce');
|
||||
});
|
||||
|
||||
test('GetQBCoreResourceReference includes categories', function () {
|
||||
$tool = new GetQBCoreResourceReference;
|
||||
$request = new Request(['resource_name' => 'qb-target']);
|
||||
|
||||
$response = $tool->handle($request);
|
||||
$content = (string) $response->content();
|
||||
|
||||
expect($content)->toContain('UI & Interface');
|
||||
expect($content)->toContain('Target System');
|
||||
});
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+52
-1
@@ -8,7 +8,58 @@ export default defineConfig({
|
||||
input: ['resources/css/app.css', 'resources/js/app.js'],
|
||||
refresh: true,
|
||||
}),
|
||||
tailwindcss(),
|
||||
tailwindcss({
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
gta: {
|
||||
dark: '#1a1a1a',
|
||||
light: '#f8fafc',
|
||||
orange: '#F57C00',
|
||||
cyan: '#1de9b6',
|
||||
gray: '#334155',
|
||||
indigo: '#3b82f6',
|
||||
slate: {
|
||||
50: '#f8fafc',
|
||||
100: '#f1f5f9',
|
||||
200: '#e2e8f0',
|
||||
300: '#cbd5e1',
|
||||
400: '#94a3b8',
|
||||
500: '#64748b',
|
||||
600: '#475569',
|
||||
700: '#334155',
|
||||
800: '#1e293b',
|
||||
900: '#0f172a',
|
||||
},
|
||||
accent: {
|
||||
50: '#fff7ed',
|
||||
100: '#ffedd5',
|
||||
200: '#fed7aa',
|
||||
300: '#fdba74',
|
||||
400: '#fb923c',
|
||||
500: '#f57c00',
|
||||
600: '#ea580c',
|
||||
700: '#c2410c',
|
||||
800: '#9a3412',
|
||||
900: '#7c2d12',
|
||||
},
|
||||
neon: {
|
||||
50: '#ecfdf5',
|
||||
100: '#d1fae5',
|
||||
200: '#a7f3d0',
|
||||
300: '#6ee7b7',
|
||||
400: '#34d399',
|
||||
500: '#1de9b6',
|
||||
600: '#10b981',
|
||||
700: '#059669',
|
||||
800: '#047857',
|
||||
900: '#065f46',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
server: {
|
||||
watch: {
|
||||
|
||||
Reference in new issue
Block a user