{
  "markdown": "# ScrapeCheck MCP: the verification beat for agents that spend\n\n[![scrapecheck-mcp MCP server](https://glama.ai/mcp/servers/FieldmodeLLC/scrapecheck-mcp/badges/score.svg)](https://glama.ai/mcp/servers/FieldmodeLLC/scrapecheck-mcp)\n[![scrapecheck-mcp MCP server](https://glama.ai/mcp/servers/FieldmodeLLC/scrapecheck-mcp/badges/card.svg)](https://glama.ai/mcp/servers/FieldmodeLLC/scrapecheck-mcp)\n\n> **Here for the offline verifier?** It's in this repo:\n> [`tools/verify-verdict.mjs`](tools/verify-verdict.mjs) — one file, no\n> dependencies, verifies any ScrapeCheck verdict with no network access.\n> [How to use it →](#verify-a-verdict-yourself-offline)\n\nAgents now find a provider, pay through x402, receive data, and act on\nit. Nothing in that flow asks whether the data is true. This server adds\nthe missing beat. Before your agent acts on a value it fetched or paid\nfor, it sends the source URL, the value, and what was asked; ScrapeCheck\nre-fetches the page from its own infrastructure and returns an\ned25519-signed verdict: `pass`, `fail`, or `unverifiable`. Never a\nguess, and anything unconfirmed is unverifiable, never pass.\n\nOne line to install, and the agent pays per check through the same x402\nrail it already spends on: no API key, no signup, a free allowance\nbefore payment is required, and every verdict verifiable offline against\nour published key.\n\nWant to see a verdict before installing anything? One free check runs\nin the browser at scrapecheck.fly.dev.\n\nAll four integration lanes (MCP, x402-native, Apify, plain HTTP), each\nwith a tested snippet: [scrapecheck.fly.dev/integrations](https://scrapecheck.fly.dev/integrations)\n\n**Endpoint:** `https://scrapecheck-mcp.fly.dev/mcp` (streamable HTTP)\n**Payment:** x402 in-band (USDC on Base) — no API key, no signup. A free\nallowance per client identity is served before payment is required.\n\n**Check us yourself — the three things you can attack:**\n[verify any verdict offline](#verify-a-verdict-yourself-offline) · [live run stats, misses included](https://scrapecheck.fly.dev/stats) · [the benchmark and its limits](#the-trust-guarantee-is-structural-not-statistical)\n\n## Tools\n\n- `verify_web_field` — $0.01 — Full verification: value present on the re-fetched live page, served live, and an independent LLM judge confirms it answers what was asked. Positive verdict: `pass`.\n- `verify_presence` — $0.002 — Presence only — does **NOT** confirm the value answers the question. Positive verdict: `present`, never `pass`.\n- `get_verifier_info` — free — The trust artifact: public key, benchmark summary, scope, endpoints.\n\n## Where this sits in an agent's spending loop\n\nThe payment rail answers who paid what, on whose authority. The receipt\nis perfect, and the receipt holds no evidence about the data. This tool\nis the step between receiving and acting: one call per value your agent\nis about to trust, priced in the same cents the data itself cost.\n\n## The trust guarantee is structural, not statistical\n\nA claim is never certified unless ScrapeCheck independently re-fetches the\npage and finds the claimed value there itself — and the judge's vote is\nmechanically voided if its restatement of the claim doesn't match what was\nactually claimed. Absence cannot pass, and substitution cannot pass. Anything\nunconfirmed — a skipped check, a failed fetch, a judge that errors —\nreturns `unverifiable`, never `pass`.\n\nCorroborated by benchmark (full verification only): **0 false passes across\n67 frozen labeled cases** (26 held out from all calibration, including\nadversarial traps where the claimed value appears on the page as the wrong\nthing), and 0 false passes across 21 live-web cases including 9 adversarial\ntraps. Small-N corroboration of the structural guards — not a population\naccuracy claim.\n\n## Why trust this server's own claims?\n\nBecause you don't have to. Every verdict is ed25519-signed over canonical\nsorted-key JSON of all fields except `signature`; the public key is served\nat [`/pubkey`](https://scrapecheck.fly.dev/pubkey) and in-band via\n`get_verifier_info`; and every verdict carries an engine digest identifying\nexactly which prompt+calibration produced it. Verify offline — no need to\ntrust the transport, the storefront, or us.\n\nLive, unfiltered run stats — misses included:\n[scrapecheck.fly.dev/stats](https://scrapecheck.fly.dev/stats). A verifier\nthat only shows its passes isn't showing anything.\n\n## Payment flow (x402 in-band)\n\nStandard `@x402/mcp` v2 flow: an unpaid call past the free allowance returns\na `PaymentRequired` challenge in the tool result; pay with any x402 v2\nclient (e.g. `wrapMCPClientWithPaymentFromConfig` from `@x402/mcp` with an\nEVM signer) and the retried call returns the verdict plus the on-chain\nsettlement in `_meta[\"x402/payment-response\"]`. A refused or failed payment\nnever yields a verdict, and a verdict that fails to produce never settles —\nyou are charged only for completed work.\n\n## Integrator notes\n\n- The full signed verdict object is in **`structuredContent`** on the wire\n  (and byte-identical as JSON in `content[0].text`). Note: `@x402/mcp`'s\n  paying-client convenience result forwards `content` only — parse\n  `content[0].text` there, or read `structuredContent` with a plain MCP\n  client.\n- Input contract (frozen): `{ url, claim, asked }` — `claim` is an object of\n  field values, e.g. `{\"price\": \"£51.77\", \"in_stock\": true}`.\n- Scope (v1): server-rendered pages. Client-rendered (JS-only) content\n  returns `unverifiable` — never a false `fail`, never a false `pass`.\n- Verification is of the moment: a pass means the claimed value was on the\n  page when we fetched it, not that the page itself is current. A page\n  carrying staleness signals can still pass when the claimed value is\n  genuinely present.\n- The same engine is also sold as a raw x402 HTTP API\n  (`https://scrapecheck.fly.dev/verify`) and as the\n  [Scrape QA Apify actor](https://apify.com/fieldmodellc/scrape-qa) for\n  batch dataset verification. One engine, one signing key, one durable log.\n\n## Verify a verdict yourself (offline)\n\nThis repo ships a zero-dependency verifier — check any ScrapeCheck verdict\nwithout trusting us, the transport, or this server:\n\n```console\n$ node tools/verify-verdict.mjs examples/verdict.json\n(public key fetched from https://scrapecheck.fly.dev/pubkey — pass --pubkey to verify fully offline)\nVALID: signature verifies against the public key\n  verdict:    pass (confidence 0.97)\n  verdict_id: 7af5f1df-1b86-42a5-a784-9b302a55f94e\n  check_type: web_field_v1\n  engine:     web_field_v1/0.2.0+2ae28205cac4\n$ echo $?\n0\n\n# flip a single field — \"verdict\": \"pass\" -> \"fail\" — and run it again\n$ node tools/verify-verdict.mjs tampered.json\n(public key fetched from https://scrapecheck.fly.dev/pubkey — pass --pubkey to verify fully offline)\nINVALID: signature does not verify — the verdict was altered or was not signed by this key\n$ echo $?\n1\n```\n\nOmit `--pubkey` to fetch the current key from\n[`/pubkey`](https://scrapecheck.fly.dev/pubkey); pass it (an `ed25519:…`\nstring or a saved `/pubkey` response) to verify fully offline.\n[`examples/verdict.json`](examples/verdict.json) is a real production verdict\n— alter any field and verification fails. A verdict is valid iff its ed25519\nsignature verifies over the canonical (recursively key-sorted) JSON of every\nfield except `signature`. MIT licensed — vendor the ~40 relevant lines into\nyour own pipeline freely.\n\n### Envelope fields added August 2026\n\nNew verdicts carry three additional signed fields. `key_id` names which key\nin the /pubkey archive signed the verdict; it is advisory — the signature\neither verifies against a published key or it doesn't — and a mismatch\nbetween the claim and the verifying key is surfaced as a warning.\n`verifier_url` is the canonical origin for /pubkey and /verdicts lookups;\nit is a pointer home, never a trust root — a verifier must not fetch keys\nfrom a URL the document itself supplies, so ours pins the known origin and\nuses the embedded value only for display and mismatch warnings.\n`source_hash` is the SHA-256 of the normalized page text the verdict\nactually judged, a fingerprint of the page state at refetched_at. Hash\nequality is meaningful between verdicts carrying the same engine digest;\nacross digests it is best-effort only, and today it is comparable\nverdict-to-verdict rather than independently recomputable. Verdicts issued\nbefore these fields existed verify exactly as before.\n\n## Key rotation, August 2026\n\nOn 6 August 2026 the ed25519 signing key was treated as exposed: an operator\nerror placed a credentials file into an external chat channel. Under our own\ndoctrine — a key that has touched an untrusted channel is compromised whether\nor not anyone used it — the key was rotated the same day.\n\nNo verdict was affected. Signatures cover the verdict payload, so verdicts\nissued before the rotation are unchanged and still verify against the retired\nkey, which is published permanently as `k1` at\n[`/pubkey`](https://scrapecheck.fly.dev/pubkey). Verdicts issued afterwards are\nsigned with `k2`. The offline verifier tries every published key and reports\nwhich one matched.\n\n**If you hold a verdict signed by `k1`, confirm it.** A valid signature from a\nretired key proves that key signed the verdict — not that we issued it, because\nanyone holding the exposed private key can sign anything, including a forgery\nthat reuses a real verdict_id. So we publish an issuance record:\n\n    GET https://scrapecheck.fly.dev/verdicts/<verdict_id>\n\nIt returns whether we issued that id and, where available, `signature_sha256`\n— the SHA-256 of the signature we issued under it. ed25519 is deterministic,\nso hashing the signature on your copy and comparing binds your verdict's exact\ncontent to ours. Match means it is the verdict we issued — the same signed\ncontent. Mismatch means forged content under a real id. The endpoint returns no verdict content, no\nclient data, and nothing enumerable. Running the verifier without `--pubkey`\nperforms this check for you automatically on any `k1`-signed verdict.\n\n**One honest limitation.** Signature hashes were not logged before 6 August\n2026, so for most pre-rotation verdicts we can confirm issuance but cannot bind\ncontent; those return `content_binding: \"unavailable_legacy\"`, and the verifier\nreports `PARTIAL` rather than confirming. Where we can bind a pre-rotation\nverdict from an artifact published before the exposure — the example verdict in\nthis repository, whose signature is fixed in public git history that no forger\ncan rewrite — the record says so and labels the provenance. Bindings recovered\nfrom artifacts we merely retained privately are labeled\n`available_backfilled`, because a binding is only as good as the provenance of\nthe artifact behind it. Every pre-rotation verdict was issued to ourselves; no\nexternal customer holds one.\n\n**A commitment that follows.** Because the issuance record is public, a logged\nverdict can never be deleted. Reporting `issued: false` about a verdict we\nreally signed would be a lie about our own history, so retention is now part of\nthe trust contract rather than an operational preference.\n\nWhat the exposure meant: a holder of the old private key could produce forged\nverdicts that verify against the old public key. They could not alter any\nverdict already issued, and the key gave no access to the service, its logs, or\nany funds. No forged verdict has been observed.\n\nThis is the procedure working as designed, and it is written down here because\na verifier that hides its own incidents is not a verifier.\n\n## About this repository\n\nThis repo contains the thin MCP storefront only — transport, payment\nhandling, and tool registration. The verification engine (the anchored\nre-fetch, the lenses, the judge, the signing key, and the benchmark\nfixtures) runs at the ScrapeCheck origin and is not part of this codebase.\n\n## Changelog\n\n- **2026-08-13** — The live stats page counted our own test traffic in its\n  totals; it now separates self, crawler, and external. `/stats` gained a\n  `traffic` section publishing both numbers — including `external_paid`,\n  which reads zero at the time of this change and stays a permanently named\n  line. Self traffic was always labeled in the durable log; the public\n  surface now says so too.\n",
  "bytes": 12274,
  "sha": "5dbaf84ef6d674f7c650e2517ff18bbd708815197b69209ef90ef7a7fc16bb45",
  "repo_slug": "fieldmodellc/scrapecheck-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_fieldmodellc_scrapecheck_75d92fd1/readme"
}