NO

navisbio/ops-patent-search-mcp

Developer tools
20 stars 0 forks 品質 55 トレンド 55

Unofficial MCP server for exploring patents via the EPO Open Patent Services (OPS) API. Covers the full global patent database (EP, US, WO, JP, CN, and more).

概要

Unofficial MCP server for exploring patents via the EPO Open Patent Services (OPS) API. Covers the full global patent database (EP, US, WO, JP, CN, and more). This is an — useful for quick searches, reading individual patents, checking legal status, and getting an initial sense of a technology area. It works well in Claude Desktop and other consumer MCP clients, but these environments have limited context windows and are subject to API rate limits, so results for broad queries will be incomplete. For exhaustive patent landscape analysis, systematic FTO assessments, or large-scale prior art searches, use specialised frameworks designed for parallel retrieval and structured knowledge bases. 1. Register at developers.epo.org for a Consumer Key and Secret (free tier available). 2. Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS): The search_patents tool uses EPO's CQL (Contextual Query Language).

README

ops-patent-search

Unofficial MCP server for exploring patents via the EPO Open Patent Services (OPS) API. Not affiliated with the EPO. Covers the full global patent database (EP, US, WO, JP, CN, and more).

This is an exploratory tool — useful for quick searches, reading individual patents, checking legal status, and getting an initial sense of a technology area. It works well in Claude Desktop and other consumer MCP clients, but these environments have limited context windows and are subject to API rate limits, so results for broad queries will be incomplete.

For exhaustive patent landscape analysis, systematic FTO assessments, or large-scale prior art searches, use specialised frameworks designed for parallel retrieval and structured knowledge bases.

Tools

Tool Description
search_patents CQL search across title, abstract, applicant, inventor, IPC/CPC, dates, and forward citations. Supports auto-pagination for landscape searches.
get_patent_details Title, abstract, applicants, inventors, classifications, dates, priorities. Batch mode up to 100 patents.
get_patent_claims Paginated claims text. Auto-falls back to EP/WO family equivalent if needed.
get_patent_description Paginated specification text. Same family fallback as claims.
search_in_patent_text Keyword search within claims + description. Returns snippets with paragraph indexes for targeted reading.
search_and_filter_fulltext Search, then keep only the hits whose claims or description actually contain your terms. One call instead of a search plus one full-text call per hit.
get_patent_family INPADOC patent family members across jurisdictions.
get_patent_legal_status Grant, opposition, lapse, withdrawal events. Determines whether a patent is in force.
get_patent_citations Backward citations (prior art) split into patent and non-patent literature.

Setup

Requires Node.js 22 or newer.

  1. Register at developers.epo.org for a Consumer Key and Secret (free tier available).

  2. Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

{
  "mcpServers": {
    "ops-patent-search": {
      "command": "npx",
      "args": ["-y", "ops-patent-search"],
      "env": {
        "PATENT_CONSUMER_KEY": "your_consumer_key",
        "PATENT_CONSUMER_SECRET_KEY": "your_consumer_secret"
      }
    }
  }
}

CQL query syntax

The search_patents tool uses EPO’s CQL (Contextual Query Language). Key fields:

ta (title+abstract), ti (title), ab (abstract), pa (applicant), in (inventor), cl (IPC+CPC), ic (IPC), cpc (CPC), pd (publication date), pn (publication number), ct (forward citations).

Operators: AND, OR, NOT (uppercase). Wildcards: * (right truncation, on ta/ti/ab/pa/in only).

ta="CRISPR" AND pd>=2023
pa="Novartis*" AND ta="cancer" AND ic="A61K"
ta="antibody drug conjugate" AND pa="Roche*"
ct="EP3750919"

Full-text fields (claims, desc, ftxt) are unreliable for phrase searches and don’t support wildcards. Use ta= for CQL filtering, then search_in_patent_text for keyword analysis within specific patents.

Examples

Search for CRISPR patents by the Broad Institute since 2020 and summarise the top 5.
Is EP3750919 currently in force? Check its legal status.
Find prior art on antibody-drug conjugates targeting HER2 by Roche. Search the most relevant result for 'linker' and summarise the key claims.

Skills (Claude Code plugin)

When installed as a Claude Code plugin, guided workflow skills become available. These provide structured starting points for common patent tasks — but keep in mind this is an exploratory tool, not a substitute for professional patent search platforms.

Skill Description
Prior Art Search Guided CQL query construction, result triage, keyword search in full text
Patent Landscape Sample-based overview of a technology area — top applicants, filing trends, classification clusters
FTO Analysis Spot-check in-force patents and map claims against product features (not exhaustive)
Citation Network Explore backward/forward citations and identify key patents in a citation chain
LOE Analysis Look up patent family coverage, legal status, and expiry timelines for a compound

Development

Rate limits

The server retries rate-limited OPS requests (HTTP 403/429) with backoff, honoring Retry-After in seconds or as an HTTP date. Each request gets at most two retries, within the tool time budget (55 seconds by default; OPS_TOOL_TIMEOUT_MS overrides it). The server remembers the cooldown across tool calls. If the wait exceeds 15 seconds or cannot fit in the next call’s budget while reserving time for a request, it returns a rate-limit error without sending another OPS request.

Agents receive error: "rate_limited", retryable: true, retryAfterSeconds, and retryAttempts on rate-limit errors. Interrupted multi-step searches preserve retrieved results and return partial: true, rateLimit, and isError: true. Unchecked sections and documents are unknown; zero matches in partial results do not establish absence. Wait for the reported delay before retrying, preserve partial results, and avoid parallel calls. Successful calls that waited or retried include _retry activity; _throttle reports OPS quota headers when available. OPS also reports service load and request limits in X-Throttling-Control. Following EPO guidance, section 2.3.3, the server retains the most restrictive observations for 60 seconds and paces search, retrieval, family, and legal requests. _throttle.quota reports requestLimit (requests per 60 seconds), not remaining quota. Overload is surfaced as a warning even when the service colour is green; successful results remain valid. Zero search results under overload include a suggestion to confirm later, a precaution rather than evidence that the result is incorrect.

Preventive waits over 15 seconds, or waits that cannot fit the tool budget with room for the next request, return error: "ops_deferred", requestSent: false, and retryAfterSeconds. This is a local deferral, not an HTTP 403/429 failure. Interrupted multi-step calls retain results and include partial: true, deferred, and isError: true. Search pagination supplies a continuation query and range_start, range_end, and auto_paginate: false; use these arguments to resume. For searches split by year, that continuation covers the interrupted year; subsequent years still need review. Full-text filters list remainingDocuments for individual text searches; rerunning the filter starts over. Array payloads retain their format and receive metadata in a separate MCP text content block.

Text searches with section_filter retrieve only the requested sections.

Commands

npm install
npm run build              # Compile TypeScript → dist/
npm run test:unit          # Offline regression tests (no credentials needed)
npm test                   # Integration tests (requires PATENT_CONSUMER_KEY and PATENT_CONSUMER_SECRET_KEY in .env)

Scenario tests:

npx tsx integration_tests/run-all.ts

Smoketest (end-to-end eval harness via headless Claude Code):

./smoketest/run-claude.sh                          # all tests
./smoketest/run-claude.sh basic-search             # single test
SMOKETEST_MODEL=sonnet ./smoketest/run-claude.sh   # pick the evaluator model (default: CLI default)

Each smoketest runs a 3-message conversation: execute the task using the MCP tools, verify entities against the database (hallucination check), then collect structured feedback on what worked and what should be improved. Results land in smoketest/results/[_model]/ as .task.txt, .hallucination.txt, and .feedback.txt per test. The evaluator runs from a scratch directory outside the repo so the repo’s own .mcp.json is not loaded a second time as a project server.

Three things measure the result, none of them the evaluator’s own opinion: ground-truth assertions per scenario (smoketest/grade.py), a separate judge model that scores each report from the tool log and can compare two runs pairwise (smoketest/judge.py), and a findings index that tracks which issues recur across runs (smoketest/findings.py). Two scenarios are hold-outs whose critiques are never collected. The fix protocol, from reproduce-before-fix to marking a finding resolved, is in smoketest/README.md.

Run as Claude Code plugin (local dev):

claude --plugin-dir /path/to/ops-patent-search

.mcp.json is the plugin server manifest: its ${CLAUDE_PLUGIN_ROOT} path is only expanded when the server is loaded as a plugin. Enabling it as a plain project MCP server instead leaves the variable unexpanded and the server exits with Cannot find module '.../${CLAUDE_PLUGIN_ROOT}/dist/index.js'. Use --plugin-dir as above, or register a separate absolute-path server with claude mcp add.

Privacy

This server communicates only with the EPO OPS API (ops.epo.org) using your credentials.

License

MIT

View this README on GitHub

インストール

npx -y ops-patent-search

設定

{ "mcpServers": { "ops-patent-search": { "command": "npx", "args": ["-y", "ops-patent-search"], "env": { "PATENT_CONSUMER_KEY": "your_consumer_key", "PATENT_CONSUMER_SECRET_KEY": "your_consumer_secret" } } } }