One spec, two ways in.

A Bearer-token JSON API and an MCP server over stdio that wraps it - 11 tools, 11 routes, generated from the same list the server itself registers against.

Authentication

Every call is a Bearer token scoped to one workspace. Mint one under Settings, API tokens - the plaintext shows once, can be pinned to a single project, and carries spec:read, or spec:read plus spec:write. A token only ever resolves the workspace that minted it, never another tenant's projects.

curl

curl -H "Authorization: Bearer $CRAWLSPEC_TOKEN" https://crawlspec.dev/api/spec/projects/yourdomain.com/recommendations

MCP config

Add to your agent's .mcp.json, with CRAWLSPEC_API_KEY set to a workspace API token. Leave the key out and the server still starts: the two bootstrap tools below run a free audit without an account, and every other tool answers with how to get a token rather than failing.

Availability: @crawlspec/mcp is published with the next release. Until it lands on npm this config will not resolve, and the Spec API above is the way in.

{
  "mcpServers": {
    "crawlspec": {
      "command": "npx",
      "args": [
        "-y",
        "@crawlspec/mcp"
      ],
      "env": {
        "CRAWLSPEC_API_KEY": "<your workspace API token>",
        "CRAWLSPEC_API_URL": "https://crawlspec.dev"
      }
    }
  }
}

Spec API routes

Read-only JSON, with one deliberate exception: marking a brief applied. All routes sit under /api/spec; {domain} is the project's bare domain (for example "yourdomain.com").

