Skip to main content
Glama
ricky9w
by ricky9w

namestack-uspto

English | 简体中文

Screen a brand name against US federal trademarks before you commit to it. Read-only: it finds identical and similar marks, and never files, opposes, or registers anything.

One command serves both audiences over the same query engine: a CLI for people, and namestack-uspto mcp, an MCP server for agents.

Results are a knockout screen, not a clearance opinion. They cover federal US trademarks only, and say nothing about state, common-law, or non-US rights.

Quick start

Installation

Requires Node.js 22.18 or newer. There is no account, API key, or login.

npm install --global @namestack/uspto            # installs namestack-uspto
npx -y @namestack/uspto check --name=yourbrand   # or run it without installing

To build and install from a clone instead:

bun install --frozen-lockfile
bun run build
npm pack
npm install --global ./namestack-uspto-*.tgz

The installed command needs Node, not Bun. Bun is only used to build.

Usage

Confirm live access, find the class your goods or services fall in, then screen the name against it:

namestack-uspto doctor --online
namestack-uspto classes --class=025
namestack-uspto check --name=aurora --classes=025 --related --limit=3
aurora
  identical 34  contains 168  spelling 85  fuzzy 43  sound 476
  resultId 6cb6299e-fd40-4c29-8408-4f2b33a4fe9c  (fetched 2026-09-18T08:12:13.572Z)
  Read a tier: namestack-uspto results --id=6cb6299e-fd40-4c29-8408-4f2b33a4fe9c --tier=sound
  identical
    AURORA                                live  reg  IC 025  same  #85952176  2013-06-06  The Aurora Project, LLC (LI…
    AURORA                                live  pend  IC 025  same  #99825705  2026-05-15  AURORA FASHION INCORPORATED…
    AURORA                                live  reg  IC 009,042  coordinated  #78192660  2002-12-09  EPIS, Inc. (CORPORATION; OR…

The second line counts matches per tier. The marks below are the strongest --limit of them, grouped by tier. --related widens class 025 to the classes USPTO coordinates with it, which is why a mark in class 042 appears as coordinated. doctor --online runs one small search; without --online it only reports local setup.

Screen up to ten candidates in one command. Each name costs one upstream request, unless the same query ran in the last 24 hours:

namestack-uspto check --name=aurora,northwind,lumenpath --classes=009,042 --related

To query from Claude Code or another MCP host instead, see MCP server.

Related MCP server: mcp-sanctions-screening

Command reference

Put the complete command path first, then its options. Every command supports --help.

Command

What it does

How to use it

check

Screens 1–10 names for identical and similar marks, grouped by match tier.

--name=aurora,northwind --classes=009,042 --related. --refresh bypasses the cache.

results

Pages one tier of a saved screening snapshot, without network access.

--id=RESULT_ID --tier=sound, then pass the returned cursor as --cursor="NEXT".

search

Runs a USPTO field tag query, for refining a screen.

--query="CM:aurora AND IC:025" --sort=filed, then --cursor="NEXT".

mark

Shows one record by number.

--serial=85952176 or --registration=NUMBER. --history adds prosecution history and maintenance deadlines.

classes

Lists the 45 international classes and US classes A, B, and 200, with their coordinated classes.

Offline. --class=025 shows one.

doctor

Reports the version, platform, cache directory, and cache settings.

--online runs one small search to verify live access.

schema

Prints JSON Schema for every input and result.

Offline.

mcp

Serves the query tools to an MCP host over stdio.

The host starts it; see MCP server.

check and search share three filters. --classes takes up to 48 comma-separated classes, each three digits or A or B, and defaults to every class. --related also matches the classes USPTO coordinates with them, and requires --classes. --status is live by default, or all to include dead records.

--limit takes 1–100 and defaults to 25: marks per name for check, records per page for search and results. A check name is 1–80 characters. A search query is up to 1,000 characters, sorts by relevance, filed, registered, mark, or serial, and cannot page past 10,000 records. mark takes a 7–8 digit serial number or a registration number of up to 8 digits.

Common options and defaults

Option

What it controls

--format=auto|json|human

auto prints human output to a terminal outside CI, and JSON otherwise.

--no-input

Disables the progress spinner. The tool never prompts, and JSON mode never shows a spinner.

--quiet, --no-color

Suppress progress, disable color. A nonempty NO_COLOR and TERM=dumb also disable color.

--timeout=SECONDS

Total deadline, 1–600, default 60. Screening paces its own requests, so it needs more than one query does.

--env-file=PATH

Loads a dotenv file for this call. Existing environment values win.

Exit codes: 0 success, including names with no matches; 1 operational failure, including PARTIAL_FAILURE; 2 invalid usage, configuration, or query; 124 timeout; 130 and 143 interrupted.

