Skip to main content
Glama
Congenital

remote-skill-mcp

by Congenital
README.md
# remote-skill-mcp

> 把**远程 HTTP 服务**上的技能文件(`skill.md` 及其子文件)动态暴露为 **MCP(Model Context Protocol)** 工具、资源与提示词,让任意 MCP 客户端(Claude Desktop、Cursor、LobeHub 等)通过 stdio 直接读取远程技能文档。

[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
[![MCP SDK](https://img.shields.io/badge/mcp-1.29%2B-2563EB.svg)](https://github.com/modelcontextprotocol/python-sdk)
[![Transport](https://img.shields.io/badge/transport-stdio-111.svg)]()
[![License](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)

> 📖 **English documentation / 英文文档:** [README.en.md](./README.en.md)

基于**标准 MCP SDK** 的 `FastMCP` 运行时实现(非手写 JSON-RPC 协议层),完全符合 MCP 规范,可直接被任意 MCP 客户端接入,并已适配 **LobeHub MCP 市场**(见 [`lhm.plugin.json`](./lhm.plugin.json))。

---

## 工作原理(懒加载,省上下文)

```
┌─────────────┐   stdio (newline-delimited JSON-RPC)   ┌──────────────────┐
│  MCP 客户端  │ ◄────────────────────────────────────► │   server.py      │
│ (Claude等)  │      initialize / tools/* /            │  (本仓库)         │
└─────────────┘      resources/* / prompts/*          └────────┬─────────┘
                                                                 │ HTTP GET/HEAD
                                                                 ▼
                                                      ┌─────────────────────┐
                                                      │ 远程 SimpleHTTP 服务 │
                                                      │  /skill.md          │
                                                      │  /image/*.md 等子文件│
                                                      └─────────────────────┘
```

启动时(lifespan,懒加载):

1. 从 `REMOTE_SKILL_BASE_URL` 拉取 `skill.md`(轻量能力目录,描述有哪些技能方向);
2. 解析其中的 **markdown 链接 / 图片 / 裸文件 token / 目录名**,对每个引用做 **HEAD 探测**(不下载正文):
   - 引用是**文件** → 记录路径 + mime/size;
   - 引用是**目录** → GET 其 HTML 列表页,把列出的文件记录进来(不递归下载文件正文);
   - 404 的裸文件名会在已知目录中自动重试;
3. 动态生成 MCP 暴露物(description 只含**路径清单**,不含正文,避免上下文膨胀):
   - **工具** `get_skill_file(path)` —— 按路径**按需**取文件内容;
   - **资源** `skill://<相对路径>` —— 每个发现的文件一个资源(`read` 时才下载;文本内联,二进制转 base64);
   - **提示词** `skill` / `list_skills` —— 返回 `skill.md` 全文 / 能力目录摘要。

> 这样 agent 平时只看到"有哪些能力方向",真正用到某个技能时才拉取详细文档,
> 避免一次性把所有技能详情灌进上下文。若 `skill.md` 不直接列全所有文件、需要钻取目录,
> 可设 `MCP_DISCOVER_DEPTH>=1` 递归 N 层(会下载中间层正文以解析更多引用)。

---

## 特性

- ✅ 基于**标准 MCP SDK**(`FastMCP`)实现,完全符合 MCP 规范,stdio 传输
- ✅ **懒加载**:启动只读 `skill.md`,子文件仅记录路径,正文按需下载(省上下文)
- ✅ 动态发现:HEAD 探测文件 + GET 目录列表页,解析 `skill.md` 的链接/图片/裸文件/目录名
- ✅ 404 重试:对失败路径在已知目录中自动重试
- ✅ MIME 推断:`content-type` 为 `application/octet-stream` 时按扩展名回退(`.md` 等仍按文本)
- ✅ 三种暴露方式:工具 / 资源 / 提示词(description 只含路径清单,不含正文)
- ✅ 大文件保护:超过 `MCP_MAX_FILE_BYTES` 拒绝读取
- ✅ 日志只走 stderr,stdout 仅用于协议消息
- ✅ 工具错误用 `isError=True` 返回(符合 MCP 约定,客户端不抛异常)
- ✅ 适配 **LobeHub MCP 市场**:含 `lhm.plugin.json` 清单、`pyproject.toml` 元数据、MIT 许可

---

## 提供的 MCP 能力

| 类型 | 名称 | 说明 |
|------|------|------|
| 工具 | `get_skill_file(path)` | 按路径读取文件内容(文本/图片/二进制 base64) |
| 资源 | `skill://<相对路径>` | 每个发现的文件一个资源 URI,可 `resources/read` |
| 提示词 | `skill` | 返回 `skill.md` 全文(可用 `file` 参数指定子文件) |
| 提示词 | `list_skills` | 返回可用技能方向摘要(文件清单) |

---

## 安装

```bash
cd remote_skill_mcp
pip install -r requirements.txt
```

依赖:`mcp`(协议类型 + stdio 传输 + FastMCP 运行时)、`httpx`(HTTP 客户端)。

---

## 配置(环境变量)

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `REMOTE_SKILL_BASE_URL` | `http://192.168.2.6:4000` | 远程服务根地址 |
| `SKILL_FILE` | `skill.md` | 技能入口文件(相对 BASE_URL) |
| `MCP_MAX_FILE_BYTES` | `524288`(512KB) | 单文件最大字节,超过则拒绝 |
| `MCP_MAX_FILES` | `200` | 记录文件数上限 |
| `MCP_TIMEOUT` | `30` | 单次 HTTP 超时(秒) |
| `MCP_DISCOVER_DEPTH` | `0` | 发现深度:`0`=只读 `skill.md`(默认,最省);`>=1` 递归 N 层 |
| `MCP_CACHE_READS` | `false` | 是否缓存已读取文件内容(省重复请求,但占内存) |

---

## 运行

### 直接运行(调试)

```bash
export REMOTE_SKILL_BASE_URL=http://192.168.2.6:4000
python server.py
```

服务启动后会阻塞等待 stdio 输入。

### 接入 MCP 客户端

**Claude Desktop**(`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "remote-skill": {
      "command": "python",
      "args": ["/绝对路径/remote_skill_mcp/server.py"],
      "env": {
        "REMOTE_SKILL_BASE_URL": "http://192.168.2.6:4000"
      }
    }
  }
}
```

**Cursor / 其他支持 stdio MCP 的客户端**同理,把 `server.py` 作为子进程启动即可。

---

## 发布到 LobeHub MCP 市场

本仓库已包含市场清单 [`lhm.plugin.json`](./lhm.plugin.json)(`identifier`/`name`/`version`/`author`/`homepage`/`icon`/`category`/`tags`/`description`/`tools`/`prompts`/`resources` 齐全)。

1. 确保仓库已 push 到 GitHub(`origin` = `git@github.com:Congenital/remote_skill_mcp.git`);
2. 安装市场 CLI(需 Node.js ≥ 22)并登录:

   ```bash
   npx -y @lobehub/market-cli login
   npx -y @lobehub/market-cli github connect
   ```

3. 发布(读取本仓库根目录的 `lhm.plugin.json`):

   ```bash
   npx -y @lobehub/market-cli plugin publish https://github.com/Congenital/remote_skill_mcp
   ```

   后续版本更新:`npx -y @lobehub/market-cli plugin update`(改 `lhm.plugin.json` 的 `version` 即可)。

> 市场按 活跃度 / 稳定性 / 社区反馈 等维度排名。本清单已补齐 作者、主页、图标、分类、标签、工具/提示词/资源 等字段以提升完整度评分。

---

## 测试

```bash
python tests/e2e_test.py
```

端到端测试通过 `mcp.ClientSession` 启动 server,验证 `initialize` / `tools/list` / `tools/call`(含非法路径报错)/ `resources/list` / `resources/read` / `prompts/list` / `prompts/get`(`skill` + `list_skills`)全链路。

---

## 目录结构

```
remote_skill_mcp/
├── server.py            # MCP 服务(FastMCP 运行时 + 发现 + 工具/资源/提示词)
├── lhm.plugin.json      # LobeHub MCP 市场清单
├── pyproject.toml       # 项目元数据(名称/版本/作者/许可/入口点)
├── LICENSE              # MIT 许可
├── requirements.txt
├── README.md            # 中文文档
├── README.en.md         # 英文文档
└── tests/
    └── e2e_test.py      # 端到端测试
```

---

## 远程服务要求

- 一个可静态列出/下载文件的 HTTP 服务(如 `python -m http.server`);
- 根目录下有 `skill.md`(或用 `SKILL_FILE` 指定入口);
- 子文件用相对路径引用(支持 markdown 链接、图片、裸文件名、`目录名:` 形式)。