Skip to content
MCP Server Β· Protocol 2026-07-28

Data Refinery

Real performance data for UK small-business websites, queryable by an AI agent. Not a survey and not scraped from a directory β€” every figure comes from running 134 checks against thousands of independent businesses with one engine and one methodology.

Endpoint

https://mcp.xsoftlimited.com/

Streamable HTTP, POST only. Four of the five tools are free and need no key.

What it will not tell you

It will not return a stored score for a business you did not name. There is no search, no leaderboard, and no way to ask "show me the worst restaurant websites in Leeds".

That is deliberate. The corpus covers thousands of real trading companies, many of them sole traders. Publishing a searchable quality verdict on each would mean publishing a judgement about a named business, from a dataset that has been wrong before β€” dead-domain detection silently broke for six days and misfiled over a thousand rows; a rate limit we triggered ourselves was recorded as site failures; an earlier engine version reported roughly half the true server response time. Each of those was found by checking, not by being told. Aggregates survive that kind of error. Verdicts about somebody's livelihood do not.

Tools

corpus_stats free Β· no key

Size of the corpus, coverage per vertical, methodology and stated limits.

Call this first. It tells you what the data can and cannot support before you build on it.

{}
benchmark_sector free Β· no key

Distribution of one metric for one vertical β€” median, p25/p75/p90/p99, mean, and the share meeting Google thresholds.

The core benchmark. Refuses any cell below 30 audits.

{ "vertical": "STAY", "metric": "ttfb" }
sector_comparison free Β· no key

One metric across several verticals at once, ranked.

Where the non-obvious findings are. Hotels and restaurants fail for opposite reasons.

{ "metric": "ttfb" }
check_adoption free Β· no key

Adoption rate of a practice, with the score gap between adopters and non-adopters.

Returns a circularity-adjusted gap alongside the raw one, because the practice is itself scored.

{ "check": "llms_txt" }
compare_domain API key required

Audits a domain you name, live, and returns its percentile against its sector.

Runs a fresh audit rather than reading a stored one, so the answer is current. ~30 seconds.

{ "domain": "example.co.uk", "vertical": "FOOD" }

compare_domain needs a key because each call runs a live audit β€” about 30 seconds of compute and one Google PageSpeed quota unit. Everything else is a read over data already collected, so it is free. The split is by cost, not by value.

Parameters

metric

ttfb β€” Time to first byte, cold β€” the first uncached request
lcp β€” Largest Contentful Paint, via Google PageSpeed Insights
fcp β€” First Contentful Paint
page_weight β€” Transferred page size in KB
score β€” Overall audit score out of 100, across 134 checks

vertical

FOODSTAYRETAILPROFESSIONALHEALTHPERSONALMOTORLEISURETRADE

Omit it to query the whole corpus. Cells below 30 audits are refused β€” smaller samples are meaningless, and with a narrow filter they risk identifying individual businesses.

Connecting

Add it to any MCP client that speaks Streamable HTTP:

{
  "mcpServers": {
    "data-refinery": {
      "type": "streamable-http",
      "url": "https://mcp.xsoftlimited.com/"
    }
  }
}

Or call it directly:

curl -X POST https://mcp.xsoftlimited.com/ \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2026-07-28' \
  -H 'Mcp-Method: tools/call' \
  -H 'Mcp-Name: benchmark_sector' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "benchmark_sector",
      "arguments": { "vertical": "STAY", "metric": "ttfb" },
      "_meta": {
        "io.modelcontextprotocol/protocolVersion": "2026-07-28",
        "io.modelcontextprotocol/clientInfo": { "name": "my-agent", "version": "1.0" },
        "io.modelcontextprotocol/clientCapabilities": {}
      }
    }
  }'

Protocol 2026-07-28 carries the protocol version, client info and capabilities in params._meta on every request β€” there is no initialize handshake and no session. The Mcp-Method and Mcp-Name headers must match the body, or the request is rejected with error -32020. Most MCP clients handle all of this for you.

Where the data comes from

Sample

UK independent businesses across nine verticals and 44 counties, sourced from OpenStreetMap. Chain domains are excluded by frequency, so one hotel group cannot skew a cohort.

Speed

Time to first byte is the COLD measurement β€” the first uncached request, which is what a first-time visitor and Googlebot actually experience. Warm figures are roughly half as large and flatter every site.

Rendering

Largest Contentful Paint and First Contentful Paint come from Google PageSpeed Insights, a lab measurement on a simulated connection. Directionally sound; not field data from real visitors.

Statistics

Percentiles are linearly interpolated. Audits that ran but could not score a site are counted separately and excluded from every distribution β€” never imputed.

The published study behind this data: the national audit of UK hospitality websites β†’

Limits worth knowing

Observational, not causal.

Sites publishing an llms.txt file score better. Nothing here shows that adding one would raise a score.

Businesses without a website are invisible.

The sample is drawn from businesses that listed one, which makes this a study of the industry’s web presence rather than of the industry.

Coverage is uneven across verticals.

Call corpus_stats for the current per-vertical counts rather than assuming they are comparable.

Rate limited.

20 requests per minute for anonymous callers. Enough to evaluate the data properly, not enough to mirror it.

Need a key?

Only compare_domain requires one. Email info@xsoftlimited.com with what you are building. Everything else works right now with no signup.