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,
Claude Desktop, OpenAI Codex CLI, Google Gemini CLI, Cursor, Windsurf,
Cline, Zed, Continue.dev, VS Code Copilot Chat, JetBrains AI Assistant,
CoWork, or a homegrown fastmcp Client. See
installation.md §5
for per-client config snippets.
Install¶
This installs the runtime (fastmcp, starlette) and adds the
patent-client-agents-mcp console script.
Run¶
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:
MCP client configuration (example: Claude Code)¶
Per-client config locations and exact syntax for Codex CLI, Gemini CLI,
Cursor, Windsurf, Cline, Zed, Continue.dev, VS Code Copilot Chat,
JetBrains AI, and Claude Desktop are in
installation.md §5.
For Claude Code specifically — add one of the following blocks to your
MCP config (.mcp.json at the project root or ~/.claude.json for
user-scope):
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).
Tools exposed¶
The server mounts ip_mcp, which composes the per-source and per-intent
sub-servers under src/patent_client_agents/mcp/tools/.
111 patent + IP MCP tools are exposed by default. Private/local deployments expose up to 168 tools when every env-gated family is configured. Tool counts are generated by importing the composed FastMCP server, not by static decorator scans:
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:
- An HMAC-signed
download_url(HTTPS) whenLAW_TOOLS_CORE_PUBLIC_URLis set on a remote HTTP deployment. - A
pca://...MCP resource URI served viaresources/readover 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_mpep_section", {"section": "2106"})
print(result.data.get("title") if result.data else None)
asyncio.run(main())
Expect 111 tools by default and up to 168 tools when every env-gated
family is configured. Title should be 2106 … Patent Subject Matter
Eligibility.
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]'.