12 Commits
Author SHA1 Message Date
Adrian Mejias 9ef6bcf371 Merge branch 'main' of https://github.com/adrianmejias/fivem-mcp 2026-03-08 03:57:43 -05:00
Adrian Mejias 9001610eda fix: update file permissions for artisan script 2026-03-08 03:57:15 -05:00
Adrian Mejias 0c7730de8f chore: update documentation and enforce testing rules
- Added testing rules to CLAUDE.md and GEMINI.md, specifying that every change must be programmatically tested and to run the minimum number of tests for efficiency.
- Updated _ide_helper.php to remove unnecessary whitespace in PHPDoc comments.
- Changed file permissions for artisan to ensure it is not executable.
- Updated composer.lock to reflect new versions for several packages, including league/commonmark, psy/psysh, and symfony components.
- Updated package-lock.json to upgrade postcss to version 8.5.8.
2026-03-08 03:57:00 -05:00
Adrian Mejias 0fce6d164e Create SECURITY.md for security policy
Add a security policy document outlining supported versions and vulnerability reporting.
2026-03-07 19:00:37 -06:00
Adrian Mejias b5eff9f40d Update index.blade.php 2026-03-02 08:40:20 -06:00
Adrian Mejias c4b2d7695f Remove documentation site link from README
Removed link to the documentation site.
2026-03-01 22:21:42 -06:00
Adrian Mejias 82498b9189 Add GitHub link to navigation bar 2026-03-01 22:20:13 -06:00
Adrian Mejias 949a9230c5 Refactor documentation layout and styles
- Updated the index page to improve text formatting and structure.
- Enhanced feature sections with consistent styling and updated icons.
- Modified quick start guide for better clarity and visual appeal.
- Adjusted footer links for consistent styling.
- Updated navigation links to reflect new color scheme.
- Added new color definitions in Vite configuration for better theme support.
2026-03-01 18:07:35 -06:00
Adrian Mejias f6da6705db Refactor documentation layout and styling
- Removed the old layout file `layout.blade.php` and created a new layout structure in `layouts/app.blade.php`.
- Introduced partial views for navigation and footer in `layouts/partials/navigation.blade.php` and `layouts/partials/footer.blade.php`.
- Updated the `quickstart.blade.php` to extend the new layout and utilize the new partials.
- Enhanced the styling with dark mode support and improved color themes in `vite.config.js`.
2026-03-01 17:47:48 -06:00
Adrian Mejias 686b41e406 Add test for dynamic tools data in documentation page 2026-03-01 17:09:52 -06:00
Adrian Mejias 24c53368a7 Add COX tools for doorlock, fuel, and target functionalities
- Implemented GetOxDoorlockServerFunction and GetOxDoorlockClientFunction for server-side and client-side door management, respectively.
- Created GetOxFuelServerFunction and GetOxFuelClientFunction for handling fuel management on server and client sides.
- Developed GetOxTargetClientFunction to manage targeting interactions, including global options and zone management.
- Added feature tests for all new tools to ensure functionality and error handling for unknown functions.
2026-03-01 15:35:04 -06:00
Adrian Mejias 29b854fd44 Add feature tests for QBCore and FiveM tools
- Implement tests for GetInventoryClientFunction and GetInventoryServerFunction in the COX namespace.
- Create tests for GenerateManifest and GenerateResourceBoilerplate in the FiveM namespace.
- Add tests for event and native function references in the FiveM namespace.
- Introduce tests for QBCore client and server event references, functions, and configurations.
- Implement tests for shared data retrieval in QBCore.
- Ensure all tests validate expected responses and handle edge cases.
2026-03-01 15:23:07 -06:00
58 changed files with 3705 additions and 1332 deletions

No files matched your search

