The conversation is the report

Raptor's MCP server lets Claude, or any MCP client, crawl a site on your machine and read every finding. Ask the way you'd ask a colleague who has read every page: the answers come back ranked, with the fix, in Raptor's own words. 9 tools; 7 of them only read.

Claude Codewith Raptor’s MCP serverFixture site: Fernhollow Outdoor, a month later, 127.0.0.1:8006

You

We shipped the migration fixes. Crawl http://127.0.0.1:8006/ again and tell me what changed since last time. Keep it short.

Claude

Baseline is da9a5fe6 (the earlier 8006 crawl).

Compared with the last crawl of :8006 (13:33 today), the site went from 79 (C) to 89 (B). The two crawls use the same scoring model, so the scores are directly comparable. This crawl covered 26 pages.

Fixed (11 issues): 2 canonicals, 2 content, 2 directives, 2 sitemaps, 1 headings, 1 links and 1 response code.

New (5 issues on 3 URLs), all in the /waterproofs section:

  • /waterproofs/ridge-trousers now returns a 4xx error but is still listed in the sitemap. It's the only error page in the crawl.
  • /waterproofs links to that page, so it now has a broken internal link.
  • /waterproofs and /waterproofs/storm-shell both have duplicate H2s.

To clear the regressions, either restore ridge-trousers or redirect it, and remove it from the sitemap and the /waterproofs links. The duplicate H2s look like a template change in that section.

The site still has 2 critical issues and 5 warnings in total.

You

Is /waterproofs/ cleared for indexing now?

Claude

Yes. /waterproofs/ is clear for indexing.

  • The noindex is gone. Last crawl the page had <meta robots="index, follow"> but the server sent an X-Robots-Tag: noindex header, and search engines follow the stricter rule. This crawl flags no directives or noindex on the page at all, so the header fix worked.
  • The page itself checks out: it returns 200, its canonical points to its own address, and it's no longer flagged as a noindexed page in the sitemap.

One thing is still open on the page, though it won't stop indexing: it links to /waterproofs/ridge-trousers/, which now returns 410 Gone and is still in the sitemap. That's the change to make next. The duplicate "Help choosing" H2 is a minor note.

This only shows the site now allows indexing. Google won't drop the noindex until it recrawls the page, so it's worth asking for indexing in Search Console.

A real Claude Code session (claude-opus-5-5, Raptor 0.3.0, 17 Oct 2026). The fixture shop from the home page has shipped its migration fixes, and one of them broke something else. Claude finds the earlier crawl by itself, compares the two, then inspects a page. The calls, replies and answers are verbatim, status polls are shown by their key fields, and the waits are shortened: the two turns took 22.2 s and 25.7 s.

Connect it

Raptor speaks MCP over stdio: your client starts raptor serve --mcp on your machine and talks to it. Build Raptor first (see Install on the home page); every client needs the full path to the binary.

Claude Code

One command, as the README gives it, with the path to the binary you built.

Shell
$ claude mcp add raptor -- /full/path/to/target/release/raptor serve --mcp

Claude Code shows text, not panels; its model reads the same facts from Raptor’s written digests.

Claude Desktop

Add Raptor to Claude Desktop’s MCP config, claude_desktop_config.json, then restart it.

claude_desktop_config.json
{
  "mcpServers": {
    "raptor": {
      "command": "/full/path/to/target/release/raptor",
      "args": ["serve", "--mcp"]
    }
  }
}

Claude Desktop shows Raptor’s panels, inline and full screen.

Other MCP clients

Anything that can run a local stdio server works: point it at raptor serve --mcp. VS Code (GitHub Copilot), Cursor and Goose show the panels inline.

Not for web or mobile clients

claude.ai on the web, Claude on mobile and ChatGPT reach only remote servers with a public HTTPS address. A local stdio server doesn’t reach them.

To crawl localhost or an intranet, set RAPTOR_ALLOW_PRIVATE_TARGETS=1 in the server’s environment. Private addresses are refused by default.

Prompts that work

Ask for an outcome, not a tool. Claude picks the tools; these are the ones it reaches for. Prompts marked Ran on this site are word for word from the sessions on this site, and some come from Raptor's README. The rest are suggestions.

Audit a site

raptor_crawlraptor_statusraptor_summary

  • Crawl example.com and tell me what I should fix first.From the README
  • Our waterproofs traffic fell off a cliff after last month's site migration. Crawl http://127.0.0.1:8006/ and tell me what's going on. Keep it short.Ran on this site

Dig into a finding

