# Owlbear Rodeo 扩展文档工具集
> 现包含两个核心模块:
> 1. `mcp-docs-server`:基于 uv 发布的 MCP Python 服务端,可直接通过 `uvx mcp-docs-server` 暴露 Owlbear Rodeo 文档资源(搜索 + 打开全文)。
> 2. `obr_docs_to_md.py`:抓取官网扩展文档、生成 Markdown 的离线脚本,仍用于保持 `docs/markdown` 最新。
## MCP 文档服务器快速上手
1. **安装依赖**
```bash
uv sync
```
2. **查看帮助**
```bash
uv run mcp-docs-server --help
```
3. **最小可运行示例**
```bash
uvx mcp-for-owlbear-rodeo mcp-docs-server --transport stdio
```
- 默认从 `docs/markdown` 自动加载所有 Markdown 文件,每个文件即一个 MCP 资源 (`doc://owlbear/<category>/<slug>`)。
- 自动注册两个工具:
- `search_docs(query, top_k=5)`:返回资源链接列表。
- `open_doc(name)`:返回完整 Markdown 内容(与资源 URI 对齐)。
- 资源描述 (`description`) 直接取自文档首段正文,无人工编写,满足“不要瞎编”约束。
4. **接入自定义文档目录**
```bash
uv run mcp-docs-server --docs-path D:/cache/markdown
```
或通过环境变量:
```bash
set MCP_DOCS_ROOT=D:/cache/markdown
uvx mcp-docs-server
```
5. **在其他 MCP 客户端中测试**
- 以 Claude MCP Tool 为例,配置 `command`: `"uvx"`, `args`: `["mcp-for-owlbear-rodeo", "mcp-docs-server"]`。
- 客户端会自动发现全部 `doc://owlbear/...` 资源,并可调用 `search_docs`/`open_doc`。
> ⚠️默认打包会随 wheel 附带 `docs/markdown`,无需联网即可开箱即用;若要更新内容,请运行下方的抓取脚本刷新 Markdown 再重新构建。
## Owlbear Rodeo 扩展文档抓取工具使用说明
> 脚本入口:`obr_docs_to_md.py`
> 目标:批量抓取 https://docs.owlbear.rodeo/extensions/ 下的 API 及 Reference 文档,转换为纯文本 Markdown,方便后续切分与注入 MCP。
## 环境准备
1. **Python**:推荐 Python 3.9 及以上版本。
2. **命令行依赖**
- `curl`:用于抓取 HTML。
- `pandoc`:将清洗后的 HTML 转换为 GitHub Flavored Markdown。
3. **Python 包**
- `lxml`(标准库以外)
- `cssselect`(本仓库近期新增,务必安装)
安装示例:
```bash
python -m pip install lxml cssselect
```
> 小贴士:在 Windows 上使用本脚本时,建议通过 Git Bash 或 PowerShell 运行;确保 `curl` 与 `pandoc` 已加入 `PATH`。
## 输出结构总览
默认输出位于 `./out`,脚本会自动创建并复用目录:
```
out/
raw_html/ # 原始抓取的 HTML(按 apis/reference 分类)
cleaned_html/ # 清洗后的 HTML,供 Pandoc 转换
md/ # 最终 Markdown,纯文本无 HTML 标签
assets/ # Pandoc 提取出的媒体文件(当前已全部剔除,不再使用)
logs/
run.log # 逐条处理日志(北京时间,含缓存/抓取标记)
failures.txt # 失败记录(包含最终错误信息,便于重试)
url-map.json # 成功/缺失页面概览 + 元数据
```
`url-map.json` 结构示例:
```json
{
"generated_at": "2025-10-19T02:24:42+08:00",
"timezone": "UTC+08:00",
"output_root": ".../out",
"expected_items": [
{"url": "...", "category": "apis", "slug": "action"}
],
"items": [
{
"url": "...",
"category": "apis",
"title": "Action",
"slug": "action",
"raw_html": "raw_html/apis/action.html",
"cleaned_html": "cleaned_html/apis/action.html",
"markdown": "md/apis/action.md"
}
],
"missing_items": []
}
```
> `missing_items` 非空时,请查看 `logs/failures.txt` 并考虑使用 `--force-fetch` 重试。
## 常用命令
### 1. 全量抓取(推荐初次执行)
```bash
python obr_docs_to_md.py
```
- 自动解析 `sitemap.xml`(优先)/ 各分类索引页,收集 `/extensions/apis/` 与 `/extensions/reference/` 全部页面。
- 默认输出位置:`./out`。可通过 `--out` 自定义目录。
执行结束后,终端会输出如下概览(示例):
```
成功转换 42/45 个页面(apis:30, reference:12),Markdown 位于 D:\...\out\md\apis
仍有以下页面未成功生成 Markdown:
- [reference] https://docs.owlbear.rodeo/extensions/reference/foo
- [reference] https://docs.owlbear.rodeo/extensions/reference/bar
```
### 2. 单页调试
```bash
python obr_docs_to_md.py --single https://docs.owlbear.rodeo/extensions/reference/manifest
```
- 仅处理指定 URL,适用于调试清洗规则。
- 同样会更新 `url-map.json`,记录当前运行期望/缺失项。
### 3. 复用缓存 / 强制刷新
- **默认行为**:若 `out/raw_html/<category>/<slug>.html` 存在且非空,脚本直接复用,避免重复请求。
- **强制刷新**:添加 `--force-fetch` 即可忽略缓存从远端重新抓取。
```bash
python obr_docs_to_md.py --force-fetch
```
### 4. 其他常用参数
| 参数 | 说明 | 默认值 |
| --- | --- | --- |
| `--out PATH` | 指定输出根目录 | `out` |
| `--sleep-min` | 连续请求的最小间隔(秒) | `0.5` |
| `--sleep-max` | 连续请求的最大间隔(秒) | `1.5` |
| `--urls-file FILE` | 从自定义列表读取 URL(每行一个) | 无 |
> 建议保持合理的间隔,避免触发远端限流。即使启用缓存,解析失败也会在下一次尝试自动重新抓取。
## 运行后如何自检
1. **命令行输出**:优先关注终端概览,确认成功/缺失数量。
2. **`logs/failures.txt`**:若有失败条目,逐条定位原因(网络异常、Cloudflare 质询、Pandoc 转换失败等)。
3. **`out/url-map.json`**:快速查询生成的 Markdown 路径及未覆盖页面,可供后续脚本读取。
4. **Markdown 纯文本校验**:脚本已移除所有 `<img>/<a>` 等 HTML 标签,仅保留 Markdown 语法。可配合 `rg "<"` 检查是否仍有漏网标签。
## 常见问题
- **Cloudflare 验证导致 403**:脚本已内置通用 UA 与重试机制,但若仍无法通过,可适当增加 `--sleep-min/--sleep-max` 间隔或手动复制 HTML 至 `raw_html` 后重跑清洗。
- **本地没有安装 Pandoc**:请从 [https://pandoc.org/installing.html](https://pandoc.org/installing.html) 下载对应平台版本,并添加到 `PATH`。
- **输出时间看不懂**:所有日志、`url-map.json` 都使用北京时间(UTC+08:00),便于与本地排查时区一致。
## 后续扩展建议
- 在 CI 中配置定时任务,结合 `--force-fetch` 每日刷新文档。
- 依据 `url-map.json` 中的 `expected_items` / `missing_items` 生成告警报告,确保 MCP 数据源随站点更新。
- 如需合并 Markdown,可编写额外脚本,根据 `category` 字段聚合生成章节化文档。
> 如果后续需要新增其它目录(例如 `/extensions/tutorials/`),可以参照 `CATEGORY_CONFIGS` 增加配置项并复用现有流程。
• 整体思路
- 仓库当前只有两个核心模块:MCP 文档服务器 mcp-docs-server 与离线抓
取脚本 obr_docs_to_md.py,可以也应该分别测试,全部流程都能在本地
完成,不需要先发到 PyPI。pyproject.toml 里已声明入口脚本 mcp-docs- server = "docs_server:main",因此 uv run mcp-docs-server ... 就
能直接启动最新源码版的服务端,等到发布到 PyPI 后再用 uvx mcp-for-
owlbear-rodeo ... 跑线上版即可(README.md:7-41, pyproject.toml:1-
33)。
MCP 文档服务器本地验证路径
- 安装依赖:首次或更新后运行 uv sync,uv 会按 pyproject.toml
把 mcp[cli]>=1.21.0 与其余运行时(FastMCP 在依赖里)装好
(README.md:9-16, pyproject.toml:8-10)。
- 直接跑 CLI:uv run mcp-docs-server --transport stdio --log-level
DEBUG,默认会自动从仓库内的 docs/markdown 扫描文档并注册成资源;
命令行里可观察 “完成资源注册: X 篇文档” 的日志判断加载是否成功
(README.md:17-25, src/docs_server/server.py:1-123)。
- 用 MCP 官方 Inspector 做冒烟测试(不用任何 AI 客户端):
uv run mcp dev src/docs_server/server.py:main -- --transport stdio
--log-level DEBUG
- 前半段让 mcp dev 启动 Inspector,-- 后的参数原样传进 main()。
- Inspector 打开后:
1. Resources → Refresh:确认列表里出现 doc://owlbear/
<category>/<slug>,数量要与 docs/markdown 内文件数一致;
若缺少,回溯日志看哪个 Markdown 无法解析。
2. Tools → search_docs:输入 viewport 等关键词,检查返回的
resource_link 是否能点开。
3. Tools → open_doc:输入 apis/viewport 等名称,确认能收到整 篇 Markdown。
- 与 Codex/Claude/VS Code Copilot 等客户端对接:凡是支持自定
义 MCP 命令的客户端,都只需把命令设置成 uv run mcp-docs-server
--transport stdio 或(若已发版)uvx mcp-for-owlbear-rodeo mcp-
docs-server --transport stdio,客户端就能自动发现 search_docs /
open_doc 两个工具(README.md:17-40)。Codex 这类基于标准 MCP 的代
理只需在其配置里填写同样命令即可,无需额外桥接。
- 自动化/脚本化自检:可用下述最小脚本确认服务端即将暴露的文档数量、
示例条目是否正确;脚本只读 DocumentStore,不需启动 MCP:
uv run python - <<'PY'
"""快速列出可用文档, 方便比对数量"""
from docs_server.doc_store import DocumentStore
store = DocumentStore()
docs = store.documents
print(f"共加载 {len(docs)} 篇文档, 根目录={store.doc_root}")
for record in docs[:5]:
# 逐条示例, 确认类别/URI/简介是否符合预期
print(f"- {record.name} -> {record.uri}")
PY
如果脚本抛出 DocumentIndexEmptyError / DocumentNotFoundError(定义 在 src/docs_server/exceptions.py),就说明文档目录不完整或名称输入 错误,可据此定位(src/docs_server/doc_store.py:1-188)。
VS Code Copilot / 其他编辑器联调建议
- 目前 GitHub Copilot MCP 集成仍在逐步放出,若你所在版本尚未开放,可 以先用 mcp dev Inspector 或 Claude Desktop(支持自定义 MCP)验证; 待 Copilot 支持后,沿用同一命令即可,无需改造。调试时可把 --log-
level DEBUG 打开,通过终端日志追踪客户端何时发起 tool call,便于
排查。
文档抓取脚本测试(确保资源不缺失)
1. 基础运行:python obr_docs_to_md.py 会抓取官网并在 out/ 生
成 raw_html / cleaned_html / md / logs / url-map.json。若只想
更新仓库随包发出的 Markdown,可跑完后把 out/md/* 覆盖到 docs/
markdown(README.md:43-135)。
2. 强制刷新 & 指定 URL:
- 网络状态良好但怀疑缓存过期:python obr_docs_to_md.py --force-
fetch。
- 单页调试:python obr_docs_to_md.py --single
<URL>(README.md:109-143)。
3. 验证是否“漏文档”:
- 查看 out/url-map.json,missing_items 非空就代表有文档没转成
功,需结合 logs/failures.txt 排查(README.md:64-161)。
- 可配合 rg "<" out/md 确认 Markdown 是否仍混入 HTML,若命中则表 示清洗规则需调整(README.md:155-161)。
4. 回填到 MCP:当 url-map.json 中 missing_items 为空后,把最新
Markdown 覆盖到 docs/markdown,再按上节步骤重启 mcp-docs-server
验证资源数是否同步增加;DocumentStore 会在日志里打印“使用文档
目录: ...”,可双重确认指向的是你刚更新的目录(src/docs_server/
doc_store.py:70-142)。
“初步手动测试”Checklist(新手友好)
1. uv sync → uv run mcp-docs-server --transport stdio --log-level
DEBUG(服务器能启动,日志里有“完成资源注册”)。
2. 另开终端跑 uv run mcp dev src/docs_server/server.py:main --
--transport stdio,在 Inspector 里:
- Resources 显示的数量 = docs/markdown 实际 Markdown 数(可用 rg --files docs/markdown | wc -l 对比)。
- search_docs 输入冷门/热门关键词各一次,确保有有/无命中两种情况 都能得到合理文本提示。
Raw data
{
"_id": null,
"home_page": null,
"name": "mcp-for-owlbear-rodeo",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": null,
"keywords": "documentation, mcp, owlbear",
"author": "DnD5e Tools",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/5d/be/17d667959cecba58559717c4c6bfcd07a3e7de4fbdb72f2b29f246e6f9be/mcp_for_owlbear_rodeo-0.1.0.tar.gz",
"platform": null,
"description": "# Owlbear Rodeo \u6269\u5c55\u6587\u6863\u5de5\u5177\u96c6\n\n> \u73b0\u5305\u542b\u4e24\u4e2a\u6838\u5fc3\u6a21\u5757\uff1a\n> 1. `mcp-docs-server`\uff1a\u57fa\u4e8e uv \u53d1\u5e03\u7684 MCP Python \u670d\u52a1\u7aef\uff0c\u53ef\u76f4\u63a5\u901a\u8fc7 `uvx mcp-docs-server` \u66b4\u9732 Owlbear Rodeo \u6587\u6863\u8d44\u6e90\uff08\u641c\u7d22 + \u6253\u5f00\u5168\u6587\uff09\u3002\n> 2. `obr_docs_to_md.py`\uff1a\u6293\u53d6\u5b98\u7f51\u6269\u5c55\u6587\u6863\u3001\u751f\u6210 Markdown \u7684\u79bb\u7ebf\u811a\u672c\uff0c\u4ecd\u7528\u4e8e\u4fdd\u6301 `docs/markdown` \u6700\u65b0\u3002\n\n## MCP \u6587\u6863\u670d\u52a1\u5668\u5feb\u901f\u4e0a\u624b\n\n1. **\u5b89\u88c5\u4f9d\u8d56**\n ```bash\n uv sync\n ```\n2. **\u67e5\u770b\u5e2e\u52a9**\n ```bash\n uv run mcp-docs-server --help\n ```\n3. **\u6700\u5c0f\u53ef\u8fd0\u884c\u793a\u4f8b**\n ```bash\n uvx mcp-for-owlbear-rodeo mcp-docs-server --transport stdio\n ```\n - \u9ed8\u8ba4\u4ece `docs/markdown` \u81ea\u52a8\u52a0\u8f7d\u6240\u6709 Markdown \u6587\u4ef6\uff0c\u6bcf\u4e2a\u6587\u4ef6\u5373\u4e00\u4e2a MCP \u8d44\u6e90 (`doc://owlbear/<category>/<slug>`)\u3002\n - \u81ea\u52a8\u6ce8\u518c\u4e24\u4e2a\u5de5\u5177\uff1a\n - `search_docs(query, top_k=5)`\uff1a\u8fd4\u56de\u8d44\u6e90\u94fe\u63a5\u5217\u8868\u3002\n - `open_doc(name)`\uff1a\u8fd4\u56de\u5b8c\u6574 Markdown \u5185\u5bb9\uff08\u4e0e\u8d44\u6e90 URI \u5bf9\u9f50\uff09\u3002\n - \u8d44\u6e90\u63cf\u8ff0 (`description`) \u76f4\u63a5\u53d6\u81ea\u6587\u6863\u9996\u6bb5\u6b63\u6587\uff0c\u65e0\u4eba\u5de5\u7f16\u5199\uff0c\u6ee1\u8db3\u201c\u4e0d\u8981\u778e\u7f16\u201d\u7ea6\u675f\u3002\n\n4. **\u63a5\u5165\u81ea\u5b9a\u4e49\u6587\u6863\u76ee\u5f55**\n ```bash\n uv run mcp-docs-server --docs-path D:/cache/markdown\n ```\n \u6216\u901a\u8fc7\u73af\u5883\u53d8\u91cf\uff1a\n ```bash\n set MCP_DOCS_ROOT=D:/cache/markdown\n uvx mcp-docs-server\n ```\n\n5. **\u5728\u5176\u4ed6 MCP \u5ba2\u6237\u7aef\u4e2d\u6d4b\u8bd5**\n - \u4ee5 Claude MCP Tool \u4e3a\u4f8b\uff0c\u914d\u7f6e `command`: `\"uvx\"`, `args`: `[\"mcp-for-owlbear-rodeo\", \"mcp-docs-server\"]`\u3002\n - \u5ba2\u6237\u7aef\u4f1a\u81ea\u52a8\u53d1\u73b0\u5168\u90e8 `doc://owlbear/...` \u8d44\u6e90\uff0c\u5e76\u53ef\u8c03\u7528 `search_docs`/`open_doc`\u3002\n\n> \u26a0\ufe0f\u9ed8\u8ba4\u6253\u5305\u4f1a\u968f wheel \u9644\u5e26 `docs/markdown`\uff0c\u65e0\u9700\u8054\u7f51\u5373\u53ef\u5f00\u7bb1\u5373\u7528\uff1b\u82e5\u8981\u66f4\u65b0\u5185\u5bb9\uff0c\u8bf7\u8fd0\u884c\u4e0b\u65b9\u7684\u6293\u53d6\u811a\u672c\u5237\u65b0 Markdown \u518d\u91cd\u65b0\u6784\u5efa\u3002\n\n## Owlbear Rodeo \u6269\u5c55\u6587\u6863\u6293\u53d6\u5de5\u5177\u4f7f\u7528\u8bf4\u660e\n\n> \u811a\u672c\u5165\u53e3\uff1a`obr_docs_to_md.py` \n> \u76ee\u6807\uff1a\u6279\u91cf\u6293\u53d6 https://docs.owlbear.rodeo/extensions/ \u4e0b\u7684 API \u53ca Reference \u6587\u6863\uff0c\u8f6c\u6362\u4e3a\u7eaf\u6587\u672c Markdown\uff0c\u65b9\u4fbf\u540e\u7eed\u5207\u5206\u4e0e\u6ce8\u5165 MCP\u3002\n\n## \u73af\u5883\u51c6\u5907\n\n1. **Python**\uff1a\u63a8\u8350 Python 3.9 \u53ca\u4ee5\u4e0a\u7248\u672c\u3002 \n2. **\u547d\u4ee4\u884c\u4f9d\u8d56** \n - `curl`\uff1a\u7528\u4e8e\u6293\u53d6 HTML\u3002 \n - `pandoc`\uff1a\u5c06\u6e05\u6d17\u540e\u7684 HTML \u8f6c\u6362\u4e3a GitHub Flavored Markdown\u3002 \n3. **Python \u5305** \n - `lxml`\uff08\u6807\u51c6\u5e93\u4ee5\u5916\uff09 \n - `cssselect`\uff08\u672c\u4ed3\u5e93\u8fd1\u671f\u65b0\u589e\uff0c\u52a1\u5fc5\u5b89\u88c5\uff09 \n \u5b89\u88c5\u793a\u4f8b\uff1a\n ```bash\n python -m pip install lxml cssselect\n ```\n\n> \u5c0f\u8d34\u58eb\uff1a\u5728 Windows \u4e0a\u4f7f\u7528\u672c\u811a\u672c\u65f6\uff0c\u5efa\u8bae\u901a\u8fc7 Git Bash \u6216 PowerShell \u8fd0\u884c\uff1b\u786e\u4fdd `curl` \u4e0e `pandoc` \u5df2\u52a0\u5165 `PATH`\u3002\n\n## \u8f93\u51fa\u7ed3\u6784\u603b\u89c8\n\n\u9ed8\u8ba4\u8f93\u51fa\u4f4d\u4e8e `./out`\uff0c\u811a\u672c\u4f1a\u81ea\u52a8\u521b\u5efa\u5e76\u590d\u7528\u76ee\u5f55\uff1a\n\n```\nout/\n raw_html/ # \u539f\u59cb\u6293\u53d6\u7684 HTML\uff08\u6309 apis/reference \u5206\u7c7b\uff09\n cleaned_html/ # \u6e05\u6d17\u540e\u7684 HTML\uff0c\u4f9b Pandoc \u8f6c\u6362\n md/ # \u6700\u7ec8 Markdown\uff0c\u7eaf\u6587\u672c\u65e0 HTML \u6807\u7b7e\n assets/ # Pandoc \u63d0\u53d6\u51fa\u7684\u5a92\u4f53\u6587\u4ef6\uff08\u5f53\u524d\u5df2\u5168\u90e8\u5254\u9664\uff0c\u4e0d\u518d\u4f7f\u7528\uff09\n logs/\n run.log # \u9010\u6761\u5904\u7406\u65e5\u5fd7\uff08\u5317\u4eac\u65f6\u95f4\uff0c\u542b\u7f13\u5b58/\u6293\u53d6\u6807\u8bb0\uff09\n failures.txt # \u5931\u8d25\u8bb0\u5f55\uff08\u5305\u542b\u6700\u7ec8\u9519\u8bef\u4fe1\u606f\uff0c\u4fbf\u4e8e\u91cd\u8bd5\uff09\n url-map.json # \u6210\u529f/\u7f3a\u5931\u9875\u9762\u6982\u89c8 + \u5143\u6570\u636e\n```\n\n`url-map.json` \u7ed3\u6784\u793a\u4f8b\uff1a\n\n```json\n{\n \"generated_at\": \"2025-10-19T02:24:42+08:00\",\n \"timezone\": \"UTC+08:00\",\n \"output_root\": \".../out\",\n \"expected_items\": [\n {\"url\": \"...\", \"category\": \"apis\", \"slug\": \"action\"}\n ],\n \"items\": [\n {\n \"url\": \"...\",\n \"category\": \"apis\",\n \"title\": \"Action\",\n \"slug\": \"action\",\n \"raw_html\": \"raw_html/apis/action.html\",\n \"cleaned_html\": \"cleaned_html/apis/action.html\",\n \"markdown\": \"md/apis/action.md\"\n }\n ],\n \"missing_items\": []\n}\n```\n\n> `missing_items` \u975e\u7a7a\u65f6\uff0c\u8bf7\u67e5\u770b `logs/failures.txt` \u5e76\u8003\u8651\u4f7f\u7528 `--force-fetch` \u91cd\u8bd5\u3002\n\n## \u5e38\u7528\u547d\u4ee4\n\n### 1. \u5168\u91cf\u6293\u53d6\uff08\u63a8\u8350\u521d\u6b21\u6267\u884c\uff09\n\n```bash\npython obr_docs_to_md.py\n```\n\n- \u81ea\u52a8\u89e3\u6790 `sitemap.xml`\uff08\u4f18\u5148\uff09/ \u5404\u5206\u7c7b\u7d22\u5f15\u9875\uff0c\u6536\u96c6 `/extensions/apis/` \u4e0e `/extensions/reference/` \u5168\u90e8\u9875\u9762\u3002 \n- \u9ed8\u8ba4\u8f93\u51fa\u4f4d\u7f6e\uff1a`./out`\u3002\u53ef\u901a\u8fc7 `--out` \u81ea\u5b9a\u4e49\u76ee\u5f55\u3002\n\n\u6267\u884c\u7ed3\u675f\u540e\uff0c\u7ec8\u7aef\u4f1a\u8f93\u51fa\u5982\u4e0b\u6982\u89c8\uff08\u793a\u4f8b\uff09\uff1a\n\n```\n\u6210\u529f\u8f6c\u6362 42/45 \u4e2a\u9875\u9762\uff08apis:30, reference:12\uff09\uff0cMarkdown \u4f4d\u4e8e D:\\...\\out\\md\\apis\n\u4ecd\u6709\u4ee5\u4e0b\u9875\u9762\u672a\u6210\u529f\u751f\u6210 Markdown\uff1a\n- [reference] https://docs.owlbear.rodeo/extensions/reference/foo\n- [reference] https://docs.owlbear.rodeo/extensions/reference/bar\n```\n\n### 2. \u5355\u9875\u8c03\u8bd5\n\n```bash\npython obr_docs_to_md.py --single https://docs.owlbear.rodeo/extensions/reference/manifest\n```\n\n- \u4ec5\u5904\u7406\u6307\u5b9a URL\uff0c\u9002\u7528\u4e8e\u8c03\u8bd5\u6e05\u6d17\u89c4\u5219\u3002 \n- \u540c\u6837\u4f1a\u66f4\u65b0 `url-map.json`\uff0c\u8bb0\u5f55\u5f53\u524d\u8fd0\u884c\u671f\u671b/\u7f3a\u5931\u9879\u3002\n\n### 3. \u590d\u7528\u7f13\u5b58 / \u5f3a\u5236\u5237\u65b0\n\n- **\u9ed8\u8ba4\u884c\u4e3a**\uff1a\u82e5 `out/raw_html/<category>/<slug>.html` \u5b58\u5728\u4e14\u975e\u7a7a\uff0c\u811a\u672c\u76f4\u63a5\u590d\u7528\uff0c\u907f\u514d\u91cd\u590d\u8bf7\u6c42\u3002 \n- **\u5f3a\u5236\u5237\u65b0**\uff1a\u6dfb\u52a0 `--force-fetch` \u5373\u53ef\u5ffd\u7565\u7f13\u5b58\u4ece\u8fdc\u7aef\u91cd\u65b0\u6293\u53d6\u3002 \n ```bash\n python obr_docs_to_md.py --force-fetch\n ```\n\n### 4. \u5176\u4ed6\u5e38\u7528\u53c2\u6570\n\n| \u53c2\u6570 | \u8bf4\u660e | \u9ed8\u8ba4\u503c |\n| --- | --- | --- |\n| `--out PATH` | \u6307\u5b9a\u8f93\u51fa\u6839\u76ee\u5f55 | `out` |\n| `--sleep-min` | \u8fde\u7eed\u8bf7\u6c42\u7684\u6700\u5c0f\u95f4\u9694\uff08\u79d2\uff09 | `0.5` |\n| `--sleep-max` | \u8fde\u7eed\u8bf7\u6c42\u7684\u6700\u5927\u95f4\u9694\uff08\u79d2\uff09 | `1.5` |\n| `--urls-file FILE` | \u4ece\u81ea\u5b9a\u4e49\u5217\u8868\u8bfb\u53d6 URL\uff08\u6bcf\u884c\u4e00\u4e2a\uff09 | \u65e0 |\n\n> \u5efa\u8bae\u4fdd\u6301\u5408\u7406\u7684\u95f4\u9694\uff0c\u907f\u514d\u89e6\u53d1\u8fdc\u7aef\u9650\u6d41\u3002\u5373\u4f7f\u542f\u7528\u7f13\u5b58\uff0c\u89e3\u6790\u5931\u8d25\u4e5f\u4f1a\u5728\u4e0b\u4e00\u6b21\u5c1d\u8bd5\u81ea\u52a8\u91cd\u65b0\u6293\u53d6\u3002\n\n## \u8fd0\u884c\u540e\u5982\u4f55\u81ea\u68c0\n\n1. **\u547d\u4ee4\u884c\u8f93\u51fa**\uff1a\u4f18\u5148\u5173\u6ce8\u7ec8\u7aef\u6982\u89c8\uff0c\u786e\u8ba4\u6210\u529f/\u7f3a\u5931\u6570\u91cf\u3002 \n2. **`logs/failures.txt`**\uff1a\u82e5\u6709\u5931\u8d25\u6761\u76ee\uff0c\u9010\u6761\u5b9a\u4f4d\u539f\u56e0\uff08\u7f51\u7edc\u5f02\u5e38\u3001Cloudflare \u8d28\u8be2\u3001Pandoc \u8f6c\u6362\u5931\u8d25\u7b49\uff09\u3002 \n3. **`out/url-map.json`**\uff1a\u5feb\u901f\u67e5\u8be2\u751f\u6210\u7684 Markdown \u8def\u5f84\u53ca\u672a\u8986\u76d6\u9875\u9762\uff0c\u53ef\u4f9b\u540e\u7eed\u811a\u672c\u8bfb\u53d6\u3002 \n4. **Markdown \u7eaf\u6587\u672c\u6821\u9a8c**\uff1a\u811a\u672c\u5df2\u79fb\u9664\u6240\u6709 `<img>/<a>` \u7b49 HTML \u6807\u7b7e\uff0c\u4ec5\u4fdd\u7559 Markdown \u8bed\u6cd5\u3002\u53ef\u914d\u5408 `rg \"<\"` \u68c0\u67e5\u662f\u5426\u4ecd\u6709\u6f0f\u7f51\u6807\u7b7e\u3002\n\n## \u5e38\u89c1\u95ee\u9898\n\n- **Cloudflare \u9a8c\u8bc1\u5bfc\u81f4 403**\uff1a\u811a\u672c\u5df2\u5185\u7f6e\u901a\u7528 UA \u4e0e\u91cd\u8bd5\u673a\u5236\uff0c\u4f46\u82e5\u4ecd\u65e0\u6cd5\u901a\u8fc7\uff0c\u53ef\u9002\u5f53\u589e\u52a0 `--sleep-min/--sleep-max` \u95f4\u9694\u6216\u624b\u52a8\u590d\u5236 HTML \u81f3 `raw_html` \u540e\u91cd\u8dd1\u6e05\u6d17\u3002 \n- **\u672c\u5730\u6ca1\u6709\u5b89\u88c5 Pandoc**\uff1a\u8bf7\u4ece [https://pandoc.org/installing.html](https://pandoc.org/installing.html) \u4e0b\u8f7d\u5bf9\u5e94\u5e73\u53f0\u7248\u672c\uff0c\u5e76\u6dfb\u52a0\u5230 `PATH`\u3002 \n- **\u8f93\u51fa\u65f6\u95f4\u770b\u4e0d\u61c2**\uff1a\u6240\u6709\u65e5\u5fd7\u3001`url-map.json` \u90fd\u4f7f\u7528\u5317\u4eac\u65f6\u95f4\uff08UTC+08:00\uff09\uff0c\u4fbf\u4e8e\u4e0e\u672c\u5730\u6392\u67e5\u65f6\u533a\u4e00\u81f4\u3002\n\n## \u540e\u7eed\u6269\u5c55\u5efa\u8bae\n\n- \u5728 CI \u4e2d\u914d\u7f6e\u5b9a\u65f6\u4efb\u52a1\uff0c\u7ed3\u5408 `--force-fetch` \u6bcf\u65e5\u5237\u65b0\u6587\u6863\u3002 \n- \u4f9d\u636e `url-map.json` \u4e2d\u7684 `expected_items` / `missing_items` \u751f\u6210\u544a\u8b66\u62a5\u544a\uff0c\u786e\u4fdd MCP \u6570\u636e\u6e90\u968f\u7ad9\u70b9\u66f4\u65b0\u3002 \n- \u5982\u9700\u5408\u5e76 Markdown\uff0c\u53ef\u7f16\u5199\u989d\u5916\u811a\u672c\uff0c\u6839\u636e `category` \u5b57\u6bb5\u805a\u5408\u751f\u6210\u7ae0\u8282\u5316\u6587\u6863\u3002\n\n> \u5982\u679c\u540e\u7eed\u9700\u8981\u65b0\u589e\u5176\u5b83\u76ee\u5f55\uff08\u4f8b\u5982 `/extensions/tutorials/`\uff09\uff0c\u53ef\u4ee5\u53c2\u7167 `CATEGORY_CONFIGS` \u589e\u52a0\u914d\u7f6e\u9879\u5e76\u590d\u7528\u73b0\u6709\u6d41\u7a0b\u3002\n\n\n\n\u2022 \u6574\u4f53\u601d\u8def\n \n - \u4ed3\u5e93\u5f53\u524d\u53ea\u6709\u4e24\u4e2a\u6838\u5fc3\u6a21\u5757\uff1aMCP \u6587\u6863\u670d\u52a1\u5668 mcp-docs-server \u4e0e\u79bb\u7ebf\u6293 \n \u53d6\u811a\u672c obr_docs_to_md.py\uff0c\u53ef\u4ee5\u4e5f\u5e94\u8be5\u5206\u522b\u6d4b\u8bd5\uff0c\u5168\u90e8\u6d41\u7a0b\u90fd\u80fd\u5728\u672c\u5730 \n \u5b8c\u6210\uff0c\u4e0d\u9700\u8981\u5148\u53d1\u5230 PyPI\u3002pyproject.toml \u91cc\u5df2\u58f0\u660e\u5165\u53e3\u811a\u672c mcp-docs- server = \"docs_server:main\"\uff0c\u56e0\u6b64 uv run mcp-docs-server ... \u5c31 \n \u80fd\u76f4\u63a5\u542f\u52a8\u6700\u65b0\u6e90\u7801\u7248\u7684\u670d\u52a1\u7aef\uff0c\u7b49\u5230\u53d1\u5e03\u5230 PyPI \u540e\u518d\u7528 uvx mcp-for- \n owlbear-rodeo ... \u8dd1\u7ebf\u4e0a\u7248\u5373\u53ef\uff08README.md:7-41, pyproject.toml:1- \n 33\uff09\u3002 \n \n MCP \u6587\u6863\u670d\u52a1\u5668\u672c\u5730\u9a8c\u8bc1\u8def\u5f84 \n \n - \u5b89\u88c5\u4f9d\u8d56\uff1a\u9996\u6b21\u6216\u66f4\u65b0\u540e\u8fd0\u884c uv sync\uff0cuv \u4f1a\u6309 pyproject.toml \n \u628a mcp[cli]>=1.21.0 \u4e0e\u5176\u4f59\u8fd0\u884c\u65f6\uff08FastMCP \u5728\u4f9d\u8d56\u91cc\uff09\u88c5\u597d \n \uff08README.md:9-16, pyproject.toml:8-10\uff09\u3002 \n - \u76f4\u63a5\u8dd1 CLI\uff1auv run mcp-docs-server --transport stdio --log-level \n DEBUG\uff0c\u9ed8\u8ba4\u4f1a\u81ea\u52a8\u4ece\u4ed3\u5e93\u5185\u7684 docs/markdown \u626b\u63cf\u6587\u6863\u5e76\u6ce8\u518c\u6210\u8d44\u6e90\uff1b \n \u547d\u4ee4\u884c\u91cc\u53ef\u89c2\u5bdf \u201c\u5b8c\u6210\u8d44\u6e90\u6ce8\u518c: X \u7bc7\u6587\u6863\u201d \u7684\u65e5\u5fd7\u5224\u65ad\u52a0\u8f7d\u662f\u5426\u6210\u529f \n \uff08README.md:17-25, src/docs_server/server.py:1-123\uff09\u3002 \n - \u7528 MCP \u5b98\u65b9 Inspector \u505a\u5192\u70df\u6d4b\u8bd5\uff08\u4e0d\u7528\u4efb\u4f55 AI \u5ba2\u6237\u7aef\uff09\uff1a \n \n uv run mcp dev src/docs_server/server.py:main -- --transport stdio\n --log-level DEBUG \n - \u524d\u534a\u6bb5\u8ba9 mcp dev \u542f\u52a8 Inspector\uff0c-- \u540e\u7684\u53c2\u6570\u539f\u6837\u4f20\u8fdb main()\u3002 \n - Inspector \u6253\u5f00\u540e\uff1a \n 1. Resources \u2192 Refresh\uff1a\u786e\u8ba4\u5217\u8868\u91cc\u51fa\u73b0 doc://owlbear/ \n <category>/<slug>\uff0c\u6570\u91cf\u8981\u4e0e docs/markdown \u5185\u6587\u4ef6\u6570\u4e00\u81f4\uff1b \n \u82e5\u7f3a\u5c11\uff0c\u56de\u6eaf\u65e5\u5fd7\u770b\u54ea\u4e2a Markdown \u65e0\u6cd5\u89e3\u6790\u3002 \n 2. Tools \u2192 search_docs\uff1a\u8f93\u5165 viewport \u7b49\u5173\u952e\u8bcd\uff0c\u68c0\u67e5\u8fd4\u56de\u7684 \n resource_link \u662f\u5426\u80fd\u70b9\u5f00\u3002 \n 3. Tools \u2192 open_doc\uff1a\u8f93\u5165 apis/viewport \u7b49\u540d\u79f0\uff0c\u786e\u8ba4\u80fd\u6536\u5230\u6574 \u7bc7 Markdown\u3002 \n - \u4e0e Codex/Claude/VS Code Copilot \u7b49\u5ba2\u6237\u7aef\u5bf9\u63a5\uff1a\u51e1\u662f\u652f\u6301\u81ea\u5b9a \n \u4e49 MCP \u547d\u4ee4\u7684\u5ba2\u6237\u7aef\uff0c\u90fd\u53ea\u9700\u628a\u547d\u4ee4\u8bbe\u7f6e\u6210 uv run mcp-docs-server \n --transport stdio \u6216\uff08\u82e5\u5df2\u53d1\u7248\uff09uvx mcp-for-owlbear-rodeo mcp- \n docs-server --transport stdio\uff0c\u5ba2\u6237\u7aef\u5c31\u80fd\u81ea\u52a8\u53d1\u73b0 search_docs / \n open_doc \u4e24\u4e2a\u5de5\u5177\uff08README.md:17-40\uff09\u3002Codex \u8fd9\u7c7b\u57fa\u4e8e\u6807\u51c6 MCP \u7684\u4ee3 \n \u7406\u53ea\u9700\u5728\u5176\u914d\u7f6e\u91cc\u586b\u5199\u540c\u6837\u547d\u4ee4\u5373\u53ef\uff0c\u65e0\u9700\u989d\u5916\u6865\u63a5\u3002 \n - \u81ea\u52a8\u5316/\u811a\u672c\u5316\u81ea\u68c0\uff1a\u53ef\u7528\u4e0b\u8ff0\u6700\u5c0f\u811a\u672c\u786e\u8ba4\u670d\u52a1\u7aef\u5373\u5c06\u66b4\u9732\u7684\u6587\u6863\u6570\u91cf\u3001 \n \u793a\u4f8b\u6761\u76ee\u662f\u5426\u6b63\u786e\uff1b\u811a\u672c\u53ea\u8bfb DocumentStore\uff0c\u4e0d\u9700\u542f\u52a8 MCP\uff1a \n \n uv run python - <<'PY' \n \"\"\"\u5feb\u901f\u5217\u51fa\u53ef\u7528\u6587\u6863, \u65b9\u4fbf\u6bd4\u5bf9\u6570\u91cf\"\"\" \n from docs_server.doc_store import DocumentStore \n \n store = DocumentStore() \n docs = store.documents \n print(f\"\u5171\u52a0\u8f7d {len(docs)} \u7bc7\u6587\u6863, \u6839\u76ee\u5f55={store.doc_root}\") \n for record in docs[:5]: \n # \u9010\u6761\u793a\u4f8b, \u786e\u8ba4\u7c7b\u522b/URI/\u7b80\u4ecb\u662f\u5426\u7b26\u5408\u9884\u671f \n print(f\"- {record.name} -> {record.uri}\") \n PY \n \u5982\u679c\u811a\u672c\u629b\u51fa DocumentIndexEmptyError / DocumentNotFoundError\uff08\u5b9a\u4e49 \u5728 src/docs_server/exceptions.py\uff09\uff0c\u5c31\u8bf4\u660e\u6587\u6863\u76ee\u5f55\u4e0d\u5b8c\u6574\u6216\u540d\u79f0\u8f93\u5165 \u9519\u8bef\uff0c\u53ef\u636e\u6b64\u5b9a\u4f4d\uff08src/docs_server/doc_store.py:1-188\uff09\u3002 \n \n VS Code Copilot / \u5176\u4ed6\u7f16\u8f91\u5668\u8054\u8c03\u5efa\u8bae \n \n - \u76ee\u524d GitHub Copilot MCP \u96c6\u6210\u4ecd\u5728\u9010\u6b65\u653e\u51fa\uff0c\u82e5\u4f60\u6240\u5728\u7248\u672c\u5c1a\u672a\u5f00\u653e\uff0c\u53ef \u4ee5\u5148\u7528 mcp dev Inspector \u6216 Claude Desktop\uff08\u652f\u6301\u81ea\u5b9a\u4e49 MCP\uff09\u9a8c\u8bc1\uff1b \u5f85 Copilot \u652f\u6301\u540e\uff0c\u6cbf\u7528\u540c\u4e00\u547d\u4ee4\u5373\u53ef\uff0c\u65e0\u9700\u6539\u9020\u3002\u8c03\u8bd5\u65f6\u53ef\u628a --log- \n level DEBUG \u6253\u5f00\uff0c\u901a\u8fc7\u7ec8\u7aef\u65e5\u5fd7\u8ffd\u8e2a\u5ba2\u6237\u7aef\u4f55\u65f6\u53d1\u8d77 tool call\uff0c\u4fbf\u4e8e \n \u6392\u67e5\u3002 \n \n \u6587\u6863\u6293\u53d6\u811a\u672c\u6d4b\u8bd5\uff08\u786e\u4fdd\u8d44\u6e90\u4e0d\u7f3a\u5931\uff09 \n\n 1. \u57fa\u7840\u8fd0\u884c\uff1apython obr_docs_to_md.py \u4f1a\u6293\u53d6\u5b98\u7f51\u5e76\u5728 out/ \u751f \n \u6210 raw_html / cleaned_html / md / logs / url-map.json\u3002\u82e5\u53ea\u60f3 \n \u66f4\u65b0\u4ed3\u5e93\u968f\u5305\u53d1\u51fa\u7684 Markdown\uff0c\u53ef\u8dd1\u5b8c\u540e\u628a out/md/* \u8986\u76d6\u5230 docs/ \n markdown\uff08README.md:43-135\uff09\u3002 \n 2. \u5f3a\u5236\u5237\u65b0 & \u6307\u5b9a URL\uff1a \n - \u7f51\u7edc\u72b6\u6001\u826f\u597d\u4f46\u6000\u7591\u7f13\u5b58\u8fc7\u671f\uff1apython obr_docs_to_md.py --force- \n fetch\u3002 \n - \u5355\u9875\u8c03\u8bd5\uff1apython obr_docs_to_md.py --single \n <URL>\uff08README.md:109-143\uff09\u3002 \n 3. \u9a8c\u8bc1\u662f\u5426\u201c\u6f0f\u6587\u6863\u201d\uff1a \n - \u67e5\u770b out/url-map.json\uff0cmissing_items \u975e\u7a7a\u5c31\u4ee3\u8868\u6709\u6587\u6863\u6ca1\u8f6c\u6210 \n \u529f\uff0c\u9700\u7ed3\u5408 logs/failures.txt \u6392\u67e5\uff08README.md:64-161\uff09\u3002 \n - \u53ef\u914d\u5408 rg \"<\" out/md \u786e\u8ba4 Markdown \u662f\u5426\u4ecd\u6df7\u5165 HTML\uff0c\u82e5\u547d\u4e2d\u5219\u8868 \u793a\u6e05\u6d17\u89c4\u5219\u9700\u8c03\u6574\uff08README.md:155-161\uff09\u3002 \n 4. \u56de\u586b\u5230 MCP\uff1a\u5f53 url-map.json \u4e2d missing_items \u4e3a\u7a7a\u540e\uff0c\u628a\u6700\u65b0 \n Markdown \u8986\u76d6\u5230 docs/markdown\uff0c\u518d\u6309\u4e0a\u8282\u6b65\u9aa4\u91cd\u542f mcp-docs-server \n \u9a8c\u8bc1\u8d44\u6e90\u6570\u662f\u5426\u540c\u6b65\u589e\u52a0\uff1bDocumentStore \u4f1a\u5728\u65e5\u5fd7\u91cc\u6253\u5370\u201c\u4f7f\u7528\u6587\u6863 \n \u76ee\u5f55: ...\u201d\uff0c\u53ef\u53cc\u91cd\u786e\u8ba4\u6307\u5411\u7684\u662f\u4f60\u521a\u66f4\u65b0\u7684\u76ee\u5f55\uff08src/docs_server/ \n doc_store.py:70-142\uff09\u3002 \n \n \u201c\u521d\u6b65\u624b\u52a8\u6d4b\u8bd5\u201dChecklist\uff08\u65b0\u624b\u53cb\u597d\uff09 \n \n 1. uv sync \u2192 uv run mcp-docs-server --transport stdio --log-level \n DEBUG\uff08\u670d\u52a1\u5668\u80fd\u542f\u52a8\uff0c\u65e5\u5fd7\u91cc\u6709\u201c\u5b8c\u6210\u8d44\u6e90\u6ce8\u518c\u201d\uff09\u3002 \n 2. \u53e6\u5f00\u7ec8\u7aef\u8dd1 uv run mcp dev src/docs_server/server.py:main -- \n --transport stdio\uff0c\u5728 Inspector \u91cc\uff1a \n - Resources \u663e\u793a\u7684\u6570\u91cf = docs/markdown \u5b9e\u9645 Markdown \u6570\uff08\u53ef\u7528 rg --files docs/markdown | wc -l \u5bf9\u6bd4\uff09\u3002 \n - search_docs \u8f93\u5165\u51b7\u95e8/\u70ed\u95e8\u5173\u952e\u8bcd\u5404\u4e00\u6b21\uff0c\u786e\u4fdd\u6709\u6709/\u65e0\u547d\u4e2d\u4e24\u79cd\u60c5\u51b5 \u90fd\u80fd\u5f97\u5230\u5408\u7406\u6587\u672c\u63d0\u793a\u3002",
"bugtrack_url": null,
"license": null,
"summary": "Owlbear Rodeo \u6587\u6863\u7684 MCP \u670d\u52a1\u7aef, \u652f\u6301\u641c\u7d22\u4e0e\u8d44\u6e90\u8bfb\u53d6",
"version": "0.1.0",
"project_urls": null,
"split_keywords": [
"documentation",
" mcp",
" owlbear"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "50e71b300c434b576b5d28a08120500f09f5fcc2122efc21933de8149e8e61bd",
"md5": "cb13fba64c64a575aa3abf54d207ad62",
"sha256": "fa44ddc5bd17af334cfa228a1f5395258ec0fcd68e88e8ff1d6b5cd1de0386fe"
},
"downloads": -1,
"filename": "mcp_for_owlbear_rodeo-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cb13fba64c64a575aa3abf54d207ad62",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 73018,
"upload_time": "2025-11-10T12:38:05",
"upload_time_iso_8601": "2025-11-10T12:38:05.042946Z",
"url": "https://files.pythonhosted.org/packages/50/e7/1b300c434b576b5d28a08120500f09f5fcc2122efc21933de8149e8e61bd/mcp_for_owlbear_rodeo-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5dbe17d667959cecba58559717c4c6bfcd07a3e7de4fbdb72f2b29f246e6f9be",
"md5": "1a9ea42db918e4dd1642d1d21a06a991",
"sha256": "3cebc278729cebe437d1fef00b4595b0e9015f6e9dde0afa399f9d7801215b98"
},
"downloads": -1,
"filename": "mcp_for_owlbear_rodeo-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "1a9ea42db918e4dd1642d1d21a06a991",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 47423,
"upload_time": "2025-11-10T12:38:07",
"upload_time_iso_8601": "2025-11-10T12:38:07.575058Z",
"url": "https://files.pythonhosted.org/packages/5d/be/17d667959cecba58559717c4c6bfcd07a3e7de4fbdb72f2b29f246e6f9be/mcp_for_owlbear_rodeo-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-10 12:38:07",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "mcp-for-owlbear-rodeo"
}