Skip to main content
Glama
CrawlForge MCP Server

CrawlForge MCP Server

serp_rank

Read-onlyIdempotent

Use this to check where a domain ranks in Google's ORGANIC results for a keyword - real SERP position, not search_web's order. Returns the target's organic rank, the ranking URL, and every position it holds.

Instructions

Use this to check where a domain ranks in Google's ORGANIC results for a keyword - real SERP position, not search_web's order. Returns the target's organic rank, the ranking URL, and every position it holds. Not for general search (search_web). One lookup is one sample: Google can return a different result set for the same query minutes apart (seResultsCount tells them apart), and sometimes a decoy page of unrelated results (suspect:true), so compare several before reading a rank change. Requires DataForSEO credentials and returns configured:false without them - do not retry in that case. Cost: 5 credits (0 when unconfigured). Example: serp_rank({keyword: "managed wordpress hosting", target: "dashboardhosting.com", location_name: "United States"})

Input Schema

NameRequiredDescriptionDefault
depthNoHow many results to scan, 10-200 (default 30; DataForSEO bills ~$0.002 per 10 and gets slower the deeper it goes)
deviceNoDevice to emulate
targetYesDomain or URL to locate in the results (e.g. 'example.com'). Matched by host, not exact URL: any page on that host or its subdomains counts
keywordYesThe search query to check ranking for
language_codeNoLanguage code (e.g. 'en')
location_codeNoNumeric DataForSEO location code (overrides location_name)
location_nameNoLocation, e.g. 'United States' or 'London,England,United Kingdom'

Output Schema

