Klavis CLI MCP Server:为 AI Agent 构建安全可控的命令行执行能力
【免费下载链接】klavisKlavis AI: MCP integration platforms that let AI agents use tools reliably at any scale项目地址: https://gitcode.com/GitHub_Trending/kl/klavis
导读
CLI MCP Server 是 Klavis 开源仓库中位于mcp_servers/local/terminal/的一个本地 MCP(Model Context Protocol)服务器,它把"在终端执行命令"这一能力以受控、可审计的方式暴露给 Claude Desktop、Cursor 等 MCP 客户端。本文以该模块的 README 为核心脉络,结合 server.py 源码逐层拆解其安全模型、环境变量配置、两个内置工具(run_command与show_security_rules)、错误处理体系以及构建发布流程。读完本文,你将掌握如何把该服务器接入主流 MCP 客户端,理解命令白名单、路径穿越防护、Shell 操作符注入防护等安全机制在源码中的具体实现方式。
项目定位:给 LLM 一把"上了锁"的终端
直接让大语言模型执行任意命令行存在明显的安全风险:模型可能误触危险命令、路径可能越界访问敏感目录、Shell 操作符可能被用来拼接恶意指令。CLI MCP Server 的核心设计目标就是在"把终端能力交给 LLM"与"维持安全边界"之间取得平衡。正如 README 所述,它是一个"用于执行受控命令行操作、并附带全面安全特性的 MCP 服务器实现",适合为 LLM 应用提供受控的 CLI 访问。
从源码结构看,该模块只有两个文件构成核心实现:src/cli_mcp_server/server.py(全部业务与安全逻辑)和 src/cli_mcp_server/init.py(包入口,通过asyncio.run(server.main())启动 stdio 服务),配合 pyproject.toml 完成打包与命令行入口注册。仓库的文档索引页 docs/mcp-server/local/terminal.mdx 也将其归类为"本地 MCP 服务器"——即运行在用户自己机器上、通过 stdio 与客户端通信的服务器。
核心特性一览
README 明确列出的能力包括:
- 🔒 严格校验的安全命令执行
- ⚙️ 可配置的命令与 flag 白名单,支持
all通配选项 - 🛡️ 路径穿越(directory traversal)防护与路径校验
- 🚫 Shell 操作符注入防护
- ⏱️ 执行超时与命令长度限制
- 📝 详细的错误报告
- 🔄 异步操作支持
- 🎯 工作目录限制与校验
环境变量配置:六个开关决定安全边界
服务启动时完全通过环境变量进行安全配置,load_security_config() 负责读取并解析这些变量。完整参数表如下(来源:README 配置章节,默认值可与源码逐一对应):
| 变量 | 说明 | 默认值 |
|---|---|---|
ALLOWED_DIR | 命令执行的基础目录(必填) | 无(必填) |
ALLOWED_COMMANDS | 允许的命令列表(逗号分隔)或all | ls,cat,pwd |
ALLOWED_FLAGS | 允许的 flag 列表(逗号分隔)或all | -l,-a,--help |
MAX_COMMAND_LENGTH | 命令字符串最大长度 | 1024 |
COMMAND_TIMEOUT | 命令执行超时时间(秒) | 30 |
ALLOW_SHELL_OPERATORS | 是否允许 Shell 操作符(&&、\|\|、\|、>等) | false |
注意:将
ALLOWED_COMMANDS或ALLOWED_FLAGS设为all将分别放行任意命令或任意 flag,务必在受信任的环境中使用。
源码中的解析细节
对照源码可以发现几个容易忽略的细节:
all的大小写不敏感:load_security_config使用allowed_commands.lower() == "all"判断通配模式,因此ALL、All均有效(server.py)。ALLOW_SHELL_OPERATORS的取值语义:只有"true"或"1"(不区分大小写)会被视为开启,其他任意值均视为关闭(server.py)。- 白名单去重:命令与 flag 会被解析为
set,天然去重,且all模式下白名单集合为空集、仅靠布尔标志判断(server.py)。 ALLOWED_DIR启动即校验:CommandExecutor.__init__会检查目录是否存在,否则抛出ValueError("Valid ALLOWED_DIR is required")(server.py),这说明该变量虽然只标注为"必填",但缺失或无效时服务会直接启动失败,而非静默降级。- 目录会做规范化:
allowed_dir被存储为os.path.abspath(os.path.realpath(allowed_dir)),即先解析符号链接再取绝对路径,作为后续所有路径安全判断的基准(server.py)。
这些配置会被封装进SecurityConfigdataclass(server.py),成为整个执行链路的唯一安全事实来源。
内置工具:run_command 与 show_security_rules
该服务器通过 handle_list_tools() 向客户端注册两个工具,所有工具调用统一由 handle_call_tool() 分发处理。
run_command:受控命令执行
执行白名单内命令的核心工具。其输入 Schema 为:
{ "command": { "type": "string", "description": "Single command to execute (e.g., 'ls -l' or 'cat file.txt')" } }一个值得注意的细节是:run_command的工具描述(description)是动态生成的,会包含当前工作目录、可用命令列表、可用 flag 列表以及 Shell 操作符支持状态(server.py)。这意味着 LLM 在调用前就能"看到"自己可以做什么,从而减少无效调用。
README 强调的安全约束如下:
- Shell 操作符(
&&、|、>、>>等)默认不支持,可通过ALLOW_SHELL_OPERATORS=true开启; - 命令必须命中白名单,除非
ALLOWED_COMMANDS='all'; - flag 必须命中白名单,除非
ALLOWED_FLAGS='all'; - 所有路径都会被校验,确保位于
ALLOWED_DIR之内。
show_security_rules:运行时安全状态自省
无参数工具,输出当前生效的安全配置,包括:工作目录、允许的命令、允许的 flag、安全限制(最大命令长度与超时时间)(server.py)。这一工具对 LLM 特别有用——当模型不确定自己能执行什么时,可以先调用它获取环境约束,再规划命令。输出格式为纯文本的安全配置摘要,如:
Security Configuration: ================== Working Directory: /path/to/allowed/dir Allowed Commands: ---------------- cat, ls, pwd Allowed Flags: ------------- -a, -l, --help Security Limits: --------------- Max Command Length: 1024 characters Command Timeout: 30 seconds安全机制深度解析:从声明到源码实现
README 的安全特性清单(Security Features 章节)每一项都能在CommandExecutor中找到对应实现。下面逐条对照。
1. 命令白名单与 flag 校验
_validate_single_command使用shlex.split将命令字符串拆分为[命令, 参数...](server.py):
- 命令部分:非
all模式下,若命令不在allowed_commands集合中,抛出CommandSecurityError(f"Command '{command}' is not allowed"); - 参数部分:以
-开头的参数被视为 flag,非all模式下必须命中allowed_flags,否则拒绝执行。
2. 路径穿越防护与路径规范化
这是最核心的安全环节,分两层实现:
- 显式路径识别:参数以
./、../、/开头(但不以//开头),或参数本身是.时,被判定为"显式路径",必须走路径校验(server.py);此外,包含/且拼接到allowed_dir后真实存在的参数也会被视为路径参数。 - 边界检查:
_normalize_path先对相对路径做os.path.join(allowed_dir, path)拼接,再统一经过os.path.abspath(os.path.realpath(...))解析——realpath会解析符号链接,因此allowed_dir内部的 symlink 若指向外部目录也会被识破。随后_is_path_safe检查解析后的绝对路径是否以allowed_dir的绝对路径开头(server.py)。
从源码结构看,
realpath+startswith的组合是"双重保险":既防../字面量穿越,也防符号链接逃逸。
另外值得一提的是_is_url_path(server.py):对http:///https://开头的参数(如curl https://example.com),服务器不做路径规范化、直接放行,避免将 URL 误判为本地路径。
3. Shell 操作符注入防护
源码中定义了完整的操作符黑名单:["&&", "||", "|", ">", ">>", "<", "<<", ";"](server.py)。当命令中包含任一操作符时:
- 若
ALLOW_SHELL_OPERATORS未开启,直接抛出CommandSecurityError,并提示"Set ALLOW_SHELL_OPERATORS=true to enable"(server.py); - 若已开启,则进入
_validate_command_with_operators:用正则把命令按操作符切段,逐段独立执行_validate_single_command校验,确保ls -l; rm -rf /这类拼接中的每一段都合法,只有全部通过后才以shell=True方式执行原始字符串(server.py)。
4. 命令长度限制与执行超时
execute方法在执行前先检查len(command_string) > max_command_length,超限即抛CommandSecurityError(server.py);随后调用subprocess.run时传入timeout=command_timeout与cwd=allowed_dir,超时由subprocess.TimeoutExpired捕获并转换为CommandTimeoutError(server.py)。
5. shell=True 与 shell=False 的区分执行
execute的执行策略体现了"最小特权"思想(server.py):
- 命令不含Shell 操作符时,用
shell=False并传入[command] + args列表——不经过 shell 解析,参数注入风险显著降低; - 命令包含Shell 操作符(且已获授权)时,才以
shell=True执行原始字符串。
两种模式都使用text=True、capture_output=True,同时捕获 stdout 与 stderr。
错误处理体系
README 的 Error Handling 章节 定义了完整的异常层级,源码中全部位于 server.py:
| 异常类型 | 触发场景 |
|---|---|
CommandError | 命令相关错误的基类 |
CommandSecurityError | 安全违规:命令/flag 不在白名单、路径越界、长度超限、Shell 操作符被禁 |
CommandExecutionError | 命令执行失败(进程启动/运行异常) |
CommandTimeoutError | 命令执行超时 |
在工具调用层,handle_call_tool会把这些异常转换为带error=True标记的TextContent返回给客户端(server.py),例如安全违规会返回Security violation: ...。正常执行时则返回 stdout、stderr 以及Command completed with return code: N三部分内容(server.py),LLM 可以据此判断命令是否真正成功。
接入 MCP 客户端:以 Claude Desktop 为例
安装方式
README 提供了两条安装路径:
方式一:通过 Smithery 自动安装到 Claude Desktop
npx @smithery/cli install cli-mcp-server --client claude方式二:手动配置 Claude Desktop
编辑~/Library/Application\ Support/Claude/claude_desktop_config.json,按部署形态选择以下两种配置之一。
开发/未发布服务器配置(从仓库源码目录启动):
{ "mcpServers": { "cli-mcp-server": { "command": "uv", "args": [ "--directory", "<path/to/the/repo>/cli-mcp-server", "run", "cli-mcp-server" ], "env": { "ALLOWED_DIR": "</your/desired/dir>", "ALLOWED_COMMANDS": "ls,cat,pwd,echo", "ALLOWED_FLAGS": "-l,-a,--help,--version", "MAX_COMMAND_LENGTH": "1024", "COMMAND_TIMEOUT": "30", "ALLOW_SHELL_OPERATORS": "false" } } } }已发布服务器配置(通过uvx从 PyPI 拉取):
{ "mcpServers": { "cli-mcp-server": { "command": "uvx", "args": [ "cli-mcp-server" ], "env": { "ALLOWED_DIR": "</your/desired/dir>", "ALLOWED_COMMANDS": "ls,cat,pwd,echo", "ALLOWED_FLAGS": "-l,-a,--help,--version", "MAX_COMMAND_LENGTH": "1024", "COMMAND_TIMEOUT": "30", "ALLOW_SHELL_OPERATORS": "false" } } } }如果客户端界面中看不到该服务器或配置不生效,README 建议先执行
uv clean清理缓存后再重启客户端。
配置建议
从源码行为可以给出几条实际配置建议:
ALLOWED_DIR务必收敛到最小需要的目录(如项目工作区),切勿设为/或~,因为_is_path_safe的startswith判断意味着白名单目录越宽,LLM 可触碰的文件面就越大;- 白名单命令越少越好,默认的
ls,cat,pwd已经覆盖最常见的文件浏览需求;需要新增命令时(如echo、git status),按需追加即可; - 默认 flag 只有
-l,-a,--help,ls -la这类常见组合恰好覆盖;但rm -rf的-rf不在默认白名单内,这是有意为之的防护; - 生产环境保持
ALLOW_SHELL_OPERATORS=false,仅在受信任的沙箱场景下才开启。
开发、构建与发布
环境要求
- Python 3.10+(pyproject.toml 声明
requires-python = ">=3.10") - MCP 协议库(依赖
mcp>=1.10.1)
构建与发布(基于 uv 工具链)
# 1. 同步依赖并更新 lockfile uv sync # 2. 构建分发包(生成 source 与 wheel 到 dist/ 目录) uv build # 3. 发布到 PyPI uv publish --token {{YOUR_PYPI_API_TOKEN}}其中命令行入口在 pyproject.toml 的[project.scripts]段注册:cli-mcp-server = "cli_mcp_server:main",指向init.py 中的main()——该函数通过asyncio.run启动 stdio 服务。另可注意到:pyproject.toml中包版本为0.2.5,而服务初始化时向客户端宣告的server_version为0.2.1(server.py),两者在源码中目前并不完全一致。
调试:使用 MCP Inspector
由于 MCP 服务器基于 stdio 通信,调试较为困难。README 推荐使用 MCP Inspector,通过 npx 启动:
npx @modelcontextprotocol/inspector uv --directory {{your source code local directory}}/cli-mcp-server run cli-mcp-server启动后 Inspector 会输出一个可在浏览器中访问的 URL,用于交互式地浏览工具列表、手动触发run_command/show_security_rules调用并观察返回内容——这是验证安全配置是否生效的最快途径。
许可证与更多参考
本项目以 MIT 许可证发布(见 LICENSE)。相关参考资源:
- 模块 README:mcp_servers/local/terminal/README.md
- 核心实现:mcp_servers/local/terminal/src/cli_mcp_server/server.py
- 包入口:mcp_servers/local/terminal/src/cli_mcp_server/init.py
- 打包配置:mcp_servers/local/terminal/pyproject.toml
- 文档索引页:docs/mcp-server/local/terminal.mdx
该服务器与仓库中mcp_servers/local/目录下的 filesystem、git、memory 等同属"本地 MCP 服务器"家族,均可通过相同的方式接入 MCP 客户端。如果你需要在自有环境中让 AI Agent 安全地操作终端,以 terminal/README.md 为起点、配合本文的源码级剖析,即可快速完成部署与定制。
【免费下载链接】klavisKlavis AI: MCP integration platforms that let AI agents use tools reliably at any scale项目地址: https://gitcode.com/GitHub_Trending/kl/klavis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考