使用说明
文档查询
一个文档搜索和索引平台,允许您抓取、索引和语义搜索任何文档网站。包括一个MCP(模型上下文协议)服务器,用于与Cursor等AI编码助手集成。
概述
Docs Hound解决了让AI代理访问外部文档的问题。Docs Hound允许您:
- 索引任何文档网站 -添加URL,预览发现的页面,然后建立索引
- 语义搜索 -使用自然语言查询查找相关内容
- 与文档聊天 -提问并获得源引用的答案
- AI代理集成 -将文档暴露给Cursor和其他MCP兼容代理
特性
| 特性 | 描述 |
|---|---|
| 两阶段索引 | 在索引之前预览发现的URL以确保质量 |
| URL筛选器 | 基于正则表达式的包含/排除模式用于版本控制 |
| 软404检测 | 自动过滤掉404类内容的页面 |
| 1000页限制 | Discovery限制在1000页以内,以防止失控的抓取 |
| 语义搜索 | 基于OpenAI嵌入的矢量搜索 |
| 源过滤 | 搜索所有文档或按特定文档站点筛选 |
| 流媒体聊天 | 具有文档上下文的实时AI响应 |
| MCP 服务器 | AI代理工具的标准兼容端点 |
| 状态轮询 | 发现和索引期间的实时更新 |
建筑学
系统概述
┌─────────────────────────────────────────────────────────────────┐
│ Docs Hound │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Web UI │ │ MCP Server │ │ Chat API │ │
│ │ (Next.js) │ │ (stdio) │ │ (streaming) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └──────────────────┼──────────────────┘ │
│ │ │
│ ┌────────┴────────┐ │
│ │ Search Tool │ │
│ └────────┬────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ │ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ Crawler │ │ Upstash │ │ Upstash │ │
│ │ (scraper) │ │ Vector │ │ Redis │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
数据流
User adds URL → Discovery Crawl → URL Review → Full Index → Searchable
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
pending → discovering → discovered → indexing → indexed
存储策略
Docs Hound使用 Uptash 满足所有存储需求:
| 存储 | 目的 | 关键模式 |
|---|---|---|
| 瑞迪斯 | 网站注册表、元数据、发现的URL | site:{domain}, site:{domain}:discovered |
| 矢量 | 语义搜索的文档嵌入 | 单索引 source 元数据过滤器 |
为什么使用单个矢量索引?
- 统一的跨文档搜索
- 更简单的基础设施(一个Uptash Vector数据库)
- 免费套餐成本更低
- 需要时通过元数据进行源过滤
项目结构
docs-hound/
├── apps/
│ └── web/ # Next.js 16 + React 19 web application
│ ├── src/
│ │ ├── app/
│ │ │ ├── page.tsx # Dashboard - list all sites
│ │ │ ├── chat/ # Chat interface
│ │ │ ├── settings/ # MCP configuration
│ │ │ ├── sites/
│ │ │ │ ├── new/ # Add new site form
│ │ │ │ └── [domain]/ # Site detail with workflow
│ │ │ └── api/
│ │ │ ├── chat/ # Streaming chat endpoint
│ │ │ ├── discover/ # Start preview crawl
│ │ │ ├── index/ # Start full indexing
│ │ │ └── sites/ # Site CRUD operations
│ │ └── components/
│ │ ├── ChatInterface.tsx
│ │ ├── DeleteSiteButton.tsx
│ │ ├── DiscoveredUrlsList.tsx
│ │ ├── IndexedPagesList.tsx
│ │ └── SiteStatusPoller.tsx
│ └── package.json
│
├── packages/
│ ├── agents/
│ │ └── chat/ # Chat agent with tool integration
│ │ └── src/index.ts # runChatAgent() with searchDocsTool
│ │
│ ├── doc-scraper/ # Web crawling and content extraction
│ │ └── src/
│ │ ├── lib/
│ │ │ ├── crawler.ts # URL discovery with depth limiting
│ │ │ └── smart-scraper.ts # Content extraction (Readability + Turndown)
│ │ └── storage/
│ │ └── upstash.ts # Vector storage with embeddings
│ │
│ ├── shared/
│ │ └── db/ # Site registry (Upstash Redis)
│ │ └── src/
│ │ ├── redis-client.ts # SiteRegistry class
│ │ └── types.ts # Site, SiteMetadata types
│ │
│ └── tools/
│ └── docs-search/ # Semantic search tool
│ └── src/
│ ├── index.ts # searchDocsTool definition
│ └── lib/
│ └── search-client.ts # Upstash Vector query
│
├── mcp-server/ # MCP server for Cursor integration
│ └── src/index.ts # search_docs, list_sources, get_source_info
│
├── turbo.json # Turborepo task configuration
├── pnpm-workspace.yaml # pnpm workspace definition
└── package.json # Root scripts and dependencies
入门指南
先决条件
- Node.js 20+ -Next.js 16需要
- pnpm 9+ -包管理器(工作区)
- Uptash账户 -适用于Redis和Vector数据库
- OpenAI API密钥 -用于嵌入和聊天
安装
# Clone the repository
git clone <repository-url>
cd docs-hound
# Install dependencies
pnpm install
# Set up environment variables (choose one method):
# Method 1: Pull from Vercel (if you have a linked Vercel project)
pnpm env:pull
# Method 2: Copy from template and edit manually
cp env.template apps/web/.env.local
# Edit apps/web/.env.local with your credentials
# Start development server
pnpm dev
环境变量
创造一个 apps/web/.env.local 文件包含以下内容:
# OpenAI - Required for embeddings and chat
OPENAI_API_KEY=sk-...
# Upstash Vector - Single index for all documentation
UPSTASH_VECTOR_REST_URL=https://...upstash.io
UPSTASH_VECTOR_REST_TOKEN=...
# Upstash Redis - Site registry and metadata
# For local dev, use UPSTASH_REDIS_* naming
# Vercel uses KV_REST_API_URL and KV_REST_API_TOKEN (code supports both)
UPSTASH_REDIS_REST_URL=https://...upstash.io
UPSTASH_REDIS_REST_TOKEN=...
# QStash - Optional, for background job processing
QSTASH_TOKEN=...
# Security - Optional
CRON_SECRET=...
UI_PASSWORD=...
MCP_API_KEY=...
重要:在这个monorepo中
.env.local文件必须放置在apps/web/.env.local(不在根目录中),因此Next.js可以找到它。
从Vercel中提取环境变量
如果您有一个链接到此存储库的Vercel项目,则可以自动提取环境变量:
# From the project root
pnpm env:pull
这运行 vercel env pull --yes apps/web/.env.local 其中:
- 连接到您的Vercel项目
- 下载开发环境的所有环境变量
- 将它们保存到
apps/web/.env.local(Next.js的正确位置)
先决条件 env:pull:
- 全局安装的Vercel CLI:
npm i -g vercel - 已通过Vercel认证:
vercel login - 与Vercel关联的项目:
vercel link(或至少部署一次)
Vercel部署注意事项:使用Vercel Upstash集成时,Vercel会自动设置:
- Redis:
KV_REST_API_URL,KV_REST_API_TOKEN(和其他KV_*变量)- 矢量:
UPSTASH_VECTOR_REST_URL,UPSTASH_VECTOR_REST_TOKEN- 质量标准:
QSTASH_URL,QSTASH_TOKEN,QSTASH_CURRENT_SIGNING_KEY,QSTASH_NEXT_SIGNING_KEY该代码同时支持Vercel
KV_*命名和UPSTASH_REDIS_*Redis的命名。
创造高端资源
-
创建上行向量索引:
- 首选 Uptash控制台
- 创建新的矢量数据库
- 选择 1536个维度 (适用于OpenAI嵌入)
- 选择 余弦 相似性度量
- 复制REST URL和令牌
-
创建Uptash Redis数据库:
- 在Upstash控制台中,创建一个新的Redis数据库
- 复制REST URL和令牌
使用指南
添加文档站点
- 导航到仪表板 -打开
http://localhost:3000 - 点击“添加网站” -输入文档URL(例如。,
https://docs.example.com) - 查看网站详细信息 -确认名称、描述和基本URL
- 配置URL筛选器(可选) -添加正则表达式模式来控制抓取哪些页面:
- 包括图案:仅抓取与这些模式匹配的URL(例如,对于特定版本)
- 排除模式:跳过与这些模式匹配的URL
- 看 URL筛选器指南 详细示例
- 开始发现 -单击“添加并开始发现”开始爬网
两阶段索引工作流程
索引过程有两个阶段来确保质量:
第一阶段:发现(预览爬行)
当你开始发现:
- 爬虫访问基本URL
- 它遵循内部链接来发现页面
- 已应用URL筛选器 如果已配置(包括/排除模式)
- 最多1000页 被发现(以防止失控的爬行)
- 最大深度5 从基本URL开始的级别
- 仅发现同一域上的URL
站点状态更改: pending → discovering → discovered
第二阶段:回顾与索引
发现完成后:
- 您可以看到已发现的URL列表
- 检查并确认页面看起来正确
- 单击“开始索引”开始完整内容提取
- 每个页面都被抓取、转换为markdown并嵌入
站点状态更改: discovered → indexing → indexed
站点状态状态
| 状态 | 描述 | 下一步操作 |
|---|---|---|
pending |
网站已添加,可供查找 | 开始查找 |
discovering |
正在爬行 | 等待完成 |
discovered |
已找到URL,正在等待审核 | 审核和索引 |
indexing |
正在提取/嵌入内容 | 等待完成 |
indexed |
准备搜索 | 聊天或重新发现 |
error |
出现故障 | 检查日志,重试 |
与文档聊天
- 导航到聊天 -点击“与文档聊天”或转到
/chat - 选择来源 (可选)-筛选到特定的文档站点
- 提出问题 -键入自然语言问题
- 获取答案 -AI搜索文档并综合响应
使用带有游标的MCP服务器
MCP服务器允许Cursor(和其他MCP兼容代理)搜索您的索引文档。它可以在两种模式下运行:
- 本地模式(stdio) -通过命令行在本地运行(建议用于开发)
- 托管模式(HTTP) -在Vercel上作为API端点运行(建议用于生产/共享使用)
本地MCP服务器配置
添加到光标设置(.cursor/mcp.json 或通过设置):
{
"mcpServers": {
"docs-hound-local": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/docs-hound/mcp-server/src/index.ts"],
"cwd": "/absolute/path/to/docs-hound",
"env": {
"OPENAI_API_KEY": "your-key",
"KV_REST_API_URL": "your-redis-url",
"KV_REST_API_TOKEN": "your-redis-token",
"UPSTASH_VECTOR_REST_URL": "your-vector-url",
"UPSTASH_VECTOR_REST_TOKEN": "your-vector-token"
}
}
}
}
备注:
- 使用 绝对路径 对两者
cwd并且在args(例如。,/Users/you/Projects/docs-hound/...)- 使用Vercel时,从Vercel环境变量中复制这些确切的变量名称和值
- 对于本地开发,您可以使用
UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN而不是KV_*名称(代码支持两者)- MCP服务器自动设置
MCP_MODE=true抑制信息日志
托管MCP服务器配置
如果您已部署到Vercel,则可以使用托管的MCP端点:
- 生成API密钥:
openssl rand -base64 32
-
添加到Vercel:
- 转到“设置”→ 环境变量
- 添加
MCP_API_KEY使用您生成的密钥 - 重新部署
-
在游标中配置:
{
"mcpServers": {
"docs-hound-hosted": {
"url": "https://your-app.vercel.app/api/mcp",
"headers": {
"Authorization": "Bearer your-mcp-api-key-here"
}
}
}
}
您可以同时配置本地服务器和托管服务器。 看 docs/HOSTED_MCP_SERVER.md 有关详细的设置说明。
可用的MCP工具
本地和托管的MCP服务器都提供相同的工具:
| 工具 | 说明 | 参数 |
|---|---|---|
search_docs |
跨文档的语义搜索 | query (字符串), source (可选字符串), limit (可选编号) |
list_sources |
列出所有索引文档网站 | 无 |
get_source_info |
获取特定来源的详细信息 | domain (字符串) |
游标用法示例
配置后,您可以询问Cursor:
“搜索文档以了解如何配置身份验证”
光标将使用 search_docs 工具来查找相关内容。
API 参考
REST端点
网站API
GET /api/sites # List all sites
POST /api/sites # Add new site
GET /api/sites/[domain] # Get site details
DELETE /api/sites/[domain] # Delete site and its data
发现API
POST /api/discover # Start discovery crawl
Body: { domain: string }
API索引
POST /api/index # Start full indexing
Body: { domain: string }
聊天API
POST /api/chat # Streaming chat
Body: {
messages: Array<{role: 'user'|'assistant', content: string}>,
selectedDomain?: string
}
MCP API
POST /api/mcp # Hosted MCP server endpoint
Headers: Authorization: Bearer <MCP_API_KEY>
Body: JSON-RPC message (standard MCP protocol)
包API
@hound docs/共享数据库
import {
getSiteRegistry,
type Site,
type SiteMetadata,
} from '@docs-hound/shared-db'
const registry = getSiteRegistry()
// Site operations
await registry.addSite(domain, metadata)
await registry.getSite(domain)
await registry.updateSite(domain, updates)
await registry.deleteSite(domain)
await registry.listSites()
// Discovery operations
await registry.setDiscoveredUrls(domain, urls)
await registry.getDiscoveredUrls(domain)
// Indexing operations
await registry.addIndexedPage(domain, url)
await registry.getIndexedPages(domain)
@hound docs/doc scraper
import {
Crawler,
scrapePageToMarkdown,
UpstashDocStorage,
} from '@docs-hound/doc-scraper'
// Discover URLs
const crawler = new Crawler({ maxPages: 1000, maxDepth: 2 })
const urls = await crawler.discoverUrls('https://docs.example.com')
// Scrape content
const { markdown, title } = await scrapePageToMarkdown(url)
// Store in vector database
const storage = new UpstashDocStorage()
await storage.upsertDocument({
url,
content: markdown,
title,
source: 'docs.example.com',
})
@hound docs/tool文档搜索
import { searchDocsTool, searchUpstash } from '@docs-hound/tool-docs-search'
// Direct search
const results = await searchUpstash({
query: 'authentication setup',
source: 'docs.example.com', // optional
topK: 5,
})
// As AI SDK tool
import { generateText } from 'ai'
const result = await generateText({
model: openai('gpt-4o'),
tools: { searchDocs: searchDocsTool },
prompt: 'Find information about authentication',
})
@docs/agent聊天
import { runChatAgent, type ChatMessage } from '@docs-hound/agent-chat'
const response = await runChatAgent({
messages: [{ role: 'user', content: 'How do I authenticate?' }],
source: 'docs.example.com', // optional filter
})
// Returns a streaming Response
发展
脚本
| 脚本 | 描述 |
|---|---|
pnpm dev |
在开发模式下启动所有软件包 |
pnpm build |
构建所有生产包 |
pnpm typecheck |
运行TypeScript类型检查 |
pnpm lint |
运行ESLint时无警告策略 |
pnpm format |
使用Prettier格式化代码 |
pnpm format:check |
检查代码格式 |
pnpm test |
使用Vitest运行测试 |
质量检查
提交之前,运行所有检查:
pnpm typecheck && pnpm lint && pnpm format:check
这是由Husky预提交钩子执行的。
添加新包
-
创建包目录:
mkdir -p packages/tools/my-tool cd packages/tools/my-tool -
创建
package.json:{ "name": "@docs-hound/tool-my-tool", "version": "0.1.0", "type": "module", "private": true, "main": "./src/index.ts", "exports": { ".": "./src/index.ts" }, "scripts": { "lint": "eslint . --max-warnings=0", "typecheck": "tsc --noEmit", "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"", "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"", "test": "vitest run" } } -
创建
tsconfig.json和eslint.config.js(从现有包中复制) -
安装依赖项:
cd ../../../ pnpm install
传统提交
使用常规提交消息:
feat(web): add site deletion confirmation dialog
fix(scraper): handle timeout errors gracefully
docs: update MCP configuration instructions
chore(deps): update ai-sdk to v6.0.4
故障排除
常见问题
构建过程中“缺少环境变量”
构建过程运行需要环境变量的服务器组件。解决:
- 确保
.env.local存在所有必需的变量 - 对于CI/CD,在管道中设置环境变量
发现页面太少
- 检查基本URL是否正确(尝试添加
/docs或/documentation) - 确保网站不需要身份验证
- 某些网站使用JavaScript渲染(目前不支持)
聊天返回“未找到相关文档”
- 验证站点是否已完全索引(状态=
indexed) - 检查Uptash Vector数据库是否有文档
- 尝试更具体或不同的查询
MCP服务器未连接
对于本地MCP服务器:
- 验证路径
mcp-server/src/index.ts正确并使用绝对路径 - 检查MCP配置中是否设置了所有环境变量
- 查看Cursor的MCP日志以获取错误消息
- 更新配置后重新启动Cursor
对于托管MCP服务器:
- 验证
MCP_API_KEY在Vercel中设置,并与您的Cursor配置匹配 - 检查URL是否正确,包括
/api/mcp - 确保在添加环境变量后重新部署
- 检查Vercel函数日志是否有错误
调试模式
通过设置启用详细日志记录:
DEBUG=docs-hound:*
技术栈
| 层 | 技术 |
|---|---|
| 前端 | Next.js 16、React 19、Mantine UI |
| 后端 | Next.js API路由、服务器组件 |
| 数据库 | Uptash Redis(元数据),Uptash Vector(嵌入) |
| 人工智能 | OpenAI GPT-4o(聊天),OpenAI嵌入(搜索) |
| 主控程序 | @modelcontextprotocol/sdk |
| 构建 | Turborepo、pnpm工作区 |
| 质量 | TypeScript、ESLint、Prettier、Husky |
许可证
私人-仅供内部使用
