1. 为什么 Laravel 开发者需要一份能落地的 MCP 配置
MCP(Model Context Protocol)说白了就是给 AI 客户端和你的后端服务之间定一套“说话规矩”。你写好的 Laravel 接口、Eloquent 查询、队列任务,通过 MCP 暴露成一个个 Tool 或 Resource,AI 客户端就能按协议调用它们。对 Laravel 开发者来说,这件事的价值在于:不用把业务逻辑重写一遍,也不用把数据库连接直接交给 AI,而是让 AI 走你定义好的工具入口。
但真正动手时,卡人的往往不是业务代码,而是配置文件。config.toml这个骨架写不对,服务起不来;Key 和 API 通道没接好,工具调用直接 401。这篇就聚焦这两件事:一份可复制的config.toml骨架,以及用 TaoToken 统一 Key 接入 API 通道的完整过程。适合已经写过 Laravel、想把自己的服务端接进 AI 工具链的开发者,也适合刚接触 MCP、想先跑通一次连通性验证的人。
我试过把 MCP 服务拆成“协议层 + 工具层 + 通道层”三块来理解,配置文件的每个段落基本都能对应到其中一层。下面按这个思路走,先给骨架,再讲注册,最后做一次真实请求验证。
2. TaoToken 前置准备:统一 Key 与 API 通道
MCP 服务本身不负责模型推理,它只负责把工具暴露出去。真正要调用模型能力时,你需要一个稳定的 API 通道。TaoToken 在这里扮演的角色就是统一入口:一个 Key 走通模型对话、编码类请求和工具调用,省得在多个平台之间来回切换配置。
你需要先拿到两样东西:API Key 和接入地址。Key 在控制台的 API Keys 页面创建,地址用https://taotoken.net/api(注意这个地址不带任何查询参数)。官网入口是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,控制台和文档都能从那里进。
创建 Key 的时候有个细节:权限范围尽量按最小可用原则来。如果这个 Key 只给 MCP 服务用,就不要开多余的模型权限。Key 拿到后先别急着写进代码,放到.env里,config.toml通过环境变量引用,这样本地和部署环境可以共用一份配置骨架。
注意:Key 不要提交到 Git。
.env加进.gitignore,团队协作时用.env.example占位。
3. 可复制的 config.toml 骨架
MCP 服务的config.toml一般放在项目根目录,或者由启动参数指定路径。下面这份骨架覆盖了服务标识、传输方式、工具注册和 API 通道四块,你可以直接复制后改字段值。
# config.toml —— MCP 服务骨架 [server] name = "laravel-mcp-service" version = "0.1.0" # 传输方式:stdio 适合本地调试,sse 适合常驻服务 transport = "sse" host = "127.0.0.1" port = 8787 [server.sse] # SSE 保活间隔,单位秒,太小会浪费连接,太大容易被中间层断开 keepalive = 25 # 单次工具调用超时,单位秒 tool_timeout = 30 [api] # TaoToken 统一 API 通道 base_url = "https://taotoken.net/api" # Key 从环境变量读取,不写死在文件里 api_key = "${TAOTOKEN_API_KEY}" # 默认模型,工具内部需要推理时使用 default_model = "claude-sonnet-4-20250514" # 请求超时,单位秒 timeout = 60 [tools] # 工具注册目录,Laravel 侧扫描这个目录下的 Tool 类 scan_path = "app/Mcp/Tools" # 是否启用异步工具(走队列) async_enabled = true queue = "mcp-tools" [resources] # 动态资源注册开关 dynamic = true # 资源缓存驱动,和 Laravel 的 cache 配置保持一致 cache_driver = "redis" [logging] level = "info" path = "storage/logs/mcp.log"几个字段值得单独说。transport选sse是因为本地调试时用stdio不方便观察请求,SSE 可以直接用 curl 验证。api_key用${TAOTOKEN_API_KEY}这种占位写法,解析时替换成环境变量,避免明文。scan_path要和 Laravel 的命名空间对应上,否则工具注册会漏。
.env里补上对应项:
TAOTOKEN_API_KEY=你的Key MCP_SERVER_PORT=8787 MCP_CACHE_DRIVER=redis如果你用的是 Laravel Sail,端口映射记得同步改docker-compose.yml,把8787:8787加上,否则宿主机访问不到容器内的 SSE 服务。
4. MCP 服务注册与工具接入步骤
配置写好后,下一步是让 Laravel 认识这份配置,并把工具注册进去。整个过程分四步。
第一步,安装 MCP 核心包。用 Composer 拉取,版本按你项目的 PHP 版本选:
composer require php-mcp/laravel:^3.0第二步,发布配置文件。包自带一个mcp.php配置,但我们的config.toml是独立骨架,所以这里要做的是在config/mcp.php里读取 TOML 并映射成数组:
// config/mcp.php return [ 'server' => [ 'name' => 'laravel-mcp-service', 'transport' => env('MCP_TRANSPORT', 'sse'), 'port' => (int) env('MCP_SERVER_PORT', 8787), ], 'api' => [ 'base_url' => 'https://taotoken.net/api', 'api_key' => env('TAOTOKEN_API_KEY'), 'default_model' => env('MCP_DEFAULT_MODEL', 'claude-sonnet-4-20250514'), ], 'tools' => [ 'scan_path' => app_path('Mcp/Tools'), 'async_enabled' => true, 'queue' => 'mcp-tools', ], ];第三步,写一个最小工具类,确认注册链路通。放在app/Mcp/Tools/HealthTool.php:
namespace App\Mcp\Tools; use PhpMcp\Laravel\Server\Attributes\McpTool; class HealthTool { #[McpTool( name: "health_check", description: "Return service health status and current timestamp" )] public function check(): array { return [ 'status' => 'ok', 'timestamp' => now()->toIso8601String(), 'service' => config('mcp.server.name'), ]; } }第四步,启动服务并确认工具被扫描到:
php artisan mcp:serve --config=config.toml启动日志里应该能看到Registered tool: health_check这一行。如果没有,先检查scan_path是否指向了正确目录,再确认工具类的命名空间和文件路径一致。
5. 连通性验证:一次真实请求确认 Key 生效
服务起来后,用 curl 发一次 SSE 请求,验证两件事:MCP 服务能响应,TaoToken 的 Key 能通过 API 通道生效。
先验证 MCP 服务本身:
curl -N http://127.0.0.1:8787/sse \ -H "Accept: text/event-stream"正常会返回类似这样的流式响应:
event: endpoint data: {"uri":"/messages","sessionId":"abc123"} event: message data: {"jsonrpc":"2.0","method":"tools/list","result":{"tools":[{"name":"health_check","description":"Return service health status and current timestamp"}]}}看到health_check出现在工具列表里,说明 MCP 注册链路通了。接下来验证 Key。调用一次需要走模型通道的工具,或者直接用 API 通道发一个最小请求:
curl https://taotoken.net/api/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: $TAOTOKEN_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 64, "messages": [{"role": "user", "content": "ping"}] }'返回里带content字段且没有error,就说明 Key 生效、通道可用。如果返回 401,先确认 Key 有没有多余空格,再检查请求头字段名是否和文档一致。如果返回 404,检查base_url有没有多写或少写路径段。
提示:验证阶段可以把
max_tokens设小一点,减少等待时间。确认通了之后再跑完整工具调用。
6. 本篇常见错排查
启动报config.toml not found:php artisan mcp:serve默认从项目根目录找配置文件。如果你把文件放在别处,用--config指定绝对路径。另外确认文件权限,容器环境下经常因为挂载权限读不到。
工具列表为空:九成是scan_path和实际目录不一致。Laravel 的app_path()返回的是绝对路径,如果你在config.toml里写的是相对路径,解析时会出错。统一用绝对路径或者app_path()生成。
SSE 连接几秒后断开:检查keepalive值。有些反向代理默认 30 秒断空闲连接,keepalive设成 25 秒能避开。如果用了 Nginx,还要加proxy_buffering off,否则流式响应会被缓冲住。
API 返回 401:Key 没读到或者格式不对。先在 Laravel Tinker 里确认config('mcp.api.api_key')有值,再确认请求头字段名。不同通道的认证头可能不一样,以接入文档为准。
异步工具不执行:async_enabled开了但队列没跑。确认queue名称和php artisan queue:work --queue=mcp-tools一致,Redis 连接正常。
端口被占用:8787被别的服务占了,改config.toml里的port,同时同步.env和容器端口映射。改完重启服务。
7. 下一步:把 Key 和通道固定下来
跑通一次验证之后,建议把 Key 和通道配置固化到部署流程里,而不是每次手动填。TaoToken 的 API Keys 页面可以管理多个 Key,按环境区分;接入文档里有各语言的最小请求示例,照着改比对着报错猜快得多。如果你后面要长期跑编码类或 Agent 类任务,Coding Plan 那条线更适合常驻服务,模型对话入口则适合临时验证。
配置这件事,第一次写骨架最费时间,之后就是改字段值。把config.toml当成项目的一部分提交进仓库(Key 除外),下次换环境直接复制,能省掉大半排查时间。