Skip to content

🛰️ MCP

SunAdmin 接入 Laravel MCP,提供 MCP Server 工具自动发现、管理端调试入口和 AI Agent 工具适配能力。本页讲 MCP 工具创建与对接;AI 模型、知识库、用量记录等 AI 侧内容详见 AI

🎯 本页目标

读完本章节后,应能掌握:

  • MCP Server 入口和管理端调试接口分别提供哪些能力。
  • MCP Tool 与 AI Agent Tool 适配的差异、各自放在哪里。
  • 如何在模块中新增一个 MCP 工具并验证注册。
  • 如何让管理端 AI 助手在对话中按需调用模块工具。

🔧 代码地图

文件说明
AiMcpController.phpMCP 工具、调用、聊天和 RPC
McpService.phpMCP 工具服务
SunAdminMcpServer.php官方 MCP Server
modules/{Module}/Mcp/ToolsMCP Server 工具目录,自动发现
modules/{Module}/Ai/ToolsLaravel AI Agent 工具适配目录,自动发现

🛰️ MCP 能力入口

SunAdmin 同时提供两类 MCP 入口:

入口用途
/mcp/sunadmin官方 Laravel MCP Server,给外部 MCP 客户端调用
/adminapi/system/ai/mcp/*后台管理端调试、工具调用、AI 助手聊天和 RPC

官方 MCP Server 路由:

text
/mcp/sunadmin

外部 MCP 客户端需要携带有效后台管理员令牌。后台调试接口同样需要管理员登录。

后台调试接口:

URI说明
GET /adminapi/system/ai/mcp/tools查看已自动发现的 MCP 工具
POST /adminapi/system/ai/mcp/call直接调用某个 MCP 工具
POST /adminapi/system/ai/mcp/chat管理端 AI 助手对话,模型可按需调用工具
POST /adminapi/system/ai/mcp/rpc简化 JSON-RPC 入口,支持 tools/listtools/callai/chat

内置工具:

工具说明
system.overview获取系统后台概览,包括用户、管理员、文章、AI 助手配置与最近 7 天 AI 用量
system.user_count获取用户数量统计
system.latest_articles获取最新文章
system.ai_settings获取 AI 助手基础配置
system.ai_usage_stats获取最近 N 天 AI 用量统计

🧭 工具目录规范

MCP Server 工具目录:

text
modules/{Module}/Mcp/Tools

Laravel AI Agent 工具适配类位于:

text
modules/{Module}/Ai/Tools

两类工具的区别:

类型目录作用必须实现
MCP Toolmodules/{Module}/Mcp/Tools给 MCP Server、后台工具调试接口调用继承 Laravel\Mcp\Server\Tool
AI Toolmodules/{Module}/Ai/Tools给 Laravel AI Agent 注入,让模型在对话中按需调用实现 Laravel\Ai\Contracts\Tool

如果工具只需要给 MCP 客户端或后台调试接口调用,只创建 MCP Tool 即可。如果希望“管理端 AI 助手聊天”也能让模型主动调用该能力,需要额外创建 AI Tool 适配类。

自动发现是宽松模式:

  • 模块下没有 Mcp/Tools 目录时会自动跳过,不需要创建空目录。
  • 模块下没有 Ai/Tools 目录时也会自动跳过,不影响 MCP 工具使用。
  • 目录存在但没有符合继承或接口要求的工具类时,会返回空工具列表,不会抛异常。
  • 只有调用某个不存在的工具名时,才会返回 MCP Tool [name] 未注册

♻️ 工具发现缓存

MCP 工具和 AI Agent 工具会在运行时按模块目录自动发现。为了避免同一请求内反复扫描模块目录,框架会缓存本次运行周期内的工具类列表。

正常通过应用中心或命令行执行模块生命周期操作时,框架会自动清理模块运行时缓存:

bash
# 安装或覆盖安装模块后会刷新模块注册、路由和 MCP 工具发现缓存
php artisan module:install {Module}
php artisan module:install {Module} --force

# 启用或停用模块后会刷新 MCP 工具发现缓存
php artisan module:enable {Module}
php artisan module:disable {Module}

# 卸载、删除或清理残留记录后会刷新 MCP 工具发现缓存
php artisan module:uninstall {Module}
php artisan module:delete {Module}

开发时如果只是手动往已启用模块中新增 Mcp/ToolsAi/Tools 文件,而没有执行模块安装、启用或停用命令,普通 PHP-FPM 下一次请求通常可以重新发现;Octane、队列 Worker、Tinker、Swoole 等常驻进程需要重启对应进程,或重新执行一次模块启用命令触发运行时缓存刷新:

bash
# 常驻进程中新增工具后,可重新启用模块触发运行时缓存刷新
php artisan module:enable {Module}

🧑‍💻 创建 MCP 工具示例

下面以 Shop 模块新增一个“订单数量统计”工具为例。实际项目中把 Shop 替换成你的模块名即可。

1. 创建 MCP Tool

文件路径:

text
modules/Shop/Mcp/Tools/ShopOrderCountTool.php

示例代码:

php
<?php

namespace Modules\Shop\Mcp\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Attributes\Description;
use Laravel\Mcp\Server\Attributes\Name;
use Laravel\Mcp\Server\Tool;
use Modules\Shop\Dao\OrderDao;

#[Name('shop.order_count')]
#[Description('获取商城订单数量统计,可按订单状态筛选。')]
class ShopOrderCountTool extends Tool
{
    public function handle(Request $request, OrderDao $orderDao): Response
    {
        $status = $request->get('status');
        $filters = [];

        if ($status !== null && $status !== '') {
            $filters['status'] = $status;
        }

        return Response::json([
            'total' => $orderDao->count($filters),
        ]);
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'status' => $schema->string()->description('订单状态,可选。不传则统计全部订单。'),
        ];
    }
}

说明:

  • #[Name('shop.order_count')] 是工具对外暴露的唯一名称,建议使用 module.ability 格式。
  • schema() 用来告诉 MCP 客户端和模型这个工具接受哪些参数。
  • handle() 可以通过 Laravel 容器自动注入 Dao、Service 等依赖。
  • 返回值建议使用 Response::json(),只输出必要字段,不返回敏感数据。

2. 验证 MCP Tool 是否注册

登录后台后调用:

http
GET /adminapi/system/ai/mcp/tools

返回的 data.tools 中应该能看到:

json
{
  "name": "shop.order_count",
  "description": "获取商城订单数量统计,可按订单状态筛选。"
}

也可以直接调用工具:

http
POST /adminapi/system/ai/mcp/call
Content-Type: application/json

{
  "name": "shop.order_count",
  "arguments": {
    "status": "paid"
  }
}

🤝 创建 AI Agent 工具适配示例

如果希望后台 AI 助手在聊天时自动调用 shop.order_count,需要再创建一个 Laravel AI Tool 适配类。

文件路径:

text
modules/Shop/Ai/Tools/ShopOrderCount.php

示例代码:

php
<?php

namespace Modules\Shop\Ai\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Modules\Shop\Dao\OrderDao;
use Stringable;

class ShopOrderCount implements Tool
{
    public function __construct(
        protected OrderDao $orderDao,
    ) {
    }

    public function description(): Stringable|string
    {
        return '获取商城订单数量统计,可按订单状态筛选。';
    }

    public function handle(Request $request): Stringable|string
    {
        $arguments = $request->all();
        $status = $arguments['status'] ?? null;
        $filters = [];

        if ($status !== null && $status !== '') {
            $filters['status'] = $status;
        }

        return json_encode([
            'total' => $this->orderDao->count($filters),
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'status' => $schema->string()->description('订单状态,可选。不传则统计全部订单。'),
        ];
    }
}

说明:

  • MCP Tool 和 AI Tool 可以复用同一个 Dao / Service,避免两套业务逻辑。
  • AI Tool 的 description() 要写清楚工具能力,模型会根据描述判断是否调用。
  • AI Tool 的 schema() 要和 MCP Tool 保持一致,减少调试成本。
  • AI Tool 返回字符串即可,推荐返回 JSON 字符串,方便模型理解结构化结果。

✅ 新增工具检查清单

  • 工具名称使用 module.ability 格式,例如 system.user_count
  • MCP Tool 放在 modules/{Module}/Mcp/Tools
  • AI Tool 适配类放在 modules/{Module}/Ai/Tools,只有需要 AI 助手对话调用时才需要创建。
  • 命名空间必须和目录一致,例如 Modules\Shop\Mcp\Tools
  • 入参 schema 要明确,避免模型猜字段。
  • 工具只返回必要数据,不返回敏感字段。
  • 涉及后台数据的工具必须走管理员认证。
  • 工具执行失败要返回可理解错误,不吞异常。
  • 管理端 /adminapi/system/ai/mcp/tools 能列出工具后,再接入聊天。

🗂️ 安全与治理

  • 管理端工具调用需要管理员 token。
  • 工具只返回必要数据,不输出敏感字段(密钥、明文密码、未脱敏的个人信息)。
  • 工具执行涉及写入或外部副作用时,应在 handle() 中显式校验权限与业务前置条件。
  • 模型输出不能直接作为高风险业务动作依据,例如支付、提现、权限变更。

🧯 排查顺序

问题排查
MCP 工具不出现工具目录、类命名空间、继承类型、tools 接口、管理员认证
工具调用失败工具入参 schema、handle 实现、异常日志
AI 助手对话不调用工具检查 Ai/Tools 适配类是否存在、description() 是否清晰
外部 MCP 客户端无法连接检查 /mcp/sunadmin 路由、管理员令牌、CORS