philipnee/mvmt

GitHub: philipnee/mvmt

一个基于 MCP 协议的本地文件安全访问层,通过显式挂载和精细化权限控制,让 AI 客户端安全地访问指定本地文件夹。

Stars: 0 | Forks: 1

# mvmt **多卷挂载传输。** mvmt 通过一个小巧、具权限控制的工具 API 暴露选定的本地文件夹。 将文件夹挂载到稳定路径下,例如 `/notes`、`/workspace` 或 `/research`, 然后允许客户端在这些挂载内搜索、列出、读取、写入或移除文件。 客户端永远不会获得完整的计算机访问权限。它们只能看到您允许的挂载和 操作。 ``` client | v mvmt | |-- /notes -> ~/Documents/Obsidian |-- /workspace -> ~/code/mvmt |-- /research -> ~/papers ``` mvmt **不是同步工具**。 mvmt **不是云存储**。 mvmt **不是通用文件系统服务器**。 它是一个本地优先的访问层,通过显式挂载、窄范围工具和按客户端分配的权限, 将您机器的特定部分暴露出来。 ![mvmt 在交互模式下运行](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/6ebb967e15030714.png) ## 为什么会有 mvmt 许多工具需要受控地访问本地文件。 赋予工具广泛的文件系统访问权限是有风险的。将所有内容上传到云工作区通常是 不必要的。临时的本地服务器通常缺乏清晰的权限模型。 mvmt 采取了更狭窄的方法: - 仅挂载您希望客户端看到的文件夹。 - 通过稳定的虚拟路径暴露这些文件夹。 - 给每个客户端分配独立的路径/操作权限。 - 将数据保留在您的机器上。 - 审计客户端的搜索、读取、写入和移除操作。 ## 核心理念 ### 统一的本地命名空间 客户端操作虚拟路径: ``` /notes /workspace /research ``` 它们不需要知道这些文件夹在磁盘上的具体位置。 ### 显式挂载 每次挂载将一个虚拟路径映射到一个真实的本地文件夹。 ``` mounts: - name: notes path: /notes root: /Users/you/Documents/Obsidian writeAccess: false ``` ### 按客户端分配权限 不同的客户端可以看到命名空间的不同部分。 ``` clients: - id: codex permissions: - path: /workspace/** actions: [search, read, write] - id: readonly-client permissions: - path: /notes/** actions: [search, read] ``` ### 默认只读 写入操作需要同时满足: 1. 客户端拥有该路径的 `write` 权限;并且 2. 挂载配置了 `writeAccess: true`。 受保护的路径,如 `.env`、`.claude/**` 或其他配置的模式, 不能被写入或移除。mvmt 还具有全局密钥路径拒绝名单, 针对 `.mvmt/**`、`.ssh/**`、`.aws/**`、`.kube/**` 等路径以及常见的 云/开发凭据文件。即使旧版配置中没有列出这些路径,它们也会被阻止。 ## 快速开始 从当前检出的源码运行 mvmt: ``` npm install npm run build npm link mvmt serve -i ``` 当前名为 `mvmt` 的 npm 包尚未包含此 CLI 发布版。在包含 `mvmt` 可执行文件的 该包发布之前,请使用上述源码安装方式。 首次运行时,mvmt 会创建: ``` ~/.mvmt/config.yaml ``` 然后它会引导您完成: - 添加本地文件夹挂载; - 可选启用模式编辑器; - 启动 MCP 服务器。 如果要在不更改已保存配置的情况下临时提供只读文件夹: ``` mvmt serve --path ~/Documents -i ``` 至少需要启用一个挂载。如果未配置任何挂载,mvmt 将没有 数据可供提供服务。 ## 示例设置 添加只读笔记挂载: ``` mvmt mounts add notes ~/Documents/Obsidian \ --mount-path /notes \ --read-only \ --description "Personal notes and project journals" \ --guidance "Search first. Read specific files before answering." ``` 添加可写项目挂载: ``` mvmt mounts add workspace ~/code/mvmt \ --mount-path /workspace \ --write \ --protect ".env" \ --protect ".env.*" \ --protect ".claude/**" \ --description "mvmt source code and design docs" \ --guidance "Read README.md and docs before changing code." ``` 然后重建索引并提供服务: ``` mvmt reindex mvmt serve -i ``` ## 状态 | 领域 | 状态 | | --- | --- | | 本地文件夹挂载 | 已支持 | | 文本索引 | 作为 JSON 原型索引受到支持 | | MCP 工具 | `search`、`list`、`read`、`write`、`remove` | | 挂载管理 CLI | 已支持 | | API 令牌路径权限 | 通过 `mvmt token add` 支持 | | 本地可流式 HTTP | 在 `127.0.0.1` 上支持 | | Stdio 模式 | 已支持 | | 面向 Web 客户端的 OAuth/PKCE | 已支持,包括动态客户端注册 | | 隧道模式 | 支持个人远程访问 | | 模式编辑器插件 | 已支持 | | 旧版代理连接器配置 | 为兼容性被 schema 接受,被仅挂载的 CLI 运行时忽略 | | 管理 UI | 未发布 | | API 令牌颁发 | 支持 Bearer 令牌客户端 | | 远程 mvmt 挂载 | 未发布 | | 二进制/PDF/图像索引 | 未发布 | ## 客户端兼容性 mvmt 可供 MCP 客户端、本地 HTTP 客户端和远程 Web 客户端通过 隧道模式使用。 | 客户端 | 传输方式 | 状态 | 认证方式 | 备注 | | --- | --- | --- | --- | --- | | Claude Desktop | stdio | 已支持 | 进程启动 | 从客户端配置运行其自己的 mvmt 进程 | | Claude Code | Streamable HTTP | 已支持 | bearer token | 使用通过 `mvmt token add` 获取的作用域 API 令牌 | | Codex CLI | Streamable HTTP | 已支持 | bearer token | 使用通过 `mvmt token add` 获取的作用域 API 令牌 | | Cursor | Streamable HTTP | 预期支持 | bearer token | 行为取决于 Cursor 的 MCP 实现 | | VS Code / Copilot | Streamable HTTP | 预期支持 | bearer token | 行为取决于 MCP 扩展 | | claude.ai / ChatGPT web | 公共 HTTPS 隧道 | 支持的远程模式 | OAuth/PKCE | 需要可访问的隧道 URL | | Raw HTTP / curl | Streamable HTTP | 仅用于调试 | bearer token | 必须遵循 MCP 会话初始化规则 | 大多数本地 HTTP 客户端需要: ``` URL: http://127.0.0.1:4141/mcp Authorization: Bearer ``` 在本地旧版模式下,`` 可以是 `mvmt token session` 中的内部会话令牌。 对于普通的作用域访问,请使用 `mvmt token add` 创建 API 令牌并改为使用该令牌。 远程 Web 客户端使用隧道 URL(通常以 `/mcp` 结尾),并通过 OAuth 2.1 + PKCE 进行授权。 mvmt 支持 RFC 7591 动态客户端注册。颁发的 OAuth 访问令牌在受众上 绑定到当前的 mvmt 资源,因此为一个 mvmt 实例生成的令牌无法用于对 另一个实例进行重放攻击。 Claude Desktop 则不同:它通过 stdio 启动 mvmt,因此没有 HTTP 监听器,也没有 bearer token 头。 ## 工具接口 当配置了 `mounts[]` 时,mvmt 会暴露五个 MCP 工具: | 工具 | 用途 | 所需权限 | | --- | --- | --- | | `search` | 搜索允许挂载中的已索引文本块 | `search` | | `list` | 列出可见的挂载根目录或目录 | `read` | | `read` | 按虚拟路径读取一个文本文件 | `read` | | `write` | 创建或覆盖一个文本文件 | `write` | | `remove` | 删除一个文本文件 | `write` | 重要行为: - `list("/")` 返回可见的挂载根目录,包含描述、指导和写入访问状态。 - `search` 对已索引的文本块使用简单的关键词评分。 - `read` 和 `write` 仅支持文本。 - `write` 支持 `expected_hash`,以便客户端避免覆盖过时的读取内容。 - `remove` 永久删除文件。它不会删除目录。 - 非文本文件会在 `list` 中隐藏,被索引跳过,并被 `read`/`write` 拒绝。 受支持的类文本文件包括 Markdown、纯文本、JSON、YAML、TOML、CSV、 日志、Shell 脚本、HTML/CSS/XML 和常见的源代码扩展名。 超过 2 MiB 的文件会被索引跳过,并被直接文本读取拒绝。 ## 配置 保存的配置位于: ``` ~/.mvmt/config.yaml ``` 查看配置: ``` mvmt config ``` 验证配置: ``` mvmt doctor ``` 管理挂载: ``` mvmt mounts list mvmt mounts add mvmt mounts edit mvmt mounts remove ``` 最小配置: ``` version: 1 server: port: 4141 allowedOrigins: [] access: local mounts: - name: notes type: local_folder path: /notes root: /Users/you/Documents/Obsidian description: Personal notes and project journals. guidance: Search first. Read specific files before answering. exclude: - .git/** - node_modules/** - .claude/** - .mvmt/** - .ssh/** - .aws/** protect: - .env - .env.* - .claude/** - .mvmt/** - .ssh/** - .aws/** writeAccess: false enabled: true - name: workspace type: local_folder path: /workspace root: /Users/you/code/mvmt description: mvmt project source and design docs. guidance: Read README.md and docs before changing code. exclude: - .git/** - node_modules/** - dist/** protect: - .env - .env.* - .claude/** - .mvmt/** - .ssh/** - .aws/** writeAccess: true enabled: true plugins: - name: pattern-redactor enabled: true mode: redact ``` 挂载字段: | 字段 | 含义 | | --- | --- | | `name` | 稳定的小写挂载 ID,例如 `notes` | | `path` | 对客户端可见的虚拟路径,例如 `/notes` | | `root` | 磁盘上的本地文件夹 | | `description` | 从 `list("/")` 返回的简短摘要 | | `guidance` | 从 `list("/")` 返回的可选面向客户端的指导 | | `exclude` | 在列出、读取、写入、移除和索引中隐藏的路径 | | `protect` | 不能被写入或移除的路径 | | `writeAccess` | 挂载级别的写入门控;默认为 `false` | | `enabled` | 挂载是否处于活动状态 | Obsidian 仓库只是一个本地文件夹挂载。在当前的仅挂载形态中,没有 特殊的 Obsidian 运行时连接器。 ## API 令牌与策略 对于本地测试,当未配置 API 令牌时,mvmt 保持旧版行为: 内部会话 bearer 令牌可以访问所有已配置的挂载。会话 令牌存储在 `~/.mvmt/.session-token` 中,文件模式为 `600`。HTTP `mvmt serve` 在其缺失时会创建它。 为了实现可重复的客户端访问,请创建作用域 API 令牌: ``` mvmt token add codex --read /notes --ttl 7d mvmt token add codex --write /workspace --ttl 30d ``` `mvmt token add` 会打印一次明文令牌。mvmt 在配置中仅存储 scrypt 验证器。令牌默认在 30 天后过期;在创建或编辑令牌时,请使用诸如 `--ttl 30m`、`--ttl 7d` 或 `--ttl never` 的值。 如果客户端请求授权令牌,请粘贴打印出的 `mvmt_...` 值。如果 Web 客户端让您通过 OAuth 进行授权,请将相同的令牌粘贴到 mvmt 批准页面中。 一旦存在 API 令牌,`/mcp` 将变得严格: - bearer 令牌必须与已配置的客户端 `tokenHash` 匹配; - OAuth 访问令牌继承在批准页面上选择的 API 令牌身份; - 会话令牌不再授予数据平面访问权限; - 未知的 OAuth 客户端会被隔离,具有零权限。 隧道模式可以在没有 API 令牌的情况下启动,但 MCP 数据访问会拒绝 旧版会话令牌。添加 API 令牌以授予访问权限。仅用于临时调试, 设置 `MVMT_ALLOW_LEGACY_TUNNEL=1` 以允许通过隧道使用旧版会话令牌。 API 令牌权限是针对虚拟路径而非本地磁盘路径编写的。 底层配置字段当前名为 `clients[]`。 ``` clients: - id: codex name: Codex CLI description: Local Codex token expiresAt: "2026-05-06T12:00:00.000Z" auth: type: token # Verifier for the client API key. # Do not store the plaintext key. tokenHash: "scrypt:v1:..." rawToolsEnabled: false permissions: - path: /workspace/** actions: [search, read, write] - path: /notes/** actions: [search, read] - id: readonly-client name: Read-only client auth: type: token tokenHash: "scrypt:v1:..." rawToolsEnabled: false permissions: - path: /notes/** actions: [search, read] ``` 策略是累加的。只有当解析后的 API 令牌对目标虚拟路径 具有所需的操作权限时,调用才会成功。 对于写入操作,挂载本身也必须具有 `writeAccess: true`,且目标 不能匹配 `protect`。 ## 命令 | 命令 | 描述 | | --- | --- | | `mvmt serve` | 如果需要,配置 mvmt,然后启动 MCP 服务器 | | `mvmt serve -i` | 使用交互式控制提示启动 | | `mvmt serve --path ` | 临时提供一个只读文件夹 | | `mvmt reindex` | 重建文本索引 | | `mvmt mounts` | 列出已配置的挂载 | | `mvmt mounts --json` | 以 JSON 格式列出已配置的挂载 | | `mvmt mounts add [name] [root]` | 添加本地文件夹挂载 | | `mvmt mounts edit [name]` | 编辑挂载 | | `mvmt mounts remove [name]` | 移除挂载 | | `mvmt mounts remove [name] --yes` | 无需交互式确认即可移除挂载 | | `mvmt config` | 显示已保存的配置摘要 | | `mvmt config setup` | 重新运行引导式设置 | | `mvmt doctor` | 验证配置和启动先决条件 | | `mvmt token` | 列出作用域 API 令牌 | | `mvmt token add [id]` | 创建或更新作用域 API 令牌 | | `mvmt token edit [id]` | 编辑作用域 API 令牌 | | `mvmt token rotate [id]` | 替换作用域 API 令牌密钥 | | `mvmt token remove [id]` | 移除作用域 API 令牌 | | `mvmt token session` | 用于内部会话令牌的隐藏兼容性命令 | | `mvmt tunnel` | 显示隧道状态 | | `mvmt tunnel config` | 选择并保存隧道命令 | | `mvmt tunnel start` | 启动已配置的隧道 | | `mvmt tunnel refresh` | 重启隧道并打印新的 URL | | `mvmt tunnel stop` | 停止公共隧道暴露 | | `mvmt tunnel disable` | 将配置切换回仅本地访问 | | `mvmt tunnel logs` | 显示最近的隧道输出 | | `mvmt tunnel logs stream` | 流式传输实时隧道输出 | | `mvmt --version` | 打版本并检查更新 | 交互模式接受相同的命令组: ``` > mounts > mounts add > mounts edit > mounts remove > config > config setup > token > token add > token edit > token rotate > token remove > tunnel > tunnel refresh ``` ## 索引生命周期 在 `mvmt serve` 时,mvmt 会立即开始提供服务并在后台重建文本索引。 在重建完成之前,搜索可能会返回较少的结果。 请使用: ``` mvmt reindex ``` 在通过 mvmt 外部更改文件或编辑挂载配置后使用。 通过 mvmt 执行的写入和移除操作会自动重建索引。 当前索引是配置文件旁边的一个 JSON 文件。SQLite 和增量 文件监控已计划但尚未发布。 ## 安全模型 每个数据操作都受路径和操作的门控。 - HTTP 模式绑定到 `127.0.0.1`,而不是 `0.0.0.0`。 - HTTP `/mcp` 和 `/health` 需要身份验证。 - 会话令牌存储在 `~/.mvmt/.session-token` 中,模式为 `600`。 - 挂载根目录在访问前会被解析。 - 超出挂载根目录的路径遍历会被拒绝。 - `exclude` 会在列出、读取、写入、移除和索引中隐藏路径。 - `protect` 会阻止对敏感路径(如 `.env` 和 `.claude/**`)的写入/移除。 - 全局密钥路径,如 `.mvmt/**`、`.ssh/**`、`.aws/**`、`.kube/**` 和常见的凭据文件,无论每个挂载的配置如何,都会被拒绝。 - 写入操作需要同时具备客户端 `write` 权限和挂载的 `writeAccess`。 - 一旦存在 API 令牌/OAuth 策略,未知的 OAuth 客户端将被隔离。 - 浏览器来源检查会阻止来自非本地来源的随发浏览器请求。 - 可选的模式编辑器可以在输出到达客户端之前,对配置的正则表达式匹配发出警告、编辑或阻止。 - 工具调用会附加到 `~/.mvmt/audit.log` 中。 身份验证控制谁可以连接。挂载和客户端策略控制他们可以访问什么。 ## 远程访问 mvmt 是本地优先的。 远程客户端无法直接访问 `127.0.0.1`,因此隧道模式可以发布一个 公共 HTTPS URL。 远程访问检查清单: 1. 仅挂载远程客户端需要的文件夹。 2. 优先使用只读挂载。 3. 准备好时启动隧道。如果没有 API 令牌,公共端点 可以访问,但无法读取数据。 4. 使用 `mvmt token add` 创建作用域 API 令牌。 5. 对秘密和私有文件夹使用 `protect`。 6. 在测试新的远程客户端时关注 `~/.mvmt/audit.log`。 7. 使用稳定的隧道 URL 以实现可重复的 OAuth 流程。 快速隧道虽然方便,但是临时的。 ## 当前限制 - 本地文件夹是唯一已发布的挂载提供者。 - mvmt 当前作为单实例运行。 - 远程 mvmt 挂载未发布。 - 活跃的 CLI 运行时仅限挂载。 - 旧版代理连接器配置仍会为兼容性进行解析,但代理连接器不会作为运行时工具加载。 - 搜索是原型关键词评分,而不是语义嵌入搜索。 - PDF、图像、归档文件和其他二进制文件会被跳过。 - 尚无文件监控器。 - API 令牌轮换和管理 UI 未发布。 - mvmt 不会跨机器同步、复制或解决冲突。 ## 近期计划 近期: - 基于 SQLite 的文本索引。 - 增量索引更新。 - 更好的挂载和 API 令牌管理命令。 - 用于客户端密钥、路径权限、审计和挂载可见性的管理 UI。 稍后: - 远程 mvmt 挂载。 - 在相同的 `search`/`list`/`read`/`write`/`remove` 接口背后提供多个挂载提供者。 - `resolve(path) -> AccessPlan`,用于将虚拟路径路由到本地或远程后端。 ## 项目文档 - [安装指南](docs/setup.md) - [客户端配置](docs/client-setup.md) - [文本索引原型](docs/text-index-prototype.md) - [远程访问](docs/remote-access.md) - [审计日志](docs/audit-log.md) - [故障排除](docs/troubleshooting.md) - [架构](docs/architecture.md) - [安全策略](SECURITY.md) - [贡献](CONTRIBUTING.md) - [更新日志](CHANGELOG.md) ## 贡献 在项目早期阶段欢迎贡献。 保持更改专注且具有安全意识。请阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 并通过 [SECURITY.md](SECURITY.md) 报告漏洞。 ## 许可证 MIT
标签:API网关, HTTP工具, MITM代理, Python开发, 代理服务, 安全沙箱, 客户端权限, 数据隐私, 文件共享, 文件搜索, 文件系统隔离, 文件读写, 文档管理, 文档结构分析, 本地优先, 本地开发环境, 本地文件访问, 本地服务器, 权限控制, 目录映射, 细粒度访问控制, 网络安全审计, 虚拟挂载, 访问控制列表(ACL), 路径映射