mcp-fetch-patents
Used as a web search fallback to locate patent PDFs when structured patent sources fail.
Integrates with Google Patents to fetch patent documents from all jurisdictions, providing PDFs, Markdown, and metadata.
Provides access to bulk patent data via Google BigQuery, enabling large-scale patent analysis.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-fetch-patentsFetch US7654321, EP1234567B1, and WO2024/123456"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-fetch-patents
The last patent data tool your agent will ever need.
Give any AI agent instant access to the entire global patent corpus. One MCP tool call. Throw any patent ID at it — US, EP, WO, JP, CN, KR, AU, CA, NZ, BR, IN — in any format, with or without kind codes, even raw Google Patents URLs. Get back PDF, Markdown, and structured metadata in seconds. Ask for it again? Instant, from cache.
Your agent shouldn't have to know that US patents live on USPTO PPUBS, European ones require EPO OPS OAuth2, and PCT applications need to be scraped from WIPO PatentScope. It shouldn't care that Espacenet has different HTML than CIPO, or that Google Patents needs a headless browser. This server ate all of that complexity so your agent never has to think about it.
"Fetch US7654321, EP1234567B1, and WO2024/123456"
→ 3 PDFs, 3 Markdown files, 3 metadata objects — cached forever9 patent sources. 4 PDF-to-Markdown converters with OCR. Two-layer SQLite cache. Automatic retry with exponential backoff. Web search fallback when everything else fails. Zero configuration required — works out of the box with 6 of 9 sources.
Why this exists
Patent data is the most fragmented public dataset on the planet. Every national patent office has its own API, auth scheme, document format, and rate limits. An agent doing patent analysis shouldn't need to know any of that — it should just say "get me this patent" and get it.
9 patent sources, 1 tool call:
Source | Coverage | Auth required? |
USPTO PPUBS | US granted + applications | No (session-based) |
EPO OPS | EP, WO, 100+ offices via exchange data | Yes (OAuth2) |
Espacenet | EP + EPO member states | No (scraped) |
WIPO PatentScope | WO / PCT international | No (scraped) |
IP Australia | AU patents | No (REST API) |
CIPO | Canadian patents | No (scraped) |
Google Patents | All jurisdictions | No |
Google BigQuery | Bulk patent data | Yes (GCP credentials) |
Web search fallback | Anything missed | No (DuckDuckGo) / Optional (SerpAPI) |
Sources are tried in priority order. First success wins (unless you set PATENT_FETCH_ALL_SOURCES=true to aggregate from all). If every structured source fails, the web search fallback finds the PDF anyway. We really don't like returning empty-handed.
Related MCP server: USPTO Patent MCP Server
Quick start
Install
# Rust (recommended)
cargo install patent-mcp-server
# or build from source:
cargo build --release --manifest-path src/rust/Cargo.toml
# Python (reference implementation, also works standalone)
pip install patent-mcp-serverConfigure your MCP client
Add to your Claude Desktop, Claude Code, Cursor, or Cline config:
{
"mcpServers": {
"patents": {
"command": "patent-mcp-server"
}
}
}That's the whole setup. No API keys needed — 6 of 9 sources work without auth (USPTO, Espacenet, WIPO, IP Australia, CIPO, DuckDuckGo). Add keys later to unlock EPO OPS, BigQuery, and SerpAPI. See docs/api-keys.md.
For an installed Rust server, secrets can live in ~/.patents.toml, normal environment variables, or ~/.patents-mcp.env autoloaded by the server. A repo-local .env is only useful when the server is launched from that checkout.
If your MCP client launches stdio servers inside a sandboxed subprocess, use the localhost HTTP transport instead:
patent-mcp-server serve-httpThen configure the client to connect to:
http://127.0.0.1:38473/mcpThe repo pins the Python HTTP endpoint to /mcp, and the Rust server uses the same default URL. The shared contract today is that URL and localhost-only binding, not byte-for-byte HTTP transport parity.
Use it
"Fetch patents US7654321 and EP1234567B1, then summarize the key claims."The agent calls fetch_patents, gets back file paths and metadata, reads the Markdown, and does its thing. You don't configure sources. You don't pick formats. You don't manage cache. It just works.
Tools
fetch_patents
Fetch one or more patents by ID. Accepts any format — bare numbers, jurisdiction-prefixed, with kind codes, even Google Patents URLs.
Parameters:
Name | Type | Required | Description |
|
| Yes | Patent IDs in any format |
|
| No | Bypass cache, re-fetch from sources |
|
| No | Requested formats (default: |
|
| No | Reserved for v2 post-processing |
Response:
{
"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": "Method and apparatus for ...",
"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
List all cached patents. No parameters, returns {patents: [...], count: N}.
get_patent_metadata
Cache-only metadata lookup — no network calls, instant response.
Parameters: patent_ids: string[]
Returns: {results: [{patent_id, canonical_id, metadata}]}
Search tools (patent-search MCP server)
The search server (python -m patent_mcp.search) provides tools for natural language patent search, structured queries, citation chains, and research sessions.
It also supports localhost Streamable HTTP:
python -m patent_mcp.search serve-httpSearch startup includes a best-effort browser prewarm only when the optional browser dependencies are installed. It is safe to ignore if unavailable, and it does not guarantee that later search calls reuse the same browser/profile.
patent_search_natural
Search using plain English. The planner expands your description into multiple query variants using keyword/synonym expansion, runs them against Google Patents (browser and/or SerpAPI), and reranks results.
Parameters:
Name | Type | Required | Description |
|
| Yes | Natural language description of the technology |
|
| No | ISO date — only return patents before this date |
|
| No | Filter by jurisdiction (e.g. |
|
| No | Auto-save results to a research session |
|
| No | Maximum results after ranking (default 25) |
|
| No |
|
|
| No | Enrich top N hits with full metadata (default 5) |
Other search tools
patent_search_structured— Expert Boolean query syntax against USPTO, EPO OPS, Google Patentspatent_citation_chain— Follow citations forward/backward (depth 1-3)patent_classification_search— Search by IPC/CPC codepatent_family_search— Find patent family members across jurisdictionspatent_suggest_queries— Generate search strategy without executingpatent_search_profile_login_start— Launch headed browser for Google login
Research sessions
Sessions persist search results across multiple tool calls:
patent_session_create— Start a new research sessionpatent_session_load/list/note/annotate— Manage session statepatent_session_export— Generate Markdown report
Patent ID formats
Don't worry about formatting. The canonicalizer has seen it all:
Input | Canonical form | Jurisdiction |
|
| US |
|
| US (with kind code) |
|
| US application |
|
| US (inferred) |
|
| EP |
|
| International (PCT) |
|
| Japan |
|
| China |
|
| South Korea |
|
| Australia |
|
| Canada |
|
| (extracted) |
Also handles NZ, BR, and IN formats. 22+ patterns total. If it looks like a patent number, we'll figure it out.
How it works
Agent MCP Server (Rust)
│ │
├─ fetch_patents ──────────►│
│ ├─ cache lookup (SQLite)
│ │ HIT? return immediately
│ │ MISS?
│ │ ├─ try sources in priority order
│ │ │ USPTO → EPO → Espacenet → WIPO → ...
│ │ ├─ download PDF (async, concurrent)
│ │ ├─ convert PDF → Markdown
│ │ │ (pymupdf4llm → pdfplumber → pdftotext → marker)
│ │ ├─ extract metadata
│ │ └─ store in cache
│◄──────────────────────────┤
│ files + metadata │Cache: Single global SQLite DB at ~/.local/share/patent-cache/index.db shared across all projects. Patent files live in ~/.local/share/patent-cache/patents/{CANONICAL_ID}/. First fetch takes seconds. Every subsequent fetch is instant — even across different repos.
HTTP transport: Rust, Python fetch, and Python search can each run on localhost HTTP at the default URL http://127.0.0.1:38473/mcp when launched with serve-http. Stdio remains the default when you launch a server without serve-http. The implementations share the same default URL and localhost-only bind, but this repo does not currently claim wire-level Rust/Python HTTP parity.
Activity journal: Each tool call is logged to .patent-activity.jsonl in the current working directory (JSONL format). This file is meant to be git-tracked so each project retains a record of what was searched, fetched, and accessed. Disable with PATENT_ACTIVITY_JOURNAL="".
PDF → Markdown: Four converter backends tried in order (pymupdf4llm → pdfplumber → pdftotext → marker). If one fails, the next picks up. Tables extracted and merged. OCR via tesseract for scanned patent figures. The output is clean enough for an LLM to read directly.
Dual implementation, cross-verified: Rust is the production server — standalone, async, with native HTTP fetchers and retry logic. Python is the reference implementation. 39 cross-implementation parity tests verify both produce identical results for ID canonicalization, source ordering, converter output, and web search queries. When we say they match, we mean it — it's tested.
Configuration
All config via autoloaded env files, ~/.patents.toml, or environment variables (env vars take precedence). The Rust server autoloads ~/.patents-mcp.env and then .env from the current working directory before reading ~/.patents.toml and explicit environment variables.
Env var | Default | Description |
|
| Cache directory for patent files |
|
| Max concurrent fetches |
|
| HTTP timeout (seconds) |
| — | EPO OPS |
| — | Lens.org API key |
| — | SerpAPI key (web search fallback) |
| — | GCP project for BigQuery source |
|
| Try all sources even after first success |
|
| Per-repo activity journal (empty = disabled) |
|
| Default search backend ( |
|
| Run Playwright in headless mode |
|
| Browser idle timeout in seconds (default 30 min) |
|
| Max Google Patents result pages per query |
|
| Enrich top N search results with full metadata |
Development
Running tests
# Rust tests (237 tests, <0.1s)
cargo test --manifest-path src/rust/Cargo.toml
# Start the Rust server over localhost HTTP
just serve-rust-http
# Start the Python fetch server over localhost HTTP
just serve-http
# Start the Python search server over localhost HTTP
just serve-search-http
# Direct stdio MCP smoke test against the Rust dev server
just mcp-smoke-rust
# Direct stdio MCP smoke test against the installed Rust binary
just mcp-smoke-rust-installed
# Fast Python unit tests (<1s, all I/O mocked)
pytest tests/python/ -m "not browser and not integration and not slow"
# Full Python suite (includes fuzz tests via Hypothesis, slow tests)
pytest tests/python/
# Cross-implementation parity — verifies Python == Rust (39 tests)
pytest tests/cross_impl/
# Manual E2E tests — automated script (31 tests)
python3 run_manual_e2e.pyProject structure
src/
python/patent_mcp/ # Python reference implementation
id_canon.py # Patent ID canonicalization (22+ formats)
cache.py # Dual-layer SQLite cache
config.py # TOML + env var config loading
fetchers/
http.py # All HTTP/API source implementations
web_search.py # DuckDuckGo / SerpAPI fallback
orchestrator.py # Priority-ordered source orchestration
converters/ # PDF → Markdown (4 backends + OCR)
server.py # MCP server (FastMCP, stdin/stdout)
rust/ # Rust production server (standalone)
src/
id_canon/ # Canonicalization (must match Python)
cache/ # Two-layer SQLite cache (rusqlite)
config/ # TOML + env var config loading
converters/ # PDF → Markdown (4 backends + OCR)
fetchers/
http/ # 9 native async HTTP sources with retry
web_search/ # DuckDuckGo + SerpAPI fallback
browser.rs # Native Google Patents HTML/microdata fetcher
mod.rs # Priority-ordered source orchestrator
server/ # JSON-RPC 2.0 over stdin/stdout
tests/
python/ # 16 test files: unit, integration, fuzz
cross_impl/ # Python == Rust parity tests
fixtures/ # Shared test data
docs/
api-keys.md # API key setup for each sourceWhat makes this different
Most patent tools give you an API wrapper for one database. This gives your agent the entire global patent system behind a single function call. It handles the authentication, the format differences, the fallbacks, the caching, and the PDF-to-text conversion. Your agent asks for a patent and gets back something it can read. That's it. That's the product.
MCP Debugging
If your editor or MCP client seems to be using a stale server process, test the Rust server directly over stdio JSON-RPC instead of guessing whether the client reloaded:
# Current checkout / dev binary
just mcp-smoke-rust
# Installed binary from ~/.cargo/bin
just mcp-smoke-rust-installed
# Different patent
just mcp-smoke-rust US7654321B2These recipes send initialize and tools/call requests straight to the server process, so they verify the real binary behavior without depending on Claude/OpenCode reload state.
License
CC0 1.0 Universal
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/clankercode/mcp-fetch-patents'
If you have feedback or need assistance with the MCP directory API, please join our Discord server