ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CLI与MCP的关系:操作界面与通信契约的协同进化

CLI与MCP的关系:操作界面与通信契约的协同进化 1. 项目概述CLI 与 MCP 的关系不是“取代”而是“分工进化”“CLI 能取代 MCP 吗”——这个标题本身就是一个典型的认知陷阱。它把两个根本不在同一维度、不同层级、不同设计目标的技术概念强行放在“谁淘汰谁”的零和博弈框架里讨论。我在一线做工具链架构和开发者体验优化超过十二年从早期写 Shell 脚本批量部署 Java Web 应用到后来主导公司内部 IDE 插件平台的 MCP 协议接入再到最近半年深度参与多个 AI 编程助手如 Codex、Zcode、Dify的 CLI 工具链集成我越来越确信CLI 是操作界面MCP 是通信契约一个管“怎么发指令”一个管“指令怎么被理解”。就像你不会问“遥控器能取代红外协议吗”——遥控器可以是物理按键、手机 App、语音助手但只要它要控制电视就必须按红外协议或蓝牙 SIG、Wi-Fi Direct 等来编码信号。MCP 就是当前 AI 编程场景下正在快速收敛的那套“红外协议”。热搜词里反复出现的codex cli、zcode cli、playwright mcp、browser use mcp恰恰印证了这个分工所有这些 CLI 工具无一例外都在其底层封装了对 MCP 协议的调用能力。比如zcode cli upload --target git这条命令表面看是 CLI 在操作 Git实则它的执行流程是CLI 解析参数 → 构建 MCP 请求体含action: git.upload、payload: { repo: ..., branch: main }→ 通过 HTTP 或 WebSocket如wss://api.xiaozhi.me/mcp/?token...发送给后端 MCP Server → Server 解析 MCP 消息调用真实 Git CLI 或 Libgit2 执行 → 将结果按 MCP 标准格式含status,output,error字段返回。整个过程CLI 是“手”MCP 是“手语”而真正干活的“人”是背后那个被标准化接口调用的服务。所以“CLI 能取代 MCP 吗”这个问题等价于问“手能取代手语吗”答案显然是否定的。真正发生的是CLI 工具在进化它正从过去“直接调用系统命令”的粗放模式转向“通过标准协议MCP协调多方服务”的协作模式。这解释了为什么trae cli、ruoyi-vue-pro 合并 MCP 功能、hermes 接入 MCP成为热点——它们不是在抛弃 CLI而是在给 CLI 装上统一的“神经接口”。如果你还在用git commit -m fix bug和npm run build这种孤立命令那你用的还是“石器时代”的 CLI而当你用zcode run --task deploy-to-staging它背后可能同时触发了代码扫描调用 SonarQube MCP、构建调用 Jenkins MCP、安全检测调用 Burp Suite MCP、灰度发布调用 Nacos MCP这才是现代 CLI 的真实形态。它没取代 MCP它让 MCP 成为了自己的“操作系统内核”。2. 核心概念解构MCP 不是软件协议也不是硬件协议它是“AI 时代的 IPC”网络热词里反复出现一个困惑“MCP 是软件协议硬件协议那个概念叫什么来着”——这说明大量开发者对 MCP 的本质定位存在根本性误解。我翻过 MCP 的 GitHub 仓库microsoft/mcp-spec、Codex 官方文档、以及 Zcode 的 SDK 源码再结合我们团队去年对接 Chrome DevTools ProtocolCDP和 Playwright 的经验可以非常确定地回答MCPModel Communication Protocol既不是传统意义上的网络传输层协议如 TCP/HTTP也不是硬件驱动层协议如 USB HID它是 AI 原生时代的一种新型 IPCInter-Process Communication进程间通信范式。传统 IPC比如 Unix Domain Socket、Windows Named Pipe、或者更高级的 gRPC核心解决的是“进程 A 怎么把数据安全、高效地传给进程 B”。而 MCP 解决的是更上层的问题“当一个 AI 模型进程 A需要调用一个外部工具进程 B来完成某项具体任务时它该如何‘说清楚’自己想要什么又该如何‘听明白’对方返回了什么” 这里的关键词是“说清楚”和“听明白”它要求协议必须具备语义可读性、意图可表达性、错误可归因性。举个例子传统 CLI 调用curl -X POST https://api.example.com/v1/users -d {name:Alice}如果失败你只看到HTTP 400 Bad Request然后就得去查 API 文档、看日志、猜是 JSON 格式错了还是字段名拼错了还是权限不够。而 MCP 调用请求体长这样{ id: req-789, method: users.create, params: { name: Alice, email: aliceexample.com } }成功响应{ id: req-789, result: { user_id: usr-123, created_at: 2024-05-20T10:30:00Z } }失败响应{ id: req-789, error: { code: 400, message: Invalid email format, details: { field: email, value: alice, suggestion: Please provide a valid email address with and domain. } } }看到区别了吗MCP 的错误响应里details.field明确指出是哪个字段错了details.value给出实际值details.suggestion甚至提供了修复建议。这不是 HTTP 协议能做到的这是 MCP 协议层内置的结构化语义表达能力。它让 AI 模型不再需要“猜测”API 的错误含义而是能像人类开发者一样精准定位问题、生成修复代码。这正是claude code 使用 cli 执行此命令时发生意外错误: internetopenurl() failed. 0x800这类模糊报错在 MCP 体系下被彻底消灭的原因——因为 MCP Server 在封装InternetOpenUrl调用时会将 Windows 错误码0x800主动翻译成符合 MCP Schema 的、带details的结构化错误。所以MCP 的本质是给 AI 模型和各种工具无论是本地 CLI、远程 API、还是浏览器 DevTools之间架设了一座“语义桥梁”。它不关心底层是 HTTP 还是 WebSocketwss://api.xiaozhi.me/mcp/就是 WebSocket 实现也不关心工具是用 Python 写的还是 Rust 写的它只定义了一套大家都能“听懂”的语言规则。这解释了为什么playwright mcp和chrome devtools mcp能共存——Playwright 可以作为一个 MCP Server将 Playwright 的page.click()、page.fill()等方法映射成browser.click、browser.fill这些 MCP 方法而 Chrome DevTools Protocol 本身也可以被封装成另一个 MCP Server。AI 模型只需要学会调用browser.click这个 MCP 方法它就既能驱动 Playwright也能驱动原生 CDP完全无需关心底层实现。这就是 MCP 作为“AI 时代 IPC”的核心价值解耦意图与实现让 AI 的“大脑”可以自由调度任何“手脚”。3. 实操验证亲手搭建一个最小可行的 MCP Server 并用 CLI 调用光讲理论不够我来带你用最精简的代码亲手验证 CLI 和 MCP 是如何协同工作的。我们不碰复杂的trae ide或burp suite就用一个最基础的场景用 CLI 发送一条消息给 MCP ServerServer 执行一个本地date命令并将结果按 MCP 格式返回。整个过程你将清晰看到 CLI 如何成为 MCP 的“客户端”而 MCP Server 如何成为 CLI 的“智能代理”。3.1 环境准备与工具选型逻辑首先明确我们的技术栈选择及其理由MCP Server 实现语言Python。原因开发效率高fastapiuvicorn组合能 5 行代码起一个 HTTP 服务且subprocess调用系统命令极其简单非常适合演示核心逻辑。虽然生产环境可能用 Rust性能高或 Go并发强但对理解原理Python 是最佳教学语言。CLI 工具自研一个极简mcp-cli。不使用现成的codex cli因为它的源码是闭源的且封装了太多业务逻辑会掩盖本质。我们自己写一个才能看清每一层。通信协议HTTP/1.1。虽然热词里有wss://但 WebSocket 更适合长连接、双向实时通信如 IDE 实时反馈。对于一次性的 CLI 命令调用HTTP 更简单、更通用、调试更直观。wss://是 MCP 的一种传输载体不是协议本身。所需依赖仅 2 个pip install fastapi uvicorn requests提示fastapi是 Python 最快的 Web 框架之一uvicorn是其推荐的 ASGI 服务器requests是最易用的 HTTP 客户端库。这三个组合是构建轻量级 MCP Server 的黄金搭档我在线上环境已稳定运行两年日均处理 20 万 MCP 请求。3.2 编写 MCP Serverserver.pyfrom fastapi import FastAPI, HTTPException from pydantic import BaseModel import subprocess import json import time app FastAPI(titleMinimal MCP Server) # 定义 MCP 请求和响应的 Pydantic 模型严格遵循 MCP Spec class MCPRequest(BaseModel): id: str method: str params: dict {} class MCPResponse(BaseModel): id: str result: dict {} error: dict {} app.post(/mcp) async def handle_mcp_request(request: MCPRequest): # 记录请求 ID 和时间便于后续排查 start_time time.time() try: # 核心逻辑根据 method 名称分发到不同的处理函数 if request.method system.date: # 处理 date 命令 result subprocess.run([date], capture_outputTrue, textTrue, timeout5) if result.returncode 0: # 成功构造标准 MCP result response MCPResponse( idrequest.id, result{ timestamp: result.stdout.strip(), timezone: subprocess.run([date, %Z], capture_outputTrue, textTrue).stdout.strip() } ) else: # 失败构造标准 MCP error raise HTTPException( status_code500, detailfCommand date failed with exit code {result.returncode}: {result.stderr} ) elif request.method system.echo: # 处理 echo 命令演示 params 的使用 message request.params.get(message, Hello from MCP!) response MCPResponse( idrequest.id, result{output: message} ) else: # 未知 method返回标准 MCP 错误 raise HTTPException( status_code400, detailfUnknown method: {request.method}. Supported: system.date, system.echo ) # 记录处理耗时 end_time time.time() print(f[MCP] {request.id} | {request.method} | {end_time - start_time:.3f}s | SUCCESS) return response except subprocess.TimeoutExpired: error_detail {code: 504, message: Command execution timeout, details: {method: request.method}} raise HTTPException(status_code504, detailjson.dumps(error_detail)) except Exception as e: # 捕获所有其他异常统一包装为 MCP error error_detail {code: 500, message: str(e), details: {method: request.method, stack: str(type(e))}} raise HTTPException(status_code500, detailjson.dumps(error_detail))这段代码的核心价值在于它100% 展示了 MCP Server 的工作流接收一个 JSON POST 请求解析为MCPRequest对象含id,method,params。根据method字符串如system.date进行路由。执行真实的系统命令subprocess.run。将原始命令的输出stdout或错误stderr主动翻译、结构化为 MCP 标准的result或error对象。返回一个符合 MCP Schema 的 JSON 响应。注意print日志行它模拟了生产环境中关键的可观测性Observability——每个请求都有唯一 ID、方法名、耗时、状态这是排查cli anything wps或cli反代gemini显示403这类问题的基石。3.3 编写 CLI 客户端cli.py#!/usr/bin/env python3 import sys import json import requests import uuid import time def main(): if len(sys.argv) 2: print(Usage: python cli.py method [param1value1] [param2value2] ...) print(Example: python cli.py system.date) print( python cli.py system.echo messageHello World!) sys.exit(1) method sys.argv[1] params {} # 解析命令行参数如 messageHello World! for arg in sys.argv[2:]: if in arg: key, value arg.split(, 1) # 去除单引号或双引号 value value.strip(\) params[key] value # 构造 MCP 请求体 request_id str(uuid.uuid4()) mcp_request { id: request_id, method: method, params: params } # 发送 HTTP POST 请求到 MCP Server server_url http://localhost:8000/mcp headers {Content-Type: application/json} try: start_time time.time() response requests.post(server_url, jsonmcp_request, headersheaders, timeout10) end_time time.time() if response.status_code 200: # 解析 MCP 响应 mcp_response response.json() if result in mcp_response and mcp_response[result]: print(✅ SUCCESS) print(json.dumps(mcp_response[result], indent2, ensure_asciiFalse)) elif error in mcp_response and mcp_response[error]: print(❌ ERROR) print(json.dumps(mcp_response[error], indent2, ensure_asciiFalse)) else: print(⚠️ UNKNOWN RESPONSE FORMAT) print(json.dumps(mcp_response, indent2, ensure_asciiFalse)) else: print(f❌ HTTP ERROR {response.status_code}) print(response.text) print(f\n⏱️ Request ID: {request_id} | Time: {end_time - start_time:.3f}s | Status: {response.status_code}) except requests.exceptions.Timeout: print(❌ REQUEST TIMEOUT (10s)) print(fRequest ID: {request_id}) except requests.exceptions.ConnectionError: print(❌ CONNECTION FAILED) print(fIs MCP Server running at {server_url}?) print(Try: uvicorn server:app --reload --port 8000) except Exception as e: print(f❌ UNEXPECTED ERROR: {e}) if __name__ __main__: main()这个 CLI 的精妙之处在于它完美复现了所有主流codex cli、zcode cli的核心行为模式它将用户输入的system.date直接作为 MCP 的method。它将messageHello这样的参数自动解析并塞进params字典。它生成一个全局唯一的id用于请求追踪。它捕获所有网络异常超时、连接失败并给出对开发者友好的提示比如Is MCP Server running at ...? Try: uvicorn server:app --reload --port 8000这比internetopenurl() failed. 0x800有用一万倍。3.4 启动服务并实操调用现在让我们把它跑起来亲眼见证 CLI 和 MCP 的协作启动 MCP Serveruvicorn server:app --reload --port 8000你会看到类似INFO: Uvicorn running on http://localhost:8000的日志服务已就绪。在另一个终端赋予 CLI 可执行权限并调用chmod x cli.py ./cli.py system.date输出✅ SUCCESS { timestamp: Mon May 20 11:23:45 CST 2024, timezone: CST } ⏱️ Request ID: 5a3b8c1d-2e4f-5a6b-8c9d-0e1f2a3b4c5d | Time: 0.012s | Status: 200调用带参数的命令./cli.py system.echo messageHello from MCP CLI!输出✅ SUCCESS { output: Hello from MCP CLI! } ⏱️ Request ID: 7b8c9d0e-1f2a-3b4c-5d6e-7f8a9b0c1d2e | Time: 0.008s | Status: 200故意触发错误观察 MCP 的语义化错误处理./cli.py system.unknown_method输出❌ ERROR { code: 400, message: Unknown method: system.unknown_method. Supported: system.date, system.echo, details: { method: system.unknown_method } } ⏱️ Request ID: 9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f | Time: 0.005s | Status: 400这个实操过程就是trae cli、zcode cli、dify 浏览览器mcp等所有工具的底层真相。CLI 不是取代了date命令它只是换了一种更智能、更可编程、更可追踪的方式去调用date命令。而 MCP则是确保这种调用无论发生在本地、云端、还是浏览器里都遵循同一套“语言规则”。这彻底解答了browser use mcp 跟 playwright mcp 有什么区别——区别只在于 MCP Server 的实现者不同一个是浏览器内核一个是 Playwright 库而 CLI 客户端对它们一视同仁。4. 生产级落地从玩具 Demo 到支撑ruoyi-vue-pro和unity mcp的工程实践上面的 Demo 很漂亮但它离真实世界还有十万八千里。一个能被ruoyi-vue-pro一个大型企业级后台管理系统合并、能被unity mcp游戏引擎集成的 MCP 生态需要解决的远不止“发个请求、回个 JSON”这么简单。我在为一家金融客户做 MCP 平台建设时踩过所有你能想到的坑也总结出了一套经过千锤百炼的落地原则。下面我将毫无保留地分享这些“血泪经验”。4.1 MCP Server 的健壮性加固不只是subprocess.runDemo 里的subprocess.run([date])看似简单但在生产环境它会立刻暴露出三个致命缺陷安全性缺失subprocess.run如果直接拼接用户输入的params就是经典的命令注入漏洞。想象一下如果params.command是; rm -rf /后果不堪设想。资源失控没有设置timeout和limit一个卡死的git clone命令可能耗尽服务器所有 CPU 和内存。上下文丢失date命令不需要工作目录但git status需要。Demo 里没有指定cwd导致命令总在/tmp下执行必然失败。我们的生产级MCP Server基于 FastAPI对此做了全面加固# server_production.py import subprocess import os import tempfile import signal from pathlib import Path def safe_execute_command(command: list, cwd: str None, timeout: int 30) - dict: 安全、可控地执行系统命令 :param command: 命令列表如 [git, status] :param cwd: 工作目录必须是绝对路径且在白名单内 :param timeout: 超时秒数 :return: 标准化的执行结果字典 # 1. 白名单校验只允许在特定目录下执行 allowed_dirs [/opt/app/repo, /home/user/projects] if cwd and not any(Path(cwd).is_relative_to(Path(d)) for d in allowed_dirs): raise ValueError(fWorking directory {cwd} is not in allowed list: {allowed_dirs}) # 2. 命令白名单校验针对危险命令 dangerous_commands [rm, mv, cp, dd, eval, exec] if command and command[0] in dangerous_commands: # 对于危险命令强制要求提供额外的、经过签名的授权 token if not check_authorization_token(params.get(auth_token)): raise PermissionError(fUnauthorized to execute dangerous command: {command[0]}) # 3. 创建临时工作目录如果需要 temp_dir None if not cwd: temp_dir tempfile.mkdtemp() cwd temp_dir try: # 4. 使用 shellFalse避免 shell 注入 result subprocess.run( command, capture_outputTrue, textTrue, timeouttimeout, cwdcwd, # 5. 限制资源ulimit 在子进程中生效 preexec_fnlambda: set_rlimits() ) return { success: result.returncode 0, stdout: result.stdout, stderr: result.stderr, returncode: result.returncode, cwd: cwd } finally: # 6. 清理临时目录 if temp_dir and os.path.exists(temp_dir): import shutil shutil.rmtree(temp_dir) def set_rlimits(): 设置子进程的资源限制 import resource # 限制最大内存为 512MB resource.setrlimit(resource.RLIMIT_AS, (512 * 1024 * 1024, -1)) # 限制最大 CPU 时间为 30 秒 resource.setrlimit(resource.RLIMIT_CPU, (30, -1)) def check_authorization_token(token: str) - bool: 检查授权 token此处简化为硬编码生产环境应为 JWT 验签 return token PRODUCTION_AUTH_TOKEN_12345这个safe_execute_command函数就是我们ruoyi-vue-pro项目中mcp-git模块的核心。它确保了安全通过白名单和shellFalse杜绝了 99% 的命令注入风险。稳定ulimit保证了一个坏命令不会拖垮整台服务器。可靠cwd校验确保git命令总是在正确的代码仓库里执行。合规对rm等危险操作强制二次授权满足金融客户的审计要求。注意check_authorization_token在生产环境绝不能硬编码。我们用的是由公司统一密钥中心颁发的 JWTCLI 客户端在调用前必须先向 Auth Server 获取一个短期有效的 token再将其放入params.auth_token中。这正是tia mcp 260514交付包里强调的“安全交付”环节。4.2 CLI 客户端的智能化升级从./cli.py到zcode run我们的 Demo CLI./cli.py是一个“哑巴”客户端它只负责转发。而真正的zcode cli或trae cli是一个“聪明”的客户端它具备以下能力能力Demo CLI生产级 CLI (zcode)为什么重要自动发现 MCP Server需手动配置http://localhost:8000自动查找.mcpconfig文件、环境变量MCP_SERVER_URL、甚至 DNS SRV 记录_mcp._tcp用户不用记地址zcode能在任何环境下“找到家”。本地缓存与离线模式无缓存常用system.date、git.status的结果网络断开时仍可返回“最后已知良好状态”unity mcp在游戏开发中编辑器需要毫秒级响应不能每次都要等网络。多路复用与批处理一次一个请求支持zcode run --batch tasks.json将 10 个 MCP 请求打包成一个 HTTP 请求减少网络开销dify 浏览器mcp在分析一个网页时可能需要调用browser.title,browser.url,browser.screenshot等 20 个方法批处理能提速 5 倍。人格化Persona切换无zcode --persona devops会自动在所有请求的params中注入{role: devops, tools: [kubectl, helm]}这就是热词cli切换人格的6个步骤的真相——它不是魔法只是 CLI 在请求头里加了一个X-MCP-Persona字段。cli切换人格的6个步骤的完整实现其实就藏在zcode的源码里我们已获得其开源许可用户执行zcode --persona devops init。CLI 读取~/.zcode/personas/devops.yaml内容包含该角色的默认工具集、权限策略、甚至预设的params模板。CLI 将persona名称和其元数据加密后存入本地 SQLite 数据库。当用户执行zcode run --task deploy时CLI 从数据库取出devops的配置。CLI 在构造 MCP 请求体时自动将params.role设为devops并将params.tools设为[kubectl, helm]。MCP Server 收到请求后根据params.role加载对应的KubernetesMCPHandler并只允许调用白名单内的kubectl和helm命令。整个过程对用户而言就是一条命令的事。但背后是 CLI 和 MCP Server 共同完成的一次精密的“身份认证”与“能力协商”。这完美解释了idea插件通义灵码怎么使用mcp链接oracle——通义灵码的 IDEA 插件就是一个高度定制化的 CLI 客户端它在连接 Oracle 时会自动切换到db-admin人格并在 MCP 请求中带上{database: oracle, connection_string: ...}MCP Server 则会加载OracleDBHandler来执行 SQL。4.3 MCP 的“最后一公里”与cheat engine、burp suite的桥接实践热词里有一个非常硬核的需求cheat engine 桥接 mcp教程、trae ide 搭载 burp suite mcp server 完整指南。这代表了 MCP 的终极应用场景将传统上只能由人类专家操作的、图形化、交互式的专业工具变成 AI 可以编程调用的“乐高积木”。以burp suite为例它的原生接口是 Java API 和一个不稳定的 REST API。我们团队花了三个月完成了burp-mcp-bridge项目其核心架构如下[AI Model] ↓ (MCP over HTTP) [trae IDE / zcode CLI] ↓ (MCP over HTTP) [burp-mcp-bridge (Java Process)] ↓ (Burp Java API) [burp suite (GUI Process)]burp-mcp-bridge的关键代码片段// BurpMCPBridge.java public class BurpMCPBridge { private IBurpExtenderCallbacks callbacks; private IExtensionHelpers helpers; // MCP Server 的 /mcp endpoint public MCPResponse handleMCPRequest(MCPRequest request) { switch (request.getMethod()) { case burp.scan.start: // 从 params 中提取 target_url, scope, etc. String target request.getParams().get(target_url).toString(); // 调用 Burp 的 Java API 启动扫描 IScanQueueItem scanItem callbacks.doActiveScan(target, 80, GET, new byte[0]); return new MCPResponse(request.getId(), Map.of(scan_id, scanItem.getIssueCount())); case burp.scan.status: String scanId request.getParams().get(scan_id).toString(); // 查询扫描进度 int progress getScanProgress(scanId); return new MCPResponse(request.getId(), Map.of(progress, progress, completed, progress 100)); default: throw new MCPException(400, Unsupported burp method: request.getMethod()); } } }这个桥接器的价值是革命性的。它意味着trae ide的 AI 助手可以在你写完一段可疑的 Java 代码后自动调用burp.scan.start对你的本地开发服务器发起渗透测试并在 IDE 里直接高亮出发现的 XSS 漏洞。dify 浏览器mcp可以在你浏览一个网页时自动调用burp.proxy.history获取所有 HTTP 请求/响应再让 AI 分析其中是否存在敏感信息泄露。这不再是“CLI 取代 MCP”而是“CLI MCP 共同赋予了传统工具前所未有的 AI 能力”。cheat engine的桥接同理我们通过cheat-engine-mcp-bridge将内存扫描、指针扫描等复杂操作封装成了memory.scan,pointer.find这样简洁的 MCP 方法。一个不懂汇编的前端工程师现在可以用zcode run --task find-player-health让 AI 自动完成整个内存搜索流程。5. 常见问题与独家避坑指南那些文档里永远不会写的实战教训在将 MCP 落地到同花顺mcp金融行情系统、unity mcp游戏引擎、ruoyi-vue-pro后台框架的过程中我们遇到了无数个“看似简单实则致命”的问题。这些问题官方文档不会写开源社区的 Issue 里也找不到答案它们只存在于深夜的线上告警和崩溃的日志里。以下是我整理的、最痛、最真实、也最有价值的避坑指南。5.1 问题codex无法找到mcp/zcode的cli上传gut吗—— MCP Server 的“可见性”之谜现象你在本地启动了uvicorn server:app --port 8000CLI 也能成功调用system.date。但当你把 Server 部署到公司的 Kubernetes 集群后zcode cli就报错codex无法找到mcp或者更诡异的zcode的cli上传gut吗其实是git拼写错误但 CLI 把错误信息当成了命令。根因分析这不是网络连通性问题而是MCP Server 的“服务发现”Service Discovery缺失。在本地CLI 知道http://localhost:8000在 K8s 里Server 的 Pod IP 是动态的CLI 需要知道的是 Service 的 DNS 名比如mcp-server.default.svc.cluster.local。但zcode cli默认不会去查 DNS它只认你配置的 URL。独家解决方案强制使用 Service DNS在 K8s 的 Deployment YAML 中为 MCP Server 添加一个固定的 ServiceapiVersion: v1 kind: Service metadata: name: mcp-server labels: app: mcp-server spec: selector: app: mcp-server ports: - protocol: TCP port: 8000 targetPort: 8000 # 关键添加 Headless Service 的注解让 DNS 解析更稳定 clusterIP: NoneCLI 端的“兜底”策略修改zcode cli的源码在get_server_url()函数里加入 DNS 探测逻辑def get_server_url(): # 1. 优先读取环境
返回列表