MethodRouteDescription
GET/api/spec/projectsList every CrawlSpec project with its domain, last Search Console sync date and open issue count.
GET/api/spec/projects/{domain}/recommendationsPrioritized fix cards for a project - technical (template/config/infrastructure fixes) AND content (briefs to implement, cannibalization verdicts, topic opportunities). Default status OPEN.
GET/api/spec/projects/{domain}/briefsContent briefs with full outline/change-list content. Use status=READY for human-approved briefs only - governance: only READY briefs should be implemented. Each brief also carries currentVersion, appliedVersion, revisionCount, provenance (ai_draft | human_edited | accepted_ai_draft), demand (search volume and Search Console impressions this term has, if any) and its questionsToAnswer/entities, plus, for APPLIED briefs, appliedDelta (Search Console clicks/impressions/position before and after it was applied). A project may require a human-written outline before a brief can go READY (Project.requireHumanOutline) - check provenance rather than assuming every READY brief was AI-only.
GET/api/spec/projects/{domain}/topicsTopic coverage: accepted topic clusters with their demand-weighted content gap entries.
GET/api/spec/projects/{domain}/keywordsThe keyword map: terms with intent, monthly search volume and the page each ranks with. mapped=false returns unmapped opportunities (demand with no ranking page). Paginated: default 200 rows, pass the returned nextCursor as cursor for the next page.
GET/api/spec/projects/{domain}/consolidated-auditThe latest human-approved consolidated audit (WebSite Auditor report reconciled against the crawl, frozen on approval). 404 until one exists.
PATCH/api/spec/projects/{domain}/briefs/{briefId}Report that a READY content brief was actually published on the site: flips it to APPLIED and closes its recommendation card. Accepts an optional appliedVersion (positive integer, defaults to the brief's currentVersion) recording which revision was published. The only write in the Spec API; needs a token with spec:write. Refuses DRAFT briefs (the human review gate) and cannot revert APPLIED.
GET/api/spec/projects/{domain}/page-auditOn-demand audit of one page: indexability, title/meta/H1 checks, content depth, striking-distance queries, open issues. url may be absolute or a bare path.
GET/api/spec/projects/{domain}/cannibalizationPage pairs competing for the same searches, with merge/differentiate verdicts and the contested queries. Computed on demand from Search Console data.
GET/api/spec/projects/{domain}/briefs/{briefId}/prompt-packThe versioned, brand- and stack-agnostic hand-off for a content brief: a generic composer instruction (plus the project's and brief's own preamble, if set), the page's blocks in order with their content inlined, questions to answer, entities to mention, must-fix items and structured data. Pinned to an immutable revision - version defaults to the brief's currentVersion. Pass sinceVersion (lower than version) to also get a patch prompt: only what changed between the two revisions, for a composer that already implemented the earlier one.
POST/api/spec/projects/{domain}/briefs/{briefId}/recheckEnqueue a free, 1-3 page verification crawl of an APPLIED brief's target page, checking whether its must-fix items actually landed. Free, up to 10 times per brief per day; refuses a brief that is not APPLIED. Poll the verdict with get_briefs (Landed / Partially landed / Not landed / Could not check) rather than this call - it only starts the check.

MCP tools

The same 11 operations wrapped as MCP tools an agent calls by name instead of a URL, plus 2 bootstrap tools that need no credential at all: an agent with a fresh install can start a free audit of a site its human owns and poll it to completion before any token exists.

No token
No token. The free door.
Free scan
The free token from a scan answers this in full.
Free scan, capped
Answered, capped: the top 3 fix cards, bodies truncated, evidence omitted. The totals stay truthful.
Workspace
Needs a workspace token.
ToolTierDescription
start_free_auditNo tokenStart a free CrawlSpec audit of a website you own or have permission to audit - no account and no API token. Before calling this you MUST read the exact attestation sentence to the human, word for word, and get an explicit yes; pass that same sentence verbatim as `attestation` (a paraphrase is refused) and set `tosAccepted` only if they also agreed to the Terms at /terms. Never invent the email address - ask for it. Returns a report URL to poll with get_audit_status; the emailed report carries a free API token that unlocks list_projects, get_page_audit and the top fixes from get_recommendations.
get_audit_statusNo tokenPoll a free audit started with start_free_audit: crawl phase, pages fetched, whether the report is ready, and how it failed if it did. Takes the report token (or the whole /scan/<token> URL). Read-only and unauthenticated - the token is the credential.
list_projectsFree scanList every CrawlSpec project with its domain, last Search Console sync date and open issue count.
get_recommendationsFree scan, cappedPrioritized fix cards for a project - technical (template/config/infrastructure fixes) AND content (briefs to implement, cannibalization verdicts, topic opportunities). Default status OPEN.
get_briefsWorkspaceContent briefs with full outline/change-list content. Use status=READY for human-approved briefs only - governance: only READY briefs should be implemented. Each brief also carries currentVersion, appliedVersion, revisionCount, provenance (ai_draft | human_edited | accepted_ai_draft), demand (search volume and Search Console impressions this term has, if any) and its questionsToAnswer/entities, plus, for APPLIED briefs, appliedDelta (Search Console clicks/impressions/position before and after it was applied). A project may require a human-written outline before a brief can go READY (Project.requireHumanOutline) - check provenance rather than assuming every READY brief was AI-only.
get_topicsWorkspaceTopic coverage: accepted topic clusters with their demand-weighted content gap entries.
get_keywordsWorkspaceThe keyword map: terms with intent, monthly search volume and the page each ranks with. mapped=false returns unmapped opportunities (demand with no ranking page). Paginated: default 200 rows, pass the returned nextCursor as cursor for the next page.
get_consolidated_auditWorkspaceThe latest human-approved consolidated audit (WebSite Auditor report reconciled against the crawl, frozen on approval). 404 until one exists.
mark_brief_appliedWorkspaceReport that a READY content brief was actually published on the site: flips it to APPLIED and closes its recommendation card. Accepts an optional appliedVersion (positive integer, defaults to the brief's currentVersion) recording which revision was published. The only write in the Spec API; needs a token with spec:write. Refuses DRAFT briefs (the human review gate) and cannot revert APPLIED.
get_page_auditFree scanOn-demand audit of one page: indexability, title/meta/H1 checks, content depth, striking-distance queries, open issues. url may be absolute or a bare path.
get_cannibalizationWorkspacePage pairs competing for the same searches, with merge/differentiate verdicts and the contested queries. Computed on demand from Search Console data.
get_brief_prompt_packWorkspaceThe versioned, brand- and stack-agnostic hand-off for a content brief: a generic composer instruction (plus the project's and brief's own preamble, if set), the page's blocks in order with their content inlined, questions to answer, entities to mention, must-fix items and structured data. Pinned to an immutable revision - version defaults to the brief's currentVersion. Pass sinceVersion (lower than version) to also get a patch prompt: only what changed between the two revisions, for a composer that already implemented the earlier one.
request_brief_recheckWorkspaceEnqueue a free, 1-3 page verification crawl of an APPLIED brief's target page, checking whether its must-fix items actually landed. Free, up to 10 times per brief per day; refuses a brief that is not APPLIED. Poll the verdict with get_briefs (Landed / Partially landed / Not landed / Could not check) rather than this call - it only starts the check.

Questions on scopes, rate limits, or a project-pinned token - we reply within two business days.

Contact us