Read the results

Each mark carries matchedBy, naming the tier it matched. Tiers are exclusive and run strongest first, so a mark appears once, under the strongest tier that found it:

Tier

Matches

identical

The same letters, ignoring case, spacing, and punctuation: AURORA, AU-RORA, AURORA!.

contains

The name inside a longer mark or its pseudo mark: LA AURORA.

spelling

Alternate spellings of the same sounds: ARORA, ORORA.

fuzzy

Near spellings within a small edit distance: AUROVA. For a multi-word name, any one word within that distance.

sound

Similar pronunciation, from USPTO's phonetic index. Matches broadly.

meaning

The name in a mark's translation statement.

identical, contains, fuzzy, sound, and meaning use USPTO index features as documented. spelling is this tool's own composition of the sound-alike regex pieces USPTO publishes; USPTO publishes the pieces, not this procedure, and its precision has not been measured.

  • live and classRelation matter most together. A live mark in the same or a coordinated class is the conflict worth acting on; a dead mark is history, not an obstacle.

  • Within a tier, marks rank live first, then by class relation (same, coordinated, other), then registrations before pending applications, then by earliest filing, since earlier rights are senior, and finally by serial number. A tier's sample is the top of this ranking over the whole tier, so a truncated tier leaves out only lower-ranked marks, and repeating a query against the same index returns the same sample.

  • Read each tiers[] entry's status before its count. searched carries the tier's upstream total, the marks returned in this report, and truncated: true when the tier holds more. skipped carries total: null and a reason; it does not mean zero matches.

  • Names longer than 40 characters or 6 words after normalization skip identical, contains, and spelling to bound query cost. Shorten the name or refine with search when those tiers matter.

  • pseudoMarks are USPTO's alternate spellings of a mark, so a hit there is a real signal even when the printed text differs. classes flags each class cancelled for that mark; a cancelled class does not count toward classRelation.

  • mark --history adds history from USPTO's case-detail service. If that second request fails, the record still returns, with historyError beside history: null.

  • search returns total, count, cursor, and truncated. cursor: null ends the pages. Every sort ends on the serial number, so tied records keep their order from page to page.

  • Every result carries operation, source, checkedAt, notice, and authoritative: false. PARTIAL_FAILURE keeps the names that succeeded; a failed name carries its own error and empty tiers and marks, never invented counts.

The envelope stays at schemaVersion: 1. Operation contracts follow the package version; schema prints them.

Errors

Code

Meaning

RATE_LIMITED

The request budget is spent, or USPTO throttled the source. Wait retryAfterSeconds; do not retry in a loop.

UPSTREAM_BLOCKED

USPTO answered with a bot challenge or refused the request. Use tmsearch.uspto.gov directly.

UPSTREAM_INCOMPLETE

USPTO timed out or lost search shards, even though HTTP succeeded. The partial result is discarded; narrow the query or retry later.

UPSTREAM_CHANGED

The response no longer matches docs/tmsearch.md.

UPSTREAM_ERROR, NETWORK_ERROR, TIMEOUT

The request failed in transit. retryable says whether a later retry can help.

INVALID_QUERY

USPTO or the local guard rejected the field tag query. Field tags and operators must be uppercase.

RESULT_WINDOW_EXCEEDED

A search page would read past 10,000 records. Narrow the query.

NOT_FOUND

No record carries that serial or registration number.

RESULT_EXPIRED, RESULT_NOT_FOUND

The snapshot is past retention or gone. Run check again for a new ID.

CACHE_INVALID, CACHE_UNAVAILABLE, CACHE_BUSY

Local cache data, storage, or locking failed. check still returns fresh data with cacheError; results fails.

INVALID_USAGE, CONFIG_INVALID

Arguments, environment, or cache settings are invalid. Nothing was sent.

Saved results

check saves each name's fetched tier samples as a snapshot, then trims the report to --limit. A saved name carries a resultId and cache metadata: hit, fetchedAt, freshUntil, retainUntil, and stale.

  • Reuse. The same query within the reuse TTL, 24 hours by default, returns the snapshot without contacting USPTO. --refresh fetches a new one; older IDs stay readable. A batch's checkedAt is the oldest fetchedAt among its names.

  • Continuation. results --id=RESULT_ID --tier=sound pages one tier of the snapshot offline. The cursor belongs to that snapshot and tier. Each tier saves its highest-ranked max(3 × limit, 30) records, capped at 100, which is 75 at the default limit. cachedCount counts that sample and total the upstream matches, so cursor: null with truncated: true means more matches exist than were saved. Reach them with a narrower check or a search.

  • Retention. A snapshot stays readable for 7 days from fetchedAt, marked stale: true once past its TTL. Reading it extends neither deadline. After retention, results fails with RESULT_EXPIRED instead of switching to newer data.

