mattiasgeniar/filament-mcp
Expose your Filament resources to AI agents over MCP. Per-record create, read, and update tools are generated from your existing resource forms; delete tools are opt-in. Access is forbidden by default, gated by a token and your own authorization callback, and every call is audited.
Install and wire it up
composer require mattiasgeniar/filament-mcp
php artisan vendor:publish --tag="filament-mcp-config"
Check your laravel/mcp version before anything else. As of v0.1, the package tracks Laravel MCP 1.0. If your app is still on laravel/mcp 0.x, Composer will silently resolve you to v0.0.10 and you'll be reading docs for a package version you don't have. Run composer show laravel/mcp mattiasgeniar/filament-mcp and confirm both. The upgrade path is: bump laravel/mcp to ^1.0 first, read the upstream 1.0 upgrade notes, then take filament-mcp v0.1 — the release note is a single line, so assume the behaviour changes come from upstream, not from this package.
Then read the published config/filament-mcp.php first — it is the whole package. You need three things configured before anything works:
~/.claude.json / Cursor config holds it, not your repo).User model's policies are applied automatically. Verify this deliberately (see Gotchas).Confirm the MCP server is actually registered — the package builds on the official laravel/mcp server, so php artisan list should show the MCP serve/route command. v0.1 changed the upstream server API, so if the command is missing after the upgrade, you're looking at a registration/API mismatch, not a config typo. Point Claude Code or Cursor at that endpoint with the token and ask the client to list its tools before you ask it to do anything. The tool list is your debugging ground truth.
Where to look next
tests/ directory — with a PHPStan badge and a tests badge but only ~13 stars, the test suite is the most reliable specification of behaviour, especially around form introspection and authorization. On v0.1, check that the suite has been updated for the laravel/mcp 1.0 API before trusting green.CHANGELOG.md before you pin a version. v0.1's changelog is one line, so treat the upstream laravel/mcp changelog as the real release notes.tools/list output) rather than the README, since they are derived from your forms and therefore your reality.First use case
Pick a low-blast-radius resource — a Post, Product, or Category — and enable read only first. Have the agent list and fetch records and narrate what it sees. Only then add create/update. Leave delete off entirely for the first sprint; it's an explicit per-resource opt-in for a reason.
Roll out in capability tiers. Treat the three capabilities as independent feature flags per resource: list/show → create/update → delete. Most teams will never need delete; the agent can call an update to soft-delete or set a status column instead, which is auditable and reversible.
Your form schema is now a public API contract. Because tools are introspected from the form, every TextInput::make('title')->required()->maxLength(255) becomes a tool argument with those constraints. Two consequences:
helperText() and label() deliberately — they are the prompt the model reads when filling the argument.Repeater and a Builder becomes a 30-argument tool with a monstrous JSON schema, which burns context and confuses the model. Consider a slimmed-down form or a separate resource for agent-facing work.Let validation do the work. Don't re-implement rules in the agent's prompt. Required fields, maxLength, unique, exists, and Rule objects all surface as tool-schema constraints and server-side validation errors, and a competent MCP client will read the error and retry. Good errors beat good prompting.
Keep the human and agent paths identical. The whole value proposition is that a new field shows up in the agent's tools automatically. Resist the urge to fork a separate "agent form" unless you genuinely need a narrower surface — the moment you fork, you own drift.
Authorize narrowly, in the callback. Pattern this as: token → identity/scope → policy check. Log the decision. If your callback returns a boolean, add logging around it, because a silent false looks identical to a missing tool from the client's perspective.
Use separate tokens per agent and per environment. A staging token in CI, a personal token in your editor, a read-only token for a "reporter" agent. Never reuse the prod-write token locally.
Complement, don't replace, custom tools. Generated CRUD handles the boring 80%. For anything with side effects — "publish and notify subscribers", "import CSV" — write a small explicit tool or a Filament Action and expose that, so the agent can't assemble the wrong sequence of primitive writes. Verify the custom-tool API against laravel/mcp 1.0, since that is where the breaking changes land.
Test the tools like an API. Feature-test the MCP endpoint: assert a tool exists for a resource, assert the schema contains a new field after you add it to the form, assert an unauthorized token gets nothing back. This is cheap insurance for a young package — and it is also your upgrade safety net for exactly this kind of dependency-major bump.
laravel/mcp first, snapshot your tools/list output before the upgrade, and diff it after. Argument names, required-ness, and error shapes are the things most likely to shift without a line in this package's changelog.is_admin, role_id, published_at, price. Audit each exposed resource with fresh eyes and ->hidden() / ->disabled() anything sensitive — but verify how those map into the generated schema, because a hidden field that's still required() is a trap. Re-verify after any upgrade, since this mapping is introspector logic.auth()->user(), so Gate/policy checks may pass, fail, or throw depending on the implementation. Confirm this on day one with a resource that has a restrictive policy. Do not assume $user->can() guards are doing anything. If laravel/mcp 1.0 reworked how requests are authenticated, this is the first thing to retest.FileUpload, RichEditor, Repeater, Builder, KeyValue, and Select::relationship() with thousands of options rarely map cleanly to JSON tool arguments. Probe each one you actually use before enabling that resource; don't let an agent attempt a file upload on a Friday afternoon.Select whose options() hits the database means the tool schema changes as data changes — or gets frozen at boot. Prefer enums and static option lists for agent-facing fields.created_by from auth(). Over MCP there may be no user. Add explicit attribution (a source column, an audit log, or a wrapper in your authorization callback) if "who did this?" matters — and it will, the first time something looks wrong.tools/list output → your authorization callback's logs → the package's tests/. If a tool is missing, it's almost always the resource whitelist or the callback returning false, not the form introspector. On a fresh major bump, add "is the MCP server command even registered?" to the top of that list.v0.1 on laravel/mcp ^1.0 and v0.0.10 on 0.x — so state explicitly in your composer.json which one you're on and why.How can I help you explore Laravel packages today?