ProRank SEO

AI Discovery & AI Endpoints

Operator reference for the three endpoints ProRank SEO exposes for AI clients: /schema-map, /ask, and /mcp.

Overview

AI Discovery is the operator-facing surface built on ProRank's Schema Aggregation system. It exposes three related endpoints that all share a single on/off gate:

  • /wp-json/prorank-seo/v1/schema-map — site-wide structured graph (GET).
  • /wp-json/prorank-seo/v1/ask — NLWeb list-mode query endpoint (POST).
  • /wp-json/prorank-seo/v1/mcp — MCP-compatible agent endpoint over the same underlying data (POST, JSON-RPC 2.0).
All three endpoints close together when the gate is off — they return HTTP 404. There is no way to serve one and close the others.

Free installs ship the three endpoints and the gate, but not an admin UI. The gate is controlled by the prorank_schema_map_enabled option (default on) and the prorank_schema_map_endpoint_enabled filter. Pro and above adds an admin panel under Technical SEO → AI Discovery with a toggle, endpoint URLs, cache status, and a Rebuild / Flush Cache button.

/schema-map — site-wide graph

Returns a deduplicated JSON-LD @graph containing your site identity (Organization / Person), every indexable post, and connected premium entities (LocalBusiness, Product, FAQPage, HowTo). Entities use stable @id values so content nodes reference Person / Organization / WebPage nodes by ID instead of duplicating them.

Method: GET. Pagination: ?page=N&per_page=M. Caching: results are cached and auto-invalidate on post saves, schema-meta writes, site-basics updates, and premium source changes.

fetch the graphbash
curl "https://example.com/wp-json/prorank-seo/v1/schema-map?page=1&per_page=25"

On Pro and above, the AI Discovery admin panel has a Rebuild / Flush Cache button to force a fresh graph before the next AI crawl. Free installs flush by bumping the cache version directly: run do_action('prorank_schema_map_flush') from a WP-CLI one-liner, or let the cache invalidate on the next post/schema write.

/ask — NLWeb-compatible query endpoint

Accepts a natural-language query and returns the top ranked Schema.org items from the same graph. The response is the raw NLWeb envelope — no {success, data} wrapper — with query_id and a results array of {url, name, site, score, description, schema_object}.

Method: POST. Required field: query. Optional: limit (1–50), query_id, site, prev, decontextualized_query.

Modes by edition. Free installs expose mode=list only. Pro and above additionally expose mode=summarize and mode=generate (both authenticated, BYOK). The route's mode enum is advertised dynamically — free sites omit the LLM modes from the enum so WP's REST validator rejects them at the wire with a 400 rest_invalid_param.
minimal list-mode querybash
curl -X POST "https://example.com/wp-json/prorank-seo/v1/ask" \
  -H "Content-Type: application/json" \
  -d '{"query":"local seo","limit":5}'

mode=summarize (Pro+, authenticated, BYOK)

Pro and above only. Adds an LLM-generated summary string at the top of the envelope, alongside the same results array list mode returns. The summary is written by whatever AI provider the site has configured under AI Tools — your own OpenAI, Anthropic, Gemini, or DeepSeek key (BYOK). We never proxy the call. On free installs, the route does not advertise summarize and WP rejects it at arg validation.

Auth required. Send a WordPress application password as HTTP Basic auth. Unauthenticated requests return HTTP 401 with a structured auth_required error.

summarize with app-password authbash
curl -X POST "https://example.com/wp-json/prorank-seo/v1/ask" \
  -u "admin:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{"query":"opening hours","mode":"summarize","limit":5}'

Response shape (summarize):

/ask summarize envelopejson
{
  "query_id": "…",
  "query": "opening hours",
  "mode": "summarize",
  "site": "example.com",
  "results": [ … same items as list mode … ],
  "total": 5,
  "summary": "A 2–4 sentence answer grounded in the items above.",
  "usage": { "provider": "openai", "model": "gpt-…", "cached": false }
}
Because summarize is BYOK, each request burns the site owner's provider credits. That is why it requires authentication — an unauthenticated public summarize endpoint would let any caller drain the owner's account.

mode=generate (Pro+, authenticated, BYOK)

Pro and above only. Returns a grounded natural-language answer plus a citations array alongside the same results every mode returns. The model is prompted to cite supporting items with bracket markers like [1] or [1,3], which map 1:1 to entries in the citations array (index N ↔ results[N-1]). On free installs, the route does not advertise generate and WP rejects it at arg validation.

Auth required. Same rule as summarize: WordPress application password on the request for a user with edit_posts capability. Unauthenticated → HTTP 401 auth_required.

generate with app-password authbash
curl -X POST "https://example.com/wp-json/prorank-seo/v1/ask" \
  -u "admin:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{"query":"opening hours","mode":"generate","limit":5}'

Response shape (generate):

/ask generate envelopejson
{
  "query_id": "…",
  "query": "opening hours",
  "mode": "generate",
  "site": "example.com",
  "results": [ … same items list mode returns … ],
  "total": 5,
  "answer": "Hours are listed on the contact page [1]. Some locations offer evening pickup [2,3].",
  "citations": [
    { "index": 1, "url": "https://example.com/contact", "name": "Contact" },
    { "index": 2, "url": "https://example.com/locations/downtown", "name": "Downtown" },
    { "index": 3, "url": "https://example.com/locations/north", "name": "North" }
  ],
  "usage": { "provider": "openai", "model": "gpt-…", "cached": false }
}
Generate is BYOK. Each request burns the site owner's provider credits, the same budget summarize uses. Citations come from the ranked results only — the model is explicitly instructed to say "no" rather than invent external sources when the items don't support an answer.

/mcp — MCP-compatible agent endpoint

