持久化Shell服务器

一个通过流式HTTP传输提供持久化Shell访问的MCP服务器,专为LLM代理设计,用于执行有状态的Shell会话工作流程。

  • by manikmakki
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 manikmakki/mcp-persistent-shell

使用说明

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_shell

MCP工具

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://<your-server-ip>: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

安全注意事项

⚠️ 默认:安全是 禁用 默认情况下,为了便于开发。

生产部署检查表:

  1. ✅ 安装 config/security.yaml 随着 enabled: true
  2. ✅ 使用命令 allowed_executables 允许名单
  3. ✅ 绑定到 127.0.0.1 或使用防火墙规则
  4. ✅ 以非root用户身份在Docker中运行(UID 1000)
  5. ✅ 设置适当 max_execution_time 和 max_output_size
  6. ✅ 监控审核日志(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 领域

已知限制

  1. 单一全球壳牌:所有MCP客户端共享一个shell会话

    • 状态更改会影响所有用户
    • 在为多用户场景部署时考虑这一点
  2. 无会话隔离:未来将增强对每个客户端shell的支持

  3. 仅限Bash:目前仅支持bash(可通过配置 SHELL__DEFAULT_SHELL)

未来的增强功能

  • []每个MCP会话外壳隔离
  • []多种shell类型(zsh、python REPL等)
  • []资源限制(内存、CPU通过cgroups)
  • []身份验证/授权
  • []Redis支持的会话存储,用于横向扩展

许可证

GNU Affero通用公共许可证v3.0(AGPL-3.0)

参考文献