raptor_findingsraptor_query

  • Crawl mysite.com, then tell me which pages Google can't index and why.From the README
  • Give me the fix brief for the canonical problem, so I can send it to our developer.

Check one page

raptor_inspect

  • Is /waterproofs/ cleared for indexing now?Ran on this site
  • Inspect our pricing page. Is anything stopping it from ranking?

Follow the links

raptor_link_graph

  • Which of my blog posts have no internal links pointing at them?From the README
  • And how does our internal linking treat the waterproofs pages?Ran on this site

Re-audit

raptor_compare

  • Compare that against last month's crawl — did anything get worse?From the README
  • We shipped the migration fixes. Crawl http://127.0.0.1:8006/ again and tell me what changed since last time. Keep it short.Ran on this site

Stop a crawl

raptor_cancel

  • That's taking too long. Stop it and tell me what you've found so far.

Panels in the conversation

Four tools come with a small interactive view, an MCP Apps panel, beside their result. Each is one self-contained page: no network requests, its own theme following the host's, and crawled text always shown as text, never run.

Raptor's site health panel
Site health raptor_summaryThe grade, one sentence on what holds the score back, the top three fixes, and buttons to open the report and see every finding.
Raptor's page check panel
Page check raptor_inspectThe page's status, title, description and headings with their lengths, and the findings on it.
Raptor's findings panel
Findings raptor_findingsThe ranked list inline. Expanded to full screen, a filterable, sortable table beside one finding's fix brief, with Copy fix brief and Ask your assistant to fix.
Raptor's crawl progress panel
Crawl progress raptor_crawlA live bar, counts, the phase in flight and recent errors, polling raptor_status. Cancel crawl while it runs; Show summary when it's done.

Which hosts show them

HostPanels
Claude DesktopInline and full screen
VS Code (GitHub Copilot), CursorInline, with more rows in place of Expand
GooseInline
Claude CodeText only; the model reads the digests
claude.ai, Claude mobile, ChatGPTReach remote servers only, not a local one

Screenshots from Raptor’s panel test harness, which renders each panel in a fake host: the health, page and findings panels for the repo’s Kestrel Bay fixture, the crawl panel mid-crawl on its 2,000-page synthetic fixture. They follow your theme here, as they follow the host’s in Claude.

What the model reads

Every tool answers with a written digest: the verdict first, then the ranked fixes in the check catalogue's own words, lists capped with their true totals, and the next call to make. A host that passes the model only text still gives it everything it needs.

raptor_findings, as Claude read it on the home page's crawl (2,349 characters)
79/100: Needs Work. Here is what is holding the score back.
127.0.0.1: 17 findings, 13 to fix.
1. [Fix now] 1 page returns an error instead of its content — 1 page · +3.7 · response_codes.internal_client_error · e.g. /products/storm-shell
2. [Fix now] 1 page names a preferred version that search engines cannot use — 1 page · +3.7 · canonicals.non_indexable_target · e.g. /waterproofs/storm-shell/
3. [Fix now] 1 page both allows and blocks listing in search results — 1 page · +3.7 · directives.conflicting_directives · e.g. /waterproofs/
4. [High] 1 page links to a page that returns an error — 1 page · +2.3 · links.broken_internal · e.g. /journal/storm-shell-review/
5. [High] 1 page shows an error message but reports success — 1 page · +2.0 · content.soft_404 · e.g. /waterproofs/ridge-trousers/
6. [Medium] 2 sitemap addresses lead to an error or a hidden page — 2 URLs · +1.1 · sitemaps.non_indexable_in_sitemap · e.g. /waterproofs/
7. [Medium] 2 pages share a title with another page — 2 pages · +1.1 · page_titles.duplicate · e.g. /tents/basecamp-4/
8. [Medium] 1 address redirects more than once — 1 URL · +0.8 · response_codes.internal_redirect_chain · e.g. /shop/sale.html
9. [Medium] 1 page lists a language version that does not list it back — 1 page · +0.8 · hreflang.missing_return_links · e.g. /
10. [Medium] 1 page has very little text — 1 page · +0.8 · content.low_content · e.g. /waterproofs/ridge-trousers/
11. [Low] 3 pages are not listed in the sitemap — /journal/ pages · +0.3 · sitemaps.urls_not_in_sitemap · e.g. /journal/
12. [Low] 1 page has no fallback for other languages — 1 page · +0.2 · hreflang.missing_x_default · e.g. /en-us/
13. [Low] 1 page has no second-level headings — 1 page · +0.2 · headings.h2_missing · e.g. /waterproofs/ridge-trousers/
14. [Note] 15 pages repeat subheadings used on other pages — 15 pages · headings.h2_duplicate · e.g. /about/
15. [Note] 3 pages name another address as their preferred version — 3 pages · canonicals.canonicalised · e.g. /tents/?colour=green
16. [Note] 2 pages have parameters after a ? in their address — 2 pages · url.has_parameters · e.g. /tents/?colour=green
17. [Note] 1 page asks search engines not to list it — 1 page · directives.noindex · e.g. /waterproofs/
Next: raptor_findings {"job_id":"da9a5fe6…","check_id":"<one of the ids above>"} for its fix brief.
2,349 characters
That digest, against 162 KB for the same crawl’s full JSON. The model gets the answer, not the data dump.
Bounded, whatever the size of the site
Any list that grows with the crawl is capped, with the true total beside it. Before bounding, one default call on a 500-page crawl returned well over 100k tokens; now a 1,000-page summary is within 10% of the size of a 50-page one.
Small enough for panels
Every result a panel reads stays within 120,000 bytes, even on a crawl where every check fires on long URLs.
Strict about arguments
An argument outside a tool’s schema is rejected with the accepted set, not ignored. A misspelled maxpages used to crawl 500 pages of someone’s production site.

