内容
# Filament MCP
[](https://github.com/mattiasgeniar/filament-mcp/actions/workflows/tests.yml)
[](https://github.com/mattiasgeniar/filament-mcp/actions/workflows/phpstan.yml)
将您的 [Filament](https://filamentphp.com) 资源通过 [模型上下文协议](https://modelcontextprotocol.io) 暴露给 AI 代理,提供每个记录的 **创建、读取和更新** 工具,直接从现有的资源表单生成。删除工具作为明确的按资源开启。
将 Claude Code、Cursor 或任何 MCP 客户端指向您的应用程序,让它像在管理面板中一样管理您的内容,通过令牌和授权回调进行控制。
## 为什么
该软件包允许 AI 代理执行人类已经可以在 Filament 仪表盘上执行的操作。Filament 自己的 AI 工具帮助您 **编写** Filament 代码,而这个软件包则相反:它允许代理 **操作** 运行中的面板。与面向读取/批量操作的替代方案不同,它在官方的 [`laravel/mcp`](https://github.com/laravel/mcp) 服务器上生成真正的每个记录的 CRUD 工具,强制执行您的策略,并几乎完全从单个配置文件中配置。
- **生成,非手写。** 每个资源的表单都会被内省,因此新字段会自动显示为工具参数。
- **默认安全。** 在您明确授予配置权限之前,访问权限被禁止。
- **仅文本字段。** 只有类似文本的字段被暴露(参见 [限制](#限制))。
- **审计。** 每个工具调用都会被记录并归因于发出调用的令牌。在面板中查看令牌的调用历史记录在其自己的活动页面上。
## 要求
- PHP 8.2+
- Laravel 12 或 13
- Filament 5
## 安装
```bash
composer require mattiasgeniar/filament-mcp
php artisan migrate
```
配置文件将通过安装命令自动发布,或者手动发布:
```bash
php artisan filament-mcp:install
# 或
php artisan vendor:publish --tag=filament-mcp-config
```
## 配置
所有内容都位于 `config/filament-mcp.php` 中。您必须设置的两件事是 **谁可以访问服务器** 和 **要暴露哪些资源**。
### 1. 谁有访问权限
在您明确授予配置权限之前,访问权限被禁止;直到您定义允许谁连接为止。请选择:
**一个 `useFilamentMcp` 门控**(推荐,缓存安全):
```php
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
Gate::define('useFilamentMcp', fn ($user) => $user->is_admin);
```
**或回调**(当规则不属于门控时很有用):
```php
use Mattiasgeniar\FilamentMcp\FilamentMcp;
FilamentMcp::authorizeUsing(fn ($user) => $user->is_admin);
```
### 2. 要暴露哪些资源
```php
// config/filament-mcp.php
use App\Filament\Resources\PageResource;
use App\Filament\Resources\PostResource;
use App\Mcp\PreparePageData;
// ...
'resources' => [
// 简写:启用列表/获取/创建/更新,当匹配的 Filament 页面存在时
PostResource::class,
// 扩展:范围能力,开启删除,并附加可选的数据准备程序
PageResource::class => [
'read' => true,
'create' => true,
'update' => true,
'delete' => false,
'prepare' => PreparePageData::class,
],
],
```
`prepare` 指向实现 [`PreparesRecordData`](src/Contracts/PreparesRecordData.php) 的类。将其用于镜像通常位于 Filament 页面中的逻辑(例如,slug 生成):
```php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Mattiasgeniar\FilamentMcp\Contracts\PreparesRecordData;
class PreparePageData implements PreparesRecordData
{
public function __invoke(array $data, ?Model $record): array
{
$data['slug'] ??= Str::slug($data['title']);
return $data;
}
}
```
### 自定义操作
将自定义每个记录的操作作为其自己的工具公开(一种受限的方式来镜像 Filament 操作或批量操作)。添加一个 `actions` 映射,并将每个条目指向一个扩展 [`ResourceAction`](src/Actions/ResourceAction.php) 的类:
```php
\App\Filament\Resources\PostResource::class => [
'actions' => [
'publish' => \App\Mcp\PublishPost::class, // 变成 publish_post 工具
],
],
```
```php
use Illuminate\Database\Eloquent\Model;
use Mattiasgeniar\FilamentMcp\Actions\ResourceAction;
class PublishPost extends ResourceAction
{
public function description(): string
{
return '发布帖子。';
}
public function handle(Model $record, array $arguments): mixed
{
$record->update(['published' => true]);
return ['published' => true];
}
}
```
操作在运行前会被授权:执行用户必须通过目标记录的资源策略能力(默认为 `update`),与内置的写入工具完全一样。重写 `ability()` 以映射到专用的策略方法。
参数是一个允许列表:只有在 `rules()` 中声明的键才会被验证并转发到 `handle()`,因此代理无法将未声明的属性走私到操作中。镜像 `schema()` 公告的内容:
```php
public function schema(JsonSchema $schema): array
{
return ['reason' => $schema->string()->description('为什么发布。')];
}
public function rules(): array
{
return ['reason' => ['required', 'string', 'max:255']];
}
```
### 其他选项
| 键 | 默认值 | 目的 |
| -------------- | --------------- | -------------------------------------------------- |
| `enabled` | `true` | 主开关;当为假时,不注册路由。 |
| `path` | `filament-mcp` | 服务器安装的 URL。 |
| `middleware` | `throttle:60,1` | 在令牌身份验证后附加的额外中间件。 |
| `panel` | `null` | 要在其中运行工具的 Filament 面板 ID。 |
| `tenant_header` | `X-Filament-Mcp-Tenant` | 用于在租户面板上选择租户的标头。 |
| `token_prefix` | `fmcp_` | 生成的令牌的前缀。 |
| `audit.retention_days` | `365` | 保留工具调用记录的天数;`0` 永久保留并禁用修剪。 |
## 审计保留
每次工具调用都存储在 `filament_mcp_tool_calls` 中。软件包每天安排 Laravel 的 `model:prune` 删除比 `audit.retention_days` (默认为一年)旧的记录。将 `FILAMENT_MCP_AUDIT_RETENTION_DAYS=0` 设置为永久保留日志并关闭修剪。只有当应用程序的调度器运行时(通过 cron 的 `schedule:run` 或开发中的 `schedule:work`),才会发生修剪。
## 发出令牌
令牌绑定到颁发 Filament 用户模型,存储前进行哈希,并仅显示一次。从 CLI 生成一个:
```bash
php artisan filament-mcp:token user@example.com --name="我的笔记本"
```
如果用户未经授权,则命令拒绝颁发令牌(使用 `--force` 覆盖)。
### 在面板中
用户可以从 Filament 页面管理自己的令牌,而不是从 CLI。 在面板上注册插件:
```php
use Mattiasgeniar\FilamentMcp\Filament\FilamentMcpPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(FilamentMcpPlugin::make());
}
```
这添加了一个 **MCP → 令牌** 页面,每个用户都可以生成和撤销自己的个人令牌(明文仅显示一次,带有复制按钮)。只有您的授权门控/回调允许的用户才能看到该页面,与控制服务器的规则相同。在 `ui` 配置键下自定义导航,或完全关闭该页面。
如果您的面板使用自定义主题,请执行 [使用自定义 Filament 主题](#使用自定义filament主题) 中的一次性步骤,以便对页面进行样式化。
## 使用自定义 Filament 主题
令牌页面由软件包附带的 Blade 视图构建。Filament 使用 Tailwind 编译面板的 CSS,它只会生成它在源代码中找到的实用类。**自定义** 主题不会扫描 `vendor/`,因此软件包的类被清除,页面呈现为未样式化(文本和令牌字段折叠成一行而不是堆叠)。
在主题 CSS 中将软件包的视图注册为 Tailwind 源,然后重建资产:
```css
/* resources/css/filament/<your-panel>/theme.css */
@import '../../../../vendor/filament/filament/resources/css/theme.css';
@source '../../../../app/Filament/**/*';
@source '../../../../vendor/mattiasgeniar/filament-mcp/resources/views/**/*'; /* 添加此行 */
```
```bash
npm run build # 或:vite build
```
路径深度:`@source` 相对于主题 CSS 文件。从默认的 `resources/css/filament/<panel>/theme.css` 位置,这是四级向上 (`../../../../`) 到达项目根目录,与上面的 Filament 导入相匹配。
您只需要为自定义主题执行此操作。**默认** Filament 主题已经编译了软件包使用的每个类,因此无需额外设置即可正常工作。
## 连接 MCP 客户端
服务器使用可流式的 HTTP 传输。 将客户端指向 URL 并将令牌作为持有者标头传递。对于 Claude Code(`.mcp.json`):
```json
{
"mcpServers": {
"my-app": {
"type": "http",
"url": "https://your-app.test/filament-mcp",
"headers": { "Authorization": "Bearer fmcp_..." }
}
}
}
```
或使用 Claude Code CLI 添加:
```bash
claude mcp add --transport http my-app https://your-app.test/filament-mcp \
--header "Authorization: Bearer fmcp_..."
```
使用以下命令删除它:
```bash
claude mcp remove my-app
```
令牌页面为 Claude Code、Cursor、VS Code 和 Codex 渲染了此即刻粘贴的配置,端点 URL 已填充完毕。在 **连接客户端** 部分下隐藏它,并设置为 `ui.show_setup_guide => false`。
如果配置的/当前 Filament 面板使用 Filament 租户,请在 `X-Filament-Mcp-Tenant` 标头(或配置的 `tenant_header`)中包含租户路由键。令牌用户必须实现 Filament 的租户契约并为该租户传递 `canAccessTenant()`,然后才能运行任何工具。
每个暴露的资源都可以生成 `list_*`、`get_*`、`create_*`、`update_*` 和自定义操作工具,名称来自模型(例如 `create_post`)。内置操作仅在相应的 Filament 资源页面存在时生成:`list_*` 需要索引或管理页面,`get_*` 需要视图、索引或管理页面(因此仅可查看的资源可以通过 ID 获取,而无需公开列表),创建需要创建或管理页面,更新需要编辑或管理页面。`delete_*` 工具永远不会通过简写配置生成;为需要公开删除的资源设置 `'delete' => true`,并且仍然会运行每个记录的策略检查。
页面推断是 **默认**,而不是硬性门控:资源配置中的显式布尔值覆盖它。设置 `'list' => true` 以在没有索引页面的仅查看资源上公开 `list_*`(适用于只读、高容量模型,如运行),或设置 `'list' => false` 以在存在索引页面的情况下隐藏它。策略、查询范围和属性可见性仍然适用。
此重写是每个操作的,优先级高于更广泛的默认值。显式 `'create' => true` 或 `'update' => true` 重新启用该工具,即使设置了 `'write' => false`,而 `'delete' => true` 强制公开 `delete_*`,而没有删除页面。重写只决定是否生成工具;每个调用仍然运行模型的 Filament 策略,每个记录都有一个,因此强制公开破坏性工具不是授权绕过。
单个 `describe_resources` 工具允许代理通过一次调用发现公开的内容(资源、操作、操作和字段)。
**读取与写入。** 写入(`create`/`update`)由资源的 **表单** 驱动,因此代理只能设置表单允许的字段。读取(`list`/`get`)返回资源的 **信息列表** (Filament 在查看页面上显示的内容)及其可写表单字段的 **并集**,因此代理始终可以读取它可以写入的内容,并仍然可以看到仅查看的条目。具有只有表单、只有信息列表或两者兼而有之的资源可以通过任一方式完全读取。模型的 `$hidden` 和 `$visible` 设置在构建工具模式之前会被强制执行,因此隐藏的属性不会被发现、写入、读取、搜索、过滤和排序选项所排除,即使它们出现在表单、信息列表或 `read_fields` 中。
当资源在其 **页面** (一个 `ViewRecord`)上构建其视图模式时,内省一无所获。 使用 `read_fields` 显式列出可读取的属性:
```php
\App\Filament\Resources\RunResource::class => [
'write' => false,
'list' => true, // 强制公开 list_runs,即使资源仅可查看
'read_fields' => ['check_id', 'result', 'started_at', 'ended_at'],
],
```
## 安全模型
1. **令牌** — 每个请求都需要有效的、未撤销的持有者令牌。
2. **授权** — 解析的用户必须通过您的门控/回调;访问权限被拒绝,直到您授予它。
3. **Filament 资源表面** — 默认情况下,工具仅为具有匹配资源页面的操作生成,删除是一个明确的选择。资源配置中的显式布尔值覆盖此默认行为。
4. **模型属性可见性** — 模型隐藏的字段不会在模式、列表控件或响应中公开。
5. **策略** — 每个工具调用还尊重模型存在的 Filament 策略。
6. **查询范围** — 记录通过资源的 `getEloquentQuery()` 读取和写入,因此您的租户范围和软删除过滤器适用。
7. **审计** — 每次调用都记录到 `filament_mcp_tool_calls`。
通过在 `filament_mcp_tokens` 行上设置 `revoked_at` 来撤销令牌。
## 限制
这是 v1 版本,有意范围:
- **仅限写入类似文本的字段。** 文本、文本区域、markdown/富文本编辑器、下拉选择、切换/复选框、数字输入(映射到 `integer`/`number`)和日期选择器被映射。文件上传、自定义组件和表单不会持久化的字段(`disabled()`、`dehydrated(false)`)被跳过,因此可写入的表面与实际保存的内容匹配。读取联合信息列表和这些表单字段(参见上面的“读取与写入”)。
- **基于闭包的表单验证在 MCP 层不强制执行**;数据库约束和模型事件仍然是最后的保障。
- **页面级逻辑** 仅通过 `prepare` 类得到尊重。
- **令牌管理** 既可以通过 CLI,也可以通过注册的插件作为用户自助的 Filament 页面。
## 测试
```bash
composer test
```
## 致谢
- [Mattias Geniar](https://github.com/mattiasgeniar)
## 许可证
MIT 许可证(MIT)。请参阅 [LICENSE.md](LICENSE.md)。