- name
- mcp-patterns
- description
- Use for how to call the DataForSEO MCP server - its tools (api_request, docs_search, docs_index, docs_list_sections), the docs-first cycle, request bodies and the .ai response mode - and to build the right call for an endpoint family without a task skill, such as SERP, Merchant, App Data or Business Data. Not for site audits, content analysis, page parsing, technologies or WHOIS (site-audit).
# DataForSEO through the v3 MCP server
The plugin runs `dataforseo-mcp-server@3`. It exposes **four tools**, not one tool per endpoint. Every DataForSEO endpoint is reached through a single request tool, and the documentation is searchable from the same server.
| Tool | What it does | Cost |
|---|---|---|
| `docs_list_sections` | Lists the 13 documentation sections: SERP, AI Optimization, Keywords Data, Domain Analytics, Labs, OnPage, Backlinks, Content Analysis, Merchant, App Data, Business Data, Databases, Appendix | free |
| `docs_index` | Lists the endpoints of one section (`{section: "SERP API"}`) or of all | free |
| `docs_search` | Returns the documentation page of one endpoint: fields, limits, Pricing link, example (`needCodeExample: true` adds PHP, Node.js, Python, C#) | free, cached 24 hours |
| `api_request` | Sends an authenticated request to the DataForSEO API | **paid** |
Claude Code names each tool with the plugin server prefix, for example `mcp__plugin_dataforseo-dev_dataforseo__api_request`; the rest of this plugin uses the short names `api_request`, `docs_search`, `docs_index` and `docs_list_sections`. The old per-endpoint tools of the v2 server (`dataforseo_labs_google_keyword_ideas`, `backlinks_summary` and the rest) no longer exist; a call to one of them fails with "tool not found".
## The docs-first cycle
Follow it for every endpoint the first time it is used in a session.
1. **Find the endpoint.** Look in [references/endpoint-paths.md](references/endpoint-paths.md) first. If the task is not there, `docs_list_sections()` then `docs_index({section: "<name>"})`.
2. **Read its page.** `docs_search({url: "dataforseo_labs/google/keyword_ideas/live"})`. Add `needCodeExample: true` only when the body shape is unclear. Note the required fields, the limits and the Pricing link. Free.
3. **Agree the budget.** State the calls you plan, with their `limit` and `depth`, and get the user's go-ahead. See the `cost-awareness` skill. No `api_request` before this.
4. **Send the request.** One call, then read `status_code` and `items` before planning the next call.
```
docs_search({url: "serp/google/organic/live/advanced"})
api_request({
method: "POST",
path: "/v3/serp/google/organic/live/advanced",
data: [{"keyword": "best crm software", "location_code": 2840, "language_code": "en", "depth": 10}]
})
```
## Shape of an `api_request`
| Field | Meaning |
|---|---|
| `method` | `POST` for every Live endpoint; `GET` for location, language, model and account lookups |
| `path` | The REST path, starting `/v3/`, without a host and without `.ai` |
| `data` | The body. For a Live endpoint an array with exactly one task object |
| `noAiMode` | `true` returns the full response instead of the trimmed one; default `false` |
| `url` | A full URL instead of `path`; leave it alone unless the user asks |
A Live endpoint takes **one task per request**. To cover many keywords or targets, use the endpoint's own array field (`keywords`, `targets`), not several tasks.
## `.ai` mode and `noAiMode`
By default the server appends `.ai` to the path. DataForSEO then returns a cropped response: the envelope shrinks to `id`, `status_code` and `status_message`; empty, `null` and `false` fields are dropped; floats are rounded to three places; `position` and `xpath` are removed; `monthly_searches` becomes `{"2025-03": 201000, ...}`; and `limit` and `depth` **default to 10** where the endpoint accepts them. It costs the same as the full response.
- Set `limit` or `depth` explicitly whenever you want more than 10 rows.
- The cropped form is documented for Live and Task GET endpoints. If a lookup or an Appendix path is rejected, retry it once with `noAiMode: true`.
- The `cost` field is not in the cropped envelope. To see what a call cost, read the balance before and after (`GET /v3/appendix/user_data` with `noAiMode: true`, free) or send that one call with `noAiMode: true`.
- Use `noAiMode: true` only when a field you need is missing from the cropped answer. It can multiply the context size.
- The server can also trim responses per endpoint through a field-config file (`--configuration`, or the `FIELD_CONFIG_PATH` or `FIELD_CONFIG_JSON` environment variable), keyed by endpoint path such as `/v3/backlinks/summary/live`. It is off in this plugin, except for a built-in trim of the Lighthouse payload.
## Pick the endpoint
The full table with a minimal body per row is [references/endpoint-paths.md](references/endpoint-paths.md). The short version:
| Task | Endpoint family |
|---|---|
| Keyword ideas, volume, difficulty, intent | Labs `keyword_ideas`, `keyword_overview`, `bulk_keyword_difficulty`, `search_intent` |
| What a competitor ranks for, who competes | Labs `ranked_keywords`, `competitors_domain`, `domain_intersection` |
| The live SERP for a keyword | SERP `google/organic/live/advanced` |
| Backlink profile, spam, link gaps | Backlinks `summary`, `referring_domains`, `bulk_spam_score`, `domain_intersection` |
| Page audit, tech stack | OnPage `lighthouse`, `instant_pages`; Domain Analytics `domain_technologies` |
| Web mentions and sentiment | Content Analysis `search`, `summary`, `phrase_trends` |
| Brand visibility in ChatGPT and Google AI | AI Optimization `llm_mentions/*`, `chat_gpt/llm_scraper` (the `ai-optimization` skill) |
| Amazon, app stores, local businesses | Merchant, App Data, Business Data |
## Parameters that appear everywhere
| Parameter | Description |
|---|---|
| `location_code` or `location_name` | One of the two. `2840` is United States. Look codes up with the GET location endpoints |
| `language_code` or `language_name` | `"en"` for English. ChatGPT data in AI Optimization is United States and English only |
| `limit`, `offset` | Rows to return and rows to skip; `limit` is 10 in `.ai` mode unless set, 1000 at most |
| `filters` | `[["field", "operator", value], "and", ["field2", "operator", value2]]` |
| `order_by` | `["field,desc"]`; at most three rules |
| `tag` | Your own label, echoed back in the response `data` |
Filter operators: `=`, `<>`, `>`, `<`, `>=`, `<=`, `like`, `not_like`, `in`, `not_in`, and on some endpoints `regex`, `ilike`, `match`. Field names differ per API; `docs_search({url: "dataforseo_labs/filters"})` and its siblings list them.
## Reading the answer
- `status_code: 20000` is success. `40000` and up is a client error, `50000` and up a server error; `docs_search({url: "appendix/errors"})` has the list.
- The data is in `tasks[].result[]`, usually in an `items` array. In `.ai` mode the envelope is flattened to `id`, `status_code`, `status_message` and `items`.
- An empty `items` array is an answer, not an error: DataForSEO has no data for that query.
- Targets are domains **without** `https://` and `www.`; pages are absolute URLs.
## Cost
Every `api_request` is billed, and the plugin never sends one without an agreed budget. The rules and the free balance check are in the `cost-awareness` skill.
View on GitHub