Metadata-Version: 2.4
Name: cursor-seo-mcp
Version: 0.3.0
Summary: Cursor SEO MCP — open-source SEO MCP server for Cursor. AEO, GEO, technical SEO, on-page audits. Evidence JSON, never invented rankings.
Author: Cursor SEO MCP Contributors
License: MIT
Project-URL: Homepage, https://github.com/engrmaziz/cursor-seo-mcp
Project-URL: Repository, https://github.com/engrmaziz/cursor-seo-mcp
Project-URL: Issues, https://github.com/engrmaziz/cursor-seo-mcp/issues
Project-URL: Bug Tracker, https://github.com/engrmaziz/cursor-seo-mcp/issues
Project-URL: PyPI, https://pypi.org/project/cursor-seo-mcp/
Keywords: cursor seo mcp,cursor-seo-mcp,cursor,seo,mcp,cursor mcp,seo mcp,aeo,geo,on-page seo,technical seo,open-source
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27.0
Requires-Dist: selectolax>=0.3.21
Requires-Dist: pydantic>=2.6.0
Requires-Dist: ddgs>=9.0.0
Requires-Dist: pillow>=10.0.0
Provides-Extra: browser
Requires-Dist: playwright>=1.40.0; extra == "browser"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Dynamic: license-file

# Cursor SEO MCP

<!-- mcp-name: io.github.engrmaziz/cursor-seo-mcp -->

**Cursor SEO MCP** (`cursor-seo-mcp`) is an open-source **SEO MCP server for Cursor**: AEO, GEO, technical SEO, on-page SEO, crawls, schema, image SEO, and local patches — with evidence JSON, not invented rankings.

Search terms this repo is built for: **cursor seo mcp**, Cursor MCP SEO, SEO MCP for Cursor, Cursor SEO.

