Skip to main content
Glama
jingchenGOD

universal-fs-mcp

by jingchenGOD
README.md
# universal-fs-mcp

一个通用、宿主无关的 [MCP](https://modelcontextprotocol.io/) 文件系统服务器。
基于官方 TypeScript SDK(`@modelcontextprotocol/sdk`)+ `zod`,走 `stdio` 传输,不依赖任何特定沙盒或客户端,任何能跑 Node.js 18+ 的环境都能用。

## 一键安装(推荐)

下载 [`universal-fs-mcp.mcpb`](https://github.com/jingchenGOD/universal-fs-mcp/releases/download/v1/universal-fs-mcp.mcpb)(或到 [Releases](../../releases/latest) 页面),**双击安装**即可,无需 node 环境配置、无需 `npm install`。

安装过程中会让你选择一个**工作区目录**,之后所有文件操作都被限制在该目录内。

> `.mcpb` 是 MCP Bundle 格式(官方打包规范),需要宿主应用支持,例如 Claude for macOS / Windows。若你的客户端不支持 `.mcpb`,请走下面的「从源码运行」。

## 从源码运行

```bash
git clone https://github.com/jingchenGOD/universal-fs-mcp.git
cd universal-fs-mcp
npm install
npm run build
```

> **注意**:仓库里不含 `dist/`(已在 `.gitignore` 中忽略)。
> **从源码运行必须先跑 `npm install && npm run build`**,否则没有 `dist/index.js`,MCP 客户端无法启动服务器。
> 用上面的 `.mcpb` 一键安装的话,不需要做任何构建。

## 特点

- **沙箱化**:所有路径 `path.resolve` 后校验必须落在工作区根目录内,`../` 穿越会被直接拒绝
- **省 token**:`fs_grep` 只回文件名 + 匹配次数 + 行号,不吐整行内容;`fs_read` 支持按行切片
- **安全写入**:`fs_write` 默认不覆盖已有文件;`fs_edit` 在匹配到多处时拒绝执行,除非显式允许
- **零污染**:stdout 只走 MCP 协议,所有日志输出到 stderr
- **依赖极简**:仅 `@modelcontextprotocol/sdk`、`zod` 和 Node 内置模块

## 自行打包 .mcpb

仓库里的 `manifest.json` 是 MCP Bundle 的打包配置(规范版本 0.3):

| 字段 | 值 |
|---|---|
| `server.type` | `node` |
| `server.entry_point` | `dist/index.js` |
| `mcp_config.command` | `node` |
| `mcp_config.args` | `["${__dirname}/dist/index.js"]` |
| `user_config.workspace_root` | 类型 `directory`、必填,安装时让用户选工作区目录,值注入到 `MCP_WORKSPACE_ROOT` |

改完代码后重新打包:

```bash
npm run build
npm install -g @anthropic-ai/mcpb   # 首次需要
mcpb validate manifest.json
mcpb pack . universal-fs-mcp.mcpb
```

> 打包工具在 npm 上的包名是 **`@anthropic-ai/mcpb`**(不是 `@modelcontextprotocol/mcpb`,后者不存在)。
> `.mcpbignore` 会把 `src`、`tsconfig.json` 和 `typescript` 等打包期依赖排除,包体约 2.5 MB。

## 配置

| 环境变量 | 默认值 | 说明 |
|---|---|---|
| `MCP_WORKSPACE_ROOT` | `process.cwd()` | 工作区根目录。所有路径参数都相对它解析,且不允许越出该目录。**强烈建议显式设置。** |

手动启动(供调试):

```bash
MCP_WORKSPACE_ROOT=/workspace node dist/index.js
```

## 工具列表(6 个)

| 工具 | 参数 | 作用 |
|---|---|---|
| `fs_list` | `path`(默认 `.`)、`show_hidden`(默认 `false`) | 列出目录内容;目录带 `/` 后缀,文件附带字节大小;`show_hidden` 控制是否显示点文件 |
| `fs_read` | `path`、`start_line`(默认 `1`)、`end_line`(可选) | 按行读取文本文件,返回指定行区间。第一条是 `# 相对路径 行 a-b/总行数` 头,适合大文件只取需要的片段,避免整包读取 |
| `fs_stat` | `path` | 查询路径是否存在,返回类型(file/directory)、大小、修改时间;不存在时返回明确提示而非报错 |
| `fs_write` | `path`、`content`、`overwrite`(默认 `false`) | 写入文件,父目录不存在会自动递归创建;文件已存在且 `overwrite=false` 时**不覆盖**,只返回提示,防止误删内容 |
| `fs_edit` | `path`、`old_text`、`new_text`、`replace_all`(默认 `false`) | 精确字符串替换。匹配为 0 处时报错;匹配到多处且未设 `replace_all=true` 时**拒绝执行**,避免误改;返回实际替换的处数 |
| `fs_grep` | `keyword`、`path`(默认 `.`)、`max_files`(默认 `20`,上限 `100`)、`ignore_case`(默认 `false`) | 正则检索文本文件。**只返回文件名、匹配次数和行号数组,绝不返回匹配行内容**;自动跳过 `.git`、`node_modules`、`dist`、二进制文件和超过 2MB 的文件;也可直接传单个文件路径 |

所有路径参数都支持相对路径(相对 `MCP_WORKSPACE_ROOT`)或该目录内的绝对路径。

## 在 MCP 客户端中注册

以 DeepSeek Harness 为例,在 profile 的 `cordis.patch.yml` 中追加:

```yaml
- insert:
    - id: mcp-universal-fs
      name: "@deepseek-ai/dsh-mcp-client"
      config:
        serverName: universal-fs
        transport: stdio
        command: node
        args:
          - /绝对路径/universal-fs-mcp/dist/index.js
        cwd: /你的工作区
        env:
          MCP_WORKSPACE_ROOT: /你的工作区
        toolCallTimeoutMs: 60000
        failOnStartupError: false
```

注册后工具名形如 `mcp__universal-fs__fs_list`。

其他客户端(Claude Desktop、Cursor 等)通用写法:

```json
{
  "mcpServers": {
    "universal-fs": {
      "command": "node",
      "args": ["/绝对路径/universal-fs-mcp/dist/index.js"],
      "env": { "MCP_WORKSPACE_ROOT": "/你的工作区" }
    }
  }
}
```

## 安全说明

- 所有路径在 `path.resolve` 之后用 `path.relative` 校验,越出根目录一律抛错
- 写操作是普通 `writeFileSync`,**没有回滚机制**,重要文件请先用 `fs_read` 读取备份
- 服务器以 stdin 上的 MCP 协议通信,不要用交互式终端直接运行后手敲命令

## License

[MIT](./LICENSE)

TDQS

C2/5.0

Scored across 6 tools

Disambiguation4/5

The verbs (list, read, stat, write, edit, grep) map to mostly distinct filesystem operations, and the fs_ prefix makes the target domain obvious. The main risk is fs_write vs fs_edit (overwrite/create vs in-place modification) and fs_read vs fs_stat, ambiguities that no descriptions exist to resolve.

Naming Consistency5/5

Every tool follows the exact same pattern: fs_ prefix plus a short lowercase verb, all snake_case. There are no deviations or mixed conventions.

Tool Count5/5

Six tools is well-scoped for a filesystem server, covering the core read/inspect/search/write operations without padding. Each tool appears to earn its place.

Completeness3/5

The surface covers reading, listing, stat, writing, editing, and searching, but there is no delete/remove, move/rename, copy, or explicit mkdir operation. These are standard filesystem lifecycle operations whose absence will force agents to find workarounds or fail.

Maintenance

ActivityMaintained
ResponsivenessNo issues