
Sshboard
io.github.meta-taro由 GitHub 账号 meta-taro 发布v0.1.39更新于 Nov 6, 2026
An AI agent reads your server over the one SSH session you are already watching.
概览
一款桌面 SSH 应用,内置 MCP 服务器,让 AI 代理在你正注视的同一条 SSH 会话上读取服务器。
- 可以做什么
- 列出连接、浏览目录、查看文件属性与读取文件、搜索、下载,并查看磁盘占用
- 查看进程、服务状态、运行时版本、日志以及正在监听的网络端口
- 仅按人工写入白名单中的 id 执行只读命令,被拒绝的调用会记录在案
- 运行或提议由固定判定条件组成的健康检查,结果会显示在界面上
- 仅按人工写入的清单执行变更操作,每次都需要屏幕前的人批准,并受每小时上限约束
- 适用场景
- 适合维护 VPS 或共享主机的场景:希望代理自己查看配置、日志和服务,而不是由你反复粘贴服务器状态。适用于线上服务器的故障排查和只读调查,写操作则被限制在人工明确写好的白名单之后。
- 运行要求
- 需要 macOS 或 Windows 桌面应用(Linux 不是发布目标);MCP 服务器内置于应用中,不是独立软件包。从源码构建需要 Rust 1.98.0、Node 20 或更高版本以及 pnpm;Docker 仅用于本地测试服务器。代理可通过应用的代理以 stdio 连接,或通过 22022 端口的 HTTP 并携带 Authorization Bearer 令牌连接。SSH 密钥建议放在 ssh-agent 中。
安装
在 SourceWeft 中
- 打开 控制台中的 Sshboard,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
sshboard
English / 日本語
Your AI agent and you, looking at the same server, on the same screen, over one SSH connection.
You keep your own SFTP client and your own terminal. The agent works beside you — inside a fence you drew — and every single thing it does scrolls past in your window while it happens.
[The connection list, with a connection being edited]
⚠️ This is alpha. It is in use on production servers (investigating a failed certificate renewal, restarting pm2, and so on). Installers are published for Windows (x64 / ARM64) and macOS. Passing tests does not mean it works as a tool — we shipped a build whose terminal displayed not one byte for three days (Issue #10).
⬇ Download · Direction · Every decision, with its reasoning
When you would reach for this
"Renew the certificates on three hosts, today"
You have a terminal open per host and you are copying the same command into each, watching for the one that fails. sshboard opens one console per connection — or two on the same host, side by side — and the agent can read all of them while you work. Not "the agent runs it for you": the agent watches what you are doing and tells you which pane went wrong.
[One shared console; the tabs along the top are the open connections]
"Mail stopped arriving and I don't know where to look"
You ask the agent. It reads /etc/postfix/main.cf, checks the service, tails the log —
over the same SSH session you are already on, and you see each step as it happens.
It cannot run an arbitrary command to do it: there is no run_command(cmd) tool.
"I want help, but not an agent loose on my server"
The agent may write only inside directories you listed, one connection at a time. The list starts empty, so it cannot write a single byte until you say where. Delete, rename, move, chmod, restart, package installs, sudo — none of them exist for the agent. You are not restricted anywhere.
[The two-pane file browser; the agent's writable directory is shown at the top]
Try it in five minutes
Install the app, then point your agent at it. There is nothing else to run — the MCP server lives inside the app.
Register 127.0.0.1:2222, user probe, connect, then press Copy the MCP command in
the window's title bar and paste it into your agent:
Prebuilt installers are on the releases page (Windows x64 / ARM64, macOS Apple Silicon). They are not code-signed, so SmartScreen and Gatekeeper will both stop you the first time.
What you see while the agent works
Every operation, yours and the agent's, lands in one band. You do not have to ask what it did.
[The activity band: one line per operation, with [AI] marking the agent's]
When something fails, the same log the agent reads over MCP is on your screen — which stage it reached, why it stopped, and what to do next. It carries no hostnames, no usernames and no secrets.
Why this exists
There are services still running on ordinary shared hosting and VPSes. Maintain one of those with an AI agent and this happens every single time:
This tool exists to delete that round trip. The agent does not need to operate your server. Letting it see is enough.
How you actually use it
This is not a tool you drive by clicking buttons. You talk to an AI agent in your terminal, and the agent calls sshboard's built-in MCP server.
You are not restricted. The two-pane file browser and the terminal tab work like any other SFTP client and terminal. Only the agent's side is fenced.
What the agent may call (Phase 1 — reading)
list_connections / list_directory / stat / read_file / search / download /
disk_usage / process_list / service_status / runtime_versions / read_log /
network_listen / run_readonly (allowlist) / list_checks / run_check / propose_check (health checks)
There is no run_command(cmd). One such tool does everything, and once you have it
the only thing standing between an agent and a destructive command is a promise not to
use it. A promise is a runbook, not a gate.
With run_readonly the agent may pass only an id that a person wrote into
readonly.toml. There is no argument slot. The list ships empty — until you write
it, nothing runs at all. Refusals show up in the window's activity band and are
recorded in readonly-refused.log. Adding entries is a person's job.
The one success criterion
The agent stops saying "please tell me the state of the server."
Not downloads, not stars. Whether the round trip disappeared during real maintenance.
It will not modernise your setup
- This is not a tool for migrating your server somewhere else
- Working with the setup you already have is the point
- These services will still be here in ten years. Nothing exists today that brings AI development to them
Shape
We do not keep two SFTP implementations, and we never open an SSH session you cannot see. Being invisible is the single biggest danger here.
Whoever touched what flows into the same band. Different surfaces, one record.
Phase 1 is read-only
No writes at all. Every intended use — incident triage, mail-config investigation, writing up a proposal — is reading. That makes the risk close to zero, which means you can point it at a live production server on day one.
There is no run_command(cmd)
Put one arbitrary-command tool in place and it can do everything. That is exactly why it does not exist.
- Hand it over and the only remaining defence against a destructive command is a promise
- A promise is a runbook, not a gate
- With an allowlist, dangerous commands are not expressible
What readonly.toml looks like (a person writes it)
The product ships with zero entries. Nobody has the list of what real maintenance
needs, and filling it in by guesswork gets it wrong. Refused calls pile up in
readonly-refused.log — read that, and add only what was genuinely needed.
What this cannot verify: whether the run you wrote is truly read-only. The
product cannot know. No machine can tell uptime from rm -rf / by inspection. What
this prevents is exactly one thing: the agent composing a command string.
The human side (the GUI) is not restricted. Use it as an ordinary SFTP client and terminal. Only the agent's side is fenced.
Health checks (checks.toml)
Group the things you look at in the same order every time — disk, memory, a service, a
listening port — into one check. Write it once; a person runs it from the menu (Checks →
Run) and an agent runs the same check with run_check.
- A step only names an id from
readonly.toml. There is no field for a command line - Criteria come in fixed shapes only: text present (
contains) / absent (absent), a numberbelow/abovea limit - Each step comes back good, bad or unknown. Something that could not be measured is never counted as good
- The run does not stop at the first bad step, and the previous value sits beside the new one (until the app quits)
- Every step shows on the band before it runs. Checks the agent runs appear in the Checks dialog too
- The list ships empty. A person writes it; the agent cannot
- The agent can propose a check with
propose_check. Every step and criterion appears on screen, and only the person can save it (saving runs nothing)
A template lives in docs/checks.example.toml.
State-changing operations (operations.toml)
The list ships empty. Until you write this file, the agent can run nothing.
This is a separate file from the read allowlist (readonly.toml), so that write
operations never live in a file called readonly. Telling them apart by name is the
point. Put it next to connections.toml.
Gates it passes through before running
- It is in the list a person wrote. Unknown ids are refused, and the refusal is recorded
- It is under the hourly ceiling
- A person approves it on screen. The agent's first call is always refused, and the window shows what would actually run
- An approval is spent once. One approval, one run
- An approval expires after five minutes. People press allow and the agent never
calls back (the conversation moves on). We do not leave approvals lying around —
with
become = "ask", the password is dropped here too
A person at the screen does not pass 3–5. They are looking at it.
The one exception is the become = "ask" password — that is not approval, it is a
credential, and the product cannot invent it.
Refused even if you write it down
No setting enables these. They are rejected even when present in operations.toml.
- The cage itself —
sudoers/visudo/authorized_keys - Keys —
.ssh/id_rsa/id_ed25519/id_ecdsa - Where passwords live —
/etc/shadow//etc/gshadow - sshboard's own config —
connections.toml/readonly.toml/operations.toml/checks.toml - Users and roles —
useradd/usermod/userdel/groupadd - Destruction —
mkfs/fdisk/dd/rm -rf
The agent cannot widen its own cage. That is what this list is for.
Operations that need root (become)
operations.toml decides which commands may run. How privilege is obtained is
written per connection (connections.toml).
Only a run that starts with sudo is touched. Everything else is left byte for
byte. Choosing ask does not make non-sudo operations ask for a password.
sudoers (recommended)
This is a gate the OS enforces, not a promise the app makes. The scope is written in
sudoers, so a person can audit it afterwards, and sshboard gains no secret.
Check that it works:
If the second one succeeds, your scope is too wide.
ask (when you cannot touch sudoers)
Not being able to touch the server is a real situation — rented, no rights, too many
machines. On a server where sudo -n answers "a password is required", the sudoers
route was never open. That is what ask is for.
A password field appears on the approval dialog and a person types it there.
- Never stored. Not on disk, not in the OS credential store
- Never on the command line. It goes in over stdin, so it does not show up in
ps - Never on screen and never in the log. What appears is
$ sudo -S -p '' …and no more - One approval, one run. Dropped the instant it is used
- Refuse, and it is dropped there and then
Reading a log only root can read works the same way:
This does not apply to the read allowlist (readonly.toml). If it did, every read
would ask for a password. Reads that need root belong in operations.toml.
Becoming root first with su is not recommended — the scope disappears. On servers
that only have su -, use the console: the person types su -, presses [Hand to the AI],
the agent carries on in the same shell, and hands it back with console_release without
closing it. The person can always take it back.
What the product cannot guarantee
Whether an operation really does only what it says, the product cannot verify. What
runs is a string a person wrote. As with readonly.toml, that is the part a person
has to read and confirm. Which is why sudoers makes the OS enforce it.
There is no way to deliver an approval to someone who is away from the screen yet
(.claude/decisions.md D47 — undecided). Today only a person at the screen can
answer. With nobody there, the operation does not run.
What this will not do
Running it
This is still alpha. Before pointing it at a production server, run it once against the local test server.
Requirements
Keeping your key in ssh-agent is recommended. Then sshboard never receives a passphrase at all.
Start
Tests
Local test server
It does not touch your servers at all. It creates a throwaway key and brings up one machine in Docker.
Connecting an agent (MCP)
Recommended — the token is never written anywhere
--scope user registers it for every folder. Without it, Claude Code keeps it only for the folder
you typed the command in — open Claude Code anywhere else and sshboard does not even appear in /mcp.
This way the token is left nowhere (Issue #2). Started with --mcp-stdio-proxy,
sshboard runs as a relay with no window. It reads the token itself and passes it to
the running app.
- The token appears neither in
~/.claude.jsonnor in your shell history - Move the port (
SSHBOARD_MCP_PORT) and you do not have to re-register - If the app is not running you get: "sshboard is not running. Start the app and try again."
Only the app opens SSH connections. The relay holds no engine and no band. It adds not one invisible SSH session (prohibition 3).
Straight over HTTP
The "Copy the MCP registration command" button at the top right of the window copies a single line, token included.
--transport http is required. The path is /mcp and the token goes in
Authorization: Bearer.
The port is fixed at 22022 (D33), and the token is reused, so you register once.
Restarting keeps the same URL.
⚠️
claude mcp addleaves the token in~/.claude.jsonin plain text. It is a loopback handle rather than a key, but whoever holds it can read the servers you are connected to. Rememberclaude mcp remove sshboardwhen you are done.
.mcp.json works too (also plain text on disk):
If the port is taken, it does not quietly move somewhere else. The window says "failed to start (port 22022)". Set
SSHBOARD_MCP_PORTto move it.
Wake the agent when the person answers (Claude Code channels)
When the person answers a passphrase, host key, console permission or operation approval on screen, sshboard pushes that fact to the agent's session. Even if the agent ended its turn instead of waiting, it wakes up and carries on — nobody has to tell it "I pressed it".
This uses Claude Code's channels (a research preview). Start Claude Code with:
Started without it, Claude Code silently drops the notice (await_answer still works as before).
The notice says only which kind of question was answered — never where the connection points.
In Team / Enterprise organisations an admin has to enable channels first.
Updates
When a new version exists, the window tells you at startup (D34).
It never replaces itself quietly. Downloading, installing and restarting are all things a person presses. This tool handles SSH keys, so it does not rewrite itself without being asked.
The update itself is signed with minisign, and Tauri always verifies it. That is separate from code signing (D12 — whether the OS shows a warning); what is guaranteed here is that the update came from us.
Things to know during alpha
- It is not code-signed. Whether Windows stops you depends on how you fetched it
(Issue #3, measured):
- Downloaded in a browser, double-clicked → SmartScreen stops you
gh run download/ CI / a script → it does not. No Mark of the Web, so SmartScreen's reputation check has nothing to trigger on- macOS Gatekeeper is untested
- The agent may write only under directories a person listed for that connection. The list is empty by default — not one byte
- The
run_readonlyallowlist is empty by default too. Nothing runs until a person writesreadonly.toml. The purpose-built tools (disk_usageand friends) work without it - The terminal is shared between you and the agent. While the agent holds it your input is locked out, and [Stop] always works
- Installers are attached to each Release (D32).
Windows gets
.msiand an NSIS-setup.exe, macOS gets a.dmg. They are unsigned, so Windows shows SmartScreen and macOS shows Gatekeeper. If a warning stopped you and you did not know what to do, please open an issue — that is what decides whether we buy a certificate (D12)
Stack
Licence
MIT
Development rules
This repository follows a baseline set of rules for AI-agent development. See
.claude/rules/product-baseline.md and
CLAUDE.md.
- The AI commits, a human pushes (no pushing without human review)
- Tests are never deferred and never deleted
- This is a public repository. No server hostnames, IPs, usernames, personal names or personal email addresses in code, docs, commit history or screenshots
来源:README.md,提交 d235d8b
工具
0版本历史
12- v0.1.39最新Nov 6, 2026
- v0.1.37Nov 5, 2026
- v0.1.36Nov 5, 2026
- v0.1.35Nov 3, 2026
- v0.1.34Oct 29, 2026
- v0.1.33Oct 26, 2026
- v0.1.32Oct 26, 2026
- v0.1.30Oct 26, 2026
- v0.1.29Oct 25, 2026
- v0.1.27Oct 24, 2026
- v0.1.25Oct 23, 2026
- v0.1.24Oct 13, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分