Coolify 的 Laravel MCP Server 开发指南:从 SKILL.md 技能规范到 44 个 Tool 的落地实现
本文以 Coolify 仓库中的 MCP 开发技能文档 .agents/skills/mcp-development/SKILL.md 为主体,完整讲解 Laravel MCP 框架的注册、原语(Tool/Resource/Prompt)创建、Server 装配与验证流程,并结合 Coolify 自身 app/Mcp 目录下的真实源码,展示一个生产级 MCP Server 是如何从规范走向 44 个工具、2 个资源、2 个提示词的完整实现。读完本文,你将掌握在 Laravel 项目中搭建、调试并安全暴露 MCP 端点的全部关键步骤。
SKILL.md 的定位与适用边界
该技能文档以 YAML frontmatter 声明了自己的元信息:name: mcp-development、license: MIT、author: laravel,并在 description 中明确了两点边界:
- 只在 Laravel MCP 开发场景触发:创建或编辑 MCP 工具、资源、提示词、Server 时启用,覆盖
artisan make:mcp-*生成器、mcp:inspector、routes/ai.php、Tool/Resource/Prompt 类、schema 校验、shouldRegister()、OAuth 配置、URI 模板、只读属性与 MCP 调试; - 明确排除非 Laravel 的 MCP 项目,以及不含 MCP 的泛化 AI 功能。
这说明文档是一份“开发者操作手册”而非产品说明:它假定你已经引入 laravel/mcp 包(Coolify 在 composer.json 中声明依赖 "laravel/mcp": "^0.6.7"),接下来只讲怎么把它用对。
在 routes/ai.php 中注册 MCP Server
文档给出的最基础用法是在 routes/ai.php 中通过 Mcp 门面注册 Web 端点:
use Laravel\Mcp\Facades\Mcp;
Mcp::web();
Coolify 的实际注册比最小示例多两个关键点——指定了 URI 前缀并挂上了一组中间件(见 routes/ai.php):
use App\Mcp\Servers\CoolifyServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::web('/mcp', CoolifyServer::class)
->middleware(['mcp.enabled', 'auth:sanctum', 'api.token.team', 'mcp.team.enabled']);
两个值得注意的事实:
routes/ai.php不需要手动注册。文档在 Common Pitfalls 中特别警告“不要在 bootstrap 中注册ai.php,它是被框架自动注册的”。如果你按 Laravel 常规习惯去 bootstrap/app.php 里补一条->withRouting( ..., ai: ...),反而会出问题。- 中间件是 MCP 端点的“门禁”。Coolify 用四个中间件构成纵深防御:
mcp.enabled检查实例级开关,auth:sanctum要求 Sanctum 令牌,api.token.team校验令牌归属,mcp.team.enabled检查团队级 MCP 开关。其中 app/Http/Middleware/EnsureMcpEnabled.php 的实现非常简洁——读取InstanceSettings::get()->is_mcp_server_enabled,未开启则直接abort(404),让端点对未启用的实例“彻底隐身”,而不是返回 403 暴露端点存在。中间件别名在 app/Http/Kernel.php 中注册:
'mcp.enabled' => EnsureMcpEnabled::class,
'mcp.team.enabled' => EnsureTeamMcpEnabled::class,
用 artisan 命令生成 MCP 原语
Laravel MCP 框架为三类原语和 Server 本体都提供了生成器,这是文档给出的完整命令集:
php artisan make:mcp-tool ToolName # 创建工具
php artisan make:mcp-resource ResourceName # 创建资源
php artisan make:mcp-prompt PromptName # 创建提示词
php artisan make:mcp-server ServerName # 创建 Server
生成之后,必须在 Server 的 $tools、$resources、$prompts 属性中显式注册——框架不会自动发现这些类。Coolify 的目录结构印证了这一组织方式:app/Mcp/ 下按类型分为 Tools/(44 个工具类)、Resources/(2 个)、Prompts/(2 个)、Servers/(1 个),另有 Concerns/ 存放共享 Trait。
Tool:最小实现到带 schema 的完整实现
文档给出的最小 Tool 示例:
use Laravel\Mcp\Server\Tool;
use Laravel\Mcp\Server\Request;
use Laravel\Mcp\Server\Response;
class MyTool extends Tool
{
public function handle(Request $request): Response
{
return new Response(['result' => 'success']);
}
}
结构上就是一个“继承 Laravel\Mcp\Server\Tool、实现 handle(Request): Response”的类。Coolify 中的 app/Mcp/Tools/CoolifyHelp.php 则展示了生产级 Tool 补足了哪些要素:
$name与$description:coolify_help及其面向 LLM 的描述文本("Call first when unsure which Coolify MCP tool to use"),这段描述本身就是提示词工程的一部分;schema()方法:接收Illuminate\Contracts\JsonSchema\JsonSchema,以数组形式声明入参,例如'intent' => $schema->string()->description(...)——这就是文档提到的 schema 校验在 Coolify 侧的落点;- 权限前置检查:
handle()第一行先调$this->ensureAbility($request, 'read', $this->name),令牌能力不足时直接返回结构化的missing_ability错误,再走resolveTeamId解析团队作用域。Coolify 的所有 Tool 都通过BuildsResponse、ResolvesTeam等Concerns共享这套逻辑(见 app/Mcp/Concerns/); - 响应信封:统一走
mcpSuccess/mcpError/respond,最终输出{ data, _actions?, _pagination? }结构,与 Server 级$instructions中向客户端声明的契约一致。
Resource:URI 模板与团队作用域查询
文档要点之一是 Resource 支持 URI 模板(URI templates)。Coolify 的 app/Mcp/Resources/ApplicationResource.php 是完整示例:
class ApplicationResource extends Resource implements HasUriTemplate
{
protected string $name = 'coolify-application';
protected string $mimeType = 'application/json';
public function uriTemplate(): UriTemplate
{
return new UriTemplate('coolify://application/{uuid}');
}
public function handle(Request $request): Response
{
// 权限检查 → 解析 uuid → 按团队作用域查询 → 脱敏后返回 JSON
}
}
三个实现细节值得借鉴:
- 通过
use Laravel\Mcp\Server\Contracts\HasUriTemplate实现接口并返回UriTemplate,让客户端可以用coolify://application/{uuid}这样的地址引用资源; - 查询使用
Application::ownedByCurrentTeamAPI($teamId)这类“按当前团队限定”的作用域,MCP 令牌只能看到自己团队的数据——这正是 CoolifyServer.php$instructions中 "Every tool enforces team ownership" 承诺的落地方式; - 返回前经过
scrubSensitive()脱敏,且 Server 级说明明确 "Env values, configuration snapshots, and full deploy logs are never returned"——敏感数据在 Resource 层就被拦下。
Prompt:参数化模板与引导式工作流
文档中 Prompt 的生成命令是 php artisan make:mcp-prompt,对应 Laravel\Mcp\Server\Prompt 基类。Coolify 的 app/Mcp/Prompts/TroubleshootApplication.php 展示了 Prompt 的真正价值:它不只是返回一段文本,而是把一套“DB 优先、日志兜底”的排障 SOP 固化下来——
arguments()方法声明参数:new Argument(name: 'uuid', description: ..., required: true);handle()将用户传入的uuid注入一段多行 Markdown 模板(<<<MD ... MD),生成分三阶段(Phase A 数据库元数据 → Phase B 容器运行中才取活日志 → Phase C 有 deploy 权限才做生命周期操作)的排查步骤,并规定get_logs失败时要读reason+next_tools而不要盲目重试。
另一个 Prompt explain_failed_deploy 与之配合,覆盖了“应用故障”和“部署失败”两个高频场景。
Server 装配:CoolifyServer 的完整声明
把原语注册进 Server 是文档强调的“显式声明”原则,Coolify 的 app/Mcp/Servers/CoolifyServer.php#L56-L91 是仓库中可直接对照的完整样板:
class CoolifyServer extends Server
{
protected string $name = 'Coolify';
protected string $version = '0.2.0';
/**
* Return all registered tools in a single tools/list page (default package limit is 15).
*/
public int $maxPaginationLength = 100;
public int $defaultPaginationLength = 100;
protected string $instructions = <<<'MD'
Coolify MCP for the authenticated team token. Every tool enforces team ownership.
Start here (prefer these before deep get_*):
1. coolify_help — tool catalog by intent ...
MD;
protected array $tools = [ CoolifyHelp::class, /* ... 共 44 个 */ CancelDeployment::class ];
protected array $resources = [ InfrastructureOverviewResource::class, ApplicationResource::class ];
protected array $prompts = [ TroubleshootApplication::class, ExplainFailedDeploy::class ];
}
这里有三个文档未展开、但源码里体现得很清楚的增强点:
$instructions:一段写给 MCP 客户端(即 LLM Agent)的“使用说明书”,规定了推荐调用顺序(先coolify_help→get_infrastructure_overview→search_resources)、调试策略(DB 优先、失败时读reason + next_tools不循环重试)以及响应契约。这是 MCP 框架下“把产品知识写进协议元数据”的典型做法;- 分页调优:
laravel/mcp默认tools/list单页上限是 15 个,Coolify 注册了 44 个 Tool,因此把$maxPaginationLength与$defaultPaginationLength都调到 100,保证客户端一次性拿到完整工具清单; - 能力分层:
$tools列表里control、deploy、cancel_deployment属于生命周期操作,要求令牌具备deployability,只读令牌调用时会收到明确的missing_ability错误——权限粒度做到了工具级别。
验证:确认注册与客户端实测
文档的 Verification 一节给出两步:检查 routes/ai.php 注册是否正确,再用 MCP 客户端实测 Tool。结合仓库,验证清单可以细化为:
- 打开 routes/ai.php:确认
Mcp::web()的目标 Server 类存在、中间件链完整; - 确认 Server 类的
$tools/$resources/$prompts中每个类都已use导入且文件存在——Coolify 的 44 个 Tool 全部位于 app/Mcp/Tools/; - 打开实例级 MCP 开关(
is_mcp_server_enabled),否则mcp.enabled中间件会让/mcp直接 404(见 app/Http/Middleware/EnsureMcpEnabled.php); - 用 MCP 客户端(或
mcp:inspector)连接端点,先调用coolify_help验证意图目录返回,再抽查一个list_*工具确认数据作用域正确。
常见陷阱:六条来自实践的血泪教训
SKILL.md 的 Common Pitfalls 一节浓缩了调试 MCP 时最常踩的坑,逐条对照仓库说明:
| 陷阱 | 说明 |
|---|---|
运行 mcp:start 命令 |
该命令会挂起等待输入(stdin),在自动化/远程环境里表现为“卡死”,调试请改用 Web 端点 + 客户端 |
| 本地用 HTTPS 配 Node 系 MCP 客户端 | 本地开发用 HTTP 即可,HTTPS 自签证书常导致 Node 客户端握手失败 |
不用 search-docs 查最新文档 |
MCP 框架迭代快,本地过时的认知是主要事故源 |
未把 MCP 路由注册进 routes/ai.php |
端点不存在,客户端连接直接失败 |
在 bootstrap 中注册 ai.php |
它是框架自动注册的,重复注册反而出错 |
| OAuth 注册不支持自定义 URI scheme | 桌面原生客户端(如 cursor://、vscode://)需要自定义 scheme 回调,通过 mcp.custom_schemes 配置项支持 |
小结
这份 SKILL.md 的价值在于把 Laravel MCP 的开发路径压缩成一条可执行主线:生成器出骨架 → routes/ai.php 挂端点 → Server 显式装配 → 客户端验证。而 Coolify 仓库的 app/Mcp 目录则证明这条主线在真实项目中能长出多复杂的形态——44 个带 JSON Schema 的工具、按团队作用域查询并脱敏的资源、把排障 SOP 固化成 Prompt 的引导式模板,外加实例/团队/令牌三层中间件门禁与工具级 ability 校验。对于要在自己的 Laravel 应用中暴露 MCP 服务的开发者,建议先照 SKILL.md 的最小示例跑通 Mcp::web(),再对照 app/Mcp/Servers/CoolifyServer.php 逐步补齐 $instructions、分页与权限分层。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00