内容
# 手工匠-MCP
一款高性能的模型上下文协议(MCP),旨在将大型语言模型(LLM)转化为具有持久记忆和安全系统访问权限的自主代理。Handyman-MCP 为 AI 模型提供了“执行功能”层,结合了复杂的 SQLite 支持的长期记忆和加固的执行沙盒。
## 功能特点
* 🧠 持久上下文引擎 – SQLite + FTS5 知识库,具有项目隔离和别名解析,用于跨会话代理“记忆”。
* 🛡️ 安全执行层 – 通过 Bubblewrap 沙盒实现严格隔离,具有只读根文件系统和可丢弃的 /tmp,用于安全命令执行。
* 📈 项目生命周期审计器 – 具有时间线跟踪的结构化变更日志系统,用于跟踪错误、重构和里程碑,实现自我记录的开发。
* 🔍 高级信息检索 – 通过 DDGS 实现网络智能和通过 Trafilatura 实现高保真内容提取。
* 📂 文件系统代理 – 完整的 CRUD 操作和基于正则表达式的 Grep 搜索,针对 LLM 效率进行了行级窗口优化。
* 🏗️ 模块化设计 – 基于 FastAPI 的干净架构,每个工具都是一个独立的、热可插拔的模块,便于扩展。
## 工具列表
| 工具 | 描述 |
|------|-------------|
| `today` | 获取今日日期和时间 |
| `add` | 将两个数字相加 |
| `web_search` | 搜索网络信息 |
| `fetch_content` | 抓取 URL 并提取内容 |
| `list_files` | 列出文件和目录(使用 `recursive=true` 查看树形结构) |
| `read_file` | 读取文件,支持 AI 友好的基于行的窗口化 |
| `write_file` | 向文件中写入文本 |
| `append_to_file` | 向现有文件中追加文本 |
| `replace_in_file` | 在文件中查找并替换文本 |
| `insert_after_marker` | 在标记行后插入文本 |
| `search_files` | 在文件中搜索文本模式(精确或正则表达式) |
| `delete_file` | 从沙盒目录中删除文件 |
| `remove_directory` | 删除目录(可选递归标志) |
| `run_command` | 在沙盒中执行 shell 命令 |
| `md_to_pdf` | 将 Markdown 文件转换为样式化的 PDF 文档 |
| `store_context` | 在 SQLite 知识库中存储项目特定上下文 |
| `query_context` | 查询存储的上下文 – 支持关键词搜索(FTS5)、直接键查找或列出所有键 |
| `clear_context` | 通过键清除存储的上下文条目或清除项目的所有条目 |
| `add_project_alias` | 为项目标识符注册替代名称(别名) |
| `list_projects` | 列出所有已知项目及其最后更新时间戳 |
| `add_project_change` | 记录新的变更条目(错误修复、重构、功能、里程碑、配置等) |
| `add_change_step` | 为现有项目变更添加时间线步骤 |
| `list_project_changes` | 列出项目的变更,支持按类型和日期范围筛选 |
| `get_change_history` | 获取某个变更的完整历史记录,包括时间线步骤 |
| `search_project_changes` | 跨项目变更摘要进行 FTS 搜索 |
| `store_issue` | 存储或更新具有状态、标题、描述和提交链接的问题 |
| `query_issues` | 查询按项目、状态或键筛选的问题 |
| `get_issue_details` | 获取单个问题的完整详细信息,包括描述和提交链接 |
| `update_issue_status` | 转换问题状态(打开 → 关闭 / 不相关) |
| `list_issues` | 列出项目的所有问题,可选按状态筛选 |
| `update_issue_project` | 将问题从一个项目移动到另一个项目(更改所有权) |
## 🛠 安装
### 1. 标准方式
```bash
# 克隆仓库
git clone <仓库网址>
cd Handyman-MCP
# 使用 uv 安装依赖
uv sync
```
### 2. 👨🍳 “作者的选择”(推荐用于安全)
为了最大程度的隔离和干净的主机操作系统,建议在 **Podman Toolbox** 中运行 Handyman-MCP。这确保了 **Bubblewrap** 沙盒的一致性环境,并防止依赖项漂移。
```bash
# 创建并进入专用工具箱
toolbox create -c handyman-dev
toolbox enter -c handyman-dev
# 安装系统依赖和 uv
sudo dnf install bubblewrap # 如果不存在
curl -LsSf https://astral.sh | sh
# 同步并运行
uv sync
uv run main.py
```
## 使用
```bash
# 启动服务器
uv run main.py
```
服务器将在 `http://0.0.0.0:8000` 启动。
### 测试模式
```bash
# 以测试模式启动(端口 9000)
uv run main.py --test
```
### 环境变量
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `MCP_BASE_DIR` | 项目根目录 | 所有工具操作的基本目录 |
| `HOME` | (来自环境变量) | 沙盒配置的家目录 |
从示例创建 `.env` 文件:
```bash
cp .env.example .env
```
## 架构
服务器使用 JSON-RPC 2.0 通过 HTTP 实现 [模型上下文协议](https://modelcontextprotocol.io/)(MCP)。它公开了 **31 种工具**,组织成逻辑模块,支持关系型 SQLite 存储和 FTS5 全文搜索。
### 目录结构
```
mcp_copy/
├── main.py # FastAPI 应用,MCP 端点 (/mcp),工具调度器
├── tools.json # 工具模式定义(客户端能力的真实来源)
├── config.py # 配置 — BASE_DIR,环境变量加载
├── tools/ # MCP 工具实现(7 个模块)
│ ├── add.py # 数学:加两个数字
│ ├── today.py # 实用工具:UTC 日期/时间
│ ├── web_research.py # 网络搜索(DDGS)+ URL 抓取(Trafilatura)
│ ├── files.py # 文件操作:列表、读取、写入、追加、替换、插入、搜索、删除、删除目录
│ ├── run_command.py # 通过 Bubblewrap 沙盒执行 shell 命令
│ ├── md_to_pdf.py # Markdown → PDF 转换(使用 WeasyPrint)
│ └── sqlite_store.py # 持久上下文存储 + 项目变更跟踪器(FTS5 索引)
├── .env # 环境变量(可选;参见 `.env.example`)
└── .mcp_cache/ # 持久 SQLite 数据库(context.db)
```
### 关键设计决策
- **单个 MCP 端点** 在 `POST /mcp` 处理 `initialize`、`tools/list` 和 `tools/call` 方法
- **手动工具注册** — 每个处理程序必须在 main.py 中导入,在 __init__.py 中导出,并在 tools.json 中定义(31 个条目保持同步)
- **tools.json 作为模式源** — 客户端从此文件中发现可用工具
- **Bubblewrap 隔离** 用于 `run_command` — 只读根文件系统,可丢弃的 `/tmp`,可写的 BASE_DIR 绑定挂载
- **关系型 SQLite 存储** — 适当的 foreign keys(projects 表 → context/issues/project_changes),FTS5 索引无需 content= 参数重建,遗留查询的 backward-compat 视图
- **问题-变更链接** — 存在连接表,但目前需要手动填充(已知问题:`junction-table-empty`)
- **项目自动检测** — pyproject.toml → git remote → 目录名称备用链
## 持久上下文存储
`sqlite_store` 模块为 LLM 上下文提供跨会话知识库,使用 SQLite 和 FTS5 全文搜索。
### 项目识别和存储
项目自动检测并存储为专用 `projects` 表的行(INTEGER 主键),通过外键引用所有相关表(`context`、`issues`、`project_changes`)。这消除了脆弱的文本比较,并实现了适当的引用完整性。
检测优先级:
1. `pyproject.toml[project].name` — Python 原生,结构化
2. Git 远程源 URL — 提取仓库名称
3. 目录名称 — 最后的备用方案
### 存储和查询上下文
```json
// 存储新条目
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"store_context","arguments":{"key":"auth-flow","content":"用户使用电子邮件/密码登录","project":"my-app"}}}
// 按规范键查询
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"query_context","arguments":{"key":"auth-flow","project":"my-app"}}}
// 添加别名 — 现在“login”解析为同一个条目
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"add_project_alias","arguments":{"context_key":"auth-flow","alias_name":"login","project":"my-app"}}}
// 按别名查询 — 返回相同的条目,显示“匹配 via: 别名 'login'”
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"query_context","arguments":{"key":"login","project":"my-app"}}}
```
## 项目变更跟踪器
用于跟踪工作进度、修复的错误、完成的重构和达到的里程碑的结构化变更日志系统。每个变更都有文档记录所做和何时做的 timeline 步骤。变更存储时,与 `projects` 表具有适当的外键引用。
### 与问题自动链接
`issue_change_links` 连接表存在,但目前需要手动填充。计划了数据库触发器机制,但尚未实现。
### 记录变更
```json
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"add_project_change","arguments":{"project":"bob","key":"accordion-refactor","change_type":"refactor","summary":"将 accordion 从 Tabs.js 移至 TablesContainer"}}}
```
### 添加时间线步骤
```json
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"add_change_step","arguments":{"change_key":"accordion-refactor","project":"bob","step":"investigate","date":"2026-05-03","details":"发现 Tabs.js 在页面加载时使用 querySelectorAll — 破坏了 .map() 输出","files_changed":"app/static/js/Tabs.js, app/ts/TablesContainer.tsx"}}}
```
### 查看和搜索变更
| 工具 | 目的 |
|------|---------|
| `list_project_changes` | 列出变更,支持按类型(`bugfix`、`refactor`、`feature`、`milestone`、`config`、`other`)和日期范围筛选 |
| `get_change_history` | 获取某个变更的完整历史记录,包括所有时间线步骤 |
| `search_project_changes` | 跨变更摘要进行全文搜索(可选范围限定为项目或类型) |
## 问题跟踪器
用于跟踪具有生命周期状态的错误和观察的结构化系统。问题通过多对多连接表与项目变更链接。
### 存储问题
```json
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"store_issue","arguments":{"project":"mcp-server","key":"db-path-race","status":"open","title":"DB_PATH 单例竞争条件","description":"模块级 DB_PATH=None 全局变量在并发请求下导致重复连接。"}}}
```
### 更新状态
```json
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"update_issue_status","arguments":{"project":"mcp-server","key":"db-path-race","status":"closed"}}}
```
### 查询问题
| 工具 | 目的 |
|------|---------|
| `query_issues` | 按项目、状态或精确键筛选;显示摘要和相关变更计数 |
| `get_issue_details` | 获取单个问题的完整详细信息,包括完整描述和提交链接 |
| `list_issues` | 列出项目的所有问题,可选按状态筛选 |
状态值:`open`、`closed`、`not-relevant`。`issue_change_links` 连接表跟踪哪些项目变更与哪些问题相关(多对多)。目前不自动填充 — 一个已知问题跟踪为 `junction-table-empty`。
## 待办事项项目模式
`todo` 项目用作跨切任务列表。使用描述性键使任务可查找:
```json
// 存储待处理任务
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"store_context","arguments":{"key":"review-bob-metrics","content":"在星期五审查前检查 BOB 仪表盘的指标部分","project":"todo"}}}
// 标记为完成
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"store_context","arguments":{"key":"review-bob-metrics","content":"完成:审查了指标,标记了 3 个公民身份数据的不一致性","project":"todo"}}}
```
## 沙盒配置
`run_command` 工具使用 Bubblewrap 进行隔离:
- **只读根文件系统** (`--ro-bind / /`)
- **可丢弃的临时目录** (`--tmpfs /tmp`)
- **可写的 BASE_DIR 挂载** (`--bind <BASE_DIR> <BASE_DIR>`)
- **启用 DNS 解析** (无 `/etc` 限制)
### 传递到沙盒的环境变量
| 变量 | 值 | 目的 |
|----------|-------|---------|
| `PATH` | `/usr/local/bin:/usr/bin:<user>/.local/bin` | 包括用户安装的工具(例如 `uv`) |
| `HOME` | `<user>` | 用户主目录(从环境变量或 BASE_DIR 派生) |
| `UV_CACHE_DIR` | `/tmp/uv-cache` | 重定向 uv 的缓存(主机 `~/.cache` 是只读的) |
父进程中的所有其他环境变量都会被继承,但不会显式设置。
## MCP 客户端连接
### 端点
```
POST http://localhost:8000/mcp
Content-Type: application/json
```
### 支持的方法
| 方法 | 目的 |
|--------|---------|
| `initialize` | 握手 — 返回服务器信息和功能 |
| `tools/list` | 返回 `tools.json` 中的所有可用工具 |
| `tools/call` | 按名称调用工具并传递参数 |
### 示例:初始化连接
```bash
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
```
### 示例:列出工具
```bash
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
```
### 通过 llama-cpp-web 连接
在设置中添加您的 MCP 服务器 URL (`http://localhost:8000/mcp`),在 **Tools → MCP Servers** 下。
## 免责声明
该项目是在 **Qwen 3.6** 的协助下开发的,Qwen 3.6 是阿里巴巴集团 Tongyi Lab 的大型语言模型。虽然 AI 协助了代码生成、文档和重构,但所有技术决策和最终实现都由人类开发者审查和验证。
## 许可证
MIT 许可证