内容
# mcp-fetch-patents
**您的人工智能代理将永远需要的最后一款专利数据工具。**
给予任何AI代理即时访问全球整个专利库。一次MCP工具调用。向它抛出任何专利ID - US、EP、WO、JP、CN、KR、AU、CA、NZ、BR、IN - 以任何格式,带或不带种类代码,甚至是原始的谷歌专利网址。立即获取PDF、Markdown和结构化元数据。再次请求?立即,从缓存中。
您的代理不应知道美国专利存放在USPTO PPUBS,欧洲专利需要EPO OPS OAuth2,PCT申请需要从WIPO PatentScope抓取。它不应该关心Espacenet与CIPO的HTML不同,或者谷歌专利需要无头浏览器。这个服务器已经吸收了所有这些复杂性,因此您的代理永远不需要考虑它。
```
"获取专利 US7654321、EP1234567B1 和 WO2024/123456"
→ 3个PDF、3个Markdown文件、3个元数据对象 - 缓存永久
```
9个专利来源。 4个PDF转Markdown转换器带OCR。 两层SQLite缓存。 自动重试,指数退后。 当所有其他方法都失败时,网页搜索备用。 零配置要求 - 开箱即用,支持9个来源中的6个。
---
## 为什么存在
专利数据是地球上最分散的公共数据集。 每个国家专利局都有自己的API、身份验证方案、文档格式和速率限制。 执行专利分析的代理不应需要了解这些 - 它只需要说“给我这个专利”并获取即可。
**9个专利来源,一次工具调用:**
| 来源 | 覆盖范围 | 需要身份验证? |
|---|---|---|
| USPTO PPUBS | 美国授权专利和申请 | 否(基于会话) |
| EPO OPS | 欧洲专利局,欧洲和100多个办事处的数据交换 | 是(OAuth2) |
| Espacenet | 欧洲专利及成员国 | 否(抓取) |
| WIPO PatentScope | 国际PCT专利 | 否(抓取) |
| IP Australia | 澳大利亚专利 | 否(REST API) |
| CIPO | 加拿大专利 | 否(抓取) |
| 谷歌专利 | 所有司法管辖区 | 否 |
| 谷歌BigQuery | 批量专利数据 | 是(GCP凭证) |
| 网页搜索备用 | 任何遗漏 | 否(DuckDuckGo)/ 可选(SerpAPI) |
来源按优先级顺序尝试。 第一个成功(除非您设置`PATENT_FETCH_ALL_SOURCES=true`以聚合所有来源)。 如果所有结构化来源都失败,网页搜索备用将找到PDF。 我们真的不喜欢空手而归。
## 快速开始
### 安装
```bash
# Rust(推荐)
cargo install patent-mcp-server
# 或从源代码构建:
cargo build --release --manifest-path src/rust/Cargo.toml
# Python(参考实现,也可独立使用)
pip install patent-mcp-server
```
### 配置您的MCP客户端
将以下内容添加到您的Claude Desktop、Claude Code、Cursor或Cline配置中:
```json
{
"mcpServers": {
"patents": {
"command": "patent-mcp-server"
}
}
}
```
这就是整个设置。 不需要API密钥 - 9个来源中的6个无需身份验证(USPTO、Espacenet、WIPO、IP Australia、CIPO、DuckDuckGo)。 稍后添加密钥以解锁EPO OPS、BigQuery和SerpAPI。 请参阅[docs/api-keys.md](docs/api-keys.md)。
对于已安装的Rust服务器,机密信息可以存放在`~/.patents.toml`、普通环境变量或服务器自动加载的`~/.patents-mcp.env`中。 仓库本地的`.env`仅在服务器从该检出启动时有用。
如果您的MCP客户端在沙箱子进程中启动stdio服务器,请使用本地HTTP传输:
```bash
patent-mcp-server serve-http
```
然后将客户端配置为连接到:
```text
http://127.0.0.1:38473/mcp
```
仓库将Python HTTP端点固定到`/mcp`,Rust服务器使用相同的默认URL。 当前共享的约定是URL和仅限本地绑定,而不是字节对字节的HTTP传输奇偶校验。
### 使用它
```
"获取专利 US7654321 和 EP1234567B1,然后总结关键声明。"
```
代理调用`fetch_patents`,获取文件路径和元数据,读取Markdown并执行其操作。 您不需要配置来源。 您不需要选择格式。 您不需要管理缓存。 它直接起作用。
## 工具
### `fetch_patents`
获取一个或多个专利的ID。 接受任何格式 - 裸数字,司法管辖区前缀,带或不带种类代码,甚至谷歌专利网址。
**参数:**
| 名称 | 类型 | 必需 | 描述 |
|---|---|---|---|
| `patent_ids` | `string[]` | 是 | 任意格式的专利ID |
| `force_refresh` | `bool` | 否 | 绕过缓存,重新从来源获取 |
| `formats` | `string[]` | 否 | 请求的格式(默认:`["pdf", "txt", "md"]`) |
| `postprocess_query` | `string` | 否 | 为v2后处理预留 |
**响应:**
```json
{
"results": [
{
"canonical_id": "US7654321",
"success": true,
"from_cache": false,
"files": {
"pdf": "~/.local/share/patent-cache/patents/US7654321/US7654321.pdf",
"md": "~/.local/share/patent-cache/patents/US7654321/US7654321.md"
},
"metadata": {
"title": "方法和设备...",
"inventors": ["Jane Doe", "John Smith"],
"assignee": "Acme Corp",
"filing_date": "2005-03-15",
"publication_date": "2010-02-02",
"jurisdiction": "US",
"doc_type": "patent"
},
"sources": [
{"source": "USPTO", "success": true, "elapsed_ms": 1842}
]
}
],
"summary": {
"total": 1,
"success": 1,
"cached": 0,
"errors": 0,
"total_duration_ms": 2105
}
}
```
### `list_cached_patents`
列出所有缓存的专利。 无参数,返回`{patents: [...], count: N}`。
### `get_patent_metadata`
仅限缓存元数据查找 - 无网络调用,立即响应。
**参数:** `patent_ids: string[]`
**返回:** `{results: [{patent_id, canonical_id, metadata}]}`
## 搜索工具(专利搜索MCP服务器)
搜索服务器(`python -m patent_mcp.search`)提供自然语言专利搜索、结构化查询、引用链和研究会话等工具。
它还支持本地流式HTTP:
```bash
python -m patent_mcp.search serve-http
```
搜索启动时包括最佳努力浏览器预热,仅当安装可选浏览器依赖项时。 如果不可用,可以忽略它,并且不能保证后续搜索调用重用相同的浏览器/配置文件。
### `patent_search_natural`
使用普通英语搜索。 计划器使用关键词/同义词扩展将您的描述扩展为多个查询变体,在谷歌专利(浏览器和/或SerpAPI)上运行它们,并重新排序结果。
**参数:**
| 名称 | 类型 | 必需 | 描述 |
|---|---|---|---|
| `description` | `string` | 是 | 技术的自然语言描述 |
| `date_cutoff` | `string` | 否 | ISO日期 - 仅返回此日期之前的专利 |
| `jurisdictions` | `string[]` | 否 | 按司法管辖区过滤(例如`["US", "EP"]`) |
| `session_id` | `string` | 否 | 自动保存结果到研究会话 |
| `max_results` | `int` | 否 | 排名后最大结果数(默认25) |
| `backend` | `string` | 否 | `"browser"`、`"serpapi"`或`"auto"`(默认) |
| `enrich_top_n` | `int` | 否 | 用完整元数据丰富前N个命中(默认5) |
### 其他搜索工具
- **`patent_search_structured`** - 针对USPTO、EPO OPS、谷歌专利的专家布尔查询语法
- **`patent_citation_chain`** - 跟随引用前后(深度1-3)
- **`patent_classification_search`** - 按IPC/CPC代码搜索
- **`patent_family_search`** - 跨司法管辖区查找专利家族
- **`patent_suggest_queries`** - 在不执行的情况下生成搜索策略
- **`patent_search_profile_login_start`** - 启动谷歌登录的头部浏览器
### 研究会话
会话在多个工具调用之间保存搜索结果:
- **`patent_session_create`** - 开始新的研究会话
- **`patent_session_load/list/note/annotate`** - 管理会话状态
- **`patent_session_export`** - 生成Markdown报告
## 专利ID格式
不需要担心格式化。 规范化程序已经见过一切:
| 输入 | 规范形式 | 司法管辖区 |
|---|---|---|
| `US7654321` | `US7654321` | 美国 |
| `US7654321B2` | `US7654321` | 美国(带种类代码) |
| `US20230001234A1` | `US20230001234` | 美国申请 |
| `7654321` | `US7654321` | 美国(推断) |
| `EP1234567B1` | `EP1234567` | 欧洲专利局 |
| `WO2024/123456` | `WO2024/123456` | 国际(PCT) |
| `JP2023-123456` | `JP2023123456` | 日本 |
| `CN202310001234A` | `CN202310001234` | 中国 |
| `KR10-1234567` | `KR10-1234567` | 韩国 |
| `AU2023123456` | `AU2023123456` | 澳大利亚 |
| `CA3123456` | `CA3123456` | 加拿大 |
| `https://patents.google.com/patent/US7654321/en` | `US7654321` | (提取) |
还处理NZ、BR和IN格式。 总共22+个模式。 如果它看起来像一个专利编号,我们会弄清楚。
## 工作原理
```
代理 MCP服务器(Rust)
│ │
├─ fetch_patents ──────────►│
│ ├─ 缓存查找(SQLite)
│ │ HIT? 立即返回
│ │ MISS?
│ │ ├─ 按优先级顺序尝试来源
│ │ │ USPTO → EPO → Espacenet → WIPO → ...
│ │ ├─ 下载PDF(异步,并发)
│ │ ├─ 转换PDF → Markdown
│ │ │ (pymupdf4llm → pdfplumber → pdftotext → marker)
│ │ ├─ 提取元数据
│ │ └─ 存储在缓存中
│◄──────────────────────────┤
│ 文件 + 元数据 │
```
**缓存:** `~/.local/share/patent-cache/index.db`的单个全局SQLite DB在所有项目中共享。 专利文件存放在`~/.local/share/patent-cache/patents/{CANONICAL_ID}/`中。 第一次获取需要几秒钟。 之后的每次获取都是即时的 - 即使在不同的仓库中。
**HTTP传输:** Rust、Python获取和Python搜索都可以运行在本地HTTP,默认网址为`http://127.0.0.1:38473/mcp`,使用`serve-http`启动时。 Stdio在不使用`serve-http`启动服务器时仍然是默认的。 实现共享相同的默认网址和仅限本地绑定,但该仓库目前不声明线级Rust/Python HTTP奇偶校验。
**活动日志:** 每个工具调用都记录到当前工作目录的`.patent-activity.jsonl`(JSONL格式)。 该文件旨在被git跟踪,以便每个项目保留已搜索、获取和访问的记录。 禁用时设置`PATENT_ACTIVITY_JOURNAL=""`。
**PDF → Markdown:** 按顺序尝试四个转换后端(pymupdf4llm → pdfplumber → pdftotext → marker)。 如果一个失败,下一个继续。 使用tesseract对扫描的专利图进行OCR。 输出干净到LLM可以直接读取。
**双重实现,交叉验证:** Rust是生产服务器 - 独立的,异步的,带有本地HTTP获取器和重试逻辑。 Python是参考实现。 39个跨实现一致性测试验证两者产生相同的ID规范化、来源排序、转换输出和网络搜索查询结果。 我们说它们匹配时,确实如此 - 已测试。
## 配置
所有配置均通过自动加载的环境文件、`~/.patents.toml`或环境变量(环境变量优先级最高)。 Rust服务器自动加载`~/.patents-mcp.env`和当前工作目录的`.env`,然后读取`~/.patents.toml`和显式环境变量。
| 环境变量 | 默认值 | 描述 |
|---|---|---|
| `PATENT_CACHE_DIR` | `~/.local/share/patent-cache/patents` | 缓存目录 |
| `PATENT_CONCURRENCY` | `10` | 最大并发获取 |
| `PATENT_TIMEOUT` | `30.0` | HTTP超时(秒) |
| `PATENT_EPO_KEY` | — | EPO OPS `client_id:client_secret` |
| `PATENT_LENS_KEY` | — | Lens.org API密钥 |
| `PATENT_SERPAPI_KEY` | — | SerpAPI密钥(网页搜索备用) |
| `PATENT_BIGQUERY_PROJECT` | — | BigQuery源的GCP项目 |
| `PATENT_FETCH_ALL_SOURCES` | `true` | 尝试所有来源,即使第一个成功 |
| `PATENT_ACTIVITY_JOURNAL` | `.patent-activity.jsonl` | 每个仓库的活动日志(空 = 禁用) |
| `PATENT_SEARCH_BACKEND_DEFAULT` | `browser` | 默认搜索后端(`browser`、`serpapi`、`auto`) |
| `PATENT_SEARCH_BROWSER_HEADLESS` | `true` | 在无头模式下运行Playwright |
| `PATENT_SEARCH_BROWSER_IDLE_TIMEOUT` | `1800` | 浏览器空闲超时(秒,默认30分钟) |
| `PATENT_SEARCH_BROWSER_MAX_PAGES` | `3` | 每个查询的最大谷歌专利结果页面数 |
| `PATENT_SEARCH_ENRICH_TOP_N` | `5` | 丰富搜索结果的前N个结果(默认5) |
## 开发
### 运行测试
```bash
# Rust测试(237个测试,<0.1s)
cargo test --manifest-path src/rust/Cargo.toml
# 在本地HTTP上启动Rust服务器
just serve-rust-http
# 在本地HTTP上启动Python获取服务器
just serve-http
# 在本地HTTP上启动Python搜索服务器
just serve-search-http
# 对Rust开发服务器进行直接stdio MCP烟雾测试
just mcp-smoke-rust
# 对安装的Rust二进制文件进行直接stdio MCP烟雾测试
just mcp-smoke-rust-installed
# 快速Python单元测试(<1s,所有I/O模拟)
pytest tests/python/ -m "not browser and not integration and not slow"
# 完整的Python套件(包括Hypothesis的模糊测试,慢测试)
pytest tests/python/
# 跨实现一致性 - 验证Python == Rust(39个测试)
pytest tests/cross_impl/
# 手动E2E测试 - 自动脚本(31个测试)
python3 run_manual_e2e.py
```
### 项目结构
```
src/
python/patent_mcp/ # Python参考实现
id_canon.py # 专利ID规范化(22+格式)
cache.py # 双层SQLite缓存
config.py # TOML + 环境变量配置加载
fetchers/ # 所有HTTP/API源实现
http.py # 所有HTTP源实现
web_search.py # DuckDuckGo / SerpAPI备用
orchestrator.py # 按优先级顺序的源编排
converters/ # PDF → Markdown(4个后端 + OCR)
server.py # MCP服务器(FastMCP,stdin/stdout)
rust/ # Rust生产服务器(独立)
src/
id_canon/ # 规范化(必须与Python匹配)
cache/ # 两层SQLite缓存(rusqlite)
config/ # TOML + 环境变量配置加载
converters/ # PDF → Markdown(4个后端 + OCR)
fetchers/
http/ # 9个原生异步HTTP源重试
web_search/ # DuckDuckGo + SerpAPI备用
browser.rs # 原生谷歌专利HTML/microdata获取器
mod.rs # 优先级顺序的源编排
server/ # JSON-RPC 2.0 stdin/stdout
tests/
python/ # 16个测试文件:单元测试,集成测试,模糊测试
cross_impl/ # Python == Rust一致性测试
fixtures/ # 共享测试数据
docs/
api-keys.md # 每个源的API密钥设置
```