Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Fancy Flow Mcp Laravel Package

particle-academy/fancy-flow-mcp

A Laravel package that provides a Model Context Protocol server for Fancy Flow, exposing flows, tools, and resources to AI clients so compatible assistants can inspect and interact with your Fancy Flow workspace.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin Laravel layer over laravel/mcp: it ships Server, Tool and Resource base classes plus a #[Version] attribute that is emitted in the serverInfo block of every MCP initialize response. It deliberately does not wrap the transport — routing, sessions and protocol negotiation stay in laravel/mcp. Treat it as scaffolding for your tool surface, not as a framework you configure.

Minimal path to a working endpoint:

  1. composer require particle-academy/<package> (pull the exact name from the README). This transitively installs laravel/mcp at ^0.9|^1.0 — either line resolves, so don't be surprised if you land on 0.9.
  2. Open the package's Server class first. That is the registration point: it lists the tools and resources your server advertises. Everything else hangs off it.
  3. Write one tool extending the package's Tool base class, with a name, a description, an input schema and a handle() method.
  4. Register it on the Server.
  5. Expose the server with laravel/mcp's route helper, e.g. Mcp::web('/mcp', YourServer::class) in routes/ai.php (or wherever your app registers it — check the README).
  6. Point an MCP client at the URL and watch the initialize response. If serverInfo comes back with the right name and version, your wiring is correct.

The first genuinely useful use case is a single read-only tool — "look up an order by number", "search the docs". Ship one, verify it end-to-end through a real client, and only then add resources and write tools. The failure modes of write tools over MCP (retries, duplicate side effects, an agent calling the same tool three times) are much easier to reason about once the happy path is proven.

The package's own test suite (48 tests, run against both laravel/mcp lines) is the best executable documentation of intended usage — read it before inventing structure.

Implementation Patterns

One tool per class, thin handle(). Put business logic in an action or service and let handle() validate, delegate, and format. MCP tools get re-invoked by agents that don't read your code; a tool whose body is a 60-line transaction is one you cannot test in isolation or evolve safely. Keep handle() at the level of "validate input → call action → return structured result".

Write the description and schema for the model, not for a human. The description is the prompt the agent sees when deciding whether to call you. Say what the tool does, when not to use it, and what it returns. Overlapping tool descriptions are the most common cause of an agent picking the wrong one — if two tools are close, say explicitly which to prefer.

Validate inside the tool and return tool errors, not exceptions. A thrown exception becomes a transport-level failure the model can't reason about; a validation message returned as the tool result lets it correct the arguments and retry. Use Laravel's Validator and shape the failure into your result.

Authorize on every call. MCP sessions are not auth boundaries; the same server can back different clients with different entitlements. Put the Gate::authorize() call in handle() (or a base class), not once at connection time. This also makes local testing with actingAs() trivial.

Split servers by audience, not by domain. A single Server with a curated tool list is easier to reason about than one giant server filtered at runtime. If you need a read-only external surface and a write-capable internal one, run two servers on two routes with two tool lists — the agent's context window is the constraint, and every advertised tool costs tokens.

Test at two levels. Unit-test tool classes directly by instantiating them and calling handle() — fast, no transport, catches 90% of bugs. Then keep one integration test per server that speaks HTTP, because that is where protocol-version breakage lands (see Gotchas). Do not rely solely on manual client testing.

Version the server from a constant. The #[Version] attribute takes a constant expression only, so a literal string will drift silently — this package shipped 0.1.0 for three minor releases because of exactly that. Define const VERSION = 'x.y.z' on your server (or a dedicated Version class), reference it from the attribute, and add a test asserting it matches your changelog's newest entry. The package does this via VersionIsSingleSourcedTest, and it's worth copying regardless of whether you use the package's helper.

Moving to laravel/mcp 1.x. The package's constraint is a widen, so nothing forces you. When you want 1.x:

"require": { "laravel/mcp": "^1.0" }

then composer update laravel/mcp -W (-W matters — a plain update won't move transitive constraints).

Gotchas and Tips

laravel/mcp 1.0 changes your side of the wire, not the package's. The package needed zero code changes because it only defines Server/Tool/Resource. But Mcp::web(...) routes under 1.0 require the MCP-Protocol-Version, Mcp-Method and Mcp-Name headers from 2026-07-28 clients. Legacy initialize-only clients are exempt, which means a handshake can succeed and a subsequent call can still fail — the classic "works in the inspector, fails in CI" shape. If you POST raw JSON in tests or curl your endpoint, add the headers or use an SDK client. Read laravel/mcp's UPGRADE.md before bumping.

Request::sessionId() is gone in 1.x. Any logging middleware, rate limiter key, or test assertion that reaches for it will fatal. Switch to whatever session identifier the 1.x request object exposes; grep for sessionId before you upgrade rather than after.

A stale #[Version] is invisible until an agent logs it. serverInfo is what clients record and cache; a wrong value turns up as a mystery in someone's telemetry months later. When a client misbehaves, decode the initialize response first — it tells you which server and which version actually answered, which is often not the code you just deployed.

Attribute arguments must be constant expressions. You cannot interpolate, call a function, or read config inside #[Version]. This is the whole reason the package uses a class constant, and why the constant-plus-assertion pattern exists: a correct constant with a stale attribute still lies. If you self-report a version anywhere else, assert it against the same source.

The CI matrix is the reason both 0.9 and 1.x work. A plain composer update resolves only the newest, so the 0.9 half of the range would go untested — the package added a laravel/mcp axis (0.9.*, 1.*) for this. If you maintain your own package that depends on laravel/mcp, copy that trick; otherwise your lower bound is decorative. If you're an application, note the inverse: your lockfile picks one line, and that is the only one you actually test against.

The package is deliberately thin — that's an extension point. Because it's just base classes, your override surface is your own subclasses: put cross-cutting behaviour (authorization, audit logging, consistent error shaping, result truncation) in a project-level BaseTool extending the package's Tool, and never edit vendor code.

Release-workflow rename only affects scripts. The tag workflow moved from release-gate.yml ("Release gate") to publish.yml ("Publish"). Packagist syncs from the tag and never reads the workflow file, so Composer resolution is unaffected. The only thing that breaks is a script calling gh run list --workflow=release-gate.yml.

Pinning laravel/mcp to ^0.9 yourself silently opts you out. The package will happily resolve 0.9 forever. That is safe today, but it means you inherit none of 1.x's fixes and will face the header change in one jump later. Decide deliberately rather than by lockfile inertia.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource