Skip to main content
Glama

IP-MCP

License: MIT Python 3.12+ MCP CI GitHub release

English · 日本語

Query Japanese patents in natural language from Claude. IP-MCP wraps the Japan Patent Office's official "Patent Information Retrieval API" as an MCP server, so Claude Desktop, Claude Code, and iPhone Claude can resolve patent numbers, check registration status, pull citations, and walk five-office families — 12 official-API tools plus 1 deliberately isolated keyword-search tool.


What you can ask Claude in 30 seconds

You: "Tell me the registration status and prior art of JP-2010-228687."

Claude (under the hood):

  1. jpo_convert_patent_number → application number 2009080841

  2. jpo_get_patent_registration → registration 5094774, Hitachi Ltd., expires 2029-03-30, alive

  3. jpo_get_patent_citations → 20 prior-art references

Reply: "Train Control Ground Equipment and System" (Hitachi Ltd.) was registered as JP5094774 on 2012-09-28, currently in force, due 2029-03-30. 20 prior-art citations from search report and rejection grounds, all patent literature (no NPL)…

Keyword search is split into a separate tool (external_search_patents_by_keyword, Google Patents XHR). The LLM can never accidentally fall back from the official API to the unofficial source — every response carries an explicit source field.


Related MCP server: EKMS MCP Server

How it compares

J-PlatPat (manual web UI)

Hand-rolled Flask wrapper

IP-MCP

Hitting Google Patents directly

Data source

Official (JPO)

Official (JPO)

Official (JPO) + external (optional)

Unofficial

Number convert / progress / registration / citations

✓ (by hand)

Keyword search

△ (isolated external tool)

Callable directly from an LLM

❌ (REST + parsing needed)

✅ native MCP

△ (HTML/JSON parsing needed)

Official vs. unofficial distinction

single source

✅ mandatory source field

Automatic fallback

❌ forbidden (the LLM decides)

Auth

session

env

env or OAuth 2.1 (DCR + PKCE)

none

Deploy

DIY

Docker Compose

The official JPO API is number-lookup only — every endpoint takes an application / publication / registration number, an applicant code, or an exact-match applicant name. Keyword / IPC / F-term / date-range / partial-name search does not exist in the spec. So:

  • tools_official/ — names start with jpo_*, response is {"source": "jpo_official", …}

  • tools_external/ — names start with external_*, response is {"source": "google_patents_unofficial", …}

  • A boundary test forbids any import from tools_external/ into tools_official/. No silent fallback — the LLM decides whether to consult the unofficial source.


Architecture

flowchart LR
    User["Claude Desktop /<br/>Claude Code /<br/>iPhone Claude"]
    CF["Cloudflare<br/>(Edge TLS + Tunnel)"]
    Caddy["Caddy<br/>(CF Origin Cert)"]

    User -->|"HTTPS + OAuth"| CF
    CF -->|"outbound from home<br/>via cloudflared"| Caddy
    Caddy -->|"http+SSE"| MCP

    subgraph Docker["Docker container (Python 3.12 + FastMCP)"]
      MCP["MCP server<br/>:8765"]
      Official["tools_official/<br/>(jpo_* 12 tools)"]
      External["tools_external/<br/>(external_* 1 tool)"]
      OAuth["OAuth 2.1<br/>SQLite-backed"]
      MCP --> Official
      MCP --> External
      MCP -.->|"persisted"| OAuth
    end

    Official -->|"OAuth2 password grant"| JPO[("JPO Patent API")]
    External -->|"3s spacing + 503 backoff"| GP[("Google Patents XHR")]

    classDef boundary stroke-dasharray: 5 5
    class External,GP boundary

Core design rules:

  • tools_official/ (official JPO) and tools_external/ (unofficial Google Patents) are fully separated at the code-hierarchy, call-site, and logger level. A boundary test blocks any import from tools_external/ into tools_official/.

  • Retry is allowed only within the same data source (401 → token refresh; 303 → exponential backoff). Automatic cross-source fallback on failure is forbidden — the LLM decides.

  • Every response carries {"source": "jpo_official"} or {"source": "google_patents_unofficial"}.


Quick start

Local development

cp .env.example .env          # Fill in JPO_USERNAME / JPO_PASSWORD
chmod 600 .env
docker compose up -d --build

LAN deployment (no-auth)

Create docker-compose.override.yml to bind to your LAN interface (the repo ships a docker-compose.override.yml.example):

services:
  ip-mcp:
    ports:
      - "YOUR_SERVER_IP:8765:8765"   # your LAN IP

Claude Desktop / Code config:

{
  "mcpServers": {
    "ip-mcp": {
      "transport": { "type": "sse", "url": "http://YOUR_SERVER_IP:8765/sse" }
    }
  }
}

