# Crates Docs MCP 服务器 [![Crates.io](https://img.shields.io/crates/v/crates-docs.svg)](https://crates.io/crates/crates-docs) [![Documentation](https://docs.rs/crates-docs/badge.svg)](https://docs.rs/crates-docs) [![Docker](https://img.shields.io/docker/v/kingingwang/crates-docs/latest?label=docker)](https://hub.docker.com/r/kingingwang/crates-docs) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://github.com/KingingWang/crates-docs/workflows/CI/badge.svg)](https://github.com/KingingWang/crates-docs/actions) [![codecov](https://codecov.io/gh/kingingwang/crates-docs/branch/main/graph/badge.svg)](https://codecov.io/gh/kingingwang/crates-docs) [![GitHub stars](https://img.shields.io/github/stars/KingingWang/crates-docs?style=social)](https://github.com/KingingWang/crates-docs/stargazers) 一个高性能的 Rust crate 文档查询 MCP 服务器,支持多种传输协议。 ## 特性 - 🚀 **高性能**: 异步 Rust + TinyLFU/TTL 内存缓存,支持按条目 TTL,可选 Redis 扩展 - 📦 **多架构 Docker 镜像**: 支持 `linux/amd64` 和 `linux/arm64` - 🔧 **多种传输协议**: Stdio、HTTP (Streamable HTTP)、SSE、Hybrid - 📚 **完整文档查询**: crate 搜索、文档查找、特定项目查询 - 🛡️ **安全可靠**: 速率限制、连接池、请求验证 - 📊 **健康监控**: 内置健康检查和性能监控 - 🏗️ **模块化架构**: 清晰的模块划分,易于扩展和维护 - 🔄 **HTTP 重试机制**: 可配置的 HTTP 客户端重试逻辑,提高外部服务调用可靠性 - 📊 **Prometheus 指标**: 内置指标监控支持,便于运维观测 - ⏱️ **细粒度缓存 TTL**: 为 crate 文档、项目文档、搜索结果提供独立的 TTL 配置 ## 架构图 ### 系统架构 ```mermaid graph TB subgraph "MCP 客户端" Client[Claude/Cursor/Windsurf] end subgraph "传输层" Stdio[Stdio 传输] HTTP[HTTP 传输] SSE[SSE 传输] end subgraph "Crates Docs MCP 服务器" Server[CratesDocsServer] Handler[CratesDocsHandler] Registry[ToolRegistry] subgraph "工具层" LookupCrate[lookup_crate] SearchCrates[search_crates] LookupItem[lookup_item] HealthCheck[health_check] end subgraph "服务层" DocService[DocService] HttpClient[HTTP Client] end subgraph "缓存层" MemoryCache[MemoryCache] RedisCache[RedisCache] DocCache[DocCache] end end subgraph "外部服务" DocsRs[docs.rs] CratesIo[crates.io] end Client --> Stdio Client --> HTTP Client --> SSE Stdio --> Server HTTP --> Server SSE --> Server Server --> Handler Handler --> Registry Registry --> LookupCrate Registry --> SearchCrates Registry --> LookupItem Registry --> HealthCheck LookupCrate --> DocService SearchCrates --> DocService LookupItem --> DocService HealthCheck --> HttpClient DocService --> HttpClient DocService --> DocCache DocCache --> MemoryCache DocCache --> RedisCache HttpClient --> DocsRs HttpClient --> CratesIo ``` ### 数据流 ```mermaid sequenceDiagram participant Client as MCP 客户端 participant Server as CratesDocsServer participant Handler as CratesDocsHandler participant Tool as 工具实现 participant Cache as DocCache participant External as 外部服务 Client->>Server: MCP 请求 Server->>Handler: 路由请求 Handler->>Tool: 执行工具 alt 缓存命中 Tool->>Cache: 查询缓存 Cache-->>Tool: 返回缓存数据 else 缓存未命中 Tool->>Cache: 查询缓存 Cache-->>Tool: 未命中 Tool->>External: HTTP 请求 External-->>Tool: 返回数据 Tool->>Cache: 写入缓存 end Tool-->>Handler: 返回结果 Handler-->>Server: 格式化响应 Server-->>Client: MCP 响应 ``` ## 快速开始 ### 使用 Docker(推荐) ```bash # 从 Docker Hub 拉取镜像 docker pull kingingwang/crates-docs:latest # 运行容器(官方镜像内置配置默认监听 0.0.0.0:8080) docker run -d --name crates-docs -p 8080:8080 kingingwang/crates-docs:latest # 使用自定义配置 docker run -d --name crates-docs -p 8080:8080 \ -v $(pwd)/config.toml:/app/config.toml:ro \ kingingwang/crates-docs:latest ``` ### Docker Compose ```yaml version: '3.8' services: crates-docs: image: kingingwang/crates-docs:latest ports: - "8080:8080" environment: CRATES_DOCS_HOST: 0.0.0.0 CRATES_DOCS_PORT: 8080 CRATES_DOCS_TRANSPORT_MODE: hybrid volumes: - ./config.toml:/app/config.toml:ro - ./logs:/app/logs restart: unless-stopped ``` ```bash docker compose up -d ``` ### 从源码构建 ```bash git clone https://github.com/KingingWang/crates-docs.git cd crates-docs cargo build --release ./target/release/crates-docs serve ``` ### 从 crates.io 安装 ```bash cargo install crates-docs crates-docs serve ``` ## MCP 客户端集成 ### Claude Desktop 编辑配置文件: - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` - **Linux**: `~/.config/Claude/claude_desktop_config.json` ```json { "mcpServers": { "crates-docs": { "command": "/path/to/crates-docs", "args": ["serve", "--mode", "stdio"] } } } ``` ### Cursor 编辑 `~/.cursor/mcp.json`: ```json { "mcpServers": { "crates-docs": { "command": "/path/to/crates-docs", "args": ["serve", "--mode", "stdio"] } } } ``` ### Windsurf 编辑 `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "crates-docs": { "command": "/path/to/crates-docs", "args": ["serve", "--mode", "stdio"] } } } ``` ### Cherry Studio 1. 打开 Cherry Studio 设置 2. 找到 `MCP 服务器` 选项 3. 点击 `添加服务器` 4. 填写参数: | 字段 | 值 | |------|------| | 名称 | `crates-docs` | | 类型 | `STDIO` | | 命令 | `/path/to/crates-docs` | | 参数1 | `serve` | | 参数2 | `--mode` | | 参数3 | `stdio` | 5. 点击保存 > **注意**:将 `/path/to/crates-docs` 替换为实际的可执行文件路径。 ### HTTP 模式 适合远程访问或网络服务: ```bash crates-docs serve --mode hybrid --host 0.0.0.0 --port 8080 ``` 客户端配置: ```json { "mcpServers": { "crates-docs": { "url": "http://your-server:8080/mcp" } } } ``` ## MCP 工具 ### 1. lookup_crate - 查找 Crate 文档 从 docs.rs 获取完整文档。 | 参数 | 类型 | 必需 | 描述 | |------|------|------|------| | `crate_name` | string | ✅ | Crate 名称,如 `serde`、`tokio` | | `version` | string | ❌ | 版本号,默认最新 | | `format` | string | ❌ | 输出格式:`markdown`(默认)、`text`、`html` | ```json { "crate_name": "serde" } { "crate_name": "tokio", "version": "1.35.0" } ``` ### 2. search_crates - 搜索 Crate 从 crates.io 搜索 Rust crate,支持按相关性、总下载量、近期下载热度、最近更新时间和最新发布进行排序,适合做 crate 发现、选型和横向比较。 | 参数 | 类型 | 必需 | 描述 | |------|------|------|------| | `query` | string | ✅ | 搜索关键词 | | `limit` | number | ❌ | 结果数量(1-100),默认 10 | | `sort` | string | ❌ | 排序方式,支持 `relevance`(默认)、`downloads`、`recent-downloads`、`recent-updates`、`new` | | `format` | string | ❌ | 输出格式:`markdown`、`text`、`json` | **排序建议** - `relevance`:优先返回与关键词最相关的结果,适合通用搜索。 - `downloads`:按累计下载量排序,适合优先看生态里最常用、最成熟的 crate。 - `recent-downloads`:按近期下载热度排序,适合观察最近更活跃或更受关注的项目。 - `recent-updates`:按最近更新时间排序,适合关注仍在持续维护的 crate。 - `new`:按发布时间排序,适合探索新发布项目。 ```json { "query": "web framework", "limit": 5, "sort": "downloads" } { "query": "mcp", "sort": "recent-downloads", "format": "json" } ``` ### 3. lookup_item - 查找特定项目 查找 crate 中的特定类型、函数或模块。 | 参数 | 类型 | 必需 | 描述 | |------|------|------|------| | `crate_name` | string | ✅ | Crate 名称 | | `item_path` | string | ✅ | 项目路径,如 `serde::Serialize` | | `version` | string | ❌ | 版本号 | | `format` | string | ❌ | 输出格式 | ```json { "crate_name": "serde", "item_path": "serde::Serialize" } { "crate_name": "tokio", "item_path": "tokio::runtime::Runtime" } ``` ### 4. health_check - 健康检查 检查服务器和外部服务状态。 | 参数 | 类型 | 必需 | 描述 | |------|------|------|------| | `check_type` | string | ❌ | `all`、`external`、`internal`、`docs_rs`、`crates_io` | | `verbose` | boolean | ❌ | 详细输出 | ```json { "check_type": "all", "verbose": true } ``` ## 详细使用示例 ### Stdio 模式 Stdio 模式适合与本地 MCP 客户端集成: ```bash # 启动 Stdio 服务器 crates-docs serve --mode stdio # 或使用默认配置(stdio 是某些客户端的默认模式) crates-docs serve ``` **MCP 客户端配置示例:** ```json { "mcpServers": { "crates-docs": { "command": "/usr/local/bin/crates-docs", "args": ["serve", "--mode", "stdio"] } } } ``` ### HTTP 模式 HTTP 模式适合远程访问或网络服务: ```bash # 启动 HTTP 服务器 crates-docs serve --mode http --host 0.0.0.0 --port 8080 # 使用自定义配置 crates-docs serve --config config.toml ``` **使用 curl 测试 HTTP 端点:** ```bash # 获取服务器信息(健康检查) curl http://localhost:8080/health # MCP 工具调用示例(需要 MCP 协议格式) curl -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }' ``` ### SSE 模式 SSE 模式支持服务器推送: ```bash # 启动 SSE 服务器 crates-docs serve --mode sse --host 0.0.0.0 --port 8080 ``` **SSE 客户端连接:** ```bash # 连接到 SSE 端点 curl http://localhost:8080/sse ``` ### 工具调用示例 #### search_crates - 搜索 Crate ```bash # 使用 CLI 测试工具 crates-docs test --tool search_crates --query "serde" --limit 5 # 预期输出: # 搜索 "serde" 的结果: # 1. serde (v1.0.xxx) - 序列化框架 # 下载量: xxx # 描述: ... ``` **MCP 调用参数:** ```json { "name": "search_crates", "arguments": { "query": "web framework", "limit": 10, "sort": "downloads", "format": "markdown" } } ``` #### lookup_crate - 查找 Crate 文档 ```bash # 使用 CLI 测试工具 crates-docs test --tool lookup_crate --crate-name serde # 指定版本 crates-docs test --tool lookup_crate --crate-name tokio --version "1.35.0" ``` **MCP 调用参数:** ```json { "name": "lookup_crate", "arguments": { "crate_name": "serde", "version": "1.0.200", "format": "markdown" } } ``` #### lookup_item - 查找特定项目 ```bash # 使用 CLI 测试工具 crates-docs test --tool lookup_item --crate-name serde --item-path "serde::Serialize" ``` **MCP 调用参数:** ```json { "name": "lookup_item", "arguments": { "crate_name": "tokio", "item_path": "tokio::runtime::Runtime", "version": "1.35.0", "format": "markdown" } } ``` #### health_check - 健康检查 ```bash # 使用 CLI 执行健康检查 crates-docs health --check-type all --verbose # 仅检查外部服务 crates-docs health --check-type external ``` **MCP 调用参数:** ```json { "name": "health_check", "arguments": { "check_type": "all", "verbose": true } } ``` ## 使用示例 ### 了解新 crate **用户**: "帮我了解一下 serde" **AI 调用**: `{ "crate_name": "serde" }` ### 查找特定功能 **用户**: "tokio 怎么创建异步任务?" **AI 调用**: `{ "crate_name": "tokio", "item_path": "tokio::spawn" }` ### 搜索相关 crate **用户**: "有什么稳定、大家都常用的 HTTP 客户端?" **AI 调用**: `{ "query": "http client", "limit": 10, "sort": "downloads" }` ## 命令行 ```bash # 启动服务器 crates-docs serve # 混合模式 crates-docs serve --mode stdio # Stdio 模式 crates-docs serve --mode http --port 8080 # HTTP 模式 # 生成配置 crates-docs config --output config.toml crates-docs config --output config.toml --force # 测试工具 crates-docs test --tool lookup_crate --crate-name serde crates-docs test --tool search_crates --query "async" crates-docs test --tool search_crates --query "mcp" --sort downloads crates-docs test --tool search_crates --query "agent" --sort recent-updates --format json # CLI 健康检查入口 crates-docs health crates-docs health --check-type external --verbose # 版本信息 crates-docs version ``` > 全局参数见 [`Cli`](src/cli/mod.rs:27),常用项包括 `--config`、`--debug`、`--verbose`。 > > [`run_health_command()`](src/cli/health_cmd.rs) 会执行真实的健康检查(内部状态 + docs.rs / crates.io 探测),与 MCP 工具 [`health_check`](src/tools/health.rs) 共用同一套检测逻辑。当整体状态不是 `healthy` 时,命令以非零退出码结束,可直接用作容器/编排器的健康探针(例如 Docker Compose 的 `healthcheck`)。 ## 配置 ### 完整配置文件示例 下面是一个完整的配置文件示例,包含所有可用的配置项: ```toml # 服务器配置 [server] name = "crates-docs" # 服务器名称 version = "0.1.0" # 服务器版本 description = "Rust crate docs MCP server" # 服务器描述 host = "0.0.0.0" # 监听地址(0.0.0.0 允许外部访问) port = 8080 # 监听端口 transport_mode = "hybrid" # 传输模式:stdio/http/sse/hybrid enable_sse = true # 兼容字段;实际由 transport_mode 决定 enable_oauth = false # OAuth 尚未实现,true 会导致启动失败 max_connections = 100 # 兼容字段,当前未强制执行 request_timeout_secs = 30 # 兼容字段,当前未强制执行 response_timeout_secs = 60 # 兼容字段,当前未强制执行 dns_rebinding_protection = false # 启用后执行精确 Host/Origin 匹配 allowed_hosts = ["localhost:8080", "127.0.0.1:8080"] allowed_origins = ["http://localhost:8080", "http://127.0.0.1:8080"] # 缓存配置 [cache] cache_type = "memory" # 缓存类型:memory 或 redis memory_size = 1000 # 内存缓存大小(条目数) redis_url = "redis://localhost:6379" # Redis 连接 URL(使用 redis 时必需) key_prefix = "" # 缓存键前缀 default_ttl = 3600 # 默认 TTL(秒) crate_docs_ttl_secs = 3600 # crate 文档缓存 TTL(秒) item_docs_ttl_secs = 1800 # 项目文档缓存 TTL(秒) search_results_ttl_secs = 300 # 搜索结果缓存 TTL(秒) # 日志配置 [logging] level = "info" # 日志级别:trace/debug/info/warn/error file_path = "./logs/crates-docs.log" # 日志文件路径 enable_console = true # 启用控制台日志 enable_file = false # 启用文件日志 max_file_size_mb = 100 # 单个日志文件最大大小(MB) max_files = 10 # 保留的日志文件数量 # 性能配置 [performance] http_client_pool_size = 10 # HTTP 客户端连接池大小 http_client_pool_idle_timeout_secs = 90 # 连接池空闲超时(秒) http_client_connect_timeout_secs = 10 # 连接超时(秒) http_client_timeout_secs = 30 # 请求超时(秒) http_client_read_timeout_secs = 30 # 读取超时(秒) http_client_max_retries = 3 # HTTP 客户端最大重试次数 http_client_retry_initial_delay_ms = 100 # 重试初始延迟(毫秒) http_client_retry_max_delay_ms = 10000 # 重试最大延迟(毫秒) cache_max_size = 1000 # 最大缓存大小 cache_default_ttl_secs = 3600 # 默认缓存 TTL(秒) rate_limit_per_second = 100 # 兼容字段,当前未接入限流器 concurrent_request_limit = 50 # 兼容字段,当前未接入并发控制 enable_response_compression = false # 保留 false;true 会导致启动失败 enable_metrics = false # 保留 false;true 会导致启动失败 metrics_port = 0 # 兼容字段;当前无指标端点 # OAuth 配置仅为兼容保留;启用会导致启动失败 [auth.oauth] enabled = false # 启用 OAuth client_id = "" # OAuth 客户端 ID client_secret = "" # OAuth 客户端密钥 authorization_endpoint = "" # 授权端点 URL token_endpoint = "" # Token 端点 URL redirect_uri = "" # 回调 URI scopes = [] # OAuth 作用域 # API Key 认证配置(可选),必须使用 [auth.api_key] [auth.api_key] enabled = false # 启用 API Key 认证 keys = [] # API Key 哈希列表(Argon2 PHC 格式),不要存明文 key header_name = "X-API-Key" # API Key 请求头名称 query_param_name = "api_key" # API Key 查询参数名称 allow_query_param = false # 是否允许查询参数传递 key_prefix = "sk" # API Key 前缀(用于生成和校验结构化 key) ``` ### 环境变量配置 支持通过环境变量配置,适用于 Docker 部署。 对于 API Key,推荐先生成一次性明文 key,再把生成出的 **hash** 放入配置或环境变量中: ```bash # 生成新的 API Key(会输出明文 key、key_id 和 hash) crates-docs generate-api-key --prefix sk # 服务器配置 CRATES_DOCS_HOST=0.0.0.0 CRATES_DOCS_PORT=8080 CRATES_DOCS_TRANSPORT_MODE=hybrid # API Key 认证配置 CRATES_DOCS_API_KEY_ENABLED=true CRATES_DOCS_API_KEYS='$argon2id$...generated_hash...' CRATES_DOCS_API_KEY_HEADER=X-API-Key CRATES_DOCS_API_KEY_ALLOW_QUERY=false CRATES_DOCS_API_KEY_PREFIX=sk ``` ### Docker 部署示例 ```bash # 使用环境变量启用 API Key 认证(保存 hash,不保存明文 key) docker run -d \ -p 8080:8080 \ -e CRATES_DOCS_API_KEY_ENABLED=true \ -e CRATES_DOCS_API_KEYS='$argon2id$...generated_hash...' \ -e CRATES_DOCS_API_KEY_PREFIX=sk \ -e CRATES_DOCS_HOST=0.0.0.0 \ kingingwang/crates-docs:latest ``` ### Docker Compose 示例 ```yaml version: '3.8' services: crates-docs: image: kingingwang/crates-docs:latest ports: - "8080:8080" environment: - CRATES_DOCS_API_KEY_ENABLED=true - CRATES_DOCS_API_KEYS=$argon2id$...generated_hash... - CRATES_DOCS_API_KEY_PREFIX=sk - CRATES_DOCS_HOST=0.0.0.0 - CRATES_DOCS_PORT=8080 ``` ### 配置项详细说明 #### `[server]` 服务器配置 | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `name` | string | `"crates-docs"` | 服务器名称 | | `host` | string | `"127.0.0.1"` | 监听地址,设为 `"0.0.0.0"` 允许外部访问 | | `port` | number | `8080` | 监听端口 | | `transport_mode` | string | `"hybrid"` | 传输模式:`stdio`/`http`/`sse`/`hybrid` | | `enable_sse` | boolean | `true` | 是否启用 SSE 支持 | | `max_connections` | number | `100` | 兼容字段,当前未强制执行 | | `allowed_hosts` | array | `["localhost", "127.0.0.1"]` | 允许的 Host 列表(CORS) | | `allowed_origins` | array | `["http://localhost:*"]` | 允许的 Origin 列表(CORS) | #### `[cache]` 缓存配置 | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `cache_type` | string | `"memory"` | 缓存类型:`memory` 或 `redis` | | `memory_size` | number | `1000` | 内存缓存条目数 | | `redis_url` | string | `null` | Redis 连接 URL | | `key_prefix` | string | `""` | 缓存键前缀 | | `crate_docs_ttl_secs` | number | `3600` | crate 文档缓存时间(秒) | | `item_docs_ttl_secs` | number | `1800` | 项目文档缓存时间(秒) | | `search_results_ttl_secs` | number | `300` | 搜索结果缓存时间(秒) | #### `[logging]` 日志配置 | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `level` | string | `"info"` | 日志级别:`trace`/`debug`/`info`/`warn`/`error` | | `enable_console` | boolean | `true` | 启用控制台输出 | | `enable_file` | boolean | `false` | 启用文件日志 | | `file_path` | string | `"./logs/crates-docs.log"` | 日志文件路径 | | `max_file_size_mb` | number | `100` | 单个日志文件大小限制 | | `max_files` | number | `10` | 保留的日志文件数 | #### `[performance]` 性能配置 | 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | `http_client_pool_size` | number | `10` | HTTP 连接池大小 | | `http_client_max_retries` | number | `3` | HTTP 请求最大重试次数 | | `rate_limit_per_second` | number | `100` | 兼容字段,当前未接入限流器 | | `concurrent_request_limit` | number | `50` | 兼容字段,当前未接入并发控制 | | `enable_response_compression` | boolean | `false` | 尚未实现;设置为 `true` 会导致启动失败 | | `enable_metrics` | boolean | `false` | 尚未实现;设置为 `true` 会导致启动失败 | ### 环境变量配置 所有配置项都可以通过环境变量覆盖,环境变量优先级最高: ```bash # 服务器配置 export CRATES_DOCS_NAME="crates-docs" export CRATES_DOCS_HOST="0.0.0.0" export CRATES_DOCS_PORT="8080" export CRATES_DOCS_TRANSPORT_MODE="hybrid" # 日志配置 export CRATES_DOCS_LOG_LEVEL="info" export CRATES_DOCS_ENABLE_CONSOLE="true" export CRATES_DOCS_ENABLE_FILE="true" # 缓存配置 export CRATES_DOCS_CACHE_TYPE="memory" export CRATES_DOCS_CACHE_MEMORY_SIZE="1000" export CRATES_DOCS_CACHE_REDIS_URL="redis://localhost:6379" # 性能配置 export CRATES_DOCS_HTTP_CLIENT_POOL_SIZE="10" export CRATES_DOCS_RATE_LIMIT_PER_SECOND="100" ``` > **注意**:环境变量会覆盖配置文件中的设置。布尔值使用 `"true"` 或 `"false"` 字符串表示。 > > **API Key 安全建议**: > - 使用 `crates-docs generate-api-key --prefix sk` 生成新的 key > - 只保存生成结果中的 **hash** > - 明文 key 只展示一次,之后请存入你的密钥管理系统 > - 不要把明文 key 直接写入 `config.toml`、Docker Compose 或环境变量示例中 > ⚠️ **重要安全说明**: > - **API Key 认证**:已在 HTTP/SSE/Hybrid 传输层强制执行(需启用 `auth` feature,默认启用)。启用后,所有 MCP 请求必须携带有效的 `Authorization: Bearer `(`/health` 端点保持开放以便监控)。 > - **OAuth 认证**:已配置但**尚未实现**。启用 OAuth 将在启动时被拒绝。请使用 API Key 认证。 > - **配置变更检测**:配置文件变更会被检测并记录,但所有变更都需要重启服务器才能生效。 > - **性能配置**:`enable_metrics` 和 `enable_response_compression` 设为 `true` 会导致启动失败;速率、并发、请求超时和最大连接数等兼容字段当前未在运行时生效。 ### 生成配置文件 使用 CLI 生成默认配置文件: ```bash # 生成配置文件 crates-docs config --output config.toml # 强制覆盖已存在的文件 crates-docs config --output config.toml --force ``` ## 传输协议 | 模式 | 适用场景 | 端点 | |------|---------|------| | `stdio` | MCP 客户端集成(推荐) | 标准输入输出 | | `http` | 网络服务 | `POST /mcp` | | `sse` | 向后兼容 | `GET /sse` | | `hybrid` | 网络服务(推荐) | `/mcp` + `/sse` | ## MCP 端点 - `POST /mcp` - MCP Streamable HTTP 端点 - `GET /sse` - MCP SSE 端点 > 注意:这些是 MCP 协议端点,不是普通的 HTTP API。需要使用 MCP 客户端进行交互。 ## API Key 认证使用指南 API Key 认证用于保护 HTTP/SSE/Hybrid 模式下的 MCP 端点,防止未授权访问。启用后,所有 MCP 请求必须携带有效的 API Key,`/health` 端点始终开放以便监控。 ### 完整流程概览 ``` 1. 生成 API Key → 得到明文 key(客户端用)和 hash(服务端存) 2. 配置服务端 → 将 hash 写入 config.toml 或环境变量 3. 启动服务 → crates-docs serve --config config.toml 4. 客户端携带 key → Authorization: Bearer <明文 key> ``` ### 第一步:生成 API Key ```bash crates-docs generate-api-key ``` 输出示例: ``` Generated API key successfully. Plain-text key (show once and store securely): sk-live- Key ID: Store this hash in configuration or secret storage: $argon2id$v=19$m=47104,t=1,p=1$$ ``` **⚠️ 重要**: - **明文 key**(`sk-live-...`)只显示一次,请立即保存到密钥管理器中,服务端无法从 hash 反推出明文 - **hash**(`$argon2id$...`)写入服务端配置,用于验证客户端发来的 key - 两者不可互换:客户端用明文,服务端存 hash 也可以指定自定义前缀: ```bash crates-docs generate-api-key --prefix myapp ``` ### 第二步:配置服务端 #### 方式 A:配置文件(推荐) 创建或编辑 `config.toml`,将生成的 hash 放入 `keys` 列表: ```toml [auth.api_key] enabled = true keys = ["$argon2id$v=19$m=47104,t=1,p=1$$"] header_name = "X-API-Key" query_param_name = "api_key" allow_query_param = false key_prefix = "sk" ``` 支持多个 key(例如为不同客户端分配不同 key): ```toml [auth.api_key] enabled = true keys = [ "$argon2id$v=19$m=47104,t=1,p=1$hash1...", "$argon2id$v=19$m=47104,t=1,p=1$hash2...", ] key_prefix = "sk" ``` #### 方式 B:环境变量 ```bash export CRATES_DOCS_API_KEY_ENABLED=true export CRATES_DOCS_API_KEYS='$argon2id$v=19$m=47104,t=1,p=1$$' export CRATES_DOCS_API_KEY_PREFIX=sk ``` #### 方式 C:CLI 标志 ```bash crates-docs serve --enable-api-key ``` > 注意:CLI 标志仅启用认证开关,key 列表仍需通过配置文件或环境变量提供。 ### 第三步:启动服务 ```bash # 使用配置文件 crates-docs serve --config config.toml --mode hybrid --host 0.0.0.0 --port 8080 # 或使用环境变量 export CRATES_DOCS_API_KEY_ENABLED=true export CRATES_DOCS_API_KEYS='$argon2id$...' crates-docs serve --mode hybrid ``` 启动后日志中会显示 API Key 认证已启用。 ### 第四步:客户端使用 API Key #### curl 测试 ```bash # 使用 Bearer token(直连服务端必须用此方式) curl -H "Authorization: Bearer sk-live-" \ -X POST http://127.0.0.1:8080/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # 未携带 key 的请求会返回 401 curl -X POST http://127.0.0.1:8080/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # → 401 Unauthorized # /health 端点无需认证 curl http://127.0.0.1:8080/health ``` #### Claude Desktop 配置 ```json { "mcpServers": { "crates-docs": { "url": "http://your-server:8080/mcp", "headers": { "Authorization": "Bearer sk-live-" } } } } ``` #### Cursor 配置 编辑 `~/.cursor/mcp.json`: ```json { "mcpServers": { "crates-docs": { "url": "http://your-server:8080/mcp", "headers": { "Authorization": "Bearer sk-live-" } } } } ``` #### 其他 MCP 客户端 任何支持自定义 HTTP header 的 MCP 客户端,添加以下 header 即可: ``` Authorization: Bearer <你的明文 key> ``` ### 管理操作 #### 查看已注册的 API Key ```bash crates-docs list-api-keys ``` #### 吊销 API Key ```bash # 通过 Key ID 吊销 crates-docs revoke-api-key --key-id # 吊销后需重启服务生效 ``` #### 添加新 Key 1. 运行 `crates-docs generate-api-key` 生成新 key 2. 将新 hash 追加到 `config.toml` 的 `keys` 列表中 3. 重启服务 ### 常见问题 **Q: 为什么不能用 `X-API-Key` header 直连服务端?** A: 进程内的 MCP 中间件只识别 `Authorization: Bearer` 头。`X-API-Key` header 需要配合反向代理使用——代理将 `X-API-Key: ` 改写为 `Authorization: Bearer ` 后转发给后端。详见下方"认证与加密传输"章节。 **Q: 可以通过 URL 查询参数传递 key 吗?** A: 配置 `allow_query_param = true` 后,反向代理可以支持 `?api_key=` 方式。但直连服务端仍只接受 Bearer token。出于安全考虑,不建议在 URL 中传递 key(会出现在日志和浏览器历史中)。 **Q: 忘记了明文 key 怎么办?** A: 明文 key 只在生成时显示一次,无法从 hash 反推。如果丢失,需要生成新 key 并替换配置中的 hash。 **Q: 多个客户端可以共用同一个 key 吗?** A: 可以,但建议为不同客户端分配不同 key,便于独立吊销。 ## 认证与加密传输(TLS) 在 HTTP/SSE/Hybrid 服务器模式下,访问控制分为两层,可按需组合: | 能力 | 由谁提供 | 说明 | |------|----------|------| | **认证**(只有持有密钥者可连接) | 进程内置(默认编译进二进制) | 校验 `Authorization: Bearer `,密钥以 Argon2 哈希存储、常量时间比对 | | **加密**(被监听也无法解密) | 前置反向代理(Caddy/nginx) | 终止 TLS,并把 `X-API-Key: ` 改写为 `Authorization: Bearer ` | ### 进程内置认证(Bearer) `auth` 已包含在 `default` features 中,因此标准 `cargo build` / `cargo install` 即具备认证能力。是否真正启用是**运行时开关**,无需重新编译: - 打开/关闭由 `auth.api_key.enabled` 控制(配置文件、`--enable-api-key` CLI 标志或 `CRATES_DOCS_API_KEY_ENABLED` 环境变量),改动后**重启生效**。 - 启用后,每个 MCP 请求都必须携带 `Authorization: Bearer `,否则返回 `401`; `/health` 始终开放,便于监控。 - 密钥用 `crates-docs generate-api-key` 生成:配置里保存 **hash**,把**明文 key** 发给客户端。吊销密钥 = 从 `keys` 移除并重启。 ```bash # 启用后,直连服务端必须使用 Bearer 头: curl -H "Authorization: Bearer <明文 key>" -X POST http://127.0.0.1:8080/mcp ``` > **为什么是 Bearer 而不是 `X-API-Key`?** 进程内的 MCP 中间件**只**识别 > `Authorization: Bearer` 头,无法读取 `X-API-Key` 或查询参数。`header_name`、 > `allow_query_param` 等配置项仅对前置反向代理有意义(见下)。 ### 加密传输与 `X-API-Key`(反向代理) 进程本身只说明文 HTTP,没有 TLS。若服务要对外暴露、需要加密,或希望继续使用 `X-API-Key` 头,请在前面加一层反向代理:它终止 TLS(HTTPS),把 `X-API-Key: ` 改写为 `Authorization: Bearer `,再转发到仅监听 127.0.0.1 的后端——后端依旧做密码学校验,构成纵深防御。 ``` 客户端 --HTTPS, X-API-Key--> 反向代理 --HTTP, Authorization: Bearer--> 127.0.0.1:8080 ``` 开箱即用的配置(含 Caddy 与 nginx,以及完整步骤)见 **[`docs/reverse-proxy/`](docs/reverse-proxy/README.md)**。使用反向代理时,请把后端 绑定到回环地址(`server.host = "127.0.0.1"`),避免客户端绕过 TLS 直连后端。 ## 缓存策略 ### 内存缓存(默认) - 当前实现位于 [`MemoryCache`](src/cache/memory.rs:37) - 基于 `moka::sync::Cache`,使用 TinyLFU 淘汰策略 - 支持按条目 TTL 过期 - 适用于单实例部署 ### Redis 缓存 - 支持分布式部署 - 支持持久化 - 通过 feature flag 启用:`cache-redis` ```bash cargo build --release --features cache-redis ``` 配置示例: ```toml [cache] cache_type = "redis" redis_url = "redis://localhost:6379" default_ttl = 3600 ``` ### 缓存 TTL 配置 支持为不同类型的数据配置独立的 TTL: - `crate_docs_ttl_secs`: crate 文档缓存时间(默认 3600 秒 / 1 小时) - `item_docs_ttl_secs`: 项目文档缓存时间(默认 1800 秒 / 30 分钟) - `search_results_ttl_secs`: 搜索结果缓存时间(默认 300 秒 / 5 分钟) ## 部署 ### Docker ```bash # 使用预构建镜像 docker pull kingingwang/crates-docs:latest docker run -d -p 8080:8080 kingingwang/crates-docs:latest # 或使用特定版本 docker pull kingingwang/crates-docs:0.3.0 ``` ### Systemd 创建 `/etc/systemd/system/crates-docs.service`: ```ini [Unit] Description=Crates Docs MCP Server After=network.target [Service] Type=simple User=crates-docs WorkingDirectory=/opt/crates-docs ExecStart=/opt/crates-docs/crates-docs serve --config /etc/crates-docs/config.toml Restart=on-failure [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl enable crates-docs sudo systemctl start crates-docs ``` ### 云端部署 > **注意**:本项目是长驻 Rust 服务进程(监听端口并持续运行),不适用于 Vercel / Netlify 等 Serverless 平台。 推荐使用 [Render](https://render.com) 免费层部署(750 小时/月,无需信用卡,原生 Docker 支持)。 > **在线测试地址**:[https://crates-docs.onrender.com/mcp](https://crates-docs.onrender.com/mcp) > > 可直接在 MCP 客户端(Claude Desktop、Cursor 等)中配置此地址体验,无需自行部署。 > 该服务部署在 Render 免费层,15 分钟无请求会自动休眠,首次访问需要冷启动。 > 本项目是编译型 Rust 二进制(无 JVM 预热、无数据库初始化),应用本身启动为亚秒级,冷启动延迟主要来自 Render 免费层的容器调度。 云端部署推荐使用 `http` 传输模式(请求/响应模型,兼容性最好): ```bash # 任意 Docker 平台一键启动 docker run -d -p 8080:8080 \ -e CRATES_DOCS_HOST=0.0.0.0 \ -e CRATES_DOCS_TRANSPORT_MODE=http \ -e CRATES_DOCS_API_KEY_ENABLED=true \ -e CRATES_DOCS_API_KEYS=你的密钥 \ kingingwang/crates-docs:latest ``` 完整的 Render 部署分步教程见 **[docs/cloud-deployment.md](docs/cloud-deployment.md)**。 ## 开发 ```bash # 构建 cargo build --release # 运行所有测试 cargo test --all-features # 运行 clippy 检查 cargo clippy --all-features --all-targets -- -D warnings # 格式化检查 cargo fmt --check # 运行完整 CI 流程 cargo clippy --all-features --all-targets -- -D warnings && \ cargo test --all-features && \ cargo fmt --check ``` ### Feature Flags | Feature | 描述 | |---------|------| | `default` | 默认启用完整服务端、Stdio、HTTP/SSE、内存缓存、日志和 API Key | | `server` | 启用 rust-mcp-sdk 服务端能力 | | `client` | 启用 rust-mcp-sdk 客户端能力 | | `stdio` | 启用 Stdio 传输 | | `hyper-server` | 启用 HTTP 服务器 | | `streamable-http` | 启用 Streamable HTTP | | `sse` | 启用 SSE 传输 | | `macros` | 启用 MCP 宏支持 | | `auth` | 启用 SDK 认证基础设施(OAuth 请求校验尚未实现) | | `api-key` | 启用 API Key 认证支持(默认启用) | | `cache-memory` | 启用内存缓存相关支持 | | `cache-redis` | 启用 Redis 缓存 | | `tls` | 启用 TLS/SSL 支持 | | `logging` | 启用日志相关支持 | ## 故障排除 ### 端口被占用 ```bash lsof -i :8080 kill -9 ``` ### 网络问题 ```bash curl -I https://docs.rs/ curl -I https://crates.io/ ``` ### 日志 启用文件日志时,默认日志文件路径为 `./logs/crates-docs.log`。 ```toml [logging] level = "debug" ``` ## 许可证 MIT License ## 贡献 欢迎 Issue 和 Pull Request! 1. Fork 仓库 2. 创建分支 (`git checkout -b feature/amazing-feature`) 3. 提交更改 (`git commit -m 'Add amazing feature'`) 4. 推送分支 (`git push origin feature/amazing-feature`) 5. 创建 Pull Request ### 开发指南 - 所有代码必须通过 `cargo clippy --all-features --all-targets -- -D warnings` - 所有测试必须通过 `cargo test --all-features` - 新功能需要添加相应的单元测试 - 遵循现有的代码风格和文档规范 ## 致谢 - [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) - MCP SDK - [docs.rs](https://docs.rs) - Rust 文档服务 - [crates.io](https://crates.io) - Rust 包注册表 - [lru](https://crates.io/crates/lru) - 内存缓存淘汰策略实现 ## API 文档 ### docs.rs 文档 - **主文档**: [https://docs.rs/crates-docs](https://docs.rs/crates-docs) - **最新版本**: [https://docs.rs/crates-docs/latest](https://docs.rs/crates-docs/latest) ### 主要类型使用示例 #### CratesDocsServer ```rust use crates_docs::{AppConfig, CratesDocsServer}; #[tokio::main] async fn main() -> Result<(), Box> { // 使用默认配置 let config = AppConfig::default(); // 创建服务器 let server = CratesDocsServer::new(config)?; // 运行 HTTP 服务器 server.run_http().await?; Ok(()) } ``` #### 缓存使用 ```rust use std::sync::Arc; use crates_docs::cache::{Cache, CacheConfig, create_cache}; #[tokio::main] async fn main() -> Result<(), Box> { // 创建内存缓存 let config = CacheConfig::default(); let cache: Arc = Arc::from(create_cache(&config)?); // 设置缓存值 cache.set( "key".to_string(), "value".to_string(), Some(std::time::Duration::from_secs(3600)) ).await?; // 获取缓存值 if let Some(value) = cache.get("key").await { println!("Cached value: {}", value); } Ok(()) } ``` #### 工具注册表 ```rust use std::sync::Arc; use crates_docs::tools::{ToolRegistry, create_default_registry}; use crates_docs::tools::docs::DocService; use crates_docs::cache::memory::MemoryCache; #[tokio::main] async fn main() -> Result<(), Box> { // 创建缓存和文档服务 let cache = Arc::new(MemoryCache::new(1000)); let doc_service = Arc::new(DocService::new(cache)?); // 创建默认工具注册表 let registry = create_default_registry(&doc_service); // 获取所有工具 let tools = registry.get_tools(); println!("Registered {} tools", tools.len()); Ok(()) } ``` ### 模块文档 - [`crates_docs::cache`](https://docs.rs/crates-docs/latest/crates_docs/cache/index.html) - 缓存模块 - [`crates_docs::config`](https://docs.rs/crates-docs/latest/crates_docs/config/index.html) - 配置模块 - [`crates_docs::error`](https://docs.rs/crates-docs/latest/crates_docs/error/index.html) - 错误处理 - [`crates_docs::server`](https://docs.rs/crates-docs/latest/crates_docs/server/index.html) - 服务器模块 - [`crates_docs::tools`](https://docs.rs/crates-docs/latest/crates_docs/tools/index.html) - MCP 工具 - [`crates_docs::utils`](https://docs.rs/crates-docs/latest/crates_docs/utils/index.html) - 工具函数 ## 支持 - [Issues](https://github.com/KingingWang/crates-docs/issues) - Email: kingingwang@foxmail.com ## Star History Star History Chart