Install
$ agentstack add skill-team-markmesh-mark-mesh-skill-mark-mesh-skill ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
MarkMesh — trademark portfolio over MCP
This skill drives the MarkMesh MCP server. MarkMesh is a multi-tenant trademark-management platform; this server exposes a customer's portfolio (trademarks, filings, deadlines, clients) plus live trademark-office search/import as MCP tools, scoped to the API key's organisation.
If the MarkMesh MCP tools are not available in this session, the server isn't configured — point the user to SETUP.md (get an API key from the MarkMesh app, add the connector to Claude Desktop, restart). Don't invent a local fallback; there is no local data.
How auth & scoping work (read this first)
- Every tool runs as the API key's organisation. You only ever see that
org's data — never assume you can reach another firm's or client's records.
- Two key types:
mm_live_*→ real production portfolio;
mm_test_* → sandbox. Tell the user which one is active if it matters. The sandbox isolates the portfolio (trademarks, filings, clients, watches), NOT office search: search_office and search_conflicts read the same public register corpus either way, so a sandbox search returns real marks. Do not tell a user their sandbox search results are fake.
- Calls count against the key's rate limit (live ~300/min, test ~60/min) —
the same budget as the REST API. Don't poll in tight loops; batch your reasoning and make deliberate calls.
- Authorisation is enforced server-side by org policies. A tool returning an
empty list usually means "nothing in your org matches", not an error.
Tools
Reads (each supports filter, sort, limit, offset — so one tool covers both "list everything" and "get one by id"):
list_trademarks— trademarks in the org. Filter byid,name, etc.list_filings— filings, one row per trademark × office. Carries status,
dates, and deadline fields (expiry_date, renewal_date, renewal_status). Filter by trademark_id, office_id, status.
list_clients— the org's clients (the entities a trademark belongs to).list_organisations— the org(s) the key can see (its own; plus managed
orgs for partner/agency keys).
Office actions:
search_office— cross-office search for marks matching a term. Read-only;
results are NOT saved. Args: query (required, ≥2 chars), offices (optional list of ISO codes like ["EU","DE"] — defaults to a small set), nice_classes (optional, scope to classes 1-45), limit. The office fan-out is ONE call, not one per office. Returns results plus served_from and offices (see "Reading a response" below).
search_conflicts— clearance research. Takesnames(a shortlist of up
to 5 candidate names in one call), plus optional nice_classes, offices, limit. Returns candidates_by_name. Each candidate carries the overlap signals SEPARATELY: text_similarity, shared_nice_classes, same_jurisdiction. It returns no verdict and no combined score. Never produce one yourself — see the guardrail below.
import_filing_from_office— pull a filing from an office byoffice+
number and save it. Provide EITHER trademark_id (attach to an existing trademark) OR name + client_id (create a new trademark first). Returns the imported filing.
refresh_filing_from_office— re-sync a filing's office-sourced fields.
Asynchronous: it enqueues a sync and returns immediately with sync_status: pending. Re-fetch the filing a moment later to see updates.
Watch (monitoring):
list_watches— the org's active watches, each with the watched filing and
that filing's provenance.
create_watch— start watching a filing. Args:filing_id,
recipient_mode (all_members or specific_user), and recipient_user_id when the mode is specific_user. A recipient must be a member of the same organisation; there is no way to notify an outside address.
update_watch_recipient— change who is notified for an existing watch.watch_changes_since— poll what changed. Args:since(timestamp of
your last check). Returns only the watches whose filing recorded events after that moment, each carrying just those new events. An empty result means nothing changed, NOT that the watch is broken. There is no delete tool: you can start and re-target a watch but not remove one.
Reading a response (provenance + predictability)
Every record carries a provenance object. Two of its fields change what you are allowed to say:
served_from—localmeans MarkMesh served it from its own corpus
(fast, no dependency on the office being up). external means it was fetched from that office during this call.
citation— has akind:office_record→ a deep link to that exact record. You may cite it.office_portal→ that office publishes no per-record page; the link is
just its search form. Do not present it as the source of a specific mark.
unavailable→ no public URL is held.fetched_at— when that data was captured. Use it to tell the user how
fresh the answer is instead of implying it is live.
Cross-office calls also return an offices map: attempted, succeeded, failed, timed_out.
Common workflows
"What's expiring soon?" → list_filings, then reason over expiry_date / renewal_date / renewal_status. Deadlines live on the filing row; there is no separate deadlines tool.
"Do we already own MARK X?" → list_trademarks (filter by name) and/or list_filings. For marks NOT yet in the portfolio, search_office.
"Add EU trademark 0181xxxxx for client Acme" →
list_clientsto resolve the client'sid(or confirm it exists).import_filing_from_officewithoffice: "EU",number: "0181xxxxx",
and either trademark_id or name + client_id.
- Confirm the returned filing's status/dates back to the user.
"Is NAME safe to use?" → search_conflicts with names (their shortlist), nice_classes (ask which classes if they haven't said), and offices. Present candidates grouped by name with their signals and citations, state which offices failed or timed out, and offer a watch. Do NOT answer the literal question with yes or no; answer with what exists and who should judge it.
"Refresh the status of filing Y" → refresh_filing_from_office with the filing id, then list_filings (filter by that id) after a short pause to read the updated fields.
Conventions & guardrails
- Confirm before importing.
import_filing_from_officewrites to the
portfolio. Echo what you're about to import (office, number, target trademark/client) and get a nod first, unless the user already said "do it".
- Search before import. If the user gives a fuzzy mark name rather than an
exact application/registration number, search_office first, show the hits, let them pick.
- Offices are identified by code (e.g.
EU= EUIPO,DE= DPMA,
US = USPTO). If unsure which office a number belongs to, ask.
- No destructive tools exist in this server — you cannot delete or
overwrite a trademark/filing via MCP. Direct the user to the MarkMesh web app for edits/deletions.
- Don't fabricate ids. Resolve
trademark_id/client_idvia a read
tool; never guess a UUID.
- **Check
offices.failedandoffices.timed_outbefore saying anything is
clear.** An office that did not answer is NOT an office that found nothing. Both produce an empty list, and only that map tells them apart. Say "I couldn't reach the UK register" rather than "no conflicts in the UK".
- Never give a clearance verdict.
search_conflictsdeliberately returns
no verdict and no combined score, and you must not synthesise one. Do not tell a user a name is clear, safe, available, or low-risk, and do not invent a percentage. Show the candidates, say which signals fired (text similarity, which classes actually overlap, same territory), name what you could not check, and leave the judgement to a qualified professional. Clearance turns on how goods and services are worded, whether a mark is genuinely in use, and how a particular registry has treated similar marks — none of which this API returns.
text_similarityis blunt. It is text distance only: no phonetics, no
transliteration, no visual similarity of figurative marks. A low score means "not textually close", never "no conflict".
- Cite the register, not MarkMesh. Quote
citation.urlonly when
citation.kind is office_record. Linking five different candidates to one office search form is not five citations.
- Watch instead of re-running. If a user cares about a mark over time, end
with create_watch and poll watch_changes_since, rather than telling them to ask again later. The conflict that matters is often an application published after the search.
See reference/tools.md for the full argument reference and SETUP.md for connection setup.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: team-markmesh
- Source: team-markmesh/markmesh_skill
- License: MIT
- Homepage: https://markmesh.com/agents
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.