Skip to content

Running patent-client-agents as a stdio MCP server

The [mcp] extra ships a ready-to-run stdio MCP server that exposes all patent and IP tools to any MCP-speaking client — Claude Code, OpenAI Codex CLI, Google Antigravity CLI, Claude Desktop, Google Gemini CLI, Cursor, Windsurf, Cline, Zed, Continue.dev, VS Code Copilot Chat, JetBrains AI Assistant, CoWork, or a homegrown fastmcp Client. See the MCP client configuration guide for per-client config snippets.

Install

pip install 'patent-client-agents[mcp]'

This installs the runtime (fastmcp, starlette) and adds the patent-client-agents-mcp console script.

Run

patent-client-agents-mcp                  # default: stdio transport, no auth

patent-client-agents-mcp is a thin wrapper around patent_client_agents.mcp.server:mcp that runs via fastmcp. You can also invoke it directly:

python -m patent_client_agents.mcp.server
fastmcp run patent_client_agents.mcp.server:mcp

MCP client configuration

Native plugin packages for Claude Code, Codex CLI, and Antigravity CLI, plus per-client config locations and exact syntax for Gemini CLI, Cursor, Windsurf, Cline, Zed, Continue.dev, VS Code Copilot Chat, JetBrains AI, and Claude Desktop are in the MCP client configuration guide. The JSON below is the common stdio shape used by Claude Code and Antigravity CLI. Codex expresses the same fields in TOML.

{
  "mcpServers": {
    "patent-client-agents": {
      "command": "patent-client-agents-mcp"
    }
  }
}

If you prefer to invoke a specific venv or Python interpreter:

{
  "mcpServers": {
    "patent-client-agents": {
      "command": "/path/to/.venv/bin/patent-client-agents-mcp",
      "env": {
        "USPTO_ODP_API_KEY": "…",
        "EPO_OPS_API_KEY": "…",
        "EPO_OPS_API_SECRET": "…"
      }
    }
  }
}

The server starts with no authentication in stdio mode. Any env vars set in the env block are available to the connectors — USPTO ODP, EPO OPS, and JPO all consume credentials from env (see each connector's CATALOG.md entry). The local source access guide lists the supported credentials and corpus builders.

Tools exposed

The server mounts ip_mcp, which composes the per-source and per-intent sub-servers under src/patent_client_agents/mcp/tools/.

136 patent + IP MCP tools are exposed by default. Private/local deployments expose up to 234 tools when every env-gated family is configured. Tool counts are generated by importing the composed FastMCP server, not by static decorator scans:

uv run python scripts/mcp_tool_counts.py --check-docs

The major always-on families include Google Patents, USPTO ODP / PPUBS / assignments / office actions / petitions / bulk data, TSDR/TMEP/TM assignments, EPO OPS, CPC, MPEP, EPO/EPC/UPC substantive-law corpora, USITC, CAFC, US Copyright Office, WIPO Lex, IP Australia bulk, PRV/PRH, and the fee-schedule tools. Credential-gated families include JPO, CanLII, EUIPO, IP Australia live APIs, KIPO, TIPO, and INPI France.

Downloads — two transports

Tools that return bytes (PDFs, file-history docs, JPO bundles, etc.) ride two transports out of one fetch:

  1. An HMAC-signed download_url (HTTPS) when LAW_TOOLS_CORE_PUBLIC_URL is set on a remote HTTP deployment.
  2. A pca://... MCP resource URI served via resources/read over the existing MCP session.

Tool responses include both: structured content carries download_url, resource_uri, filename, content_type, size_bytes (and expires_at on rotating URLs); content blocks carry a ResourceLink pointing at the same pca:// URI.

Why two paths. Hosted sandboxes like Claude CoWork allowlist the MCP server but block outbound HTTP to arbitrary hosts — a curl against mcp.patentclient.com/downloads/... fails even though the tool call that minted the URL succeeded. The resources/read path rides the session the client is already holding, so the bytes flow without ever touching the network gate. URL-comfortable clients (Claude Desktop, Cursor, homegrown clients) keep fetching download_url directly and ignore the resource link.

The resource templates are advertised via resources/templates/list:

pca://patents/{publication_number}
pca://publications/{publication_number}
pca://epo/patents/{publication_number}
pca://uspto/applications/{application_number}/documents/{document_identifier}
pca://ptab/documents/{document_identifier}
pca://cafc/opinions/{appeal_number}
pca://usitc/documents/{document_id}/attachments/{attachment_id}
pca://jpo/documents/{ip_type}/{application_number}/{doc_kind}     # env-gated

The path after pca:// matches the HTTPS download path one-for-one — pca://patents/US12345678B2 and /downloads/patents/US12345678B2 resolve the same cached bytes.

Bulk downloads. Bulk tools (e.g. download_file_history, download_ptab_trial_documents) return one ResourceLink per successfully fetched item alongside a zip URL. The structured manifest carries per-item resource_uri + download_url, so resource-aware clients can pull per-doc through MCP and avoid JSON-RPC message caps that bite on large archives. Bulk zip resources themselves are HTTP-only — use the per-doc URIs over MCP, or the zip download_url over HTTPS.

In stdio mode without LAW_TOOLS_CORE_PUBLIC_URL, tools write bytes to a tempfile and return file_path instead. The resource_uri field is still set so MCP clients that resolve it locally see the same path.

Verifying

A one-off smoke test against the running server:

import asyncio
from fastmcp import Client
from fastmcp.client.transports import StdioTransport

async def main():
    async with Client(StdioTransport(command="patent-client-agents-mcp", args=[])) as c:
        tools = await c.list_tools()
        print(len(tools), "tools")
        result = await c.call_tool(
            "get_patent",
            {"patent_number": "US10000000B2", "view": "details"},
        )
        print(result.data.items[0]["title"] if result.data else None)

asyncio.run(main())

Expect 136 tools by default and up to 234 tools when every env-gated family is configured. The expected title is Coherent LADAR using intra-pixel quadrature detection. Agent users can run the equivalent first research task as a prompt.

Not installed?

If patent-client-agents-mcp is on PATH but startup fails with ModuleNotFoundError: No module named 'fastmcp', you installed patent-client-agents without the [mcp] extra. Re-install with pip install 'patent-client-agents[mcp]'.