JSON-RPC 2.0 endpoint implementing the core Model Context Protocol methods. Compatible MCP clients can connect and call tools against the same data /ask serves.

Method: POST. Wire format: JSON-RPC 2.0 request / response. Supported methods: initialize, notifications/initialized, tools/list, tools/call, prompts/list, prompts/get, notifications/cancelled, ping. Both underscore (list_tools) and slash (tools/list) method names are accepted.

Tools exposed:

  • ask — list-mode query against the schema-map data. Same underlying ranking as /ask.
  • list_sites — returns the site token(s) this endpoint answers for (one entry on single-site WordPress installs).
list available toolsbash
curl -X POST "https://example.com/wp-json/prorank-seo/v1/mcp" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
call the ask toolbash
curl -X POST "https://example.com/wp-json/prorank-seo/v1/mcp" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":2,
    "method":"tools/call",
    "params":{"name":"ask","arguments":{"query":"local seo","limit":5}}
  }'

The ask tool returns an MCP content block containing the same NLWeb envelope /ask returns, encoded as a JSON string in a text block:

tools/call response shapejson
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"query_id\":\"...\",\"query\":\"local seo\",\"mode\":\"list\",\"site\":\"example.com\",\"results\":[...],\"total\":5}"
      }
    ]
  }
}

summarize over /mcp (Pro+, authenticated)

Pro and above only. Call the ask tool with arguments.mode = "summarize". The call must carry a WordPress application password (same Basic auth as the REST path). Unauthenticated summarize calls return a JSON-RPC error, not a content-block success envelope — so MCP clients see a transport-level auth failure. On free installs, the ask tool's tools/list schema does not advertise summarize and calls with mode="summarize" return a JSON-RPC -32602 with available_modes: ["list"].

summarize via /mcpbash
curl -X POST "https://example.com/wp-json/prorank-seo/v1/mcp" \
  -u "admin:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":3,
    "method":"tools/call",
    "params":{"name":"ask","arguments":{"query":"opening hours","mode":"summarize","limit":5}}
  }'
unauthenticated summarize via /mcpjson
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32001,
    "message": "Authentication required for mode \"summarize\". …",
    "data": { "auth_methods": ["wordpress_application_password"], "mode": "summarize" }
  }
}

Pro and above: mode=generate works identically to summarize — same auth requirement, same response shape as /ask?mode=generate, delivered through an MCP content block carrying the envelope JSON. Unauthenticated generate calls return the same JSON-RPC -32001 error summarize uses. On free installs, generate is similarly absent from tools/list and calls with mode="generate" return -32602.

/mcp interoperability depends on the client. We implement the MCP core methods and JSON-RPC 2.0 transport, plus list / summarize / generate on the ask tool. Clients that stick to that surface work. Clients that assume streaming or server-side conversation state will see unsupported_mode or method-level errors — this is MCP-compatible, not full NLWeb / MCP parity.

Shared availability & gating

All three endpoints evaluate the same gate on every request. When any layer of the gate is off, the endpoint returns HTTP 404 with a raw {code: "schema_map_disabled", message: "..."} body.

The gate has three layers, checked in order. All three layers ship on every edition of the plugin:

  1. Module active. The Schema module must be loaded by the plugin. Free and Pro+ both load it by default.
  2. Operator option. The prorank_schema_map_enabled option must be on. Default is on when the option is absent. On Pro and above, the AI Discovery admin panel toggle writes this option directly. On free, set it through WP-CLI (wp option update prorank_schema_map_enabled 0) or any other option-writing path.
  3. Site code filter. The prorank_schema_map_endpoint_enabled filter must not return false. This filter is off-only — a true return has no effect when the module or option is already off.

On Pro and above, when the gate is closed the admin panel surfaces the specific layer (module_inactive, option_disabled, or filter_override) so an operator can tell which one to fix. On free, the same three states are observable programmatically via SchemaMapGate::reason_when_disabled().

Current limitations

  • Modes by edition. Free exposes list only. Pro and above additionally expose summarize and generate (both authenticated, BYOK). The route enum on /ask and the tools/list schema on /mcp reflect this — free installs never advertise the LLM modes.
  • BYOK only for the LLM modes. Summarize and generate use whatever AI provider is configured under AI Tools on the site. We never proxy LLM calls through our infrastructure.
  • Auth for summarize and generate is WordPress application passwords for a user with edit_posts. Dedicated ProRank API keys are not implemented yet.
  • No streaming / SSE. Both endpoints always return a single JSON body.
  • No server-side conversation state. prev and decontextualized_query on /ask are accepted but ignored.
  • /mcp compatibility depends on the client. We support MCP core methods over JSON-RPC 2.0, not full MCP or NLWeb parity.
Further scope (streaming, dedicated API keys, a managed-proxy LLM tier) would require product decisions that haven't been made yet.

Example requests

Replace example.com with your site host.

/schema-map

curl "https://example.com/wp-json/prorank-seo/v1/schema-map?page=1&per_page=25"

/ask

curl -X POST "https://example.com/wp-json/prorank-seo/v1/ask" \
  -H "Content-Type: application/json" \
  -d '{"query":"opening hours","limit":5}'

/mcp initialize

curl -X POST "https://example.com/wp-json/prorank-seo/v1/mcp" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"clientInfo":{"name":"my-agent","version":"1.0"}}}'

/mcp tools/call

curl -X POST "https://example.com/wp-json/prorank-seo/v1/mcp" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":2,
    "method":"tools/call",
    "params":{"name":"ask","arguments":{"query":"opening hours","limit":5}}
  }'

Gate closed — any endpoint

HTTP 404 bodyjson
{
  "code": "schema_map_disabled",
  "message": "Schema aggregation is disabled on this site."
}