- 后端
- 云原生
- 运维
- 虚拟化
- 人工智能
- AI 应用
【免费下载链接】cloudpods
开源、云原生的多云管理及混合云融合平台
Cloudpods MCP Server 是 Cloudpods 多云管理平台提供的 AI 能力网关:它通过 MCP(Model Context Protocol)协议,把平台命令行工具 climc 的命令能力自动转换、注册为 MCP tools,供 Cursor、Cline、Claude 等 AI 客户端直接调用,从而实现"用自然语言查询镜像/网络/虚拟机、创建和启停服务器"等操作。读完本文,你可以掌握 mcp-server 的目录结构与运行机制、SSE/stdio 两种模式的部署配置、AK/SK 与 Header 的认证方式、工具如何从 climc 命令表自动生成,以及如何通过mcp-desc/mcp:"true"标签快速扩展新的 MCP 工具。
一、MCP Server 定位与整体架构
docs/mcp-server/README.md 对模块的定位一句话概括:
Cloudpods MCP Server:通过 MCP 协议把 climc 能力暴露给 AI 客户端(Cursor / Claude 等)。
从源码结构看,整个模块由 cmd/mcp-server/main.go 作为进程入口,实际逻辑全部位于pkg/mcp-server/下,各目录职责如下:
| 目录 | 职责 | 关键文件 |
|---|---|---|
adapters/ | Cloudpods 认证与 ClientSession 创建 | adapter.go、credentials.go |
climcgen/ | 从 climc CommandTable + Options tag 生成 MCP tools | register.go、schema.go、exec.go、tool.go |
options/ | 服务配置项定义 | options.go |
registry/ | MCP tool 注册中心 | registry.go |
server/ | SSE / stdio 服务实现 | server.go |
service/ | 进程入口装配 | service.go |
启动装配流程在 service.go 中完成:解析mcpserver.conf配置 → 若配置了auth_url+admin_user等则初始化全局认证 → 创建CloudpodsMCPServer(内部构建 ServerInstructions、扫描并生成全部 tools)→ 启动 SSE 服务。
二、运行机制:从 climc 命令表到 MCP tools 的三步
README 中描述的三步运行机制,在源码中都能找到精确对应。
2.1 第一步:blank-import climc shell 包,填充 CommandTable
climc 的每条命令(server-create、image-list、cloud-region-list……)都以shell.CMD结构体注册在shell.CommandTable中。MCP Server 通过 imports.go 以空白导入方式引入 climc 各业务子包,触发其init()完成注册:
// 导入 climc shell 子包以填充 shell.CommandTable import ( _ "yunion.io/x/onecloud/cmd/climc/shell/compute" _ "yunion.io/x/onecloud/cmd/climc/shell/identity" _ "yunion.io/x/onecloud/cmd/climc/shell/image" _ "yunion.io/x/onecloud/cmd/climc/shell/logger" _ "yunion.io/x/onecloud/cmd/climc/shell/monitor" _ "yunion.io/x/onecloud/cmd/climc/shell/scheduler" )这意味着:只要 climc 支持某命令,MCP Server 就有能力将其暴露为工具,无需在 MCP 侧重复实现任何 API 调用逻辑。
2.2 第二步:扫描mcp-desc命令,用 struct tag 生成 schema
并非所有 climc 命令都会被注册为 MCP tool。register.go 中的BuildTools只会挑选 Options 结构体上带有mcp-desc标签的命令:
// discoverMcpDescCommands 扫描 CommandTable,收集 Options 带 mcp-desc 的命令。 // server-create /「最终动作」优先排前,便于模型在创建意图下选中。 func discoverMcpDescCommands() []string { ... for i, cmd := range shell.CommandTable { desc := collectMcpDesc(cmd.Options) if desc == "" { continue } ... } ... }标签约定定义在 mcp_tags.go 中:
mcp-desc写在 Options 结构体的_ struct{}字段上,作为该 MCP tool 的描述,直接面向 AI 模型书写(中文即可)。例如 cloudregions.go 中:
_ struct{} `mcp-desc:"【创建流程中的中间步骤】本工具不能完成创建。指定云厂商时必须传 provider,例如创建阿里云:provider=[\"Aliyun\"]。..."`mcp:"true"表示该可选参数要暴露给 AI;mcp:"required"表示建议必填。例如 snapshots.go:
Disk string `help:"Disk snapshots" json:"disk_id" mcp:"true"` Server string `help:"Filter by server" json:"server_id" mcp:"true"` DiskType string `help:"Filter by disk type" choices:"sys|data" mcp:"true"`schema 的构建在 schema.go 的buildInputSchema中完成,几个值得注意的工程细节:
- 参数精简:常量
maxSchemaProperties = 48限制了单工具生成的参数数量,"避免 BaseListOptions 等过大 schema 淹没模型";没有mcp:"true"标记的可选参数一律不暴露(见mcpKeepArg函数)。 - 类型推断:布尔型参数生成
boolean,IsMulti()参数生成array,有Choices()的参数自动带上enum,其余为string。 - 面向模型的"手把手"描述增强:针对关键命令,源码会覆写参数描述,降低模型调用门槛。例如:
server-create的disk参数被重写为:系统盘描述,数组。公有云:["size=40g,image=<镜像ID>,backend=cloud_essd"];CAS/UIS/SangFor:["size=40g,backend=dir"]...;*-list命令强制注入scope参数说明:"resource scope;省略时 MCP 默认注入 max";cloud-region-list的usable参数说明:"创建虚拟机时必须为 true,只返回网络可用区域;省略时 MCP 默认注入 true"。
- 工具命名:schema.go 的
toolNameFromCommand将 climc 命令名转为 MCP 工具名——当前版本前缀为climc_,例如server-create→climc_server_create;使用文档 中给出的cloudpods_list_images、cloudpods_create_server等名称则是文档示例时期的命名风格,工具语义一一对应。
注册完成后,registry.go 负责把每个Tool(含 schema 与 Handle 回调)挂载到 mcp-go 的MCPServer实例上;Initialize失败会以"初始化工具注册中心失败"报错退出。
2.3 第三步:工具调用时用凭据建 session,执行 climc callback,JSON 返回
工具调用入口是 tool.go 的Handle方法,流程为:
- 从请求参数中取
ak/sk(兼容从连接 Header 注入的凭据,二者缺一即返回authentication required: provide X-Auth-Token, AK/SK headers, or X-API-Key on tools/call); - 调用 adapters/adapter.go 的
GetSession:AuthenticateByAccessKey换取 Token,经 apigateway endpoint 创建mcclient.ClientSession; - 将 MCP 的 JSON 参数转成 climc 的 argv 执行(
exec.go的mcpArgsToArgv,自动处理-/_命名、布尔值true/1/yes/on等转换); - 通过
shell.PushOutput(&buf, shell.OUTPUT_FORMAT_JSON)把该 goroutine 的输出重定向为 JSON,调用命令回调后取出结果,compactJSON压缩空白降低模型上下文占用,再拼上"下一步提示"(见下文)返回给客户端。
两个特殊的流程化命令不走通用invokeCommand:server-create由 create_flow.go 处理,会先调用调度器 forecast、创建后每 5 秒轮询直至 running/ready(最长等待时间由server_create_wait_seconds控制,默认 180 秒,超时仍返回 server_id 供继续查询);server-delete同理有 delete_flow.go 处理。
多步任务引导:nextStepHint
为防止模型"只查完区域就停止",tool.go 在每次工具结果末尾追加[MCP下一步]提示,例如:
[MCP下一步] 创建虚拟机尚未完成。请用区域 id 调 climc_cloud_region_capability,再 climc_cached_image_list + climc_server_sku_list(可并行),最后 climc_server_create。配套的 instructions.go 还会生成一份全局 ServerInstructions,明确告诉模型完整规则:"严禁空口编造:未实际调用 climc_* 并拿到返回前,禁止声称'已查到/已创建成功'"、创建虚拟机的标准顺序"区域→能力→规格→镜像→创建"、监控查询的 measurement/field 写法等。这份说明可通过mcp_server_name等配置间接影响,也可经climcgen.RegisterExtraInstructions追加。
三、部署与配置
3.1 编译与配置文件
按 安装文档 的步骤部署:
# 编译 mcp-server $ cd /root/cloudpods && make cmd/mcp-server # 编写配置文件,注意根据实际情况修改 Cloudpods API 的认证信息 # 需要在系统内先创建 mcp-server-admin 用户,并以 admin 角色加入到 system 项目 $ mkdir -p /etc/yunion/mcp-server $ cat<<EOF >/etc/yunion/mcp-server/mcp-server.conf # ==================== 服务器基础配置 ==================== address = '127.0.0.1' port = 12001 admin_domain = Default admin_password = <admin密码> admin_project = system admin_project_domain = Default admin_user = mcp-server-admin auth_url = https://<apigateway_ip_or_domain>:30500/v3 session_endpoint_type = public # ==================== MCP 服务配置 ==================== mcp_server_name = cloudpods-mcp-server # MCP 服务名称 mcp_server_version = 1.0.0 # MCP 服务版本 mcp_server_description = the mcp server of the cloudpods server EOF配置项与 options.go 的对应关系如下(前缀mcp_对应结构体字段MCPServer*):
| 配置项 | 说明 | 默认值 |
|---|---|---|
address/port | 服务监听地址与端口 | 安装示例用127.0.0.1:12001 |
auth_url | 平台 apigateway 的认证地址(v3) | 必填 |
admin_user/admin_password/admin_project/admin_project_domain/admin_domain | 服务自身的平台用户身份 | 需预先创建 |
mcp_server_name | 上报给客户端的 MCP 服务名;为空时回退为PlatformName(默认Cloudpods,见options.ResolvedPlatformName) | Cloudpods |
mcp_server_version | MCP 服务版本 | 1.0.0(文档示例) |
mcp_server_description | MCP 服务描述 | - |
timeout | 到平台 API 的 SDK 连接超时(秒) | 30 |
server_create_wait_seconds | 创建虚拟机后等待 running/ready 的最长时间,超时仍返回 server_id | 180 |
其中timeout与server_create_wait_seconds支持热更新;platform_name因写入 ServerInstructions 需要重启进程(见 options.go 的OnOptionsChange注释)。
3.2 启动与验证
# 默认从以下路径查找配置文件: /etc/yunion/mcp-server/mcp-server.yaml, ./config/mcp-server.yaml, ./mcp-server.yaml $ /root/cloudpods/bin/mcp-server --log-level debug # 或使用 --conf 参数指定配置文件路径 $ /root/cloudpods/bin/mcp-server --log-level debug --conf /etc/yunion/mcp-server/mcp-server.yaml # 启动成功后检查 SSE 端点 $ curl http://localhost:12001/sse服务在 server.go 的Start中启动,除/sse外还挂载了/version、/stats、/ping、/worker_stats、/process_stats等运维端点,可用curl逐个探活。启动日志会打印Start mcp server successfully on <addr>,工具注册时逐一打印climcgen: registered MCP tool <name> (<climc命令>),可作为工具是否成功注册的核对依据。
四、MCP 客户端接入:SSE 与 stdio 两种模式
按 使用文档,主流 MCP 客户端(Cline、Cursor 等)均可接入,两种模式的配置方式如下。
SSE 模式(源码默认):/sse为长连接端点,消息 POST 到/message端点:
{ "mcpServers": { "cloudpods-sse": { "url": "http://localhost:12001/sse" } } }stdio 模式:直接拉起本地mcp-server进程:
{ "mcpServers": { "mcp-server": { "disabled": false, "timeout": 60, "type": "stdio", "command": "/path/to/mcp-server", "args": [ "config", "/path/to/mcp-server.yaml" ] } } }源码对两种协议做了兼容:server.go 在同一个/sse路径上按 HTTP method 分流——GET 走传统 SSE(Cursor 等旧客户端),POST/DELETE 走 Streamable HTTP(部分新客户端把/sse当作 Streamable HTTP 使用),避免405报错;SSE 心跳间隔 15 秒(WithKeepAliveInterval),用于在长耗时的tools/call(如公有云创建)期间防止中间代理空闲断连。
4.1 认证:Header 优先,参数兜底
凭据传递有两条路径,server.go 的authenticateRequest支持三种 Header 形态:
X-Auth-Token:平台签发的 token(服务配置了全局认证时先auth.Verify);AK+SK两个 Header;X-API-Key:值为base64("ak:sk")。
Header 中未携带时,才允许在工具参数里传ak/sk(使用文档的方式:对话中向模型提供 Access Key / Secret Key,例如先用climc credential-create-aksk创建)。credentials.go 中ErrAuthenticationRequired明确了这一优先级:provide X-Auth-Token, AK/SK headers, or X-API-Key on tools/call。initialize/tools/list允许匿名,只有tools/call强制鉴权,因此客户端"已连接"并不代表可以立即执行操作。
五、工具清单与使用示例
使用文档 梳理了 15 类典型能力(文档示例以cloudpods_前缀命名,当前代码生成climc_前缀,语义相同):
资源查询
| 工具(文档命名) | 功能 |
|---|---|
cloudpods_list_images | 查询镜像列表 |
cloudpods_list_networks | 查询网络列表(支持vpc_id过滤) |
cloudpods_list_regions | 查询区域列表(支持provider过滤) |
cloudpods_list_servers | 查询虚拟机实例列表(支持status过滤) |
cloudpods_list_serverskus | 查询服务器规格列表(支持cpu_core_count、memory_size_mb、cpu_arch、providers等) |
cloudpods_list_storages | 查询存储列表(支持storage_types、host_id等) |
cloudpods_list_vpcs | 查询 VPC 列表 |
资源操作
| 工具(文档命名) | 功能 |
|---|---|
cloudpods_create_server | 创建虚拟机实例(name/vcpu_count/vmem_size/image_id/network_id/auto_start/billing_type等) |
cloudpods_delete_server | 删除实例(delete_disks/delete_eip/purge等) |
cloudpods_start_server | 启动实例(qemu_version等) |
cloudpods_stop_server | 停止实例(is_force/stop_charging/timeout_secs) |
cloudpods_reset_server_password | 重置密码(auto_start/username) |
cloudpods_get_server_monitor | 历史监控指标(metrics/start_time/end_time) |
cloudpods_get_server_stats | 实时统计信息 |
查询类工具的返回统一带query_info(limit/offset/total 与已生效的过滤条件)和summary(has_more/next_offset/total_*),便于模型做分页续查。例如 使用文档 中cloudpods_list_images的交互示例:
提示词:"帮我查询云平台的镜像列表,要求显示前10条(从第1条开始),筛选条件为操作系统类型是Linux或Windows,关键词包含'centos'。" 模型转换为:
{ "limit": "10", "offset": "0", "search": "", "os_types": "Linux,Windows" }返回:
{ "images": [], "query_info": { "count": 0, "limit": 10, "offset": 0, "os_types": ["Linux", "Windows"], "search": "", "total": 0 }, "summary": { "has_more": false, "next_offset": 0, "returned_count": 0, "total_images": 0 } }当前源码中已带mcp-desc注册的命令远不止这 15 个,还包括域/项目/用户的增删查(identity)、操作日志查询(actions.go)、资源用量汇总(usages.go)、磁盘挂载/卸载(serverdisks.go)、快照列表(snapshots.go)等,实际数量以启动日志中registered MCP tool为准。
六、扩展新工具
README 给出的扩展方式非常轻量——在对应 climc 命令的 Options 上打标,重启 mcp-server 即可注册:
type ImageListOptions struct { cloudcommon.ListOptions OsTypes string `help:"Filter by OS types" mcp:"true"` // 按需给要暴露的字段加 mcp tag _ struct{} `mcp-desc:"查询镜像列表。可用 os-types/limit/offset 过滤"` // 作为 MCP tool 描述 }两条规则来自 mcp_tags.go 的实现细节:
mcp-desc只读取本结构体的非嵌入字段、不递归匿名嵌入(collectMcpDescFromType中if f.Anonymous { continue })。这是刻意设计:避免复用 Options(如 statistics 嵌入 List)时被误注册。servers.go 中的注释也印证了这一点:"与 server-start 复用参数时单独包一层,避免继承 mcp-desc 被注册为 MCP tool"。- 字段 token 的推导与 structarg 完全一致:优先
token标签,其次json名,再次alias,最后字段名,统一CamelSplit为 kebab-case(如MemSpec→mem-spec),并额外登记字段名与 json 名的变体,保证模型传任一写法都能落到正确的 CLI 参数。
除了 tag 方式,源码还预留了两个 Go 层面的扩展点(extra.go):
climcgen.RegisterExtraTools(fn):注册额外工具构建回调,返回自定义[]Tool,应在init()中调用;climcgen.RegisterExtraInstructions(fn):向全局 ServerInstructions 追加自定义说明。
两者在 server.go 的NewServerWithOptions中被合并进最终的 instructions 与工具列表(extra tools 排在自动生成的 climc tools 之前)。
七、小结
Cloudpods MCP Server 的设计核心是"零手写工具代码":它不逐条实现 API 客户端,而是站在 climc 命令表之上,用mcp-desc/mcp两个 struct tag 声明式地挑选命令、裁剪参数、生成 schema,再用统一的 session 建立、argv 转换、JSON 压缩输出和"下一步提示"把命令执行封装成对 LLM 友好的多步任务流。对使用者而言,部署只需一份mcp-server.conf(核心是auth_url+admin_*+ 端口),客户端接入只需一段 SSE 或 stdio 配置;对开发者而言,暴露一个新能力只需在既有 climc 命令上补两行标签后重启服务。相关入口与关键实现可沿 README、安装文档、使用文档 以及pkg/mcp-server/目录继续深入。
- 后端
- 云原生
- 运维
- 虚拟化
- 人工智能
- AI 应用
【免费下载链接】cloudpods
开源、云原生的多云管理及混合云融合平台
相关推荐
Zero MCP 接入指南:用 Better Auth 会话令牌把 AI 邮箱能力暴露给 MCP 客户端
Zero MCP 接入指南:用 Better Auth 会话令牌把 AI 邮箱能力暴露给 MCP 客户端 Zero 是一个开源的 AI 邮箱应用(仓库根目录为
后端前端AI 应用如何用 Payload MCP 插件把内容数据暴露给 MCP 客户端(/api/mcp)
如何用 Payload MCP 插件把内容数据暴露给 MCP 客户端(/api/mcp) 如果你的 Payload 项目里已经配好了 collections 和
后端CMSHorizon MCP 集成指南:将 AI 新闻雷达流水线以 MCP 协议暴露给任意客户端
Horizon MCP 集成指南:将 AI 新闻雷达流水线以 MCP 协议暴露给任意客户端 本篇技术指南围绕 Horizon 开源仓库中内置的 MCP(Mode
人工智能AI 应用MCP 服务网页爬虫
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考