1. Require the package
composer require chkltlabs/laravel-porthole
Then publish config if needed:
php artisan vendor:publish --tag=porthole-config
2. Define gates before boot
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::define('viewPorthole', function (User $user): bool {
return $user->hasRole('staff');
});
Gate::define('mutateHorizon', function (User $user): bool {
return $user->hasRole('staff');
});
Horizon, Pulse, and Telescope still apply their own gates. A caller needs both
viewPorthole and the source gate. Adjust the role check to match your app —
hasRole('staff') is an example, not a package dependency.
3. Choose a transport
Local stdio (laptop / same machine, APP_ENV=local):
{
"command": "php",
"args": ["artisan", "mcp:start", "porthole"],
"cwd": "/absolute/path/to/your-app"
}
On stdio there is normally no logged-in user. For local trust, set
auth.stdio_required to false (HTTP stays authenticated),
or use HTTP with a token instead.
HTTP with a fixed bearer token:
{
"url": "https://your-app.test/mcp/porthole",
"headers": {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
}
Configure auth.middleware (for example auth:sanctum or auth:api)
in config/porthole.php. For Porthole OAuth, omit the bearer header and follow the
README’s OAuth section — do not put the issuer URL in the client’s url field.