内容
# Devout
[![Build Status][gh-actions-badge]][gh-actions]
[![Project Logo][logo]][logo-large]
*一个 Devin 克隆的 MCP 服务器*
一个用 Erlang 编写的模型上下文协议(Model Context Protocol,MCP)服务器,为软件项目提供文件、目录和版本控制操作。
## 特性
### 🛠️ 文件操作
- **new-dir**: 创建目录并自动创建父目录
- **new-dirs**: 创建具有多个子目录的目录结构
- **move**: 安全地移动/重命名文件和目录
- **write**: 创建/写入文件,支持追加模式
- **read**: 读取文件内容,带大小限制
- **list-files**: 列出目录内容,包括文件类型和大小
- **show-cwd**: 显示当前工作目录
- **change-cwd**: 导航到相对目录
### 🐙 Git 操作
- **git-add**: 将文件添加到暂存区 (`git add <files>`)
- **git-log**: 显示提交历史 (`git log [options]`)
- **git-diff**: 显示差异(无参数、1个参数或2个参数)
- **git-pull**: 进行变基拉取 (`git pull <remote> <branch> --rebase`)
- **git-checkout-branch**: 创建并切换到新分支 (`git checkout -b <name>`)
- **git-push**: 推送到远程 (`git push <remote>`)
- **git-commit-all**: 提交所有更改 (`git commit -a -m <message>`)
- **git-commit-files**: 提交特定文件 (`git commit <files> -m <message>`)
- **git-clone**: 克隆仓库 (`git clone <url>`)
- **git-status**: 显示仓库状态 (`git status --porcelain`)
### 🔒 安全特性
- **路径验证**: 仅允许相对路径,防止目录遍历
- **沙箱**: 所有操作限制在基础目录内
- **文件大小限制**: 可配置的最大文件大小
- **扩展过滤**: 可选的文件类型限制
- **安全错误处理**: 通过错误不泄露信息
### 📚 资源与提示
- **devout://status**: 实时服务状态和配置
- **devout://help**: 综合工具文档
- **create_project**: 智能项目结构生成(Erlang、web、API、库)
## 架构
### OTP 设计
- **应用**: `devout_app` - 标准 OTP 应用回调
- **监控**: `devout_sup` - 管理服务器进程生命周期
- **服务器**: `devout_server` - 主要的 gen_server,与 erlmcp 协调
- **操作**: `devout_fs` - 文件系统操作实现
- **验证**: `devout_path_validator` - 安全和路径验证
- **Git 操作**: `devout_git` - Git 命令实现
- **入口点**: `devout_stdio_main` - 独立的 stdio 可执行文件
### 安全模型
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Claude AI │───▶│ devout_server │───▶│ devout_fs │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ ▼ ▼
┌──────────────────┐ ┌─────────────────┐
│ erlmcp_stdio │ │ path_validator │
│ (MCP Protocol) │ │ (Security) │
└──────────────────┘ └─────────────────┘
│
▼
┌──────────────────┐ ┌─────────────────┐
│ devout_git │───▶│ erlexec │
└──────────────────┘ │ (Proc. Mgmt.) │
└─────────────────┘
```
## 先决条件
- **Erlang/OTP 25+**
- **Rebar3**
- **Git**(用于依赖和 Git 操作)
## 快速开始
### 1. 构建
```bash
git clone <repository-url>
cd devout
rebar3 get-deps
rebar3 compile
```
### 2. 测试
```bash
rebar3 eunit
```
### 3. 配置 Claude Desktop
编辑 `claude_desktop_config.json`:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
**Linux**: `~/.config/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"devout": {
"command": "/Users/oubiwann/lab/erlsci/devout/bin/start.sh",
"args": []
}
}
}
```
### 4. 重启 Claude Desktop
## 使用示例
### 📁 目录操作
```
用户: 创建一个名为 "my_app" 的新项目结构,包含 src、test 和 docs 目录
Claude: 我将为您创建该项目结构。
[使用 new-dirs 工具: {"path": "my_app", "children": ["src", "test", "docs"]}]
目录结构创建成功:
- my_app
- src
- test
- docs
```
### 🔍 目录浏览
```
用户: 当前目录中有哪些文件?
Claude: 我将向您展示当前目录中的文件。
[使用 list-files 工具: {}]
当前目录内容:
[FILE] .DS_Store (6148 字节)
[DIR] .git
[DIR] .github
[FILE] .gitignore (164 字节)
[FILE] LICENSE (11358 字节)
[FILE] Makefile (4612 字节)
[FILE] README.md (9895 字节)
[DIR] _build
[DIR] bin
[DIR] config
[DIR] src
[DIR] test
```
### 📝 文件操作
```
用户: 创建一个包含一些 JSON 内容的配置文件
Claude: 我将为您创建一个配置文件。
[使用 write 工具: {"path": "my_app/config.json", "content": "{\n \"port\": 3000,\n \"debug\": true\n}"}]
内容成功写入文件: my_app/config.json (32 字节)
```
#### 🔍 导航与读取
```
用户: 显示当前目录,然后读取配置文件
Claude: 我将显示当前目录并读取配置文件。
[使用 show-cwd 工具: {}]
当前工作目录: /Users/developer/projects
[使用 read 工具: {"path": "my_app/config.json"}]
my_app/config.json 的内容 (32 字节):
{
"port": 3000,
"debug": true
}
```
#### 🏗️ 项目生成
```
用户: 使用 create_project 提示生成一个 Erlang 应用
Claude: 我将生成一个 Erlang 项目结构提示。
[使用 create_project 提示: {"project_name": "my_erlang_app", "project_type": "erlang"}]
为 'my_erlang_app' 创建项目结构(Erlang 项目)。创建一个包含目录: src、include、test、priv、rebar.config 的 Erlang/OTP 项目结构。使用 devout 工具创建必要的目录和文件。
```
### 🐙 Git 操作
#### 查看 Git 历史
```
用户: 显示最近的 5 次提交
Claude: 我将向您展示最近的提交历史。
[使用 git-log 工具: {"args": "--oneline -5"}]
Git 日志:
a1b2c3d 添加新特性
e4f5g6h 修复解析器中的错误
i7j8k9l 更新文档
m1n2o3p 初始提交
```
#### 创建特性分支
```
用户: 创建一个名为 "user-authentication" 的新特性分支
Claude: 我将为您创建并切换到新分支。
[使用 git-checkout-branch 工具: {"branch": "user-authentication"}]
Git 切换分支成功:
已切换到新分支 'user-authentication'
```
#### 提交更改
```
用户: 将这些文件添加到 git 并提交,消息为 "Add user auth"
Claude: 我将为您暂存并提交这些文件。
[使用 git-add 工具: {"files": ["src/auth.erl", "test/auth_test.erl"]}]
[使用 git-commit-files 工具: {"files": ["src/auth.erl", "test/auth_test.erl"], "message": "Add user auth"}]
Git 操作成功完成!
```
#### 与远程同步
```
用户: 从 origin main 拉取最新更改,然后推送我的分支
Claude: 我将为您与远程仓库同步。
[使用 git-pull 工具: {"remote": "origin", "branch": "main"}]
[使用 git-push 工具: {"remote": "origin"}]
Git 同步成功完成!
```
## 配置
编辑 `config/sys.config` 以自定义行为:
```erlang
[
{devout, [
{max_file_size, 10485760}, % 10MB 限制
{allowed_extensions, all}, % 或 [<<".txt">>, <<".md">>]
{enable_recursive_delete, false}, % 安全第一
{allowed_operations, [ % 限制可用操作
new_dir, new_dirs, move, write, read, list_files, show_cwd, change_cwd
]}
]},
{erlexec, [
{debug, false}, % 启用以调试 git 命令
{verbose, false}
]}
].
```
## Git 命令参考
| MCP 工具 | Git 命令 | 描述 |
|----------|----------|------|
| `git-add` | `git add <files>` | 暂存文件以进行提交 |
| `git-log` | `git log [options]` | 显示提交历史 |
| `git-diff` | `git diff [ref1] [ref2]` | 显示差异 |
| `git-pull` | `git pull <remote> <branch> --rebase` | 进行变基拉取 |
| `git-checkout-branch` | `git checkout -b <name>` | 创建新分支 |
| `git-push` | `git push <remote>` | 推送到远程 |
| `git-commit-all` | `git commit -a -m <message>` | 提交所有更改 |
| `git-commit-files` | `git commit <files> -m <message>` | 提交特定文件 |
| `git-clone` | `git clone <url>` | 克隆仓库 |
| `git-status` | `git status --porcelain` | 显示仓库状态 |
### Git 工具参数
#### git-add
```json
{
"files": ["file1.txt", "file2.txt"] // 文件数组
// 或
"file": "single_file.txt" // 单个文件
}
```
#### git-log
```json
{
"args": "--oneline -10" // 可选: git log 参数
}
```
#### git-diff
```json
{
// 无参数 = 工作目录与暂存区
// 或
"ref": "HEAD~1" // 与参考进行比较
// 或
"ref1": "HEAD~2", // 比较两个参考
"ref2": "HEAD~1"
}
```
#### git-pull
```json
{
"remote": "origin", // 必需: 远程名称
"branch": "main" // 必需: 分支名称
}
```
#### git-push
```json
{
"remote": "origin" // 必需: 远程名称
}
```
## 安全特性
### 🛡️ 路径安全
- **仅允许相对路径**: 拒绝绝对路径 (`/etc/passwd` ❌)
- **防止遍历**: 阻止访问父目录 (`../../../etc` ❌)
- **基础目录强制**: 操作限制在工作目录内
- **路径规范化**: 处理 `./`、`//` 和其他边缘情况
### 📏 资源限制
- **文件大小限制**: 可配置的最大文件大小(默认: 10MB)
- **操作白名单**: 限制每次部署可用的操作
- **扩展过滤**: 可选的文件类型限制
- **内存保护**: 对大文件进行流式处理
### 🔒 错误处理
- **信息隐藏**: 错误不泄露系统细节
- **优雅降级**: 部分失败干净处理
- **审计日志**: 所有操作记录以供安全审查
- **输入清理**: 所有输入在处理前进行验证
## 开发
### 运行测试
```bash
# 完整测试套件
rebar3 eunit
# 特定测试模块
rebar3 eunit --module=devout_test
# 带覆盖率
rebar3 cover
```
### 代码质量
```bash
# 静态分析
rebar3 dialyzer
# 交叉引用
rebar3 xref
# 代码检查
rebar3 lint
```
### 开发模式
```bash
# 交互式 shell
rebar3 shell
# 手动启动 stdio 服务器
devout_server:start_stdio().
```
### 添加文件系统操作
1. **在 `devout.app.src` 中添加到 allowed_operations**
2. **在 devout_fs.erl 中实现(如有需要)**:
```erlang
my_operation(Path) ->
case devout_path_validator:validate_path(Path) of
{ok, ValidPath} ->
% 在此处执行您的操作
ok;
{error, Reason} ->
{error, Reason}
end.
```
3. **在 devout_app.erl 中注册工具**:
```erlang
ok = erlmcp_stdio:add_tool(
<<"my-operation">>,
<<"描述">>,
fun devout_server:handle_my_operation/1,
SchemaMap
).
```
4. **在 devout_server.erl 中添加处理程序**:
```erlang
handle_my_operation(#{<<"path">> := Path}) ->
case devout_fs:my_operation(Path) of
ok -> <<"成功消息">>;
{error, Reason} -> devout_fmt:err(Reason)
end.
```
### 添加新的 Git 操作
1. **在 devout_git.erl 中添加函数**:
```erlang
my_git_operation(Args) ->
execute_git(["my-operation"] ++ Args).
```
2. **添加 MCP 处理程序**:
```erlang
handle_my_git_operation(#{<<"param">> := Value}) ->
case my_git_operation([binary_to_list(Value)]) of
{ok, Output} -> <<"成功: ", Output/binary>>;
{error, Reason} -> devout_fmt:err(Reason)
end.
```
3. **在 devout_server.erl 中注册工具**:
```erlang
ok = erlmcp_stdio:add_tool(
<<"git-my-operation">>,
<<"我的 git 操作的描述">>,
fun devout_git:handle_my_git_operation/1,
Schema
).
```
4. **在 devout_git_test.erl 中添加测试**
## 监控与调试
### 健康检查
```bash
# 检查应用是否正在运行
erl -eval "io:format('~p~n', [application:whichAppications()]), halt()."
# 验证进程
erl -eval "io:format('~p~n', [whereis(devout_server)]), halt()."
```
### 日志记录
日志输出到 stderr,以避免干扰 MCP 协议的 stdout:
- **信息**: 服务生命周期事件
- **警告**: 安全违规,无效路径
- **错误**: 操作失败,系统错误
## 故障排除
| 问题 | 原因 | 解决方案 |
|-------|-------|----------|
| 服务未启动 | 缺少依赖 | `rebar3 get-deps && rebar3 compile` |
| 路径被拒绝 | 绝对/遍历路径 | 仅使用相对路径 |
| 文件过大 | 超过大小限制 | 检查 `max_file_size` 配置 |
| 权限被拒绝 | 文件系统权限 | 检查目录所有权 |
| 找不到工具 | 版本不匹配 | 验证 erlmcp 兼容性 |
| Git 命令超时 | 长时间运行的操作 | 在 erlexec 配置中增加超时 |
| 找不到 Git | 缺少 git 安装 | 安装 git 并确保在 PATH 中 |
| 合并冲突 | 冲突更改 | 手动解决冲突 |
| 找不到仓库 | 不在 git 仓库中 | 首先使用 `git init` 初始化 |
## 性能
- **内存使用**: ~10MB 基础 + 文件缓冲
- **吞吐量**: 小文件每秒 1000+ 操作
- **延迟**: <10ms 对于典型操作
- **可扩展性**: 单线程,适合交互使用
## 贡献
1. Fork 仓库
2. 创建特性分支
3. 为新功能添加测试
4. 确保所有测试通过: `rebar3 eunit`
5. 运行静态分析: `rebar3 dialyzer`
6. 提交拉取请求
### 代码风格
- 使用 OTP 原则和 gen_server 模式
- 进行全面的错误处理,使用适当的类型
- 安全优先设计 - 验证所有输入
- 使用 edoc 文档所有公共函数
- 遵循 Erlang 命名约定
## 致谢
- 基于优秀的 [erlmcp](https://github.com/erlsci/erlmcp) 库构建
- 受到 Erlang/OTP 生态系统安全实践的启发
- 感谢 Claude Desktop 团队提供 MCP 协议规范
## 许可证
Apache 许可证 2.0 - 详见 LICENSE 文件。
## 外部资源
- [开始使用模型上下文协议(MCP)](https://modelcontextprotocol.io/introduction)
- [erlexec - 用于操作系统命令执行的 Erlang 端口程序](https://github.com/saleyn/erlexec)
- [Git 文档](https://git-scm.com/doc)
[//]: ---命名链接---
[logo]: priv/images/project-logo.png
[logo-large]: priv/images/project-logo-large.png
[gh-actions-badge]: https://github.com/erlsci/devout/workflows/ci/badge.svg
[gh-actions]: https://github.com/erlsci/devout/actions?query=workflow%3Aci
连接信息
猜你喜欢
暂无推荐服务器