Search / com.openshopgraph/mcp
OpenShopGraph
R0· no sign-inOpen, verified shop database for AI agents: products, offers, price comparison, trust and coupons.
v0.1.1 · active · website · descriptor JSON · versions
Search / com.openshopgraph/mcp
R0· no sign-inOpen, verified shop database for AI agents: products, offers, price comparison, trust and coupons.
v0.1.1 · active · website · descriptor JSON · versions
{
"mcpServers": {
"openshopgraph": {
"type": "http",
"url": "https://api.openshopgraph.com/mcp",
"headers": {
"x-api-token": "${X_API_TOKEN}"
}
}
}
}claude mcp add --transport http openshopgraph https://api.openshopgraph.com/mcp --header "x-api-token: ${X_API_TOKEN}"[mcp_servers.openshopgraph]
url = "https://api.openshopgraph.com/mcp"
env_http_headers = { "x-api-token" = "X_API_TOKEN" }
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"openshopgraph": {
"type": "remote",
"url": "https://api.openshopgraph.com/mcp",
"enabled": true,
"headers": {
"x-api-token": "{env:X_API_TOKEN}"
}
}
}
}{
"mcpServers": {
"openshopgraph": {
"type": "http",
"url": "https://api.openshopgraph.com/mcp",
"headers": {
"x-api-token": "${X_API_TOKEN}"
}
}
},
"deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=openshopgraph&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vYXBpLm9wZW5zaG9wZ3JhcGguY29tL21jcCIsImhlYWRlcnMiOnsieC1hcGktdG9rZW4iOiIke1hfQVBJX1RPS0VOfSJ9fQ%3D%3D"
}{
"servers": {
"openshopgraph": {
"type": "http",
"url": "https://api.openshopgraph.com/mcp",
"headers": {
"x-api-token": "${X_API_TOKEN}"
}
}
}
}{
"mcpServers": {
"openshopgraph": {
"httpUrl": "https://api.openshopgraph.com/mcp",
"headers": {
"x-api-token": "${X_API_TOKEN}"
}
}
}
}extensions:
"openshopgraph":
enabled: true
name: "openshopgraph"
type: streamable_http
uri: "https://api.openshopgraph.com/mcp"
headers:
"x-api-token": "${X_API_TOKEN}"
timeout: 300
Placeholders to fill from your own secret store: ${X_API_TOKEN}. The registry never accepts secret values.
protocol.modernsupports 2026-07-28 (server/discover)protocol.statelessanswers without a sessionprotocol.transportstreamable HTTPprotocol.list_ttltool list is cacheable (ttlMs 3600000)auth.prm, auth.as_metadata, auth.cimdno remote uses OAuthauth.secret_in_urlno templated URLtools.descriptionsevery tool has a descriptiontools.description_length4 tools have descriptions over 1,024 characters, which crowds the contexttools.schemasevery tool has an object input schematools.annotations9 of 9 tools declare readOnlyHint or destructiveHinttools.directory_hintsevery tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHinttools.token_costabout 3,427 tokens to load every tooltools.api_dumptools are not a one-to-one API dumpstability.changes5 tool changes in 30 daysstability.rug_pullno tool changed its meaning under the same namedeps.known_vulns, deps.mcp_sdk_version, deps.resolvableno npm or PyPI packageget_shipping_policychangeddescriptionWhat 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.
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.
get_shop_policiesaddedWhat 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.
find_shopchangeddescriptionSearch 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. `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.
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.
list_couponschangeddescription, input schemaList 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 how many codes the query found before any of that, and `withheld` breaks the difference down by reason ({expired, verified_rejected, reserved_test_domain, policy}) — total_count minus results.length always equals the sum of `withheld`, and `note` states the same balance in one sentence. 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.
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.
list_couponschangeddescriptionList 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 how many codes the query found before any of that, and `withheld` breaks the difference down by reason ({expired, verified_rejected, reserved_test_domain, policy}) — total_count minus results.length always equals the sum of `withheld`, and `note` states the same balance in one sentence. 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 was proven to work by an actual checkout attempt with proof on file — safe to recommend; "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.
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 how many codes the query found before any of that, and `withheld` breaks the difference down by reason ({expired, verified_rejected, reserved_test_domain, policy}) — total_count minus results.length always equals the sum of `withheld`, and `note` states the same balance in one sentence. 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.
Full history: list_changes · trend: quality JSON.
Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.
+dns-namespace +website +reachable +uptime-92% ~updated-46d-ago -no-repository
Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.
| remote | auth | reachable | uptime 30d | p50 | protocol | last ok |
|---|---|---|---|---|---|---|
https://api.openshopgraph.com/mcp streamable-http | none | yes | 92% | 528 ms | 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07 | 2026-10-20 |
find_shopread-only | 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. |
get_shipping_policyread-only | 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. |
get_shopread-only | 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). |
get_shop_policiesread-only | 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. |
get_trustread-only | 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). |
list_categoriesread-only | 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. |
list_couponsread-only | 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. |
report_code | 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. |
report_issue | 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. |
Schemas: list_tools.
{
"name": "com.openshopgraph/mcp",
"icons": [
{
"src": "https://openshopgraph.com/icon.png",
"sizes": [
"512x512"
],
"mimeType": "image/png"
}
],
"title": "OpenShopGraph",
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"remotes": [
{
"url": "https://api.openshopgraph.com/mcp",
"type": "streamable-http",
"headers": [
{
"name": "x-api-token",
"isSecret": true,
"description": "Per-consumer OpenShopGraph API key (issued on request). Required only for get_trust, report_code and report_issue — find_shop, get_shop, list_coupons and get_shipping_policy work without it (UCP permissionless read access). Unauthenticated calls to the three gated tools are rejected with 401."
}
]
}
],
"version": "0.1.1",
"websiteUrl": "https://openshopgraph.com",
"description": "Open, verified shop database for AI agents: products, offers, price comparison, trust and coupons."
}