文档搜索索引平台

Docs Hound是一个文档搜索和索引平台,允许用户抓取、索引和语义搜索任何文档站点,并集成AI编码助手如Cursor。

  • by appgenie-admin
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 appgenie-admin/docs-hound

使用说明

文档查询

一个文档搜索和索引平台,允许您抓取、索引和语义搜索任何文档网站。包括一个MCP(模型上下文协议)服务器,用于与Cursor等AI编码助手集成。

概述

Docs Hound解决了让AI代理访问外部文档的问题。Docs Hound允许您:

  1. 索引任何文档网站 -添加URL,预览发现的页面,然后建立索引
  2. 语义搜索 -使用自然语言查询查找相关内容
  3. 与文档聊天 -提问并获得源引用的答案
  4. 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 其中:

  1. 连接到您的Vercel项目
  2. 下载开发环境的所有环境变量
  3. 将它们保存到 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的命名。

创造高端资源

  1. 创建上行向量索引:

    • 首选 Uptash控制台
    • 创建新的矢量数据库
    • 选择 1536个维度 (适用于OpenAI嵌入)
    • 选择 余弦 相似性度量
    • 复制REST URL和令牌
  2. 创建Uptash Redis数据库:

    • 在Upstash控制台中,创建一个新的Redis数据库
    • 复制REST URL和令牌

使用指南

添加文档站点

  1. 导航到仪表板 -打开 http://localhost:3000
  2. 点击“添加网站” -输入文档URL(例如。, https://docs.example.com)
  3. 查看网站详细信息 -确认名称、描述和基本URL
  4. 配置URL筛选器(可选) -添加正则表达式模式来控制抓取哪些页面:
    • 包括图案:仅抓取与这些模式匹配的URL(例如,对于特定版本)
    • 排除模式:跳过与这些模式匹配的URL
    • 看 URL筛选器指南 详细示例
  5. 开始发现 -单击“添加并开始发现”开始爬网

两阶段索引工作流程

索引过程有两个阶段来确保质量:

第一阶段:发现(预览爬行)

当你开始发现:

  • 爬虫访问基本URL
  • 它遵循内部链接来发现页面
  • 已应用URL筛选器 如果已配置(包括/排除模式)
  • 最多1000页 被发现(以防止失控的爬行)
  • 最大深度5 从基本URL开始的级别
  • 仅发现同一域上的URL

站点状态更改: pending → discovering → discovered

第二阶段:回顾与索引

发现完成后:

  • 您可以看到已发现的URL列表
  • 检查并确认页面看起来正确
  • 单击“开始索引”开始完整内容提取
  • 每个页面都被抓取、转换为markdown并嵌入

站点状态更改: discovered → indexing → indexed

站点状态状态

状态 描述 下一步操作
pending 网站已添加,可供查找 开始查找
discovering 正在爬行 等待完成
discovered 已找到URL,正在等待审核 审核和索引
indexing 正在提取/嵌入内容 等待完成
indexed 准备搜索 聊天或重新发现
error 出现故障 检查日志,重试

与文档聊天

  1. 导航到聊天 -点击“与文档聊天”或转到 /chat
  2. 选择来源 (可选)-筛选到特定的文档站点
  3. 提出问题 -键入自然语言问题
  4. 获取答案 -AI搜索文档并综合响应

使用带有游标的MCP服务器

MCP服务器允许Cursor(和其他MCP兼容代理)搜索您的索引文档。它可以在两种模式下运行:

  1. 本地模式(stdio) -通过命令行在本地运行(建议用于开发)
  2. 托管模式(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端点:

  1. 生成API密钥:
openssl rand -base64 32
  1. 添加到Vercel:

    • 转到“设置”→ 环境变量
    • 添加 MCP_API_KEY 使用您生成的密钥
    • 重新部署
  2. 在游标中配置:

{
  "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预提交钩子执行的。

添加新包

  1. 创建包目录:

    mkdir -p packages/tools/my-tool
    cd packages/tools/my-tool
    
  2. 创建 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"
      }
    }
    
  3. 创建 tsconfig.json 和 eslint.config.js (从现有包中复制)

  4. 安装依赖项:

    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

许可证

私人-仅供内部使用