NameRequiredDescriptionDefault
urlNoURL of the target's best-ranking result
costNoUSD charged by DataForSEO for this lookup (separate from CrawlForge credits)
noteNoPresent when configured=false, explains how to enable
_costNoCost-transparency metadata (D3.5): what this call was projected to cost and what it was charged
cacheNoPage cache: whether this call reused a copy of the page fetched earlier in the session
foundNoWhether the target appeared anywhere in the scanned SERP
titleNo
deviceNo
targetNoHost the SERP was matched against: a URL target is reduced to its host, and any page on it or its subdomains counts
keywordNo
resultsNoTop organic competitors as Google actually ranks them (capped)
checkUrlNoLink to view the real SERP on DataForSEO
locationNo
positionNoBest (lowest) organic rank; null = not within top `depth`
checkedAtNo
next_stepNoFailed calls only: the tool or fix to try next
configuredNoFalse when DATAFORSEO_LOGIN/PASSWORD are unset — no rank was fabricated
allPositionsNoEvery position the target holds on this SERP
depthScannedNo
rankAbsoluteNo
organicResultsNo
seResultsCountNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv6.24.0
    • changedOutput schema / properties / _cost / description
      Previous value: -"Cost-transparency metadata (D3.5), present when injected into the text copy of the result"New value: +"Cost-transparency metadata (D3.5): what this call was projected to cost and what it was charged"
    • changedOutput schema / properties / _cost / properties / actual / description
      Previous value: -"Credits actually charged (0 in creator mode, half-rate on error)"New value: +"Credits actually charged (0 in creator mode, and 0 for a failed call)"
    • addedOutput schema / properties / cache
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Page cache: whether this call reused a copy of the page fetched earlier in the session",
      +  "properties": {
      +    "ageMs": {
      +      "description": "Age of that copy in ms",
      +      "type": [
      +        "number",
      +        "null"
      +      ]
      +    },
      +    "fetchedAt": {
      +      "description": "When the oldest page used was fetched (ISO 8601)",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "note": {
      +      "description": "Hits only: how old the copy is and how to force a fresh fetch",
      +      "type": "string"
      +    },
      +    "state": {
      +      "description": "hit: every page came from this session's copy; bypass: fetched fresh on request (maxAge 0) or not cacheable; miss: fetched",
      +      "enum": [
      +        "hit",
      +        "miss",
      +        "bypass"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / next_step
      Added value: +{
      +  "description": "Failed calls only: the tool or fix to try next",
      +  "type": "string"
      +}
  2. Changed3 schema fields changedv6.19.2
    • changedInput schema / properties / depth / description
      Previous value: -"How many results to scan, 10-200 (default 20; DataForSEO bills ~$0.002 per 10 and gets slower the deeper it goes)"New value: +"How many results to scan, 10-200 (default 30; DataForSEO bills ~$0.002 per 10 and gets slower the deeper it goes)"
    • changedInput schema / properties / target / description
      Previous value: -"Domain or URL to locate in the results (e.g. 'example.com')"New value: +"Domain or URL to locate in the results (e.g. 'example.com'). Matched by host, not exact URL: any page on that host or its subdomains counts"
    • changedOutput schema / properties / target / description
      Previous value: -"Bare target domain, normalized"New value: +"Host the SERP was matched against: a URL target is reduced to its host, and any page on it or its subdomains counts"
  3. Changed7 schema fields changedv6.0.0
    • removedInput schema / additionalProperties
      Removed value: -false
    • changedOutput schema / properties / _cost / additionalProperties
      Previous value: -trueNew value: +{}
    • changedOutput schema / properties / allPositions / items / additionalProperties
      Previous value: -trueNew value: +{}
    • removedOutput schema / properties / results / items / $ref
      Removed value: -"#/properties/allPositions/items"
    • addedOutput schema / properties / results / items / additionalProperties
      Added value: +{}
    • addedOutput schema / properties / results / items / properties
      Added value: +{
      +  "domain": {
      +    "type": "string"
      +  },
      +  "position": {
      +    "type": [
      +      "number",
      +      "null"
      +    ]
      +  },
      +  "rankAbsolute": {
      +    "type": [
      +      "number",
      +      "null"
      +    ]
      +  },
      +  "snippet": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "title": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "url": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  }
      +}
    • addedOutput schema / properties / results / items / type
      Added value: +"object"
  4. Changed1 schema field changedv5.0.5
    • changedInput schema / properties / depth / description
      Previous value: -"How many results to scan, 10-200 (100 = 1 page of cost)"New value: +"How many results to scan, 10-200 (default 20; DataForSEO bills ~$0.002 per 10 and gets slower the deeper it goes)"
  5. Changed2 schema fields changedv5.0.4
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "https://json-schema.org/draft/2020-12/schema",
      +  "additionalProperties": false,
      +  "properties": {
      +    "_cost": {
      +      "additionalProperties": true,
      +      "description": "Cost-transparency metadata (D3.5), present when injected into the text copy of the result",
      +      "properties": {
      +        "actual": {
      +          "description": "Credits actually charged (0 in creator mode, half-rate on error)",
      +          "type": "number"
      +        },
      +        "projected": {
      +          "description": "Credits projected for this call before execution",
      +          "type": "number"
      +        },
      +        "projection_note": {
      +          "description": "Human-readable note about how the cost was projected",
      +          "type": "string"
      +        },
      +        "remaining_credits": {
      +          "description": "Credits remaining on the account after this call, if known",
      +          "type": [
      +            "number",
      +            "null"
      +          ]
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "allPositions": {
      +      "description": "Every position the target holds on this SERP",
      +      "items": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "domain": {
      +            "type": "string"
      +          },
      +          "position": {
      +            "type": [
      +              "number",
      +              "null"
      +            ]
      +          },
      +          "rankAbsolute": {
      +            "type": [
      +              "number",
      +              "null"
      +            ]
      +          },
      +          "snippet": {
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          },
      +          "title": {
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          },
      +          "url": {
      +            "type": [
      +              "string",
      +              "null"
      +            ]
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "checkUrl": {
      +      "description": "Link to view the real SERP on DataForSEO",
      +      "type": "string"
      +    },
      +    "checkedAt": {
      +      "type": "string"
      +    },
      +    "configured": {
      +      "description": "False when DATAFORSEO_LOGIN/PASSWORD are unset — no rank was fabricated",
      +      "type": "boolean"
      +    },
      +    "cost": {
      +      "description": "USD charged by DataForSEO for this lookup (separate from CrawlForge credits)",
      +      "type": "number"
      +    },
      +    "depthScanned": {
      +      "type": "number"
      +    },
      +    "device": {
      +      "type": "string"
      +    },
      +    "found": {
      +      "description": "Whether the target appeared anywhere in the scanned SERP",
      +      "type": "boolean"
      +    },
      +    "keyword": {
      +      "type": "string"
      +    },
      +    "location": {},
      +    "note": {
      +      "description": "Present when configured=false, explains how to enable",
      +      "type": "string"
      +    },
      +    "organicResults": {
      +      "type": "number"
      +    },
      +    "position": {
      +      "description": "Best (lowest) organic rank; null = not within top `depth`",
      +      "type": [
      +        "number",
      +        "null"
      +      ]
      +    },
      +    "rankAbsolute": {
      +      "type": [
      +        "number",
      +        "null"
      +      ]
      +    },
      +    "results": {
      +      "description": "Top organic competitors as Google actually ranks them (capped)",
      +      "items": {
      +        "$ref": "#/properties/allPositions/items"
      +      },
      +      "type": "array"
      +    },
      +    "seResultsCount": {
      +      "type": "number"
      +    },
      +    "target": {
      +      "description": "Bare target domain, normalized",
      +      "type": "string"
      +    },
      +    "title": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "url": {
      +      "description": "URL of the target's best-ranking result",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    }
      +  },
      +  "type": "object"
      +}
  6. First observedv4.10.0

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover safety (readOnly, idempotent, openWorld, non-destructive), but the description adds critical operational context: requires DataForSEO credentials, returns configured:false without them (do not retry), costs 5 credits (0 when unconfigured), and explains sampling variability and decoy results (suspect:true). This goes well beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, followed by concise operational caveats, and ends with a compact example. Every sentence (purpose, sibling distinction, sampling caveat, auth/cost, example) contributes necessary information without waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not detail return values, yet it still names the key outputs (organic rank, ranking URL, every position). Combined with annotations and full schema coverage, the description supplies all missing operational context for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, documenting all seven parameters. The description adds an example using keyword, target, and location_name, but provides no additional syntax or format details beyond what the schema already supplies. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: 'check where a domain ranks in Google's ORGANIC results for a keyword', and explicitly distinguishes from search_web's order. An agent can identify it as a rank-checking tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use (rank checking) and when not ('Not for general search (search_web)'), and advises comparing several samples before reading a rank change. Alternatives are named, leaving no inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.