+8 -8
View File
@@ -24,12 +24,12 @@ search-docs(['mcp tools', 'mcp resources', 'mcp validation'])
### Artisan Commands
<!-- Create MCP Primitives -->
Create MCP Primitives"
```bash
{{ $assist->artisanCommand('make:mcp-tool ToolName') }}
{{ $assist->artisanCommand('make:mcp-resource ResourceName') }}
{{ $assist->artisanCommand('make:mcp-prompt PromptName') }}
{{ $assist->artisanCommand('make:mcp-server ServerName') }}
php artisan make:mcp-tool ToolName
php artisan make:mcp-resource ResourceName
php artisan make:mcp-prompt PromptName
php artisan make:mcp-server ServerName
```
### Basic Tool Implementation
@@ -114,11 +114,11 @@ $response->assertSentNotification('event/type', ['data' => 'value']);
Test interactively using the inspector:
<!-- Launch MCP Inspector -->
<!--Launch MCP Inspector-->
```bash
{{ $assist->artisanCommand('mcp:inspector mcp/my-server') }} # Web server
php artisan mcp:inspector mcp/my-server # Web server
{{ $assist->artisanCommand('mcp:inspector my-server') }} # Local server
php artisan mcp:inspector my-server # Local server
```
+22 -14
View File
@@ -2210,21 +2210,29 @@ namespace PHPSTORM_META {
registerArgumentsSet('middleware',
'web','api',);
registerArgumentsSet('routes',
'boost.browser-logs','storage.local','storage.local.upload',);
'boost.browser-logs','fivem','docs.index',
'docs.quickstart','docs.documentation','storage.local','storage.local.upload',);
registerArgumentsSet('views',
'welcome','laravel-exceptions-renderer::components.badge','laravel-exceptions-renderer::components.empty-state','laravel-exceptions-renderer::components.file-with-line','laravel-exceptions-renderer::components.formatted-source',
'laravel-exceptions-renderer::components.frame','laravel-exceptions-renderer::components.frame-code','laravel-exceptions-renderer::components.header','laravel-exceptions-renderer::components.http-method','laravel-exceptions-renderer::components.icons.alert',
'laravel-exceptions-renderer::components.icons.check','laravel-exceptions-renderer::components.icons.chevron-left','laravel-exceptions-renderer::components.icons.chevron-right','laravel-exceptions-renderer::components.icons.chevrons-down-up','laravel-exceptions-renderer::components.icons.chevrons-left',
'laravel-exceptions-renderer::components.icons.chevrons-right','laravel-exceptions-renderer::components.icons.chevrons-up-down','laravel-exceptions-renderer::components.icons.copy','laravel-exceptions-renderer::components.icons.database','laravel-exceptions-renderer::components.icons.folder',
'laravel-exceptions-renderer::components.icons.folder-open','laravel-exceptions-renderer::components.icons.globe','laravel-exceptions-renderer::components.icons.info','laravel-exceptions-renderer::components.icons.laravel-ascii','laravel-exceptions-renderer::components.laravel-ascii-spotlight',
'laravel-exceptions-renderer::components.layout','laravel-exceptions-renderer::components.query','laravel-exceptions-renderer::components.request-body','laravel-exceptions-renderer::components.request-header','laravel-exceptions-renderer::components.request-url',
'laravel-exceptions-renderer::components.routing','laravel-exceptions-renderer::components.routing-parameter','laravel-exceptions-renderer::components.section-container','laravel-exceptions-renderer::components.separator','laravel-exceptions-renderer::components.syntax-highlight',
'laravel-exceptions-renderer::components.topbar','laravel-exceptions-renderer::components.trace','laravel-exceptions-renderer::components.vendor-frame','laravel-exceptions-renderer::components.vendor-frames','laravel-exceptions-renderer::markdown',
'laravel-exceptions-renderer::show','laravel-exceptions::401','laravel-exceptions::402','laravel-exceptions::403','laravel-exceptions::404',
'laravel-exceptions::419','laravel-exceptions::429','laravel-exceptions::500','laravel-exceptions::503','laravel-exceptions::layout',
'laravel-exceptions::minimal','notifications::email','pagination::bootstrap-4','pagination::bootstrap-5','pagination::default',
'pagination::semantic-ui','pagination::simple-bootstrap-4','pagination::simple-bootstrap-5','pagination::simple-default','pagination::simple-tailwind',
'pagination::tailwind',);
'docs.documentation','docs.index','docs.quickstart','layouts.app','layouts.partials.footer',
'layouts.partials.navigation','mcp.cox.cox-event-list','mcp.cox.cox-event-reference','mcp.cox.cox-function','mcp.fivem.event-list',
'mcp.fivem.event-reference','mcp.fivem.native-function','mcp.qbcore.qbcore-config','mcp.qbcore.qbcore-event-list','mcp.qbcore.qbcore-event-reference',
'mcp.qbcore.qbcore-function','mcp.qbcore.qbcore-players','mcp.qbcore.qbcore-resource-list','mcp.qbcore.qbcore-resource-reference','mcp.qbcore.qbcore-shared-data',
'mcp.resources.best-practices','mcp.resources.code-snippets','mcp.resources.database-queries','mcp.resources.framework-comparison','mcp.shared.resource-boilerplate',
'mcp.shared.search-results','mcp.templates.client-js','mcp.templates.client-lua','mcp.templates.config-js','mcp.templates.config-lua',
'mcp.templates.fxmanifest','mcp.templates.nui-css','mcp.templates.nui-html','mcp.templates.nui-script-js','mcp.templates.nui-script-lua',
'mcp.templates.server-js','mcp.templates.server-lua','laravel-exceptions-renderer::components.badge','laravel-exceptions-renderer::components.empty-state','laravel-exceptions-renderer::components.file-with-line',
'laravel-exceptions-renderer::components.formatted-source','laravel-exceptions-renderer::components.frame','laravel-exceptions-renderer::components.frame-code','laravel-exceptions-renderer::components.header','laravel-exceptions-renderer::components.http-method',
'laravel-exceptions-renderer::components.icons.alert','laravel-exceptions-renderer::components.icons.check','laravel-exceptions-renderer::components.icons.chevron-left','laravel-exceptions-renderer::components.icons.chevron-right','laravel-exceptions-renderer::components.icons.chevrons-down-up',
'laravel-exceptions-renderer::components.icons.chevrons-left','laravel-exceptions-renderer::components.icons.chevrons-right','laravel-exceptions-renderer::components.icons.chevrons-up-down','laravel-exceptions-renderer::components.icons.copy','laravel-exceptions-renderer::components.icons.database',
'laravel-exceptions-renderer::components.icons.folder','laravel-exceptions-renderer::components.icons.folder-open','laravel-exceptions-renderer::components.icons.globe','laravel-exceptions-renderer::components.icons.info','laravel-exceptions-renderer::components.icons.laravel-ascii',
'laravel-exceptions-renderer::components.laravel-ascii-spotlight','laravel-exceptions-renderer::components.layout','laravel-exceptions-renderer::components.query','laravel-exceptions-renderer::components.request-body','laravel-exceptions-renderer::components.request-header',
'laravel-exceptions-renderer::components.request-url','laravel-exceptions-renderer::components.routing','laravel-exceptions-renderer::components.routing-parameter','laravel-exceptions-renderer::components.section-container','laravel-exceptions-renderer::components.separator',
'laravel-exceptions-renderer::components.syntax-highlight','laravel-exceptions-renderer::components.topbar','laravel-exceptions-renderer::components.trace','laravel-exceptions-renderer::components.vendor-frame','laravel-exceptions-renderer::components.vendor-frames',
'laravel-exceptions-renderer::markdown','laravel-exceptions-renderer::show','laravel-exceptions::401','laravel-exceptions::402','laravel-exceptions::403',
'laravel-exceptions::404','laravel-exceptions::419','laravel-exceptions::429','laravel-exceptions::500','laravel-exceptions::503',
'laravel-exceptions::layout','laravel-exceptions::minimal','notifications::email','pagination::bootstrap-4','pagination::bootstrap-5',
'pagination::default','pagination::semantic-ui','pagination::simple-bootstrap-4','pagination::simple-bootstrap-5','pagination::simple-default',
'pagination::simple-tailwind','pagination::tailwind',);
registerArgumentsSet('translations',
'auth.failed','auth.password','auth.throttle','pagination.previous','pagination.next',
'passwords.reset','passwords.sent','passwords.throttled','passwords.token','passwords.user',
+7
View File
@@ -133,6 +133,13 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Add useful array shape type definitions when appropriate.
=== tests rules ===
# Test Enforcement
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
=== laravel/core rules ===
# Do Things the Laravel Way
+7
View File
@@ -133,6 +133,13 @@ protected function isAccessible(User $user, ?string $path = null): bool
- Add useful array shape type definitions when appropriate.
=== tests rules ===
# Test Enforcement
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
=== laravel/core rules ===
# Do Things the Laravel Way
-1
View File
@@ -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
+21
View File
@@ -0,0 +1,21 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.
+65 -65
View File
@@ -353,7 +353,7 @@ namespace Illuminate\Support\Facades {
/**
* Get the path to the views directory.
*
*
* This method returns the first configured path in the array of view paths.
*
* @param string $path
@@ -1229,9 +1229,9 @@ namespace Illuminate\Support\Facades {
/**
* Returns true if the container can return an entry for the given identifier.
*
*
* Returns false otherwise.
*
*
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
*
@@ -2607,7 +2607,7 @@ namespace Illuminate\Support\Facades {
/**
* Log the user out of the application on their current device only.
*
*
* This method does not cycle the "remember" token.
*
* @return void
@@ -2621,7 +2621,7 @@ namespace Illuminate\Support\Facades {
/**
* Invalidate other sessions for the current user.
*
*
* The application must be using the AuthenticateSession middleware.
*
* @param string $password
@@ -3585,7 +3585,7 @@ namespace Illuminate\Support\Facades {
/**
* Register the routes for handling broadcast authentication and sockets.
*
*
* Alias of "routes" method.
*
* @param array|null $attributes
@@ -3832,7 +3832,7 @@ namespace Illuminate\Support\Facades {
/**
* Dispatch a command to its appropriate handler in the current process.
*
*
* Queueable jobs will be dispatched to the "sync" queue.
*
* @param mixed $command
@@ -4632,7 +4632,7 @@ namespace Illuminate\Support\Facades {
/**
* Retrieve multiple items from the cache by key.
*
*
* Items not found in the cache will have a null value.
*
* @param array $keys
@@ -6264,7 +6264,7 @@ namespace Illuminate\Support\Facades {
/**
* @template TReturn of mixed
*
*
* Run the callback function with the given context values and restore the original context state when complete.
* @param (callable(): TReturn) $callback
* @param array<string, mixed> $data
@@ -8382,7 +8382,7 @@ namespace Illuminate\Support\Facades {
/**
* @template TReturn of mixed
*
*
* Execute a Closure within a transaction.
* @param (\Closure(static): TReturn) $callback
* @param int $attempts
@@ -9521,7 +9521,7 @@ namespace Illuminate\Support\Facades {
/**
* Recursively delete a directory.
*
*
* The directory itself may be optionally preserved.
*
* @param string $directory
@@ -11298,7 +11298,7 @@ namespace Illuminate\Support\Facades {
/**
* Action must be taken immediately.
*
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
@@ -11315,7 +11315,7 @@ namespace Illuminate\Support\Facades {
/**
* Critical conditions.
*
*
* Example: Application component unavailable, unexpected exception.
*
* @param string|\Stringable $message
@@ -11346,7 +11346,7 @@ namespace Illuminate\Support\Facades {
/**
* Exceptional occurrences that are not errors.
*
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
@@ -11377,7 +11377,7 @@ namespace Illuminate\Support\Facades {
/**
* Interesting events.
*
*
* Example: User logs in, SQL logs.
*
* @param string|\Stringable $message
@@ -12897,7 +12897,7 @@ namespace Illuminate\Support\Facades {
/**
* Indicate that queue workers should not poll for restart or pause signals.
*
*
* This prevents the workers from hitting the application cache to determine if they need to pause or restart.
*
* @return void
@@ -14508,7 +14508,7 @@ namespace Illuminate\Support\Facades {
/**
* This method belongs to Symfony HttpFoundation and is not usually needed when using Laravel.
*
*
* Instead, you may use the "input" method.
*
* @param string $key
@@ -14582,7 +14582,7 @@ namespace Illuminate\Support\Facades {
/**
* Whether the request contains a Session object.
*
*
* This method does not give any information about the state of the session object,
* like whether the session is started or not. It is just a way to check if this Request
* is associated with a Session instance.
@@ -14831,7 +14831,7 @@ namespace Illuminate\Support\Facades {
/**
* Sets the parameters for this request.
*
*
* This method also re-initializes all properties.
*
* @param array $query The GET parameters
@@ -14863,7 +14863,7 @@ namespace Illuminate\Support\Facades {
/**
* Creates a Request based on a given URI and configuration.
*
*
* The information contained in the URI always take precedence
* over the other information (server and parameters).
*
@@ -14885,7 +14885,7 @@ namespace Illuminate\Support\Facades {
/**
* Sets a callable able to create a Request instance.
*
*
* This is mainly useful when you need to override the Request class
* to keep BC with an existing system. It should not be used for any
* other purpose.
@@ -14900,7 +14900,7 @@ namespace Illuminate\Support\Facades {
/**
* Overrides the PHP global variables according to this request instance.
*
*
* It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE.
* $_FILES is never overridden, see rfc1867
*
@@ -14915,7 +14915,7 @@ namespace Illuminate\Support\Facades {
/**
* Sets a list of trusted proxies.
*
*
* You should only list the reverse proxies that you manage directly.
*
* @param array $proxies A list of trusted proxies, the string 'REMOTE_ADDR' will be replaced with $_SERVER['REMOTE_ADDR'] and 'PRIVATE_SUBNETS' by IpUtils::PRIVATE_SUBNETS
@@ -14954,7 +14954,7 @@ namespace Illuminate\Support\Facades {
/**
* Sets a list of trusted host patterns.
*
*
* You should only list the hosts you manage using regexs.
*
* @param array $hostPatterns A list of trusted host patterns
@@ -14980,7 +14980,7 @@ namespace Illuminate\Support\Facades {
/**
* Normalizes a query string.
*
*
* It builds a normalized query string, where keys/value pairs are alphabetized,
* have consistent escaping and unneeded delimiters are removed.
*
@@ -14994,13 +14994,13 @@ namespace Illuminate\Support\Facades {
/**
* Enables support for the _method request parameter to determine the intended HTTP method.
*
*
* Be warned that enabling this feature might lead to CSRF issues in your code.
* Check that you are using CSRF tokens when required.
* If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered
* and used to send a "PUT" or "DELETE" request via the _method request parameter.
* If these methods are not protected against CSRF, this presents a possible vulnerability.
*
*
* The HTTP method can only be overridden when the real HTTP method is POST.
*
* @static
@@ -15024,7 +15024,7 @@ namespace Illuminate\Support\Facades {
/**
* Sets the list of HTTP methods that can be overridden.
*
*
* Set to null to allow all methods to be overridden (default). Set to an
* empty array to disallow overrides entirely. Otherwise, provide the list
* of uppercased method names that are allowed.
@@ -15087,11 +15087,11 @@ namespace Illuminate\Support\Facades {
/**
* Returns the client IP addresses.
*
*
* In the returned array the most trusted IP address is first, and the
* least trusted one last. The "real" client IP address is the last one,
* but this is also the least trusted one. Trusted proxies are stripped.
*
*
* Use this method carefully; you should use getClientIp() instead.
*
* @see getClientIp()
@@ -15106,13 +15106,13 @@ namespace Illuminate\Support\Facades {
/**
* Returns the client IP address.
*
*
* This method can read the client IP address from the "X-Forwarded-For" header
* when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
* header value is a comma+space separated list of IP addresses, the left-most
* being the original client, and each successive proxy that passed the request
* adding the IP address where it received the request from.
*
*
* If your reverse proxy uses a different header name than "X-Forwarded-For",
* ("Client-Ip" for instance), configure it via the $trustedHeaderSet
* argument of the Request::setTrustedProxies() method instead.
@@ -15142,11 +15142,11 @@ namespace Illuminate\Support\Facades {
/**
* Returns the path being requested relative to the executed script.
*
*
* The path info always starts with a /.
*
*
* Suppose this request is instantiated from /mysite on localhost:
*
*
* * http://localhost/mysite returns '/'
* * http://localhost/mysite/about returns '/about'
* * http://localhost/mysite/enco%20ded returns '/enco%20ded'
@@ -15164,9 +15164,9 @@ namespace Illuminate\Support\Facades {
/**
* Returns the root path from which this request is executed.
*
*
* Suppose that an index.php file instantiates this request object:
*
*
* * http://localhost/index.php returns an empty string
* * http://localhost/index.php/page returns an empty string
* * http://localhost/web/index.php returns '/web'
@@ -15184,9 +15184,9 @@ namespace Illuminate\Support\Facades {
/**
* Returns the root URL from which this request is executed.
*
*
* The base URL never ends with a /.
*
*
* This is similar to getBasePath(), except that it also includes the
* script filename (e.g. index.php) if one exists.
*
@@ -15214,10 +15214,10 @@ namespace Illuminate\Support\Facades {
/**
* Returns the port on which the request is made.
*
*
* This method can read the client port from the "X-Forwarded-Port" header
* when trusted proxies were set via "setTrustedProxies()".
*
*
* The "X-Forwarded-Port" header must contain the client port.
*
* @return int|string|null Can be a string if fetched from the server bag
@@ -15269,7 +15269,7 @@ namespace Illuminate\Support\Facades {
/**
* Returns the HTTP host being requested.
*
*
* The port name will be appended to the host if it's non-standard.
*
* @static
@@ -15296,7 +15296,7 @@ namespace Illuminate\Support\Facades {
/**
* Gets the scheme and HTTP host.
*
*
* If the URL was called with basic authentication, the user
* and the password are not added to the generated string.
*
@@ -15337,12 +15337,12 @@ namespace Illuminate\Support\Facades {
/**
* Returns the path as relative reference from the current Request path.
*
*
* Only the URIs path component (no schema, host etc.) is relevant and must be given.
* Both paths must be absolute and not contain relative parts.
* Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
* Furthermore, they can be used to reduce the link size in documents.
*
*
* Example target paths, given a base path of "/a/b/c/d":
* - "/a/b/c/d" -> ""
* - "/a/b/c/" -> "./"
@@ -15361,7 +15361,7 @@ namespace Illuminate\Support\Facades {
/**
* Generates the normalized query string for the Request.
*
*
* It builds a normalized query string, where keys/value pairs are alphabetized
* and have consistent escaping.
*
@@ -15376,10 +15376,10 @@ namespace Illuminate\Support\Facades {
/**
* Checks whether the request is secure or not.
*
*
* This method can read the client protocol from the "X-Forwarded-Proto" header
* when trusted proxies were set via "setTrustedProxies()".
*
*
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
*
* @static
@@ -15393,10 +15393,10 @@ namespace Illuminate\Support\Facades {
/**
* Returns the host name.
*
*
* This method can read the client host name from the "X-Forwarded-Host" header
* when trusted proxies were set via "setTrustedProxies()".
*
*
* The "X-Forwarded-Host" header must contain the client host name.
*
* @throws SuspiciousOperationException when the host name is invalid or not trusted
@@ -15423,13 +15423,13 @@ namespace Illuminate\Support\Facades {
/**
* Gets the request "intended" method.
*
*
* If the X-HTTP-Method-Override header is set, and if the method is a POST,
* then it is used to determine the "real" intended HTTP method.
*
*
* The _method request parameter can also be used to determine the HTTP method,
* but only if enableHttpMethodParameterOverride() has been called.
*
*
* The method is always an uppercased string.
*
* @see getRealMethod()
@@ -15481,7 +15481,7 @@ namespace Illuminate\Support\Facades {
/**
* Gets the format associated with the mime type.
*
*
* Resolution order:
* 1) Exact match on the full MIME type (e.g. "application/json").
* 2) Match on the canonical MIME type (i.e. before the first ";" parameter).
@@ -15518,9 +15518,9 @@ namespace Illuminate\Support\Facades {
/**
* Gets the request format.
*
*
* Here is the process to determine the format:
*
*
* * format defined by the user (with setRequestFormat())
* * _format request attribute
* * $default
@@ -15661,7 +15661,7 @@ namespace Illuminate\Support\Facades {
/**
* Returns the protocol version.
*
*
* If the application is behind a proxy, the protocol version used in the
* requests between the client and the proxy and between the proxy and the
* server might be different. This returns the former (from the "Via" header)
@@ -15731,7 +15731,7 @@ namespace Illuminate\Support\Facades {
* Gets the preferred format for the response by inspecting, in the following order:
* * the request format set using setRequestFormat;
* * the values of the Accept HTTP header.
*
*
* Note that if you use this method, you should send the "Vary: Accept" header
* in the response to prevent any issues with intermediary HTTP caches.
*
@@ -15798,7 +15798,7 @@ namespace Illuminate\Support\Facades {
/**
* Returns true if the request is an XMLHttpRequest.
*
*
* It works if your JavaScript library sets an X-Requested-With HTTP header.
* It is known to work with common JavaScript frameworks:
*
@@ -15827,7 +15827,7 @@ namespace Illuminate\Support\Facades {
/**
* Indicates whether this request originated from a trusted proxy.
*
*
* This can be useful to determine whether or not to trust the
* contents of a proxy-specific header.
*
@@ -16457,7 +16457,7 @@ namespace Illuminate\Support\Facades {
/**
* Retrieve data as a boolean value.
*
*
* Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false.
*
* @param string|null $key
@@ -17683,7 +17683,7 @@ namespace Illuminate\Support\Facades {
/**
* Add a middleware to the beginning of a middleware group.
*
*
* If the middleware is already in the group, it will not be added again.
*
* @param string $group
@@ -17699,7 +17699,7 @@ namespace Illuminate\Support\Facades {
/**
* Add a middleware to the end of a middleware group.
*
*
* If the middleware is already in the group, it will not be added again.
*
* @param string $group
@@ -24309,7 +24309,7 @@ namespace {
/**
* Specify attributes that should be added to any new models created by this builder.
*
*
* The given key / value pairs will also be added as where conditions to the query.
*
* @param \Illuminate\Contracts\Database\Query\Expression|array|string $attributes
@@ -24890,7 +24890,7 @@ namespace {
/**
* Add a relationship count / exists condition to the query with where clauses.
*
*
* Also load the relationship with the same condition.
*
* @param string $relation
+63 -1
View File
@@ -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();
}
}
+16
View File
@@ -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(),
];
}
}
Generated
+66 -66
View File
@@ -1535,16 +1535,16 @@
},
{
"name": "league/commonmark",
"version": "2.8.0",
"version": "2.8.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb"
"reference": "84b1ca48347efdbe775426f108622a42735a6579"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb",
"reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/84b1ca48347efdbe775426f108622a42735a6579",
"reference": "84b1ca48347efdbe775426f108622a42735a6579",
"shasum": ""
},
"require": {
@@ -1569,9 +1569,9 @@
"phpstan/phpstan": "^1.8.2",
"phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0",
"scrutinizer/ocular": "^1.8.1",
"symfony/finder": "^5.3 | ^6.0 | ^7.0",
"symfony/process": "^5.4 | ^6.0 | ^7.0",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0",
"symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0",
"symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0",
"unleashedtech/php-coding-standard": "^3.1.1",
"vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0"
},
@@ -1638,7 +1638,7 @@
"type": "tidelift"
}
],
"time": "2025-11-26T21:48:24+00:00"
"time": "2026-03-05T21:37:03+00:00"
},
{
"name": "league/config",
@@ -3092,16 +3092,16 @@
},
{
"name": "psy/psysh",
"version": "v0.12.20",
"version": "v0.12.21",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
"reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373"
"reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/19678eb6b952a03b8a1d96ecee9edba518bb0373",
"reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/4821fab5b7cd8c49a673a9fd5754dc9162bb9e97",
"reference": "4821fab5b7cd8c49a673a9fd5754dc9162bb9e97",
"shasum": ""
},
"require": {
@@ -3165,9 +3165,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.12.20"
"source": "https://github.com/bobthecow/psysh/tree/v0.12.21"
},
"time": "2026-02-11T15:05:28+00:00"
"time": "2026-03-06T21:21:28+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -3446,16 +3446,16 @@
},
{
"name": "symfony/console",
"version": "v7.4.6",
"version": "v7.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "6d643a93b47398599124022eb24d97c153c12f27"
"reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/6d643a93b47398599124022eb24d97c153c12f27",
"reference": "6d643a93b47398599124022eb24d97c153c12f27",
"url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d",
"reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d",
"shasum": ""
},
"require": {
@@ -3520,7 +3520,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.4.6"
"source": "https://github.com/symfony/console/tree/v7.4.7"
},
"funding": [
{
@@ -3540,7 +3540,7 @@
"type": "tidelift"
}
],
"time": "2026-02-25T17:02:47+00:00"
"time": "2026-03-06T14:06:20+00:00"
},
{
"name": "symfony/css-selector",
@@ -3991,16 +3991,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v7.4.6",
"version": "v7.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065"
"reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/fd97d5e926e988a363cef56fbbf88c5c528e9065",
"reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f94b3e7b7dafd40e666f0c9ff2084133bae41e81",
"reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81",
"shasum": ""
},
"require": {
@@ -4049,7 +4049,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.4.6"
"source": "https://github.com/symfony/http-foundation/tree/v7.4.7"
},
"funding": [
{
@@ -4069,20 +4069,20 @@
"type": "tidelift"
}
],
"time": "2026-02-21T16:25:55+00:00"
"time": "2026-03-06T13:15:18+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.4.6",
"version": "v7.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83"
"reference": "3b3fcf386c809be990c922e10e4c620d6367cab1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/002ac0cf4cd972a7fd0912dcd513a95e8a81ce83",
"reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3b3fcf386c809be990c922e10e4c620d6367cab1",
"reference": "3b3fcf386c809be990c922e10e4c620d6367cab1",
"shasum": ""
},
"require": {
@@ -4168,7 +4168,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.4.6"
"source": "https://github.com/symfony/http-kernel/tree/v7.4.7"
},
"funding": [
{
@@ -4188,7 +4188,7 @@
"type": "tidelift"
}
],
"time": "2026-02-26T08:30:57+00:00"
"time": "2026-03-06T16:33:18+00:00"
},
{
"name": "symfony/mailer",
@@ -4276,16 +4276,16 @@
},
{
"name": "symfony/mime",
"version": "v7.4.6",
"version": "v7.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f"
"reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/9fc881d95feae4c6c48678cb6372bd8a7ba04f5f",
"reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f",
"url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1",
"reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1",
"shasum": ""
},
"require": {
@@ -4341,7 +4341,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v7.4.6"
"source": "https://github.com/symfony/mime/tree/v7.4.7"
},
"funding": [
{
@@ -4361,7 +4361,7 @@
"type": "tidelift"
}
],
"time": "2026-02-05T15:57:06+00:00"
"time": "2026-03-05T15:24:09+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -6170,16 +6170,16 @@
},
{
"name": "barryvdh/reflection-docblock",
"version": "v2.4.0",
"version": "v2.4.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git",
"reference": "d103774cbe7e94ddee7e4870f97f727b43fe7201"
"reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/d103774cbe7e94ddee7e4870f97f727b43fe7201",
"reference": "d103774cbe7e94ddee7e4870f97f727b43fe7201",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b",
"reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b",
"shasum": ""
},
"require": {
@@ -6216,9 +6216,9 @@
}
],
"support": {
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.4.0"
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.4.1"
},
"time": "2025-07-17T06:07:30+00:00"
"time": "2026-03-05T20:09:01+00:00"
},
{
"name": "brianium/paratest",
@@ -6817,25 +6817,25 @@
},
{
"name": "laravel/boost",
"version": "v2.2.1",
"version": "v2.2.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/boost.git",
"reference": "e27f1616177377fef95296620530c44a7dda4df9"
"reference": "44ab65a5455c2d6fceb71d6145f8d5d89c02d889"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/boost/zipball/e27f1616177377fef95296620530c44a7dda4df9",
"reference": "e27f1616177377fef95296620530c44a7dda4df9",
"url": "https://api.github.com/repos/laravel/boost/zipball/44ab65a5455c2d6fceb71d6145f8d5d89c02d889",
"reference": "44ab65a5455c2d6fceb71d6145f8d5d89c02d889",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.9",
"illuminate/console": "^11.45.3|^12.41.1",
"illuminate/contracts": "^11.45.3|^12.41.1",
"illuminate/routing": "^11.45.3|^12.41.1",
"illuminate/support": "^11.45.3|^12.41.1",
"laravel/mcp": "^0.5.1",
"illuminate/console": "^11.45.3|^12.41.1|^13.0",
"illuminate/contracts": "^11.45.3|^12.41.1|^13.0",
"illuminate/routing": "^11.45.3|^12.41.1|^13.0",
"illuminate/support": "^11.45.3|^12.41.1|^13.0",
"laravel/mcp": "^0.5.1|^0.6.0",
"laravel/prompts": "^0.3.10",
"laravel/roster": "^0.5.0",
"php": "^8.2"
@@ -6843,7 +6843,7 @@
"require-dev": {
"laravel/pint": "^1.27.0",
"mockery/mockery": "^1.6.12",
"orchestra/testbench": "^9.15.0|^10.6",
"orchestra/testbench": "^9.15.0|^10.6|^11.0",
"pestphp/pest": "^2.36.0|^3.8.4|^4.1.5",
"phpstan/phpstan": "^2.1.27",
"rector/rector": "^2.1"
@@ -6879,7 +6879,7 @@
"issues": "https://github.com/laravel/boost/issues",
"source": "https://github.com/laravel/boost"
},
"time": "2026-02-25T16:07:36+00:00"
"time": "2026-03-06T20:20:28+00:00"
},
{
"name": "laravel/pail",
@@ -7030,16 +7030,16 @@
},
{
"name": "laravel/roster",
"version": "v0.5.0",
"version": "v0.5.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/roster.git",
"reference": "56904a78f4d7360c1c490ced7deeebf9aecb8c0e"
"reference": "5089de7615f72f78e831590ff9d0435fed0102bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/roster/zipball/56904a78f4d7360c1c490ced7deeebf9aecb8c0e",
"reference": "56904a78f4d7360c1c490ced7deeebf9aecb8c0e",
"url": "https://api.github.com/repos/laravel/roster/zipball/5089de7615f72f78e831590ff9d0435fed0102bb",
"reference": "5089de7615f72f78e831590ff9d0435fed0102bb",
"shasum": ""
},
"require": {
@@ -7087,7 +7087,7 @@
"issues": "https://github.com/laravel/roster/issues",
"source": "https://github.com/laravel/roster"
},
"time": "2026-02-17T17:33:35+00:00"
"time": "2026-03-05T07:58:43+00:00"
},
{
"name": "laravel/sail",
@@ -8026,16 +8026,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "6.0.1",
"version": "6.0.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e"
"reference": "897b5986ece6b4f9d8413fea345c7d49c757d6bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
"reference": "2f5cbed597cb261d1ea458f3da3a9ad32e670b1e",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/897b5986ece6b4f9d8413fea345c7d49c757d6bf",
"reference": "897b5986ece6b4f9d8413fea345c7d49c757d6bf",
"shasum": ""
},
"require": {
@@ -8085,9 +8085,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.1"
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/6.0.2"
},
"time": "2026-01-20T15:30:42+00:00"
"time": "2026-03-01T18:43:49+00:00"
},
{
"name": "phpdocumentor/type-resolver",
+3 -3
View File
@@ -2039,9 +2039,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"version": "8.5.8",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
"dev": true,
"funding": [
{
+101 -47
View File
@@ -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
View File
@@ -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');
}
});
});
});
+315 -540
View File
@@ -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&lt;?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>&lt;?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
+192 -166
View File
@@ -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>{
"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>
</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
-50
View File
@@ -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>
+371 -363
View File
@@ -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
+26
View File
@@ -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.
@@ -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();
});
+14
View File
@@ -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');
@@ -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');
});
+52 -1
View File
@@ -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: {