Codex CLI's direct HTTP MCP (codex mcp add --url) expects Streamable HTTP, so register the /mcp path when using it directly from Codex:

CODEX_HOME=/path/to/codex-home codex mcp add ip-mcp --url https://your-host.example.com/mcp
CODEX_HOME=/path/to/codex-home codex mcp login ip-mcp

SSE clients register /sse. To serve Codex direct HTTP and SSE clients from the same public server, start with MCP_TRANSPORT=both to expose both /mcp and /sse under the same OAuth config. For a single client, MCP_TRANSPORT=sse (default) or MCP_TRANSPORT=streamable-http also works.

iPhone Claude / claude.ai (public, OAuth 2.1)

For public exposure the recommended setup is Cloudflare Tunnel + Caddy (CF Origin Cert) — cloudflared dials out from your home network to the CF edge, so no router port forwarding is needed and hairpin NAT is a non-issue. A traditional reverse proxy with Let's Encrypt + direct 443 also works. Either way, set MCP_OAUTH_MASTER_PASSWORD + MCP_OAUTH_ISSUER_URL to enable OAuth 2.1 (DCR + PKCE + master-password consent). Issued client tokens persist to SQLite and survive container restarts.

MCP_OAUTH_MASTER_PASSWORD=<24+ chars random>
MCP_OAUTH_ISSUER_URL=https://your-host.example.com
# optional: MCP_OAUTH_DB_PATH=/app/data/oauth.db

See PLAN.md §9-§10 and OPERATIONS.md for full deployment + operations details (Japanese for now).


Tool list

Name

Purpose

jpo_convert_patent_number

Convert between application / publication / registration numbers

jpo_get_patent_progress

Examination progress (full / simple toggle)

jpo_get_patent_registration

Registration info & right status

jpo_get_patent_citations

Cited prior-art documents

jpo_get_divisional_apps

Divisional applications

jpo_get_priority_apps

Priority-basis applications

jpo_lookup_applicant

Applicant code ⇄ name (exact match only)

jpo_get_patent_documents

Office actions / refusal reasons / amendments (handles inline ZIP + signed URL)

jpo_get_jpp_url

J-PlatPat canonical URL

jpo_get_opd_family

Five-office patent family (JPO / USPTO / EPO / CNIPA / KIPO)

jpo_get_opd_doc_list

OPD document list

jpo_fetch_full_record

High-level composite fanning out to multiple official endpoints (stays entirely within the official API)

Response: {"ok": true, "source": "jpo_official", "data": {…}, "remaining_today": "…"}

Name

Purpose

external_search_patents_by_keyword

Free-text / assignee / IPC / date-range search of Japanese patents (Google Patents XHR, reference use)

Response: {"ok": true, "source": "google_patents_unofficial", "data": {…}}

Isolated because the official API offers no keyword search (number-lookup only). On failure it returns {"ok": false, "kind": "search_unavailable"} and never falls back to an official tool.


Rate limits (operations)

The official JPO API delegates self-throttling responsibility to the operator:

  • Per-minute rate: /api/patent/* is 10 req/min, /opdapi/* is 5 req/min (OPD is counted separately on its own bucket).

  • Daily quota: 30–800/day per endpoint (national-API quotas were doubled in March 2026). The authoritative live counter is result.remainAccessCount, returned on every response.

  • jpo_fetch_full_record fans out to 4 official endpoints in parallel, so one call consumes 1 unit from each of 4 separate daily quotas (not 4 from the same quota). The bottleneck is whichever quota is lowest.

For the tool-to-endpoint mapping and operational thresholds, see OPERATIONS.md §JPO API レート制約とクォータ (Japanese).


Docs

  • 📐 PLAN.md — Design plan (architecture, full tool list, phased plan) [JP]

  • 🤖 CLAUDE.md — Claude Code guide (non-negotiable design rules, JPO API gotchas) [JP]

  • 🔧 OPERATIONS.md — Operations runbook (access-log summary, master-password rotation, troubleshooting) [JP]


Placeholder

Example

How to set

YOUR_SERVER_IP

192.0.2.10

LAN IP of your deployment host

<SSH_USER>

youruser

SSH username on the host

your-host.example.com

your own domain

public hostname behind Cloudflare / your reverse proxy

The port binding in docker-compose.yml defaults to 127.0.0.1:8765 (same-machine only). To expose on the LAN, create a separate docker-compose.override.yml (already gitignored) to override it.

License

MIT — see LICENSE.

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
0dRelease cycle
2Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Appeared in Searches

Latest Blog Posts

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/kitepon-rgb/IP-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server