Setting

Default

Override

Reuse TTL

86400 seconds (24 hours)

NAMESTACK_USPTO_CACHE_TTL_SECONDS, or check --cache-ttl=SECONDS.

Retention

604800 seconds (7 days)

NAMESTACK_USPTO_CACHE_RETENTION_SECONDS, or check --cache-retention=SECONDS.

Both take decimal seconds. Retention must be positive and at least the TTL; a TTL of 0 disables reuse but still saves snapshots for results. Deadlines are fixed when a snapshot is created: raising a setting does not extend existing snapshots, while lowering the TTL stops reusing them sooner. Invalid values fail with CONFIG_INVALID before any request.

The cache key is the tool version plus the canonical upstream request. Output options do not affect it; --limit can, because it sets the sample depth. Class filters are normalized and deduplicated first. Simultaneous identical misses in one process share one fetch; separate processes share saved snapshots but not in-flight requests.

Only complete, successful screens are saved, genuine zero matches included; search and mark always query USPTO. When saving fails, the fresh result still returns with cacheError, and a name without a resultId cannot be continued. Corrupt cache data fails with CACHE_INVALID instead of being reset.

Where results are stored

Path

What it holds

~/.cache/namestack/uspto/queries/

Snapshots, their index, and a recovery journal for interrupted writes.

~/.cache/namestack/uspto/cooldown.json

The shared cooldown after an upstream block; see Request budget.

XDG_CACHE_HOME moves the whole tree, NAMESTACK_CACHE_DIR replaces the namestack level, and NAMESTACK_USPTO_CACHE_DIR points this tool at an absolute path.

There is no size cap and no background sweep. After a check or results, expired snapshots are deleted once the earliest retention deadline in the index has passed; an idle cache is never cleaned, but expired IDs stay unreadable. Writes are atomic and made under a cross-process lock; waiting more than two seconds for it fails with CACHE_BUSY.

Where the data comes from

USPTO publishes no API for searching trademarks by name. This tool queries the interface behind tmsearch.uspto.gov, which is undocumented and carries no availability promise; it can change or stop working without notice. What the tool relies on about that interface is recorded in docs/tmsearch.md. mark --history reads the case-detail endpoint on the same host.

The tool identifies itself as namestack-uspto/<version> in its User-Agent, sends no credentials or cookies, and never impersonates a browser or answers a bot challenge. If the interface starts requiring one, queries fail with UPSTREAM_BLOCKED.

Request budget

USPTO blocks a source that queries too often, so the tool paces itself:

  • At least 2 seconds between upstream requests, and at most 40 in any 5 minutes, per process. A long-lived MCP server shares one budget across all its tool calls.

  • When the next free slot is more than 60 seconds away, the call fails with RATE_LIMITED instead of waiting.

  • After an upstream block, a cooldown is written to cooldown.json: the server's Retry-After, or 15 minutes. Other invocations on the machine back off too, and queued requests recheck it before sending. The marker is advisory; an unwritable cache directory does not stop the tool.

  • Each attempt times out after 20 seconds, or 10 for history. Transient failures are retried at most twice within the total deadline.

A check costs one request per uncached name, mark one, and mark --history two. Cache hits, results, and classes cost nothing. --refresh still obeys the budget.

Use with AI agents and scripts

Scripts

Data commands write exactly one newline-terminated envelope to stdout, with diagnostics on stderr:

{"schemaVersion":1,"ok":true,"data":{}}
{"schemaVersion":1,"ok":false,"error":{"code":"INVALID_QUERY","message":"Logical operators must be uppercase; a lowercase and, or, or not is searched as a word.","retryable":false,"hint":"Field tags and logical operators must be uppercase, for example CM:aurora AND LD:true."}}

Select JSON and disable interaction explicitly:

namestack-uspto check --name=yourbrand --classes=042 --format=json --no-input
namestack-uspto schema --format=json

Agent skill

The bundled skill tells an agent how to choose classes, bound queries, read the tiers, and stop on rate limits, with field tag syntax in references/query-syntax.md. Install the CLI first; the skill does not install the executable.

MCP server

namestack-uspto mcp serves the queries to an MCP host over stdio. The host starts and stops the process; you do not run it yourself. There are no credentials to configure.

Set up in Claude Code

  1. Register the server. --scope user makes it available in every project:

    claude mcp add namestack-uspto --scope user -- namestack-uspto mcp
  2. Run claude mcp list and look for ✔ Connected. In a session, /mcp lists the five tools. Add the rule mcp__namestack-uspto with /permissions to allow all five without prompts.

