Skip to main content
Glama
AxRS37

web-presence-audit

by AxRS37
README.md
# web-presence-audit — lead-leak audit tools for AI agents

An [MCP](https://modelcontextprotocol.io) server that turns a proven, **£0 lead-leak audit methodology** for UK local service businesses into six tools your AI agent can call. No API keys, no accounts, no paid services — every data source is free to read.

This is the audit methodology behind real paid audits (built for B2B prospect research): it finds the fixable issues that measurably cost local businesses leads — untappable phone numbers, un-findable websites, mismatched phone numbers across directories, and forms on platforms where automated outreach simply cannot work.

- **Audience:** agencies and web-audit sellers, local-SEO freelancers, lead-gen sellers, any agent doing prospect or client website research.
- **Cost: £0.** Bing's public RSS search output + free UK directories (thomsonlocal, TrustATrader, 3BestRated) + the target site itself. No API keys, no signups, no cards.
- **Config-free:** no environment variables, no accounts. Install and add to your MCP client — done.

## What it does — the six tools

| Tool | What it answers |
|---|---|
| `check_form_platform(url)` | Which platform a site's forms run on (WPForms, Contact Form 7, Wix, Squarespace, Jotform, Gravity Forms, HubSpot, Typeform, Drupal, or `unknown`) — **and what that predicts for outreach**: Wix forms fire no network traffic on automated submits (verified in live campaigns), so that prospect needs email or social instead. Also counts *visible* form fields (hidden honeypots excluded). |
| `check_tap_to_call(url)` | Is the phone number a clickable `tel:` link? Plain-text numbers lose mobile callers. Returns every `tel:` link, plain-text numbers found, and a verdict (`ok` / `leak` / `no_phone_found`). |
| `check_nap_consistency(business, city, trade?, website_url?)` | Is the phone number identical on the business's own site and the free directories (thomsonlocal, TrustATrader)? Mismatched numbers confuse Google and customers. Verdict: `consistent` / `inconsistent` / `insufficient data`. |
| `audit_website(url)` | Quick hygiene checks: reachable?, HTTPS?, mobile viewport tag?, page weight, load time, title + meta description. |
| `find_website(business, city)` | Find a business's own website via Bing's public RSS search — only a result with a *distinguishing* word counts (trade words like "plumbing" prove nothing). |
| `run_full_audit(business, city, trade?, website_url?)` | Everything at once: search presence, website hygiene, form platform, tap-to-call, NAP, plus the 3BestRated top-3 competitors. Returns a prioritized leak list. |

Matching honesty (kept from the live-proven methodology): a directory listing or search result only counts as the business when it contains a **distinguishing word** (e.g. "driver" in "Driver Plumbing") plus 2+ name words — trade words and city names alone never count. Masked directory numbers (`+447****5682`) are excluded from NAP comparison.

## 5-minute setup

Requirements: Python 3.10+ and either [`uv`](https://docs.astral.sh/uv/) or `pip`. Nothing else — no Node, no database, no API keys.

**1. Install.**

```bash
# with uv (fastest):
uv venv && uv pip install -e .
# or with plain pip:
python3 -m venv .venv && .venv/bin/pip install -e .
```

**2. Test the install (30 seconds).**

```bash
.venv/bin/python -m pytest tests/ -q
```

You'll see `63 passed` — all tests are fully offline (canned pages + a localhost site; no live internet needed).

**3. Wire it into your MCP client.**

Example for Claude Desktop / Cursor / any MCP client with JSON config:

```json
{
  "mcpServers": {
    "web-presence-audit": {
      "command": "/ABSOLUTE/PATH/TO/web-presence-audit/.venv/bin/python",
      "args": ["-m", "web_presence_audit"]
    }
  }
}
```

No `env` block needed — the server requires nothing but a working network at call time.

**4. Try it.** Ask your agent:

> What form platform does example.co.uk run, and can I tap its phone number to call?

or

> Run a full presence audit on "Driver Plumbing & Heating" in Leicester.

## Example tool calls and responses

These are real outputs from this server's test suite (canned fixture pages; see `tests/fake_pages.py` — the shapes are exactly what the live tools return against real sites).

`check_form_platform("https://example.co.uk")` →

```json
{
  "url": "https://example.co.uk",
  "platform": "wpforms",
  "outreach_note": "WordPress site with the WPForms plugin. Contact forms accept standard fill-and-submit automation cleanly; leave the honeypot field empty.",
  "evidence": "wpforms-container",
  "visible_form_fields": 3,
  "http_status": 200
}
```

`check_tap_to_call("https://example.co.uk")` → (a plain-text number)

```json
{
  "verdict": "leak",
  "tel_links": [],
  "plain_phones": ["0116 264 5115"],
  "note": "LEAK — phone number 0116 264 5115 appears as plain text with no tel: link. Mobile visitors cannot tap to call; most will not retype it.",
  "url": "https://example.co.uk"
}
```

`check_nap_consistency("Driver Plumbing & Heating", "Leicester")` → (site and directory agree)

```json
{
  "business": "Driver Plumbing & Heating",
  "city": "Leicester",
  "trade": "plumber",
  "website": "https://www.driverplumbing.co.uk/",
  "website_phone": "0116 264 5115",
  "directory_phones": [
    { "source": "thomsonlocal", "phone": "0116 264 5115" }
  ],
  "verdict": "consistent",
  "note": "Phone number identical across all sources found."
}
```

`run_full_audit(...)` returns all of the above plus `search_presence`, `website` hygiene, `top3_competitors`, a `leaks` list, and a `score_note` summarizing what to fix first.

## How it's tested (and why you can trust the README)

63 tests in three layers — **all offline** (no live internet required to pass):

1. **Engine tests** (`tests/test_audit.py`) — platform detection per signature, honeypot exclusion from field counts, tap-to-call verdicts, phone normalisation (+44 → 0), the matching-honesty rules, Bing RSS parsing, NAP consistency logic, hygiene checks, and the full pipeline end-to-end against canned pages.
2. **Tool layer tests** (`tests/test_server_tools.py`) — each tool's output shape, URL scheme upgrading, error results (never crashes), all six tools registered with docstrings.
3. **Protocol tests** (`tests/test_protocol.py`) — launch the real server as a subprocess, speak MCP JSON-RPC over stdio (initialize → tools/list → tools/call), and verify responses against a localhost fake site. The production fetch path runs for real; only the target is pretend.

Run them yourself:

```bash
.venv/bin/python -m pytest tests/ -v
```

A note on live sources: Bing RSS, thomsonlocal, TrustATrader and 3BestRated were all reachable and parseable from our build environment. **Checkatrade is deliberately not queried** — it returns HTTP 403 to datacenter IPs, so the methodology reports honestly rather than scraping it. (Checkatrade support confirmed no public API for non-customers.) Live directory pages can change markup; the parser tests protect the logic, and any site that blocks or changes is reported as an honest error, never fabricated data.

## Works with both MCP SDK generations

The official Python SDK renamed its main class between versions: 1.x exposes `mcp.server.fastmcp.FastMCP`, 2.x renamed it to `mcp.server.mcpserver.MCPServer`. This server imports whichever is installed, so `pip install mcp` gives you either and it still runs. (Protocol-tested against 1.14.0 and 2.2.0.)

## Who it's for

- **Agencies and web-audit sellers** — run structured findings-first audits on any UK local business in minutes, with zero tooling cost.
- **Local-SEO freelancers** — NAP consistency and presence checks without paid tools.
- **Lead-gen sellers** — the form-platform check tells you which outreach channel can even work before you spend time on a prospect.
- **Any MCP client user** doing UK B2B prospect research (pairs with our [uk-company-check](../uk-company-check/) server for registry facts).

## Licence

MIT (see `LICENSE`).

Maintenance

ActivityMaintained
ResponsivenessNo issues