MCP server
Connect SEOLint to your AI client in 2 minutes. After this the agent can scan any URL, remember every issue across runs, and tell you exactly what to fix next.
Quick start
Pick your AI client below. Each one needs the SEOLint MCP server registered with your API key — the snippet does both.
One command — adds the server, sets the env var, and writes the config for you.
claude mcp add seolint \ --env SEOLINT_API_KEY=<your_key> \ -- npx -y seolint-mcp
Restart Claude Code afterwards. Verify with `npx -y seolint-mcp doctor`.
Tip
Skip the manual config — run npx -y seolint-mcp init in any terminal and it writes the right config file for you. (v0.1.5+)
Validate your setup with doctor
Run this in any terminal — no MCP client needed. It checks your API key is set, validates it against the API, confirms your subscription is active, and reports your monthly scan quota.
SEOLINT_API_KEY=<your_key> npx -y seolint-mcp doctor
Output is colored ✅ / ⚠️ / ❌ lines with specific fixes for any failure. Exits 0 on success.
seolint-mcp doctor — checking your setup ✅ SEOLINT_API_KEY found (sl_abcd…) ✅ API reachable at https://www.seolint.dev ✅ API key is valid (authenticated as you@yourdomain.com) ✅ Subscription active (plan: pro) ✅ Quota: 47 of 50 scans remaining this month ✅ Tools reachable (list_my_sites returned 200) Doctor result: all checks passed ✨
Authentication
The MCP server authenticates with a single API key per account, passed as the SEOLINT_API_KEY environment variable in your MCP client config. Get yours from the dashboard at seolint.dev/api.
The same key works across every client — Claude Code, Claude Desktop, Cursor, Windsurf, VS Code — and the REST API and CLI. Scans are unified under one user, so memory is shared everywhere.
Note
Set the env var inside your MCP client config — not your shell. Shells don't propagate env to GUI apps. After saving, fully quit and reopen the client.
Tools reference
The MCP server exposes 11 tools. Your agent decides which to call based on the user's task — these descriptions are what the agent sees.
scan_websiteRun a full scan and label issues as NEW, PERSISTING or REGRESSED based on prior scans of the same URL. The single most important tool — does scanning, history diffing, and recurring tracking in one call.
scan_websiteRun a full scan and label issues as NEW, PERSISTING or REGRESSED based on prior scans of the same URL. The single most important tool — does scanning, history diffing, and recurring tracking in one call.
Parameters
| Name | Type | Description |
|---|---|---|
url | string | Full URL to scan, e.g. https://example.com |
Returns
Markdown report with scan_id, issue counts, scan memory block, per-issue fix instructions.
get_scanFetch a previous scan by ID. Useful when scan_website timed out and you want to retrieve the result later.
get_scanFetch a previous scan by ID. Useful when scan_website timed out and you want to retrieve the result later.
Parameters
| Name | Type | Description |
|---|---|---|
scanId | string | The scan UUID returned by scan_website |
Returns
Markdown report (or status string if still pending).
cancel_scanCancel a scan that is still pending. Escape hatch when scan_website is taking too long or the wrong URL was scanned.
cancel_scanCancel a scan that is still pending. Escape hatch when scan_website is taking too long or the wrong URL was scanned.
Parameters
| Name | Type | Description |
|---|---|---|
scanId | string | The scan UUID to cancel |
Returns
Status message. No effect on scans already complete, errored or cancelled.
get_open_issuesReturn the unresolved issues for a URL based on the latest scan — without running a new scan. Use this for a flat actionable list. For higher-level trend questions, use get_site_status.
get_open_issuesReturn the unresolved issues for a URL based on the latest scan — without running a new scan. Use this for a flat actionable list. For higher-level trend questions, use get_site_status.
Parameters
| Name | Type | Description |
|---|---|---|
url | string | URL whose open issues you want |
Returns
Markdown list of open issues plus any regressed-from-fixed.
get_site_statusHigh-level memory picture: trend (improving/degrading/stable), recurring patterns, days since last scan, rescan recommendation. Use for 'how is this site doing?' questions.
get_site_statusHigh-level memory picture: trend (improving/degrading/stable), recurring patterns, days since last scan, rescan recommendation. Use for 'how is this site doing?' questions.
Parameters
| Name | Type | Description |
|---|---|---|
url | string | URL to check |
Returns
Markdown summary with trend label and rescan recommendation.
get_site_historyScan history plus resolved/dismissed/recurring state for a URL. Call this before starting any fix session for context.
get_site_historyScan history plus resolved/dismissed/recurring state for a URL. Call this before starting any fix session for context.
Parameters
| Name | Type | Description |
|---|---|---|
url | string | URL whose history you want |
Returns
Markdown timeline with full issue lifecycle.
get_site_intelligenceFull intelligence for a domain: ICP, sitemap structure and gaps, cross-page template issues, scan coverage by page type. Call at the start of any SEO session to understand the site before diving into individual pages.
get_site_intelligenceFull intelligence for a domain: ICP, sitemap structure and gaps, cross-page template issues, scan coverage by page type. Call at the start of any SEO session to understand the site before diving into individual pages.
Parameters
| Name | Type | Description |
|---|---|---|
domain | string | Domain to analyze, e.g. example.com (no protocol) |
Returns
Markdown brief covering site profile, sitemap, cross-page patterns and coverage.
list_my_sitesList every URL you have scanned with the latest scan summary per site. Use to discover what is already tracked.
list_my_sitesList every URL you have scanned with the latest scan summary per site. Use to discover what is already tracked.
No parameters.
Returns
Markdown table sorted by last-scanned, with rescan flags.
mark_issues_fixedMark issues from a scan as fixed after the user confirms. If a previously fixed issue reappeared, the resurface count is incremented so the system learns it keeps recurring.
mark_issues_fixedMark issues from a scan as fixed after the user confirms. If a previously fixed issue reappeared, the resurface count is incremented so the system learns it keeps recurring.
Parameters
| Name | Type | Description |
|---|---|---|
scan_id | string | Scan UUID containing the issues |
issue_ids | string[] | Issue IDs to mark fixed, e.g. ["missing-title"] |
Returns
Confirmation message + which IDs had previously been fixed.
dismiss_issuesDismiss issues as false positives or intentional design choices. Dismissed issues are hidden from future scans and persist across runs.
dismiss_issuesDismiss issues as false positives or intentional design choices. Dismissed issues are hidden from future scans and persist across runs.
Parameters
| Name | Type | Description |
|---|---|---|
scan_id | string | Scan UUID containing the issues |
issue_ids | string[] | Issue IDs to dismiss |
reason | string | Why these are being dismissed (kept for future scans) |
Returns
Confirmation message.
undismiss_issuesUn-dismiss previously dismissed issues so they appear as open again.
undismiss_issuesUn-dismiss previously dismissed issues so they appear as open again.
Parameters
| Name | Type | Description |
|---|---|---|
scan_id | string | Scan UUID (used to identify the URL) |
issue_ids | string[] | Issue IDs to un-dismiss |
Returns
Confirmation message.
Scan memory
Memory is what makes SEOLint different from a one-shot scanner. Every scan is compared to history and every issue is annotated with one of three labels:
🆕 NEW
First time we've seen this issue on this URL.
⏳ PERSISTING
Was in the previous scan, still not fixed.
🔁 REGRESSED
Was marked as fixed before — it's back.
When the agent calls mark_issues_fixed after applying a fix, SEOLint records the resolution. If the same issue ever resurfaces, the resurface count is incremented — over time the system learns which fixes are flaky and which stick. Use dismiss_issues with a reason to permanently silence false positives across all future scans.
Rate limits
Limits are based on your plan's monthly scan quota:
| Plan | Scans / month | Concurrent |
|---|---|---|
| Free preview | 1 | 1 |
| Pro | 50 | 3 |
| Team | 250 | 5 |
When the monthly cap is reached, the API returns HTTP 429 with a Retry-After header set to the seconds remaining until the first day of next month. The MCP server surfaces this so the agent can tell the user clearly whether to wait or upgrade.
Troubleshooting
When something feels wrong, run npx -y seolint-mcp doctor first — it covers 90% of setup problems. The rest are below.
"API key required" — but I set it
Tool calls return 401 Invalid API key
Scans are slow or hanging
HTTP 429 — Scan limit reached
Doctor reports the API is unreachable
FAQ
How do I get an API key?
Where do I put SEOLINT_API_KEY?
How do I check that my setup is working?
What happens when I hit my monthly scan limit?
How does scan memory work across runs?
Can I use SEOLint with multiple AI clients at once?
Ready to connect?
Get your API key, copy the snippet for your client, and start scanning from inside your AI workflow.
Get your API key →