MCP持久外壳服务器
模型上下文协议(MCP)服务器提供 持久shell访问 通过 可流式传输的HTTP 运输。专为LLM代理设计,用于通过有状态的shell会话执行代理工作流。
特性
- 持久Shell会话:跨请求维护单个交互式shell进程
- 状态保存(cwd、env-vars、virtualenv激活) - 命令基于以前的状态构建 - 电流限制:所有MCP客户端共享单个全局shell
- MCP流式HTTP传输:与OpenWebUI外部工具兼容
- 基于HTTP/SSE的JSON-RPC - MCP会话管理 Mcp-Session-Id 头球 - 已禁用Docker/网络访问的DNS重新绑定保护
- 安全:可配置验证(选择加入,默认禁用)
- 命令分配列表/块列表 - 执行超时和输出限制 - Docker中的非root执行
- 文件传输:将文件上传到工作区/从工作区下载文件
- 支持Base64和UTF-8编码
- 工作空间持久性:文件无限期保存
- 未自动清理(用户/代理管理清理) - 通过卷装载在容器重启过程中保持不变
快速开始
Docker(推荐)
cd /opt/gen-ai/ai-assistant-shell/mcp-persistent-shell
# Build and run
docker-compose up -d
# Check health
curl http://localhost:3000/health
# View logs
docker-compose logs -f裸机
# Install dependencies
pip install -r requirements.txt
# Run server (binds to 127.0.0.1:3000 by default)
python -m mcp_persistent_shell
# Or with custom config
MCP_SHELL_CONFIG_FILE=config/security.yaml python -m mcp_persistent_shellMCP工具
1. execute_command
在持久shell会话中执行命令。
{
"name": "execute_command",
"arguments": {
"command": "ls -la",
"timeout": 30
}
}答复:
{
"status": "success",
"exit_code": 0,
"stdout": "total 8\ndrwxrwxrwx ...",
"stderr": "",
"command": "ls -la",
"execution_time": 0.05
}2. get_working_directory
获取当前工作目录。
{
"name": "get_working_directory",
"arguments": {}
}答复:
{
"cwd": "/workspace"
}3. reset_session
将shell重置为干净状态(杀死并重新启动shell进程)。
{
"name": "reset_session",
"arguments": {}
}4. upload_file
将文件上传到工作区。
{
"name": "upload_file",
"arguments": {
"path": "script.py",
"content": "cHJpbnQoJ0hlbGxvJyk=",
"encoding": "base64"
}
}5. download_file
从工作区下载文件。
{
"name": "download_file",
"arguments": {
"path": "output.txt",
"encoding": "base64"
}
}OpenWebUI集成
在OpenWebUI中配置 管理面板→ 设置→ 外部工具:
{
"name": "Persistent Shell",
"url": "http://:3000/mcp",
"type": "mcp",
"auth_type": "none"
}重要:
- 集
auth_type到"none"(非“持票人”或空白) - 如果OpenWebUI位于其他计算机上,请使用服务器的IP地址
- 端口3000必须可以从OpenWebUI访问
配置
环境变量
使用 __ (双下划线)用于嵌套配置:
# Server (nested under 'server')
MCP_SHELL_SERVER__HOST=127.0.0.1
MCP_SHELL_SERVER__PORT=3000
# Logging (nested under 'logging')
MCP_SHELL_LOGGING__LEVEL=info
MCP_SHELL_LOGGING__FORMAT=json
# Session (nested under 'session')
MCP_SHELL_SESSION__TIMEOUT=3600
MCP_SHELL_SESSION__MAX_SESSIONS=100
MCP_SHELL_SESSION__CLEANUP_INTERVAL=300
# Shell (nested under 'shell')
MCP_SHELL_SHELL__DEFAULT_SHELL=/bin/bash
# Security (optional: path to YAML config file)
MCP_SHELL_CONFIG_FILE=config/security.yaml看 .env.example 查看完整列表。
安全配置(YAML)
通过挂载配置文件启用安全性:
config/security.yaml:
security:
enabled: true
allowed_executables: [ls, pwd, git, python3, node, npm, curl, wget]
blocked_patterns:
- 'rm\s+.*-rf.*'
- 'sudo\s+.*'
- 'chmod\s+(777|666)'
max_execution_time: 30
max_output_size: 1048576 # 1MB
working_directory: /workspace在docker-compose.yml中启用:
environment:
MCP_SHELL_CONFIG_FILE: "/etc/mcp-persistent-shell/security.yaml"
volumes:
- ./config/security.yaml:/etc/mcp-persistent-shell/security.yaml:ro安全注意事项
⚠️ 默认:安全是 禁用 默认情况下,为了便于开发。
生产部署检查表:
- ✅ 安装
config/security.yaml随着enabled: true - ✅ 使用命令
allowed_executables允许名单 - ✅ 绑定到
127.0.0.1或使用防火墙规则 - ✅ 以非root用户身份在Docker中运行(UID 1000)
- ✅ 设置适当
max_execution_time和max_output_size - ✅ 监控审核日志(
audit_log: true)
网络安全:
- DNS重新绑定保护 残疾的 允许Docker/网络访问
- 仅暴露于受信任的网络
- 考虑添加身份验证层(带身份验证的反向代理)
工作空间持久性
- 文件在
/workspace是 永久的 -未自动删除 - 会话清理仅终止shell进程,不终止文件
- Docker卷挂载:
./workspace:/workspace - 负责通过命令进行清理的代理/用户
API终点
- POST/mcp -MCP JSON-RPC请求(初始化、工具调用)
- GET/mcp -服务器通知的SSE流
- GET/健康 -健康检查
{
"status": "healthy",
"version": "0.1.0",
"shell_alive": true,
"security_enabled": false
}建筑
FastAPI Server (Streamable HTTP)
├── FastMCP (handles MCP protocol)
│ └── Streamable HTTP session manager
├── Global Shell Process (shared across all clients)
│ └── pexpect PTY wrapper (bash)
├── Security Validator (optional)
└── MCP Tool Handlers
├── execute_command
├── get_working_directory
├── reset_session
├── upload_file
└── download_file当前架构说明:
- 所有MCP客户端共享单个全局shell会话
- MCP管理自己的会话ID以进行协议处理
- 未来增强:映射MCP会话→ 单个外壳工艺
发展
# Install dev dependencies
pip install -r requirements-dev.txt
# Run tests (when implemented)
pytest
# Format code
black src tests
ruff check src tests
# Type checking
mypy src故障排除
OpenWebUI显示空命令输出
- 检查服务器日志:
docker logs mcp-persistent-shell -f - 验证auth_type是否设置为
"none"在 OpenWebUI - 确保Accept标头包含这两个
application/json和text/event-stream
连接被拒绝/超时
- 检查服务器是否正在运行:
docker ps | grep mcp-persistent-shell - 验证端口是否可访问:
curl http://localhost:3000/health - 如果OpenWebUI位于不同的计算机上,请确保端口3000已打开
命令执行以静默方式失败
- 检查安全是否被阻止:在日志中查找“安全验证失败”
- 先尝试禁用安全性,然后逐渐启用
- 验证shell是否处于活动状态:检查
/health端点shell_alive领域
已知限制
- 单一全球壳牌:所有MCP客户端共享一个shell会话
- 状态更改会影响所有用户 - 在为多用户场景部署时考虑这一点
- 无会话隔离:未来将增强对每个客户端shell的支持
- 仅限Bash:目前仅支持bash(可通过配置
SHELL__DEFAULT_SHELL)
未来的增强功能
- \[\]每个MCP会话外壳隔离
- \[\]多种shell类型(zsh、python REPL等)
- \[\]资源限制(内存、CPU通过cgroups)
- \[\]身份验证/授权
- \[\]Redis支持的会话存储,用于横向扩展
许可证
GNU Affero通用公共许可证v3.0(AGPL-3.0)
