Metadata-Version: 2.4
Name: svn-mcp
Version: 0.3.0
Summary: Unicode-safe (CJK/Japanese path) SVN MCP server with env-based auth and XML-parsed output
Author-email: hira <ship.hiramatsu@gmail.com>
License-Expression: Apache-2.0
Keywords: mcp,svn,subversion,model-context-protocol,unicode,cjk
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Version Control
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: mcp<2,>=1.2.0
Dynamic: license-file

# svn-mcp-server

一个单文件的 **Subversion（SVN）** [模型上下文协议（MCP）](https://modelcontextprotocol.io)服务器，专为 **Windows 下包含非 ASCII 字符（中日韩文字）的路径**提供可靠支持。

本项目的起因是：两款现有的 SVN MCP 服务器在日文 Windows 环境下都存在问题。其中，Node 实现因 CP932 与 UTF-8 编码差异导致日文路径乱码，另一款 Python 实现则会返回空结果，并在输出为空时崩溃。本服务器保留了两者的优点，并修复了这些问题。

## 项目特点

- **支持 Unicode 参数。** 使用**参数列表和** `shell=False` 启动命令，在 Windows 上以 Unicode 形式将路径或 URL 传递给 `CreateProcessW`，避免日文等字符乱码。
- **显式使用 UTF-8 解码。** 以字节形式捕获输出，再使用 UTF-8 解码（`errors="replace"`），不受控制台代码页影响。
- **通过 XML 解析输出。** `info` / `status` / `log` / `list` 使用 `--xml` 输出，并通过 `ElementTree` 解析，确保结果结构化且可靠，避免 `log` 意外返回空结果。
- **通过环境变量配置身份验证。** 将 `SVN_USERNAME` / `SVN_PASSWORD` 作为 `--username` / `--password` 参数传入，并使用 `--non-interactive`，不依赖操作系统的凭据缓存。
- **安全处理空输出。** 工作副本没有改动时返回空列表，而不是抛出异常。

## 环境要求

- Python >= 3.10
- `PATH` 中可用的 `svn` 命令行客户端（例如 SlikSVN、TortoiseSVN CLI、CollabNet）
- `mcp>=1.2.0,<2`（自动安装，使用 MCP 1.x 提供的 `mcp.server.fastmcp`）

## 安装

### 从 PyPI 安装

在准备运行 `svn-mcp` 的 Python 环境中执行：

```powershell
python -m pip install svn-mcp-server
```

更新到 PyPI 上的最新发布版本：

```powershell
python -m pip install --upgrade svn-mcp-server
```

以上安装方式都会提供 `svn-mcp` 启动命令；SVN 命令行客户端仍需单独安装。

## 配置（Claude Desktop / Cowork）

将以下内容添加到 `claude_desktop_config.json`（Windows 路径：`%APPDATA%\Claude\claude_desktop_config.json`）：

```json
{
  "mcpServers": {
    "svn": {
      "command": "svn-mcp",
      "env": {
        "SVN_WORKING_DIRECTORY": "C:\\path\\to\\working\\copy",
        "SVN_USERNAME": "your_user",
        "SVN_PASSWORD": "your_password",
        "SVN_TIMEOUT": "120000",
        "PYTHONUTF8": "1",
        "PYTHONIOENCODING": "utf-8"
      }
    }
  }
}
```

## 环境变量

| 变量 | 说明 | 默认值 |
| ---- | ---- | ------ |
| `SVN_PATH` | `svn` 可执行文件的路径 | `svn` |
| `SVN_WORKING_DIRECTORY` | 命令的默认工作目录 | 进程当前工作目录 |
| `SVN_USERNAME` | 用于身份验证的用户名 | 无 |
| `SVN_PASSWORD` | 用于身份验证的密码 | 无 |
| `SVN_CONFIG_DIR` | 通过 `--config-dir` 传递给 SVN 的配置目录 | 无 |
| `SVN_TRUST_SERVER_CERT` | 设置为 `1` / `true` 时接受自签名证书 | 关闭 |
| `SVN_TIMEOUT` | 每条命令的超时时间，单位为毫秒 | `120000` |

## 工具

### 读取与检查

| 工具 | 说明 |
| ---- | ---- |
| `svn_version` | 查看 SVN 客户端版本 |
| `svn_health_check` | 检查 SVN 是否可用及工作副本状态 |
| `svn_whoami` | 查看当前 SVN 用户名 |
| `svn_info` | 查看路径或 URL 的详细信息 |
| `svn_status` | 查看工作副本中的文件状态 |
| `svn_log` | 查看提交历史 |
| `svn_log_search` | 按作者、提交说明或版本范围搜索提交 |
| `svn_diff` | 查看版本之间的差异 |
| `svn_diff_stats` | 根据差异按文件和扩展名统计新增、删除行数 |
| `svn_list` | 列出目录内容 |
| `svn_cat` | 读取文件内容（读取本地文件或通过 `svn cat` 获取） |
| `svn_grep` | 在工作副本中使用正则表达式进行全文搜索 |

### 检出与更新

| 工具 | 说明 |
| ---- | ---- |
| `svn_checkout` | 将指定 URL 的内容检出到本地路径 |
| `svn_update` | 更新工作副本（支持通过 `set_depth` 设置稀疏检出深度） |
| `svn_cleanup` | 清理中断操作留下的状态 |

### 写入操作

| 工具 | 说明 |
| ---- | ---- |
| `svn_add` | 将文件加入版本控制，等待提交 |
| `svn_commit` | 提交更改（**需要人工审核**） |
| `svn_delete` | 删除文件或 URL（**需要人工审核**） |
| `svn_revert` | 撤销本地未提交更改 |
| `svn_rollback` | 反向合并已提交版本，在本地生成回退修改，不自动提交 |

> **写入操作注意事项：** `svn_commit` 和针对版本库 URL 的 `svn_delete` 会修改版本库。仅在经过明确的人工审核与批准后使用。

### 开发规模统计

以下工具用于统计本地已检出项目的规模与开发活动。

| 工具 | 说明 |
| ---- | ---- |
| `svn_loc_stats` | 按文件扩展名统计代码行数（总行数 / 代码行 / 注释行 / 空行） |
| `svn_file_loc_export` | 将逐文件代码行数导出为本地 CSV / TSV / JSONL 文件，默认仅返回摘要 |
| `svn_commit_stats` | 按作者和/或自然月汇总提交活动 |
| `svn_size_stats` | 按扩展名统计文件数量和字节大小，并列出最大的文件 |

#### `svn_loc_stats`

```
svn_loc_stats(path=None, extensions=None, filename_pattern=None, group_by="extension")
```

遍历工作副本，将每一行归类为**代码行**、**注释行**或**空行**。根据 `group_by` 指定的方式分组，并在 `total` 项中汇总结果。

- `path` — 扫描根目录，默认为 `SVN_WORKING_DIRECTORY`。
- `extensions` — 要包含的扩展名列表，例如 `[".java", ".xml"]`，默认使用内置的文本文件扩展名集合。
- `filename_pattern` — 按文件名进行 glob 模式筛选，例如 `"accept_*"` 或 `"*Form.java"`。当文件名遵循命名规范时，可用于按业务类别前缀汇总。
- `group_by` — 结果分组方式：
  - `"extension"`（默认）— 按文件扩展名分组。
  - `"dirname"` — 按相对于 `path` 的目录路径分组。
  - `"prefix_N"` — 按文件名的前 N 个字符分组，例如 `"prefix_3"`。
  - `"filename_stem"` — 按不含扩展名的文件名分组。

#### `svn_commit_stats`

```
svn_commit_stats(repo_path=None, limit=None, revision=None,
                 group_by_author=True, group_by_month=False)
```

解析 `svn log --verbose --xml` 的输出，汇总提交次数和变更路径数量。

- `group_by_author` — 是否包含按作者分组的统计，默认为 `true`。
- `group_by_month` — 是否包含按月份分组的统计，默认为 `false`。
- `limit` / `revision` — 含义与 `svn_log` 中的同名参数一致。

#### `svn_file_loc_export`

```
svn_file_loc_export(path, extensions=None, exclude_patterns=None,
                    output_path=None, output_format="csv",
                    include_svn_revision=False)
```

递归扫描 `path`，将每个文件的统计结果作为一条记录写入本地文件。
默认仅返回摘要，包括文件总数、总行数，以及按扩展名汇总的代码行、注释行和空行数，避免通过 MCP 响应传回完整文件列表而触发 token 数量或超时限制。满足下述内联条件时，也可在响应中返回逐文件记录。

| 参数 | 说明 |
| ---- | ---- |
| `path` | 扫描根路径（必填）。相对路径以 `SVN_WORKING_DIRECTORY` 为基准解析。 |
| `extensions` | 要包含的扩展名列表，例如 `[".java", ".jsp", ".sql"]`。默认使用内置的文本文件扩展名集合。 |
| `exclude_patterns` | 要排除的 glob 模式，匹配使用正斜杠的相对路径，例如 `["*/test/*"]`。 |
| `output_path` | 输出文件的保存路径。省略时，在 `path` 旁自动生成 `_loc_export_<timestamp>.csv`。 |
| `output_format` | `"csv"`（默认，使用带 BOM 的 UTF-8 编码以兼容 Excel）、`"tsv"` 或 `"jsonl"`。 |
| `include_svn_revision` | 为 `true` 时，通过 `svn info` 获取每个文件的最后修改版本号。每个文件会额外调用一次 SVN，仅在需要时启用。 |
| `inline_if_small` | 为 `true`（默认）且文件数量 ≤ `inline_threshold` 时，在响应的 `files` 字段中包含逐文件记录，便于 Claude 直接处理数据，无需读取 CSV。 |
| `inline_threshold` | 允许内联返回的最大文件数量，默认为 `10000`。超过该值时，仅返回摘要和 `output_file` 路径。 |

**输出文件列名：** `relative_path`、`extension`、`total`、`code`、`comment`、`blank`、`size_bytes`、`last_revision`

#### `svn_diff_stats`

```
svn_diff_stats(repo_path=None, revision=None, old_revision=None, new_revision=None,
               extensions=None)
```

运行 `svn diff` 并解析统一差异格式的输出，统计每个文件的新增和删除行数。返回按新增与删除行数之和排序的逐文件列表、按扩展名分组的统计，以及 `total` 汇总（`files_changed`、`added`、`removed`、`delta`）。

- 参数与 `svn_diff` 一致。
- `extensions` — 仅统计指定扩展名的文件，例如 `[".java"]`。

#### `svn_size_stats`

```
svn_size_stats(path=None, extensions=None, top_n=20)
```

从工作副本的文件系统中收集文件大小，返回按扩展名统计的文件数量与字节总数、整体大小（字节和 MB），以及最大的 `top_n` 个文件。

- 自动排除 `.svn` 元数据目录。

## 致谢

本项目为独立重新实现，参考了以下两个采用 MIT 许可证的项目，并与其兼容，未复制其代码：[gcorroto/mcp-svn](https://github.com/gcorroto/mcp-svn) 和 [manavdesai27/mcp-server-svn](https://github.com/manavdesai27/mcp-server-svn)。

## 许可证

Apache-2.0。详见 [LICENSE](LICENSE) 和 [NOTICE](NOTICE)。
