Protocol

Response Format

Every successful tools/call returns a standard MCP CallToolResult wrapped in a JSON-RPC 2.0 envelope. The structure is identical across all 41 tools; only the payload inside the single text block changes.

Envelope

200 OK
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      { "type": "text", "text": "<JSON.stringify(payload)>" }
    ],
    "isError": false,
    "_meta": {
      "precursor": {
        "request_id": "8b16efb8-9a6c-4ace-b817-11cbee626d08",
        "tool_name": "get_cve",
        "generated_at": "2026-05-18T10:24:31.118Z",
        "credits": { "charged": 1, "remaining": 9998, "refunded": false },
        "response_truncated": false
      }
    }
  }
}

content

Always a single text block. The text value is the JSON-serialised payload from the tool. Clients must JSON.parse(result.content[0].text) to get structured data.

This double-encoding is intentional and matches the MCP spec: the content array carries opaque chunks that the LLM can read, and our chunk is a JSON string that an agent can parse if it needs structured access.

If the serialised payload exceeds 1 MiB, the text is truncated with the literal suffix "...[truncated]" and _meta.precursor.response_truncated is set to true. No pagination cursor is returned, so tighten your query.

isError

  • false: the tool succeeded.
  • true: the underlying query errored or timed out. The content[0].text will be a short JSON string like {"error":"rpc_error"} or {"error":"rpc_timeout"}. The credit is refunded automatically and _meta.precursor.credits.refunded is set to true.

Note: isError: true is not the same as a JSON-RPC error object. JSON-RPC errors (auth failures, validation, unknown tool) appear in the top-level error field and never include a result. See Errors.

_meta.precursor

A Precursor Intelligence-specific block carrying request bookkeeping. Safe to ignore, but useful for telemetry and budgeting.

request_idstringoptional

UUID for this request. Echoed in the x-request-id HTTP header. Quote this in support tickets.

tool_namestringoptional

The tool that produced this response. Matches the name argument sent in tools/call.

generated_atstringoptional

ISO-8601 timestamp the response was packed. UTC.

creditsobjectoptional

{ charged: 0 | 1, remaining: int | null, refunded: boolean }. charged is 1 for paid tools, 0 for account_status and free methods. refunded is true only when an error or timeout caused the charge to be reversed.

response_truncatedbooleanoptional

true when the payload was clipped at the 1 MiB cap.

Payload shapes

The text payload comes in one of three shapes, depending on the tool:

1. jsonb (single JSON object, most tools)

The RPC returns a JSON object directly. Whatever it produced is the payload.

Example: get_cve payload
{
  "cve_id": "CVE-2024-3094",
  "description": "Malicious code was discovered in xz tarballs…",
  "cvss": { "v3": 10.0, "severity": "CRITICAL" },
  "epss": { "score": 0.94, "percentile": 0.998 },
  "kev": true
}

2. array-rows (row list)

Used by: search_cves_by_vendor, search_products, search_iocs, search_malware_samples, list_recent_malware_samples.

Example: array-rows shape
{
  "count": 23,
  "items": [ { "cve_id": "CVE-2024-3094" }, { "cve_id": "CVE-2021-44228" } ],
  "generated_at": "2026-05-18T10:24:31.118Z"
}

count is the length of items, not a total-result count.

3. tactics-row (special case for list_mitre_tactics)

Example: tactics-row shape
{
  "tactics_data": [ { "tactic_id": "TA0001", "name": "Initial Access", "technique_count": 9 } ],
  "statistics": { "total_tactics": 14, "total_techniques": 193 },
  "generated_at": "2026-05-18T10:24:31.118Z"
}

Each tool page in the reference declares which shape it returns under the Response shape heading.

Notifications

For notifications/initialized and any other notifications/* method, the server returns HTTP 202 with an empty body (there is no JSON-RPC response object, per the JSON-RPC 2.0 spec). Most clients send this automatically after initialize.