The 9 tools

As the server lists them, with the hints hosts use to decide when to ask you first: a read-only tool can run without a prompt, and a destructive one always asks. A build with the Cloudflare feature adds raptor_screenshot, and raptor_inspect's rendered and compare modes.

raptor_crawl

Crawl a siteStarts a job

Start a website crawl for SEO analysis. Returns a job_id to track progress. Use raptor_status to check when it completes, then raptor_summary and raptor_query to explore results. Where the host supports MCP Apps, shows live crawl progress.

Read-only: noDestructive: noIdempotent: noOpen world: yes
ArgumentTypeWhat it does
urlrequiredstringThe seed URL to begin crawling (e.g. https://example.com)
backendstringlocaldefault "local"Crawl backend. Only 'local' is supported by the server; for JS-rendered crawls use the CLI.
concurrencyintegerdefault 3Number of concurrent requests (default: 3)
delay_msintegerdefault 250Delay between requests in milliseconds (default: 250)
max_pagesintegerdefault 500Maximum number of pages to crawl (default: 500)
pagespeedbooleandefault falseEnable PageSpeed/Core Web Vitals analysis (default: false)
pagespeed_sampleintegerAnalyze only N random pages for PageSpeed (default: all)
pagespeed_strategystringmobile | desktopdefault "mobile"PageSpeed test strategy: 'mobile' (default) or 'desktop'

raptor_status

Crawl job statusRead-only

Check one crawl job's status and live progress, or list recent jobs when no job_id is given. Read-only: to stop a crawl, call raptor_cancel.

Read-only: yesDestructive: noIdempotent: yesOpen world: no
ArgumentTypeWhat it does
filter_domainstringFilter jobs by domain when listing
filter_statusstringFilter jobs by status when listing (queued, running, completed, failed, cancelled)
job_idstringSpecific job ID to check. Omit to list recent jobs.
limitintegerdefault 20Maximum number of jobs to return when listing (default: 20)

raptor_cancel

Cancel a crawlChanges a job

Cancel a queued or running crawl job. A queued job never starts. A running crawl stops fetching new pages; the pages it already fetched are analysed and saved, and raptor_summary then covers only those pages.

Read-only: noDestructive: yesIdempotent: yesOpen world: no
ArgumentTypeWhat it does
job_idrequiredstringThe job ID of the crawl to cancel

raptor_summary

Site health summaryRead-only

Get the high-level summary of a completed crawl: health score, grade, issue breakdown (counts URL rows; one check can list a page more than once), findings_count (checks that fired), pages_with_findings (distinct crawled pages with at least one finding), top issue categories, and worst pages (worst_pages[].issue_count counts the findings on each page). Use after raptor_crawl completes. Where the host supports MCP Apps, shows a site health card.

Read-only: yesDestructive: noIdempotent: yesOpen world: no
ArgumentTypeWhat it does
job_idrequiredstringThe job ID of a completed crawl

raptor_findings

Findings to fixRead-only

The ranked list of what to fix on a completed crawl, most important first, in plain words. Without check_id: one short row per finding (priority, title, reach, check id), filterable by priority and area. With check_id (for example "page_titles.duplicate"): that finding in full, with what was found, why it matters, how to fix it, up to 25 affected URLs with the true total, and a markdown fix brief ready to paste into a task. Where the host supports MCP Apps, shows a filterable findings list.

Read-only: yesDestructive: noIdempotent: yesOpen world: no
ArgumentTypeWhat it does
job_idrequiredstringThe job ID of a completed crawl
areastringreached | indexed | unique | found | described | fast_safeList only findings in this part of the search journey: reached (can it be reached), indexed (can it be indexed), unique (is it unique), found (can it be found), described (is it well described), fast_safe (is it fast and safe)
check_idstringOne finding's check id, as the list shows it (for example "page_titles.duplicate"). Returns that finding in full with its fix brief.
prioritystringfix_now | high | medium | low | noteList only findings of this priority

raptor_query

Query crawl resultsRead-only

Query crawl results with powerful filtering. Filter by URL pattern, issue category, severity. Returns paginated issues and optional page data. Each issue reports affected_url_count (matching URL rows; one check can list a page more than once) and affected_page_count (distinct URLs among the rows, each URL once; not resolved through redirects), plus culprits, on the issue or on an affected URL, when a finding names the offending values. This is the primary tool for exploring crawl results in detail.

Read-only: yesDestructive: noIdempotent: yesOpen world: no
ArgumentTypeWhat it does
job_idrequiredstringThe job ID of a completed crawl
categorystringresponse_codes | security | url | page_titles | meta_description | headings | content | images | canonicals | directives | hreflang | links | structured_data | sitemaps | performance | javascriptFilter issues by category
fieldsarray of stringSpecific page_data fields to return (e.g. ['title', 'status', 'word_count']). Only used when page_data is included.
includearray of issues | page_dataWhat to include in results (default: ['issues'])
max_urls_per_issueintegerdefault 5Cap on affected URLs listed per issue (default: 5, max: 500). A sitewide check affects every page, so the full list can be enormous; each issue always reports affected_url_count with the true total and sets affected_urls_truncated when the list was cut. To see specific URLs, narrow with url_pattern rather than raising this.
pageintegerdefault 1Page number for pagination (default: 1)
per_pageintegerdefault 20Results per page (default: 20, max: 100)
severitystringcritical | warning | infoFilter issues by severity: 'critical', 'warning', or 'info'
url_patternstringGlob pattern to match URLs (e.g. '*/blog/*', '*.html')
urlsarray of stringFilter to specific URLs

raptor_inspect

Inspect one pageRead-only, fetches the web

Run a single-page SEO audit on a URL. Returns page data (title, meta description, headings, word count, links, schema, security) and any issues found. Fast — no crawl needed. Where the host supports MCP Apps, shows a page check card.

Read-only: yesDestructive: noIdempotent: yesOpen world: yes
ArgumentTypeWhat it does
urlrequiredstringThe URL to inspect
modestringstaticdefault "static"Inspection mode: 'static' (raw HTML). This build has no JavaScript rendering.

raptor_compare

Compare two crawlsRead-only

Compare two crawl jobs to find regressions and improvements. Shows score changes, new issues, and resolved issues between a baseline and current crawl. Findings are matched by category, check and page, so same-named checks in different categories (page_titles duplicate, meta_description duplicate) are told apart. Always reports scoring_model {baseline, current} and comparable; when the two crawls were scored by different models, comparability_warning says the changes are not like-for-like.

Read-only: yesDestructive: noIdempotent: yesOpen world: no
ArgumentTypeWhat it does
baseline_job_idrequiredstringThe job ID of the baseline (earlier) crawl
current_job_idrequiredstringThe job ID of the current (later) crawl

How a session runs

Crawls are jobs. raptor_crawl returns a job id at once; the client polls raptor_status until the job is finished, then reads results. Apart from raptor_crawl and raptor_inspect, no tool fetches anything: they answer from what Raptor stored.

A typical session, from docs/mcp.md
raptor_crawl    { "url": "https://example.com/", "max_pages": 200 }   -> job_id
raptor_status   { "job_id": "..." }                    -> queued | running | completed | failed | cancelled
raptor_summary  { "job_id": "..." }                    -> the verdict and the top fixes
raptor_findings { "job_id": "..." }                    -> every finding, ranked
raptor_findings { "job_id": "...", "check_id": "page_titles.duplicate" }   -> one fix brief
One job store, shared
The MCP server and the REST API share a SQLite store under RAPTOR_HOME (default ~/.raptor), so a crawl started over MCP is visible over REST, and the other way round.
Cancelling keeps what was fetched
raptor_cancel stops a running crawl; the pages already fetched are analysed and saved, and the summary says it was interrupted.
Safe by default
Private, loopback, link-local and cloud-metadata addresses are refused, checking the address actually dialled. In MCP mode every log line goes to stderr; stdout is only JSON-RPC.