Tools here are PHP running inside the Laravel application itself, not a separate process calling it over an API — a custom tool is a closure with typed parameters, and the model toolkit reads through your app rather than around it. That is the whole appeal, and it is also where the thinking goes: whatever you register is what the client can reach, and on `/mcp` the middleware in `config/loop.php` is what stands in front of it. Start on STDIO with `--user-id` so the session is scoped to a real user, and turn the HTTP route on once you have decided who is allowed to call it. Two rough edges worth knowing before you pick a transport: Streamable HTTP is new enough that not every client speaks it, while SSE — which most clients do speak — is deprecated; and if you serve your local site over https, self-signed certificates will make most clients fail, so use http locally or stay on STDIO.
A Composer package — `composer require kirschbaum-development/laravel-loop` — that turns an existing Laravel application into an MCP server. Tools are PHP defined inside that application and registered on the `Loop` facade from a service provider such as `app/Providers/AppServiceProvider`; Prism builds them underneath. It speaks STDIO through `php artisan loop:mcp:start`, and it can serve MCP straight off your own app on two routes: `/mcp` for Streamable HTTP and `/mcp/sse` for the deprecated HTTP+SSE transport. It is a beta — the package and its pre-built tools are marked as still in development.
- Your models' data, read-only for now — `Kirschbaum\Loop\Toolkits\LaravelModelToolkit`, with write operations listed as still to come
- Test data made from the client — `Kirschbaum\Loop\Toolkits\LaravelFactoriesToolkit` builds records through your factories
- Stripe — `Kirschbaum\Loop\Tools\StripeTool` calls the Stripe API
- Filament — a separate package, `kirschbaum-development/laravel-loop-filament`, registered as `Loop::toolkit(Kirschbaum\Loop\Filament\FilamentToolkit::make())`
- Your own tool without writing a class — `CustomTool::make(name:, description:)` chained with `withStringParameter` / `withNumberParameter` and a `using()` closure; the parameter types come from Prism
- Your own tool as a class — implement the `Tool` contract, return a `Prism\Prism\Tool` from `build()`; group several by implementing `Toolkit` and returning a `ToolCollection`
- Client wiring generated for you — `php artisan loop:mcp:generate-config` walks through the config for Claude Code, Cursor and other clients that take a JSON file
- A way to call a tool without a client — `php artisan loop:mcp:call` runs it from the terminal so you can read the raw output
A Laravel application you can deploy into — supported versions are Laravel 10.x/11.x/12.x — plus Composer, PHP, and `php artisan vendor:publish --tag="loop-config"` to get `config/loop.php`. On STDIO the session runs as one of your own users: pass `--user-id`, and `--user-model` / `--auth-guard` when the default guard or model is not what you want; `--debug` turns on verbose output. The HTTP routes are off until you set `LOOP_STREAMABLE_HTTP_ENABLED=true` or `LOOP_SSE_ENABLED=true` (paths move with `LOOP_STREAMABLE_HTTP_PATH` and `LOOP_SSE_PATH`), and each one is fronted by the middleware in `config/loop.php` — `auth:sanctum` is the shipped default, and clients then send an `Authorization: Bearer` header. SSE keeps session state through `LOOP_SSE_DRIVER`, `file` by default with `session_ttl` at 86400 seconds; `redis` is the recommended driver in production, to avoid file locking. Node.js (> 20) comes in only when your client cannot open an SSE connection itself and you bridge through the `mcp-remote` package.
One command — composer require kirschbaum-development/laravel-loop