[![PyPI](https://img.shields.io/pypi/v/cursor-seo-mcp.svg)](https://pypi.org/project/cursor-seo-mcp/)  
Repository: [github.com/engrmaziz/cursor-seo-mcp](https://github.com/engrmaziz/cursor-seo-mcp)  
License: [MIT](LICENSE) · [Contributing](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md) · [Security](SECURITY.md)

```bash
pip install cursor-seo-mcp
cursor-seo-mcp doctor
cursor-seo-mcp audit https://example.com --no-serp
```

Add **Cursor SEO MCP** to Cursor (`.cursor/mcp.json` or Cursor Settings → Tools & MCP):

```json
{
  "mcpServers": {
    "cursor-seo-mcp": {
      "command": "cursor-seo-mcp-server"
    }
  }
}
```

No global install? Use `uvx` (downloads the PyPI package on first run):

```json
{
  "mcpServers": {
    "cursor-seo-mcp": {
      "command": "uvx",
      "args": ["--from", "cursor-seo-mcp", "cursor-seo-mcp-server"]
    }
  }
}
```

Python import remains `seocur` (`python -m seocur` is the same CLI as `cursor-seo-mcp`).

---

## What is Cursor SEO MCP?

**Cursor SEO MCP** is a Cursor-first SEO engine exposed as:

1. An **MCP stdio server** (`cursor-seo-mcp-server` / `seocur.mcp_server`) so Cursor can call audit, AEO, GEO, on-page, technical, SERP, Radar, Graph, drift, and images tools.
2. **Cursor Agent Skills** in `skills/` that tell the agent to run the CLI and trust JSON.
3. A **CLI** (`cursor-seo-mcp` / `python -m seocur`) for CI and terminals.

Every score is a list of evidence items (`check`, `evidence`, `source_url`, `confidence`). When a data source is missing, the component is `UNAVAILABLE` — **Cursor SEO MCP** never invents search volume, domain rating, traffic, or rankings.

This is **not** an official Cursor product. It is an open-source SEO MCP you run locally with Cursor.

---

## Why this exists

Most “AI SEO skill” packs look large (dozens of `/seo` commands) and then wrap **paid** APIs (DataForSEO, Firecrawl, Ahrefs, SE Ranking) or print a 0–100 after a single HTML download.

Cursor SEO MCP is a **clean-room** engine: we implement the jobs those tools advertise, with open data and code you can run offline in CI.

Related work we measured against: [seo-skills-ai](https://github.com/seoskillsai/seo-skills-ai) (MIT). That project is useful, but its public scripts are thinner than the README:

| Their claim | What the public scripts actually do | Cursor SEO MCP |
|---|---|---|
| Full-site audit / 15 agents | One HTML fetch + checkbox heuristics | Multi-page crawl, per-URL evidence |
| Information gain / Google patent | Count `%` and Title Case words | Novelty vs **fetched** SERP competitor bodies (not claimed as a patent) |
| SERP + volume | DataForSEO or empty | DuckDuckGo → Brave/Bing HTML; Google **Suggest** only; Trends labeled relative |
| Scrape | Firecrawl API key | httpx + optional Playwright |
| Backlinks | Common Crawl stub (`UNAVAILABLE`) + paid MCP | Mention search, then **verify** the `href`; CDX host sample |
| CWV | PSI / Unlighthouse MCP | Local Lighthouse CLI (`--lighthouse`) |
| Fixes | Print snippets | Review patches; `--apply` writes locally with backups |
| Scores | Opaque 0–100 | Weighted passed checks; UNAVAILABLE parts excluded, not zero-filled |

The comparison harness is [`tests/compare`](tests/compare): same fixtures, more named checks than a nine-gate single-page baseline, and JSON must not contain invented `search_volume` or `domain_rating`.

---

## What ships

AEO, GEO, on-page, technical, Radar, Graph, drift, images, plus crawl/schema/SERP. Later catalog: Discover RSS, ecommerce, dedicated hreflang, local.

| Command | What it does |
|---|---|
| `cursor-seo-mcp doctor` | Python, httpx, selectolax, pydantic, ddgs, Pillow; optional Playwright / Lighthouse |
| `cursor-seo-mcp audit <url>` | Technical + on-page + AEO + GEO + schema + images + crawl + novelty + optional CWV |
| `cursor-seo-mcp seo <url>` | Page pack: technical + on-page + AEO + GEO + content + schema + images |
| `cursor-seo-mcp aeo <url>` | **AEO** — PAA/snippet-shaped answers (not a featured-snippet rank) |
| `cursor-seo-mcp geo <url>` | **GEO** — 130–170 word passages, author/dates, `llms.txt`, AI robots |
| `cursor-seo-mcp onpage <url>` | **On-page** — title, H1, canonical, URL slug, keyword placement, links |
| `cursor-seo-mcp technical <url>` | **Technical** — HTTPS, headers, indexability, robots, sitemap, mixed content |
| `cursor-seo-mcp crawl <url>` | BFS crawl, depth, orphans, PageRank **on fetched in-site URLs only** |
| `cursor-seo-mcp content <url>` | Page-type word gates, EAV from headings/schema, numeric claims, optional Wikidata |
| `cursor-seo-mcp schema <url>` | JSON-LD vs vendored schema.org subset; reduced types (FAQPage, HowTo) |
| `cursor-seo-mcp serp "<q>"` | Open SERP + autocomplete + optional Trends |
| `cursor-seo-mcp cluster "<seed>"` | Live overlap: ≥4 shared top-10 URLs → one pillar |
| `cursor-seo-mcp backlinks <host>` | Verified inbound hrefs + Common Crawl CDX sample |
| `cursor-seo-mcp info-gain <url>` | Same novelty method used inside audit |
| `cursor-seo-mcp fix <url>` | Generate `llms.txt`, robots snippet, JSON-LD, meta; `--apply` is local-only |
| `cursor-seo-mcp radar keywords` | **Radar** — Semrush analog: open SERP keyword explorer + crowding heuristic |
| `cursor-seo-mcp radar gap` | Content gap from competitor SERP occupancy |
| `cursor-seo-mcp radar ranks` | Local rank snapshots (SQLite) |
| `cursor-seo-mcp graph profile` | **Graph** — Ahrefs analog: href-verified link sample + CDX |
| `cursor-seo-mcp graph intersect` | Referring hosts a competitor has in-sample and you lack |
| `cursor-seo-mcp drift baseline` | Store an on-page snapshot (title, canonical, robots, schema, words) |
| `cursor-seo-mcp drift compare` | Diff live (or fixture) HTML vs last local baseline |
| `cursor-seo-mcp drift history` | List stored snapshots for a URL |
| `cursor-seo-mcp images <url>` | Image SEO: alt, filenames, dimensions, format, OG; optional WebP optimize |

`python -m seocur …` accepts the same arguments.

### Page-type word gates

A product page is not a blog.

| `page_type` | Minimum body words |
|---|---|
| article | 800 |
| homepage | 400 |
| product | 300 |
| other | 500 |

---

## Radar and Graph (Semrush / Ahrefs jobs, open data)

Paid suites sell a **keyword database** and a **backlink index**. Those private crawls do not exist in open source. Cursor SEO MCP replacements are better on **evidence** (you can reopen every URL) and honest about coverage.

### Radar — keyword & competitor intel (Semrush analog)

| Semrush-style job | Cursor SEO MCP | What we refuse to fake |
|---|---|---|
| Keyword overview / KD / volume | Autocomplete expansion + live SERP + `serp_crowding_0_100` | Google Ads volume, Semrush KD, traffic |
| Keyword gap / content gap | Occupancy: competitor URL in sampled SERP, you absent | Their ranking database |
| Position tracking | SQLite snapshots in `.cursor-seo-mcp/ranks.sqlite` | Panel-wide rank history |

```bash
cursor-seo-mcp radar keywords "technical seo" --site example.com
cursor-seo-mcp radar gap example.com "technical seo" --competitor rival.com --competitor other.com
cursor-seo-mcp radar ranks example.com --keyword "technical seo"
cursor-seo-mcp radar ranks example.com --history
```

Crowding is labeled `not_semrush_kd` / `not_ahrefs_kd`. Higher = more major properties and homepages in the sample SERP.

### Graph — link explorer (Ahrefs analog)

| Ahrefs-style job | Cursor SEO MCP | What we refuse to fake |
|---|---|---|
| Site Explorer / DR | Href-verified mention sample + CDX host coverage | Domain Rating, organic traffic |
| Backlink profile | Anchors, follow vs nofollow, referring hosts **in this sample** | Full web index |
| Link intersect | Hosts that link to a competitor in-sample and not to you | Ahrefs Link Intersect |

```bash
cursor-seo-mcp graph profile example.com
cursor-seo-mcp graph intersect example.com --competitor rival.com
```

`cursor-seo-mcp backlinks` remains the lower-level verified-mention command; Graph adds summary + intersect.

### Drift — on-page regression

Radar ranks track **SERP position**. Drift tracks **the page itself** after deploys: title, canonical, noindex, H1, JSON-LD types, word count, citable passages, hreflang, OG. Snapshots live in `.cursor-seo-mcp/drift.sqlite`. No baseline → `UNAVAILABLE`, never an invented diff.

```bash
cursor-seo-mcp drift baseline https://example.com/page
cursor-seo-mcp drift compare https://example.com/page
cursor-seo-mcp drift history https://example.com/page
```

### Images — SEO audit, optimize, generate

Markup checks always run: alt, camera filenames, width/height, next-gen URL, `og:image`, LCP not `loading=lazy`. **Byte size and intrinsic pixels are only reported after a fetch or a local file.**

```bash
cursor-seo-mcp images https://example.com/page
cursor-seo-mcp images https://example.com/page --optimize --apply --project .
```

### AEO, GEO, on-page, technical

| Pillar | Command | What we measure | What we refuse |
|---|---|---|---|
| **AEO** | `cursor-seo-mcp aeo` | Question headings, lede length, lists/tables, heading ids, answer passages | Featured-snippet or AI Overview placement |
| **GEO** | `cursor-seo-mcp geo` | 130–170 word blocks, OG, author/date, llms.txt, AI robots | ChatGPT/Perplexity citation counts |
| **On-page** | `cursor-seo-mcp onpage` | Title, unique H1, canonical, slug, keyword in title/URL/lede, links | CTR, “keyword density” scores |
| **Technical** | `cursor-seo-mcp technical` | HTTPS, headers, noindex, charset, mixed content, robots, sitemap | Invented CrUX / crawl-stats |
| **SEO pack** | `cursor-seo-mcp seo` | All of the above plus content, schema, images | GSC graphs |

---

## Honest limits

- **Not Google Ads search volume.** Autocomplete is query expansion. Optional `pytrends` is relative interest 0–100.
- **Not Ahrefs DR or Semrush traffic.** Radar crowding and Graph samples are documented heuristics on pages we fetched.
- **Google SERP HTML is not scraped** (ToS). Engines: DuckDuckGo, then Brave/Bing HTML.
- **Lighthouse is lab data**, not CrUX field data.
- **GSC / GA4 are out of v1.** They must never become a score dependency.
- Search engines may block or rate-limit. That is `UNAVAILABLE`, not a reason to fabricate rows.

---

## Install Cursor SEO MCP

**Requires Python 3.11+.**

### From PyPI

```bash
pip install cursor-seo-mcp
cursor-seo-mcp doctor
```

Optional JS render: `pip install 'cursor-seo-mcp[browser]'` then `playwright install chromium`.

### From source (Windows PowerShell)

```powershell
git clone https://github.com/engrmaziz/cursor-seo-mcp.git
cd cursor-seo-mcp
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[dev]"
cursor-seo-mcp doctor
pytest -q
```

### macOS / Linux

```bash
git clone https://github.com/engrmaziz/cursor-seo-mcp.git
cd cursor-seo-mcp
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cursor-seo-mcp doctor
pytest -q
```

### Optional JS render

```bash
pip install 'cursor-seo-mcp[browser]'
playwright install chromium
cursor-seo-mcp audit https://example.com --js --no-serp
```

### Optional lab Core Web Vitals

```bash
cursor-seo-mcp audit https://example.com --lighthouse --no-serp
```

If `lighthouse` / `npx lighthouse` is missing, the CWV component is `UNAVAILABLE`.

---

## CLI reference

JSON goes to stdout. Exit `0` for `OK` / `PARTIAL` / `UNAVAILABLE`, `1` for hard errors.

```bash
cursor-seo-mcp --help
cursor-seo-mcp --version
python -m seocur --help
python -m cursor_seo_mcp --help
```

### Audit

```bash
cursor-seo-mcp audit https://example.com
cursor-seo-mcp audit https://example.com --max-pages 15 --no-serp
cursor-seo-mcp audit https://example.com --js --lighthouse
cursor-seo-mcp audit https://example.test/page --html-file tests/fixtures/good_article.html --no-dns
cursor-seo-mcp audit https://example.com --html-out report.html --json-out report.json
```

### Other commands

```bash
cursor-seo-mcp crawl https://example.com --max-pages 25
cursor-seo-mcp aeo https://example.com
cursor-seo-mcp geo https://example.com
cursor-seo-mcp onpage https://example.com
cursor-seo-mcp technical https://example.com
cursor-seo-mcp seo https://example.com
cursor-seo-mcp serp "cursor seo mcp"
cursor-seo-mcp cluster "technical seo"
cursor-seo-mcp radar keywords "technical seo" --site example.com
cursor-seo-mcp graph profile example.com
cursor-seo-mcp drift compare https://example.com/page
cursor-seo-mcp images https://example.com/page --optimize --apply --project .
cursor-seo-mcp backlinks example.com
cursor-seo-mcp fix https://example.com --apply --project .
```

`--apply` copies backups under `.cursor-seo-mcp/backups/` and writes `llms.txt` / robots / JSON-LD snippets locally. Never run `--apply` against a remote server.

### Common flags

| Flag | Meaning |
|---|---|
| `--js` | Playwright HTML (audit/crawl) |
| `--lighthouse` | Local Lighthouse (audit) |
| `--no-serp` | Skip live SERP / competitor fetch |
| `--no-dns` | Skip DNS (fixtures, some offline flows) |
| `--html-out PATH` | Write the HTML evidence report |
| `--json-out PATH` | Write the same JSON as stdout |

---

## How scoring works

1. Each component produces `EvidenceItem`s.
2. Component score = `100 * (sum of weights of passed checks) / (sum of weights)`.
3. Overall `health_score` = weighted average of components that are **not** `UNAVAILABLE`.
4. `score_partial: true` means at least one provider was skipped.
5. Critical failures stay in `critical_issues`.

---

## Architecture

```
seocur/             Python engine (imports stay `seocur`)
cursor_seo_mcp/     `python -m cursor_seo_mcp` entry
skills/             Cursor Agent Skills (Cursor SEO MCP)
.cursor/skills/     Workspace orchestrator
.cursor/mcp.json    MCP server id: cursor-seo-mcp
seocur/mcp_server.py  SEO MCP stdio (`cursor-seo-mcp-server`)
tests/fixtures/     Offline HTML / SERP samples
tests/compare/      Beats checkbox-style baseline; no invented metrics
```

Safety (`seocur/safety.py`, `seocur/robots.py`): `http`/`https` only; DNS fail-closed; private IPs blocked; redirects re-checked; `robots.txt` unless `SEOCUR_RESPECT_ROBOTS=0`; per-host delay.

### Environment

| Variable | Role |
|---|---|
| `CURSOR_SEO_MCP_OUT_DIR` or `SEOCUR_OUT_DIR` | Report/backup directory (default `./.cursor-seo-mcp`) |
| `SEOCUR_USER_AGENT` | HTTP User-Agent |
| `SEOCUR_TIMEOUT` | Request timeout seconds |
| `SEOCUR_RATE_LIMIT` | Seconds between hits per host |
| `SEOCUR_ALLOWED_HOSTS` | Comma-separated host allowlist |
| `SEOCUR_MAX_REDIRECTS` | Redirect cap |
| `SEOCUR_RESPECT_ROBOTS` | `0` to ignore robots.txt |

---

## Cursor SEO MCP — skills

Skills live in [`skills/`](skills/). The orchestrator is [`skills/cursor-seo-mcp`](skills/cursor-seo-mcp): run `cursor-seo-mcp …` and do not fabricate GSC/Ahrefs numbers.

---

## Tests

```bash
pytest -q
```

CI runs Python 3.11–3.13. Tests use fixtures; they must not require paid keys or a live SERP.

---

## Roadmap

Discover / Media RSS, ecommerce schema depth, dedicated hreflang maps, local/maps (open data). Optional free GSC/GA4 OAuth stays optional.

---

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). By participating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md).

- Bugs: [issue template](https://github.com/engrmaziz/cursor-seo-mcp/issues/new?template=bug_report.yml)
- Features: [issue template](https://github.com/engrmaziz/cursor-seo-mcp/issues/new?template=feature_request.yml)

After you rename the GitHub repo, set **About** to: `Cursor SEO MCP — open-source SEO MCP server for Cursor (AEO, GEO, technical & on-page)` and topics: `cursor`, `seo`, `mcp`, `cursor-seo-mcp`, `aeo`, `geo`.

---

## License

[MIT](LICENSE) © 2026 Cursor SEO MCP Contributors.

seo-skills-ai is cited as related work only. Their code is not vendored here.