Other hosts take the same command in their JSON configuration. If a host cannot find the command, use the absolute path from command -v namestack-uspto.

{
  "mcpServers": {
    "namestack-uspto": { "command": "namestack-uspto", "args": ["mcp"] }
  }
}

For a team, --scope project writes a .mcp.json to commit. npx spares each member a global install:

{
  "mcpServers": {
    "namestack-uspto": { "command": "npx", "args": ["-y", "@namestack/uspto", "mcp"] }
  }
}

Launch command

Command

Behavior

namestack-uspto mcp

Runs the global install and never contacts npm at startup. Upgrade with npm install --global @namestack/uspto@latest.

npx -y @namestack/uspto mcp

Needs no install and picks up new releases, because npx checks the registry on every start. Offline, npx retries for over a minute before using its cache, which exceeds Claude Code's 30-second startup limit.

npx -y --prefer-offline @namestack/uspto mcp

Skips the registry check, so it starts offline but does not look for new releases.

The first npx start downloads the package. If that is too slow, raise the limit with MCP_TIMEOUT=60000 claude.

Cache settings

MCP tools take no cache options. The server reads NAMESTACK_USPTO_CACHE_TTL_SECONDS and NAMESTACK_USPTO_CACHE_RETENTION_SECONDS on every uspto_check call, and the cache directory variables once at startup. A host does not necessarily pass your shell environment to the server, so set them explicitly:

claude mcp add namestack-uspto --scope user \
  -e NAMESTACK_USPTO_CACHE_TTL_SECONDS=3600 \
  -- namestack-uspto mcp

Tools

Tool

Input

uspto_check

Takes names (1–10), with optional classes, related, status, limit (1–100, default 25), and refresh.

uspto_results

Takes resultId and tier, with optional limit (1–100, default 25) and cursor. Reads the saved sample offline.

uspto_search

Takes query, with optional classes, related, status, sort, limit, and cursor.

uspto_mark

Takes serialNumber or registrationNumber, with optional history.

uspto_classes

Takes an optional class. Answers from bundled data, offline.

All five are annotated read-only, non-destructive, and idempotent; uspto_results and uspto_classes also declare openWorldHint: false, because they never leave the machine. Results arrive as structuredContent carrying the envelope shown under Scripts, with the same envelope as compact JSON text. An operational failure returns isError with that envelope and leaves the server running.

Known limits

  • The upstream index trails the register by about a day, and authoritative is always false. Confirm anything that matters on TSDR.

  • spelling is this tool's own heuristic, with unmeasured precision. sound is USPTO's index and deliberately broad.

  • Coordinated classes are USPTO's own grouping and do not capture every related good or service.

  • A few pre-1950s records carry a US class where an international class belongs, so their classRelation can mislead. They are almost always dead, and --status=live excludes them.

  • Design-only marks have no text to match. Find them with search by design code (DC).

  • search cannot page past 10,000 records, which is the upstream limit.

Development

bun install --frozen-lockfile
bun run dev -- check --name=aurora --classes=025   # run the CLI from source
bun run typecheck                                  # tsc --noEmit
bun run lint                                       # biome
bun run test                                       # node:test, offline
bun run build                                      # tsdown, emits dist/cli.mjs

Responsibilities are split by directory: core/ owns screening, search, the snapshot cache, and the result contracts; providers/ owns Trademark Search and case-detail requests, request pacing, and response normalization; cli/ and mcp/ adapt the same core operations to their transports. Keep terminal output and process exits out of core/, and contain upstream format changes inside providers/ and docs/tmsearch.md.

Tests use fixtures and never contact USPTO; fixtures carry synthetic owner and attorney names. CI runs the checks on Linux and macOS under Node 22.18.0 and 24, then installs the packed tarball in a clean directory with install scripts disabled and exercises the CLI and the MCP handshake. To repeat that locally, build, run npm pack, and pass the tarball's absolute path to node scripts/check-package.mjs.

Releasing

Pushing a v* tag runs release.yml. It checks that the tag matches package.json, repeats the checks and the tarball test, and publishes that same tarball to npm with provenance. It authenticates through npm trusted publishing over OpenID Connect (OIDC), with no stored npm token.

  1. Set an unpublished version in package.json and in the skill's metadata.version, push to main, and wait for CI.

  2. Tag the tested commit and push the tag, for example git tag v0.2.2 && git push origin v0.2.2.

  3. Confirm the workflow succeeded and npm shows the version with provenance.

Never reuse a published version or move a release tag. The npm trusted publisher must match user ricky9w, repository namestack-uspto, workflow release.yml, and no environment; update it if the repository or workflow is renamed.

License

MIT

Related MCP Connectors

Related MCP Servers