laravel-swarm-mcp maintained by builtbyberry
Laravel Swarm MCP
A read-only Model Context Protocol server for
Laravel Swarm, built on the
official laravel/mcp package. It exposes a
swarm's durable run history, durable-run inspection, and audit-outbox health as
MCP Resources, so any MCP-compatible AI client — Claude, Cursor, and others
— can observe your swarm runs.
Read-only by design. This release exposes observability Resources only and registers zero Tools. It can observe swarm runs but can never pause, resume, cancel, or signal them. Operator control is a deliberately deferred later minor (see Read-only by design).
It wraps Laravel Swarm's public display-read contracts (introduced in core
v0.19.0) — ReadableRunHistoryStore, InspectsDurableRuns, and
ReadableAuditOutbox — so every read is display-decrypted and degrade-safe by
construction: an undecryptable field (e.g. after an APP_KEY rotation) comes
back as null with an *_available: false flag rather than raw sw0:
ciphertext or a failed read.
Requirements
- PHP
^8.5 builtbyberry/laravel-swarm^0.19laravel/mcp^0.8
Installation
composer require builtbyberry/laravel-swarm-mcp
Optionally publish the config file:
php artisan vendor:publish --tag="swarm-mcp-config"
Configuration
config/swarm-mcp.php:
| Key | Default | Description |
|---|---|---|
server.enabled |
true |
Master switch for the observability server. |
server.name |
Laravel Swarm |
Display name reported to MCP clients. |
transports.stdio.enabled |
true |
Expose the server over stdio (local / agent-host). |
transports.http.enabled |
false |
Expose the server over the networked HTTP transport. Off by default. |
transports.http.path |
swarm-mcp |
Route path for the HTTP transport. |
authentication.middleware |
['auth:sanctum'] |
Middleware applied to the HTTP transport route. |
resources.* |
true |
Toggle individual resource groups (run_history, durable_inspection, audit_outbox). |
Connecting an MCP client
stdio (default)
The server is registered under the handle laravel-swarm and started with the
laravel/mcp command:
php artisan mcp:start laravel-swarm
Point your MCP client at that command. For example, a Claude Desktop entry:
{
"mcpServers": {
"laravel-swarm": {
"command": "php",
"args": ["artisan", "mcp:start", "laravel-swarm"]
}
}
}
HTTP (Streamable)
Set transports.http.enabled to true. The server is then reachable at the
configured path (default POST /swarm-mcp) behind the configured authentication
middleware. A networked caller must authenticate — the default guard is
auth:sanctum (your application provides Sanctum). See
Authorization.
Resources
| URI | Backed by | Returns |
|---|---|---|
swarm://runs |
ReadableRunHistoryStore::query() |
The most recent runs — a lean, decryption-free projection. |
swarm://runs/{runId} |
ReadableRunHistoryStore::findForDisplay() |
A single run with its steps; sealed fields degrade per field. |
swarm://durable-runs/{runId} |
InspectsDurableRuns::inspect() |
Assembled durable-run state: waits, signals, progress, children, branches, hierarchical outputs. |
swarm://audit-outbox/health |
ReadableAuditOutbox::healthSummary() |
Outbox availability + pending / dead-letter / reserved counts. |
swarm://audit-outbox/queue/{state} |
pending() / deadLettered() |
The pending or dead-lettered queue (metadata + last_error only). |
swarm://audit-outbox/records/{id} |
ReadableAuditOutbox::record() |
A single outbox row with its full display-decrypted payload. |
Display-safe reads
Every resource resolves the bound public contract — never the @internal
SwarmPersistenceCipher. Sealed payloads are opened through the display path,
which honors swarm.persistence.decrypt_failure_policy and degrades per
field: an undecryptable value becomes null with an explicit *_available: false flag (output_available, context_available, payload_available, …).
A rotated APP_KEY or a single poison row therefore never throws, never aborts
the read, and never leaks sw0: ciphertext to the client. The audit-outbox
reads are pure SELECTs — they cannot drain or mutate the outbox that
swarm:relay --type=audit drains.
Read-only by design
v0.1.0 is intentionally Resources-only. The server registers no Tools, so
an AI client can read swarm state but cannot act on it. Exposing the operator
control verbs (pause / resume / cancel / signal) to an autonomous agent is a
subtle surface — it requires a per-run authorization callback and deliberately
excludes fleet-wide batch verbs — and is planned for a later minor behind an
explicit opt-in. Until then, this package is a safe, observe-only window into
your swarms.
Authorization
The server authenticates a networked caller (via the configured
authentication.middleware), but it is agnostic about which runs a caller
may read — scoping run visibility to a tenant or user is your application's
responsibility. This release exposes read-only data only.
Testing
composer test # Pest
composer analyse # PHPStan (level 8)
composer lint # Pint
License
The MIT License (MIT). Please see the License File for more information.