builtbyberry / laravel-swarm-mcp
Read-only Model Context Protocol (MCP) server for Laravel Swarm — expose durable run history, durable-run inspection, and audit-outbox health as MCP Resources over the official laravel/mcp package.
Requires
- php: ^8.4
- builtbyberry/laravel-swarm: ^0.19 || ^0.20 || ^0.21 || ^0.22 || ^0.23 || ^0.24 || ^0.25 || ^0.26 || ^0.27 || ^0.28
- illuminate/contracts: ^13.0
- illuminate/support: ^13.0
- laravel/mcp: ^1.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.10
- laravel/pint: ^1.29
- orchestra/testbench: ^11.1
- pestphp/pest: ^4.7
- pestphp/pest-plugin-laravel: ^4.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main / 0.3.x-dev
- v0.3.0
- v0.2.0
- v0.1.2
- v0.1.1
- v0.1.0
- dev-release/v0.3.0
- dev-chore/0.3.0-repin-core-028-release-candidate
- dev-feat/0.3.0-native1-core028-compatibility
- dev-feat/0.2.0-native1-core027-compatibility
- dev-release/v0.1.2
- dev-chore/0.1.2-release-wrap
- dev-chore/0.1.2-core-026-compatibility
- dev-release/v0.1.0
- dev-feat/0.1.0-mcp-resources
- dev-chore/0.1.0-scaffold
This package is auto-updated.
Last update: 2026-10-06 12:15:57 UTC
README
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.4 builtbyberry/laravel-swarm^0.19through^0.28laravel/mcp^1.0
Version 0.2 requires native Laravel MCP 1.x. See Upgrading for the dependency and client protocol change. The six read-only resources retain their URIs; no tools or prompts are registered.
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
CI retains historical core lanes and the published core v0.25.0 baseline. The
v0.2.0 compatibility work was validated against pinned core v0.26.0 / AI
^0.11.2 and core v0.27.0 / AI ^1.0 candidates at minimum and current
stable dependencies. v0.3.0 extends this to the frozen core v0.28.0 candidate
(269f749, release/v0.28.0) with native AI 1.x, adding two native1-028 lanes
for twenty runtime lanes overall. All runtime
lanes use native MCP ^1.0; the existing branch-naming gate remains. Tests exercise
authenticated native HTTP discovery, exact primitive inventory, all six resource
reads, protocol errors and guest rejection. See native MCP compatibility
evidence for source pins and reproduction.
Candidate metadata was temporary CI input; those lanes are historical prepublication evidence. Fresh Packagist-only installation after core and companion publication remains a separate shipping gate.
License
The MIT License (MIT). Please see the License File for more information.