OpenShopGraph
by openshopgraph.com · remote · no sign-in to list tools · v0.1.1 · published by com.openshopgraph
Open, verified shop database for AI agents: products, offers, price comparison, trust and coupons.
9 tools: 2 change things and 7 only read.
Scanned Oct 21, 2026
- Deletes or cancels0Claude Code: deny
- Can't be undone0Claude Code: ask
- Changes things2Claude Code: ask: see these tools
- Only reads7Claude Code: allow: see these tools
2 checks matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.
claude mcp add --transport http openshopgraph https://api.openshopgraph.com/mcpFindings
Matches of fixed checks, with the text they matched.
- Warnget_trust
The description contains "every other tool", wording about other tools or servers.
What this check looks forMatched text
description: "...rchants by it as if it were one. Unlike every other tool on this page, this one requires a valid..."
- Infolist_coupons
The description is 2,682 characters long, over the 2,000 this check looks for.
What this check looks forMatched text
description ends: "...he test was inconclusive — it is not the same as a code that was never attempted."
Tools
Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.
9 tools
Changes things 2Claude Code: ask
report_codeRecord that a specific shop_domain + code (coupon) pair is wrong in one of four fixed, documented ways (invalid | mismatch | item_restricted | min_order_missing — see reasons enum;…No findings
Why it is in this group
- The input takes a statement or command to run (input.code), which can change anything it can reach.
Description, as the server wrote it Record that a specific shop_domain + code (coupon) pair is wrong in one of four fixed, documented ways (invalid | mismatch | item_restricted | min_order_missing — see reasons enum; no free text anywhere). This is a write: it appends one new report row and NEVER changes the delivered coupon directly — it never deletes or overwrites data, and it does not itself decide anything. Subject to per-source dedup it only queues a re-check (RecheckQueueEntry); only a separate Pruefurteil process may later change what list_coupons returns. Reply is a status text ('wird gemeldet, Pruefung laeuft'), never a verdict.
Annotations the server declares
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: false
report_issueRecord a shop-level or data-fact issue as one fixed, documented reason (no free text).No findings
Why it is in this group
- Nothing in its name or description says what it does, so it is counted as a write.
Description, as the server wrote it Record a shop-level or data-fact issue as one fixed, documented reason (no free text). subject_type "shop": unreachable | no_longer_exists | info_outdated | wrong_category | wrong_name_or_domain. subject_type "fact": shipping_cost | return_period | payment_methods | evidence_broken. Same write semantics as report_code: appends one report row, never changes delivered data directly, only queues a re-check subject to per-source dedup.
Annotations the server declares
- readOnlyHint: false
- destructiveHint: false
- idempotentHint: false
- openWorldHint: false
Only reads 7Claude Code: allow
find_shopSearch merchants/shops by free-text query (name or domain fragment), optionally filtered by country (ISO 3166-1 alpha-2, e.g.No findings
Why it is in this group
- The name "find_shop" says "find": a word for reading.
Description, as the server wrote it Search merchants/shops by free-text query (name or domain fragment), optionally filtered by country (ISO 3166-1 alpha-2, e.g. "DE") and/or by an EXACT category slug. Returns the public shop view only — shops still under internal review are never returned. `results` carries at most `limit` entries (default 50, max 100); `total_count` is the full match count before that cap and `truncated` is true when more results exist beyond this page — raise `offset` (default 0) to page through them. Multi-word queries are matched conjunctively: every word must be evidenced on a shop (name, domain or category). `ignored_terms` lists the words that matched nothing anywhere in the corpus and were therefore dropped to avoid an empty answer — a non-empty `ignored_terms` means the results answer a NARROWER question than you asked, so do not present them as satisfying those words. `match_quality` says how well the query was evidenced: "full" (every word found as a name/domain/category fragment — this is evidence of a fragment, NOT relevance, results are not ranked), "partial" (some words are in `ignored_terms`; the results answer a narrower question), "none" (no match). For "partial" and "none", `suggestions` carries hints instead of a guess: `categories` (slugs from `list_categories`, German words like "schuhe" are mapped, retry with `category`) and `shops` (domains within typo distance, e.g. "bergzeitt" -> bergzeit.de); both are empty for "full". `category_truncated` is true when category resolution hit its internal cap and the match set is a subset. `category`, if given, must be one of the slugs returned by `list_categories` — call that tool first, do not guess a slug; an unrecognized slug is rejected with an error (never a silent empty `results`). `category` is additive to `query` (AND, not OR) — pass `query: ""` to browse a category without a name/domain filter. If many shops match, grouping by country or category keeps the list scannable.
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
get_shipping_policyAlias of get_shop_policies (same answer, kept for existing integrations).No findings
Why it is in this group
- The name "get_shipping_policy" says "get": a word for reading.
Description, as the server wrote it Alias of get_shop_policies (same answer, kept for existing integrations). What a shop STATES about its own shipping: which destinations it names, the delivery time it claims, and any free-shipping threshold — plus the date that statement was last checked and where it was read (policy_page or structured_data). This is a shop-level statement, NOT an offer and NOT a quote: it carries no carrier and no shipping price, because OpenShopGraph does not hold that data. Pass country (ISO 3166-1 alpha-2, e.g. "DE") to get a ships_to verdict derived from the stated destination list — "unknown" is a real answer there and means the statement does not settle it. When nothing has been collected for a shop, the reply says so explicitly (collected:false): that is a gap in the data, not a statement that the shop does not ship. Relaying the checked-at date alongside any figure keeps a stale merchant claim from being read as a current fact.
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
get_shopFetch a single merchant/shop by id or domain (public view).No findings
Why it is in this group
- The name "get_shop" says "get": a word for reading.
Description, as the server wrote it Fetch a single merchant/shop by id or domain (public view). Returns "shop not found" for shops still under internal review, identical to a genuinely unknown domain — reviewers cannot be distinguished from typos. The offers array is present for schema stability but empty until merchant offers are ingested (Offer table measured empty on 2026-07-30).
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
get_shop_policiesWhat a shop STATES about its own policies, each fact with the date it was last checked and where it was read: return window in days (returns_days), free return label, tracking offe…No findings
Why it is in this group
- The name "get_shop_policies" says "get": a word for reading.
Description, as the server wrote it What a shop STATES about its own policies, each fact with the date it was last checked and where it was read: return window in days (returns_days), free return label, tracking offered, payment methods, buyer-protection seal, plus the shipping statement (destinations, stated delivery time, free-shipping threshold). Use it for questions such as "how long can I return something at this shop?". These are shop-level statements, NOT offers and NOT quotes: no carrier, no shipping price. Every fact in `policies` is an object with `collected`: when true it carries value, checked_at and source (policy_page = read from the shop, llm_gap_resolution = model-derived, say so when relaying); when false it carries a reason and means OpenShopGraph holds no checked value — a gap in the data, NOT a statement that the shop has no such policy. A fact whose value and check date are stored but whose source is unknown is also reported as collected:false (reason no_source): a value without a source is never shown. Pass country (ISO 3166-1 alpha-2, e.g. "DE") to get a ships_to verdict derived from the stated destination list — "unknown" is a real answer there. Relay checked_at alongside any figure so a stale claim is not read as current. `get_shipping_policy` is the earlier name of this tool and returns the same answer.
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
get_trustTrust-relevant facts OpenShopGraph itself measured about one merchant/shop (by id or domain): TLS certificate issuer and grade, hosting ISP and country, domain registration date, r…1 finding
Why it is in this group
- The name "get_trust" says "get": a word for reading.
Findings
- Warn
The description contains "every other tool", wording about other tools or servers.
What this check looks forMatched text
description: "...rchants by it as if it were one. Unlike every other tool on this page, this one requires a valid..."
Description, as the server wrote it Trust-relevant facts OpenShopGraph itself measured about one merchant/shop (by id or domain): TLS certificate issuer and grade, hosting ISP and country, domain registration date, registrar, and accepted payment methods. Returns INDIVIDUAL signals, never an aggregate: every entry carries its own value, `source` (where OpenShopGraph observed it) and `checked_at` (when). There is deliberately no score, rating, percentage or star value — not even an internally computed one; you are given the raw evidence and judge for yourself. A field with no source or no check timestamp is omitted entirely rather than shipped with a null placeholder. If nothing was measured, the answer is status "no_signals_collected" with an empty list — that means NOTHING IS KNOWN, it is not a score of zero and not a negative verdict. Unknown domains, shops under internal review and measured-but-empty shops are intentionally indistinguishable here. `signal_coverage` describes data completeness, not merchant trustworthiness: `present`/`total` count how many of the (up to 7) signal fields OpenShopGraph was able to deliver for this shop, and `missing` lists the rest, each with a `reason` — `not_collected_yet` (OpenShopGraph has never run that check for this shop) or `pipeline_gap` (the check ran — source and timestamp exist — but produced no usable value, e.g. an IP/ASN lookup that resolves a hosting ISP but not a country). A low `present` count is NOT evidence of a low-quality or risky merchant: it usually just means one of OpenShopGraph's own probes came back empty. Do not treat `signal_coverage` as a rating, and do not rank or filter merchants by it as if it were one. Unlike every other tool on this page, this one requires a valid `x-api-token` header — a call without one fails before reaching this tool (401, no exceptions for anonymous/public callers).
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
list_categoriesEnumerate the shop category taxonomy: every category slug currently carried by at least one public shop, together with how many public shops carry it.No findings
Why it is in this group
- The name "list_categories" says "list": a word for reading.
Description, as the server wrote it Enumerate the shop category taxonomy: every category slug currently carried by at least one public shop, together with how many public shops carry it. Call this BEFORE passing `category` to find_shop — the taxonomy is flat (no parent/child hierarchy, e.g. "fashion" and "womens-clothing" are siblings, not nested) and its slugs come from observed data, not a fixed enum baked into this tool, so a slug cannot be reliably guessed. `find_shop(category: <slug>)` only accepts a slug returned here; giving it anything else fails with an error instead of silently returning no results. Coverage measured 2026-09-03: 171 slugs across 3036 of 3100 active shops (97.9%) — a shop can carry more than one category, so counts do not sum to the total shop count.
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
list_couponsList currently USABLE discount codes/coupons, optionally filtered by shop_domain (e.g.1 finding
Why it is in this group
- The name "list_coupons" says "list": a word for reading.
Findings
- Info
The description is 2,682 characters long, over the 2,000 this check looks for.
What this check looks forMatched text
description ends: "...he test was inconclusive — it is not the same as a code that was never attempted."
Description, as the server wrote it List currently USABLE discount codes/coupons, optionally filtered by shop_domain (e.g. "otto.de"). A code is withheld from `results` when it is EXPIRED (valid_until has passed), when a real checkout test PROVED it does not work (verification_status "verified_rejected"), or when a display policy suppresses it on this channel/country. Nothing is withheld silently: `total_count` is the REAL number of codes the query found before any of that (for the collection list the full count over everything, never just the window), `examined` is how many codes this call looked at, and `withheld` breaks the difference down by reason ({expired, verified_rejected, reserved_test_domain, policy}) — examined minus results.length always equals the sum of `withheld`, and `note` states the same balance in one sentence. WITHOUT shop_domain the call returns one window of at most `limit` codes (default 100, max 100) starting at `offset` (default 0), ordered by a stable id: `truncated` is true when more codes lie beyond it and `next_offset` is the offset to pass for the next page (null on the last page) — page until `truncated` is false to see every code. limit/offset are rejected together with shop_domain, which already returns every code of that shop. So an empty `results` NEVER has to be guessed at: read `total_count` and `note` to tell "this shop has no codes at all" apart from "it has codes and every one of them is proven dead". An UNKNOWN or internal-review shop_domain is a different answer again — it is an error ("shop not found"), not an empty list; and a backend failure is reported as a failure, never as an empty list. Each result carries validUntil: an ISO timestamp when the code has a stated expiry, or null when it is open-ended — null means unlimited, NOT unknown-and-expired. Re-check validUntil against the current time before relaying a code. Each result ALSO carries verificationStatus, the verdict of a real checkout test against this exact code: "verified_applied" means the code worked in an actual checkout attempt — safe to recommend (the response carries no stored proof artifact, so do not promise a screenshot or receipt); "unverified" means no proof exists either way yet — treat it as unknown, NOT as a negative signal, and do not imply it was tested and failed. ("verified_rejected" is defined as before but no longer appears in `results` — it is counted in `withheld.verified_rejected` instead.) lastVerifiedAt is the ISO timestamp of that most recent test, or null if the code was never tested. A non-null lastVerifiedAt on an "unverified" code means it WAS tested but the test was inconclusive — it is not the same as a code that was never attempted.
Annotations the server declares
- readOnlyHint: true
- destructiveHint: false
- idempotentHint: true
- openWorldHint: false
This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.
Install
Pinned to version 0.1.1. Values in angle brackets are yours to fill in.
claude mcp add --transport http openshopgraph https://api.openshopgraph.com/mcpRun in a terminal.
Claude Code permissions
Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.
{
"permissions": {
"allow": [
"mcp__openshopgraph__find_shop",
"mcp__openshopgraph__list_categories",
"mcp__openshopgraph__get_shop",
"mcp__openshopgraph__list_coupons",
"mcp__openshopgraph__get_shop_policies",
"mcp__openshopgraph__get_shipping_policy",
"mcp__openshopgraph__get_trust"
],
"ask": [
"mcp__openshopgraph__report_code",
"mcp__openshopgraph__report_issue"
],
"deny": []
}
}Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as openshopgraph. Review it before you use it.