内容
<p align="center">
<img src="assets/logo.png" alt="SnapStack" width="440">
</p>
<p align="center">
<a href="https://github.com/bgaze/snapstack-server/actions/workflows/ci.yml"><img src="https://github.com/bgaze/snapstack-server/actions/workflows/ci.yml/badge.svg" alt="持续集成"></a>
<a href="LICENSE"><img src="https://img.shields.io/github/license/bgaze/snapstack-server?color=blue" alt="许可证:MIT"></a>
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node.js 版本 >= 18">
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-compatible-blueviolet" alt="MCP 兼容"></a>
<img src="https://img.shields.io/badge/100%25-local-success" alt="100% 本地运行">
<a href="https://www.npmjs.com/package/snapstack-server"><img src="https://img.shields.io/npm/v/snapstack-server?label=npm" alt="npm 版本"></a>
<a href="https://www.npmjs.com/package/snapstack-server"><img src="https://img.shields.io/npm/dm/snapstack-server?label=下载量" alt="npm 下载量"></a>
<a href="https://glama.ai/mcp/servers/bgaze/snapstack-server"><img src="https://glama.ai/mcp/servers/bgaze/snapstack-server/badges/score.svg" alt="Glama 评分"></a>
</p>
<p align="center">
<img src="assets/demo.gif" alt="SnapStack 示例 — 捕捉浏览器标签页,您的 AI 通过 MCP 读取截图" width="900">
</p>
**SnapStack 服务器**是一个始终在线的 Node.js 进程:它接收来自
[扩展程序](https://github.com/bgaze/snapstack-extension) 的浏览器截图,将它们堆叠在磁盘上,并通过 **可流式 HTTP** 提供给任何支持 MCP 的 LLM 客户端。它只监听 `127.0.0.1` — 任何内容都不会离开您的机器。
> **新用户?** 完整的安装和使用指南位于 **扩展程序 README** 中:
> **[snapstack-extension](https://github.com/bgaze/snapstack-extension)**。本页面是技术参考。
## 架构
一个始终在线的进程同时为扩展程序(截图)和 MCP 客户端服务,通过磁盘上的文件夹解耦。
```
[MV3 扩展程序] --POST /push (字节) ┐
▼
[SnapStack 服务器 - 127.0.0.1:4123]
├─ 写入 → 磁盘堆栈
└─ MCP /mcp (HTTP) ← MCP 客户端
```
- **截图** — 扩展程序将截图编码为 WebP(PNG 备用),缩小尺寸,并将其发布到此处。
- **堆栈** — 一个图像文件(`.webp`/`.png`)和一个双 `.json`(网址、标题、时间戳、尺寸)每个截图,
命名为 `NN <时间戳>`:一个稳定的两位 **数字** (按截图顺序分配,当堆栈
清空时重新启动为 `01`)和一个时间戳,位于 `~/.snapstack/` 下。
- **检索** — `get_screenshots` 返回一个 JSON **清单** (编号、绝对路径、尺寸、元数据 —
*无图像字节*);客户端只读取它需要的 文件,按路径。删除是一个单独的、明确的
`clear_screenshots` 步骤。**检索永远不会删除。**
## 要求
- **Node.js ≥ 18** (在 Node 20 上测试)。运行时不需要 git。
- 一个支持 **HTTP** (可流式 HTTP)或 **stdio** 传输的 **MCP 客户端**。
- 加载在您浏览器中的 **[snapstack-extension](https://github.com/bgaze/snapstack-extension)**。
## 安装和运行
> 在 Windows 上,**使用管理员终端**,否则全局 npm 安装和计划任务注册
> 可能会被拒绝。
服务器在 npm 上提供,安装在 macOS、Linux 和 Windows 上很简单:
1. 全局安装:`npm i -g snapstack-server`
2. 启用后台服务:`snapstack enable`
SnapStack 在登录时自动启动,在崩溃时重新启动,并在每次启动时更新自己。
要检查其状态或是否有更新可用,只需在终端中运行 `snapstack`。
可用命令:
```bash
snapstack # 状态报告:服务 + 服务器健康,更新检查
snapstack start | stop | restart # 控制正在运行的服务(此会话)
snapstack update # 更新 CLI(npm i -g)+ 在最新版本上重启服务器
snapstack run # 在前台运行守护进程(不自动启动)
```
**守护进程**在每次(重新)启动/登录时自我更新;**全局 CLI** (`snapstack` 命令)则不更新。
运行 `snapstack update` 以将 **两者** 升级到最新版本。
完整的端到端演练(惯用安装路径、MCP 客户端注册、扩展程序)位于
**[扩展程序 README](https://github.com/bgaze/snapstack-extension)** 中。
## MCP
SnapStack 通过同一个磁盘堆栈支持两种 MCP 传输方式 — 选择您的客户端支持的任意一种:
```jsonc
// HTTP(服务器已经运行)— 注册 http://127.0.0.1:4123/mcp;复制 deploy/mcp.json
{ "type": "http", "url": "http://127.0.0.1:4123/mcp" }
```
```jsonc
// stdio(客户端生成进程)
{ "command": "npx", "args": ["-y", "-p", "snapstack-server", "snapstack", "mcp"] }
```
HTTP `/mcp` 端点是 **无状态的** (每个请求都有一个新的服务器 + 传输);stdio 前端
(`snapstack mcp`)按需生成,并读取相同的 `~/.snapstack` 堆栈。
截图输入(`/push`)始终保留在正在运行的服务器中,与任一 MCP 前端无关。
### 暴露的工具
| 工具 | 描述 |
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `get_screenshots` | 以 JSON 清单列出待处理截图(稳定编号、绝对路径、尺寸、元数据)— **无图像字节,无删除**。传递 `numbers` (例如 `[1,3]`)以仅列出这些。 |
| `clear_screenshots` | 删除截图。传递 `numbers` 以删除特定的截图;省略以清除整个堆栈。编号在清空后重新启动为 `01`。 |
| `count_screenshots` | 截图数量,无需检索它们。 |
`get_screenshots` 和 `count_screenshots` 是 **只读** 的;只有 `clear_screenshots` 是 **破坏性** 的。
## 配置
### 环境变量(基础设施)
| 变量 | 默认值 | 目的 |
|------------------|----------------|-----------------------------------------|
| `SNAPSTACK_DIR` | `~/.snapstack` | 堆栈文件夹。 |
| `SNAPSTACK_PORT` | `4123` | 监听端口(始终在 `127.0.0.1` 上)。 |
### 截图策略(在您的浏览器中共享)
编码/截图设置由**服务器**拥有并存储在 `~/.snapstack/config.json` 中,因此单个
编辑适用于运行扩展程序的**每个浏览器**。它们从扩展程序的**选项页面**编辑 — 而不是
环境变量 — 并在每次截图前由扩展程序获取。
| 键 | 默认值 | 含义 |
|-------------|---------|---------------------------------------------------------------------------|
| `format` | `webp` | 图像格式:`webp`、`png` 或 `jpg`。 |
| `quality` | `0.85` | 有损质量(`0`–`1`;扩展程序 UI 显示为百分比)。 |
| `maxWidth` | `1568` | 缩小宽度超过此值的截图到此宽度(单位:像素)(`0` = 不调整大小)。 |
| `maxSlices` | `50` | 全页面截图:拼接切片的硬上限。 |
两个端点支持它:`GET /config` 返回有效的策略;`POST /config` 验证并替换它(主机 +
CORS 保护与每个截图路由一样)。文件是非图像,因此堆栈清除从不触及它;删除它只是
恢复上述默认值。
## 故障排除
- **扩展程序中的服务器未启动消息:** 运行 `snapstack start` (或 `snapstack run` 在前台),
或使用 `snapstack` 检查自动启动。测试:`curl http://127.0.0.1:4123/health`。
- **端口已被占用(`EADDRINUSE`):** 将 `SNAPSTACK_PORT` 设置为其他值。
- **切换 Node.js 版本后 `snapstack: command not found`:** `npm i -g`
将 `snapstack` 命令放入安装时激活的 Node.js 版本的全局 bin 中,因此切换
版本会隐藏它。这是 npm 全局变量的工作方式,而不是 SnapStack 的错误 — **后台服务不受影响,继续
捕捉**;只有 CLI 命令消失。修复:在当前 Node.js 版本下重新运行 `npm i -g snapstack-server` (或
切换回安装时使用的版本)。
- **客户端看不到工具:** 服务器必须在 MCP 客户端启动**之前**运行;检查配置
(`type: "http"`,正确的 URL)。直接测试:`curl http://127.0.0.1:4123/count`。
- **检查堆栈:** `ls ~/.snapstack` (图像文件 + 可读的 `.json`)。
## 支持
- **有疑问或想法?** → [GitHub 讨论](https://github.com/bgaze/snapstack-server/discussions)
- **发现了错误?** → [打开问题](https://github.com/bgaze/snapstack-server/issues)
## 许可证
MIT — 请参阅 [LICENSE](./LICENSE)。