脚本执行与沙箱设计
High Contrast
Dark Mode
Light Mode
Sepia
Forest
2 min read478 words

脚本执行与沙箱设计

让 AI 执行系统命令是 MCP 中风险最高的能力。本节介绍如何安全地给 AI 脚本执行权限:从最简单的受限命令列表,到完整的沙箱容器方案。

脚本执行 MCP 的风险等级

graph LR A[脚本执行能力] --> B["低风险:
只允许预定义命令
(只读操作)"] A --> C["中风险:
允许运行用户脚本
(限制目录)"] A --> D["高风险:
完整 shell 访问
(生产系统禁用)"] B --> B1["适合场景:
数据分析、文件处理"] C --> C1["适合场景:
开发辅助、自动化测试"] D --> D1["适合场景:
本地开发环境
(需要高度信任 LLM)"] style D fill:#E74C3C,color:#fff style B fill:#27AE60,color:#fff style C fill:#F39C12,color:#fff

方案一:白名单命令 MCP(最安全)

自建一个只暴露特定命令的 MCP Server,是最安全的脚本执行方案:

# allowed_commands_server.py
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import subprocess
import shlex
app = Server("allowed-commands")
# 白名单:只允许这些命令
ALLOWED_COMMANDS = {
"python3": ["/usr/bin/python3"],
"jq": ["/usr/local/bin/jq"],
"csvkit": ["/usr/local/bin/csvstat"],
"wc": ["/usr/bin/wc"],
"sort": ["/usr/bin/sort"],
"uniq": ["/usr/bin/uniq"],
}
@app.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="run_allowed_command",
description=f"运行预批准的命令。可用命令: {', '.join(ALLOWED_COMMANDS.keys())}",
inputSchema={
"type": "object",
"properties": {
"command": {
"type": "string",
"enum": list(ALLOWED_COMMANDS.keys()),
"description": "要执行的命令名"
},
"args": {
"type": "array",
"items": {"type": "string"},
"description": "命令参数列表"
}
},
"required": ["command"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name != "run_allowed_command":
raise ValueError(f"未知工具: {name}")
cmd_name = arguments["command"]
args = arguments.get("args", [])
if cmd_name not in ALLOWED_COMMANDS:
return [types.TextContent(type="text", text=f"错误:命令 '{cmd_name}' 不在白名单中")]
# 使用完整路径,防止 PATH 劫持
full_cmd = ALLOWED_COMMANDS[cmd_name] + args
try:
result = subprocess.run(
full_cmd,
capture_output=True,
text=True,
timeout=30,  # 30秒超时
cwd="/Users/yourname/ai-workspace/workspace"  # 限制工作目录
)
output = result.stdout if result.returncode == 0 else result.stderr
return [types.TextContent(type="text", text=output[:10000])]  # 限制输出大小
except subprocess.TimeoutExpired:
return [types.TextContent(type="text", text="错误:命令执行超时(30秒)")]
async def main():
async with stdio_server() as (read_stream, write_stream):
await app.run(read_stream, write_stream, app.create_initialization_options())
if __name__ == "__main__":
import asyncio
asyncio.run(main())

配置:

{
"mcpServers": {
"allowed-commands": {
"command": "python3",
"args": ["/Users/yourname/mcp-servers/allowed_commands_server.py"]
}
}
}

方案二:Docker 沙箱执行

对于需要运行任意代码的场景,Docker 提供了最强的隔离:

# docker_sandbox_server.py
import docker
from mcp.server import Server
from mcp import types
app = Server("docker-sandbox")
docker_client = docker.from_env()
@app.list_tools()
async def list_tools():
return [
types.Tool(
name="run_python_sandbox",
description="在 Docker 沙箱中运行 Python 代码",
inputSchema={
"type": "object",
"properties": {
"code": {"type": "string", "description": "Python 代码"},
"timeout": {"type": "integer", "default": 30}
},
"required": ["code"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
code = arguments["code"]
timeout = min(arguments.get("timeout", 30), 60)  # 最大60秒
try:
container = docker_client.containers.run(
"python:3.11-slim",       # 最小化 Python 镜像
["python3", "-c", code],
mem_limit="256m",          # 内存限制
cpu_period=100000,
cpu_quota=50000,           # CPU 限制:50%
network_mode="none",       # 禁用网络访问
read_only=True,            # 只读文件系统
remove=True,               # 运行后自动删除
timeout=timeout
)
return [types.TextContent(type="text", text=container.decode())]
except docker.errors.ContainerError as e:
return [types.TextContent(type="text", text=f"错误:{e.stderr.decode()}")]

Docker 沙箱的关键安全参数:

参数 说明
network_mode "none" 禁止网络访问,防止数据外泄
mem_limit "256m" 防止内存耗尽攻击
read_only True 防止修改容器内文件系统
remove True 运行后自动删除,不留痕迹
timeout 30-60 防止无限循环

方案三:使用现成的 Code Execution MCP

如果不想自己实现沙箱,几个现成方案可以直接使用:

# E2B Code Interpreter MCP(推荐,云端沙箱)
npm install -g @e2b/mcp-server
# 配置(需要 E2B API key)
{
"mcpServers": {
"e2b": {
"command": "npx",
"args": ["-y", "@e2b/mcp-server"],
"env": {
"E2B_API_KEY": "your-e2b-key"
}
}
}
}

E2B 在云端运行代码,本地没有任何副作用,适合需要 AI 执行复杂数据分析的场景。

各方案对比

方案 隔离性 灵活性 复杂度 成本
白名单命令 ⭐⭐⭐ 免费
Docker 沙箱 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ 免费
E2B 云沙箱 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 付费
原生 shell MCP ⭐⭐⭐⭐⭐ 免费

本节执行清单


下一节:本地数据处理工作流实战