jumpserver-ssh-mcp
jumpserver-ssh-mcp 是一个 MCP Server,用来让 Agent 通过直连 SSH 或 JumpServer 入口安全地执行远程命令。
产品方向是 MCP only:
gateway表示一个 JumpServer / 环境入口。- 入口匹配插件负责适配不同 JumpServer 交互界面。
- 到达目标机器 shell 后,继续复用现有 SSH 执行、安全检查、审计和输出收集机制。
- 不新增 CLI 产品工作流;仓库里保留的 CLI 只用于兼容和本地 smoke check。
当前状态
这个项目原来是 ssh-assist-mcp 原型,已经具备:
ssh.run_commandssh.run_scriptssh.rsync_uploadssh.rsync_downloadssh.file_push(文件上传工具;gateway 有有效映射时优先使用 Koko SFTP)ssh.file_pull(文件下载工具;gateway 有有效映射时优先使用 Koko SFTP)ssh.job_startssh.job_statusssh.job_logssh.job_cancelssh.job_list- 基础安全策略和审计日志
- 基础 JumpServer 交互式 gateway 执行
现在要产品化的是 JumpServer 入口层:
- matcher plugin 契约和 registry
- 内置通用 JumpServer matcher
- 用户自写声明式 matcher
- 多 JumpServer / 多环境 gateway 自由切换
- MCP resources 暴露 matcher 编写文档、示例、schema、排障说明
- README 和
docs/install/*提供 Codex、Kimi CLI、opencode 安装入口
安装入口
安装文档是普通仓库文件,所以 MCP 还没装好之前也能看:
推荐顺序:
- 先按 任意 Agent 安装 MCP 把
jumpserver-ssh-mcp接入 Agent 客户端。 - 再让 Agent 安装或读取
skills/jumpserver-agent-skill。 - Agent 按 skill 创建 profile、配置 gateway、probe、smoke test,必要时编写 matcher。
MCP 安装完成后,Agent 可以再通过 MCP resources 读取运行时文档,例如 matcher 编写指南、示例、schema 和 troubleshooting。
Agent 自主安装
可以直接把下面这段任务交给 Codex 或其他具备本地文件和终端权限的 Agent:
从
https://github.com/Shadow-linux/jumpserver_ssh_mcp.git获取或更新项目,先阅读skills/jumpserver-agent-skill/SKILL.md和references/install-and-upgrade.md。由你负责创建 venv、安装 MCP、把完整 Skill 同步到当前 Agent 的技能目录、备份并更新 MCP 客户端配置、创建用户目录下的 profile,然后重启或提示我重启客户端。不要覆盖已有运行期配置,不要读取或复制私钥内容。安装后确认 matcher、命令、文件传输工具以及五个ssh.job_*工具完整可见,再执行无害 probe 和 smoke test。
Codex 的 Skill 安装位置是:
~/.codex/skills/jumpserver-agent-skill
仓库内入口是 skills/jumpserver-agent-skill/SKILL.md。用户通常只需提供 gateway 名称、JumpServer SSH 登录命令和一个验证目标;安装路径、MCP 配置、profile、Skill 同步与验证由 Agent 负责。五个 ssh.job_* 必须同时出现,部分缺失表示 MCP 进程或客户端工具 schema 尚未更新。
快速初始化
从源码安装时,先把项目拉到一个稳定目录:
git clone <repo-url> jumpserver_ssh_mcp
cd jumpserver_ssh_mcp
创建虚拟环境并安装 MCP server:
uv venv
uv pip install -e '.[mcp]'
确认启动命令存在:
.venv/bin/jumpserver-ssh-mcp
准备本机 profile。运行期文件统一放在用户目录,避免更新源码仓库时覆盖本机配置:
mkdir -p ~/jumpserver-ssh-mcp/{config,logs,matchers}
cp config/example.yaml ~/jumpserver-ssh-mcp/config/local.yaml
配置文件说明:
config/example.yaml:推荐起步样例,只包含人类需要维护的最小字段。config/full-example.yaml:完整参考样例,给 Agent 或高级用户查看所有可选字段。~/jumpserver-ssh-mcp/config/local.yaml:本机真实配置,不放在源码仓库里。
然后把 ~/jumpserver-ssh-mcp/config/local.yaml 改成真实 JumpServer:
gateways:
pro-jumpserver:
command: ssh -i ~/.ssh/pro.pem ops@jump.example.com -p2222
matcher: builtin-generic
在任意支持 MCP 的 Agent 客户端里配置:
server name: jumpserver-ssh-mcp
command: /path/to/jumpserver_ssh_mcp/.venv/bin/jumpserver-ssh-mcp
env.SSH_ASSIST_PROFILE: /Users/you/jumpserver-ssh-mcp/config/local.yaml
env.SSH_ASSIST_AUDIT_LOG: /Users/you/jumpserver-ssh-mcp/logs/jumpserver-ssh-mcp-audit.jsonl
配置后重启或 reload Agent 客户端,然后验证:
ssh.matcher_list
能看到 profile 里的 gateway,就说明 MCP 初始化完成。
从 v0.1.0 升级
0.2.1 起推荐把运行期文件放到 ~/jumpserver-ssh-mcp/。如果旧版本已经在 MCP 客户端里显式配置了 SSH_ASSIST_PROFILE,升级后会继续优先使用这个路径。
如果旧配置还在源码仓库里,可以迁移一份:
mkdir -p ~/jumpserver-ssh-mcp/{config,logs,matchers}
cp config/local.yaml ~/jumpserver-ssh-mcp/config/local.yaml
为了兼容旧安装,无显式 SSH_ASSIST_PROFILE 时会按顺序查找:
~/jumpserver-ssh-mcp/config/local.yamlconfig/local.yamlconfig/example.yaml
Gateway 是环境入口
调用 MCP 工具时用 gateway 选择要进入哪个 JumpServer / 环境:
gateway=prod-jumpserver -> 生产 JumpServer / 环境
gateway=test-jumpserver -> 测试 JumpServer / 环境
gateway=ops-jumpserver -> 运维 JumpServer / 环境
建议运维类调用都显式传 gateway,这样审计日志能清楚记录 Agent 进入了哪个环境入口。
Agent 会话归属与残留清理
通过 JumpServer gateway 执行命令时,Agent 可以给 SSH 工具传 owner_id,例如 codex-thread-<id>。
owner_id 用来把本次 gateway SSH 子进程登记到本地运行目录:
~/jumpserver-ssh-mcp/run/sessions/<owner_id>/
下一次同一个 owner_id 启动 gateway SSH 前,MCP 会先清理该 owner 下已超过 grace 时间的残留 child 进程。不同 owner 的记录不会被清理,因此不会误杀其他 Agent 或人工打开的 SSH。
建议:
- 每个 Agent 线程或任务使用稳定且唯一的
owner_id。 - 不要复用其他 Agent 的
owner_id。 - 正常结束、超时、
SIGINT、SIGTERM、进程退出时,MCP 也会清理自己登记过的 gateway child。 kill -9或系统崩溃无法触发进程内清理;下次同 owner 调用会尝试清理残留。
Matcher 插件放在哪里
内置通用 matcher 和 reference matcher 会随 Python 包一起分发,安装后默认可用:
builtin-genericttyuyin-opt-accountqmzy-asset-list-id
用户自写 matcher 推荐放在用户运行目录:
- 用户运行目录:
~/jumpserver-ssh-mcp/matchers/
然后在 profile 中配置:
matchers:
custom_dirs:
- ~/jumpserver-ssh-mcp/matchers
每个 gateway 可以绑定自己的 matcher:
default_gateway: jumpserver-test
gateways:
jumpserver-test:
command: ssh -i ~/.ssh/jumpserver-test.pem ops@jump-test.example.com -p2222
matcher: builtin-generic
Matcher 能做什么
Matcher 只负责 JumpServer 登录入口匹配,不能执行目标机器命令。
它可以返回这些动作:
- 发送目标 host/IP
- 从主机候选列表中选择目标
- 从账号表中选择账号
- 报告已经到达 shell
- 报告未匹配,并返回脱敏 transcript 片段给 Agent 修插件
远程命令仍由 ssh.run_command / ssh.run_script 统一执行。文件传输优先使用 ssh.file_push / ssh.file_pull;ssh.rsync_upload / ssh.rsync_download 只适合 direct SSH + rsync 场景。
MCP Tools
已有 SSH tools:
ssh.run_commandssh.run_scriptssh.rsync_uploadssh.rsync_downloadssh.file_pushssh.file_pull
文件传输:
Agent 始终调用 ssh.file_push 和 ssh.file_pull。Koko SFTP 是这两个 MCP tool 内部自动选择的 优先 transport,不额外暴露 ssh.sftp_upload 或 ssh.sftp_download;未配置有效 SFTP 映射时 自动使用 Base64 portable 路径。
ssh.file_push:单文件上传,支持 direct SSH 和 JumpServer gateway,不依赖远端 rsync。
gateway 配置了 sftp_command、sftp_asset_path_by_host 和 sftp_remote_root 时优先使用 JumpServer Koko 虚拟 SFTP 单次传输;数据先写入目标目录内的随机临时文件,远端 SHA256 校验成功后再原子替换最终文件,失败时尽力清理临时文件。该路径复用 JumpServer SSH/SFTP 端口,不要求目标机新增监听端口。未配置或目标路径不在映射根目录下时自动回退到便携的 base64 分块传输。gateway Base64 会把单次 PTY 原始载荷限制在 128KiB,使用 UUID 中间 文件,并在校验成功后原子替换;普通失败、超时或可捕获的进程中断时会尽力清理中间文件。 Koko SFTP 不设应用层文件大小上限;Base64/direct portable 路径默认上限 50MB。
ssh.file_pull:单文件下载,支持 direct SSH 和 JumpServer gateway,不依赖远端 rsync。
有有效 Koko 映射时优先 SFTP,下载到本地同目录 UUID 临时文件,校验远端大小和 SHA256 后 原子替换;SFTP 不设应用层大小上限,Base64/direct portable 路径默认上限 50MB。
ssh.rsync_upload/ssh.rsync_download:保留给 direct SSH 的大文件或目录同步;交互式 JumpServer gateway 不支持 rsync 协议流。
Matcher tools:
ssh.matcher_listssh.matcher_validatessh.matcher_probessh.matcher_test_transcript
ssh.matcher_probe 只验证 matcher 能否通过 JumpServer 到达目标 shell,不执行目标机器命令。
后台 Job tools:
ssh.job_start:提交一个受管理的后台命令,返回稳定job_id;默认和最大运行时间为两小时。ssh.job_status:通过精确 ID 刷新远端状态;无法确认时返回unknown,不会猜测成功或失败。ssh.job_log:读取有界输出,默认 80 行、单次最多 64 KiB;远端逻辑输出最多保留 5 MiB。ssh.job_cancel:需要confirmed=true,只取消该 Job 的精确 systemd cgroup 或已验证进程组。ssh.job_list:只查询本地 SQLite 索引,不打开 SSH;可按 owner、host、state 筛选。
Job 索引位于 ~/jumpserver-ssh-mcp/jobs/jobs.sqlite3。每个 owner_id 最多 10 个活跃 Job,每个目标 host/account 最多 30 个。终态保留两小时后由后续 Job 操作按精确 ID 惰性清理;submitting、running 和 unknown 不会仅因时间经过而删除。
远端只有在 systemd --user 已启用 linger、能够跨 SSH 会话存活时才使用 transient service;否则自动回退到受管理的 python3 + setsid supervisor。两种能力都不满足时返回 unsupported_runner。
下载、构建、安装等长任务优先使用 job_start,由 Agent 用 job_status 和按需 job_log 轮询。不要在 job_start 回执不明确时重复提交相同命令,应保留 job_id 并继续对账。
安全与审计
远程命令会经过 SafetyPolicy 评估。
高风险操作必须显式确认。审计日志基础路径默认是 ~/jumpserver-ssh-mcp/logs/jumpserver-ssh-mcp-audit.jsonl,也可以通过 SSH_ASSIST_AUDIT_LOG 指定;实际写入时会按 UTC 日期滚动为 ~/jumpserver-ssh-mcp/logs/jumpserver-ssh-mcp-audit-YYYY-MM-DD.jsonl。
不要把私钥内容、明文密码、token 写进 profile、matcher、文档或审计日志。
开发验证
运行单元测试:
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests -p 'test_*.py'
运行 MCP server:
SSH_ASSIST_PROFILE=config/example.yaml .venv/bin/jumpserver-ssh-mcp
旧原型入口 ssh-assist-mcp 暂时保留为兼容别名。
构建 wheel:
uv build --wheel










