MCP Tools
Context Intelligence

check_content_grounding

Run a grounding scan on a document to check its factual claims against the team's context library, sorting each into supported, conflict, or gap. Waits ~20s inline; poll get_grounding_result with the scan_id if it returns running.

Parameters

NameTypeRequiredDefaultDescription
content_idstringNo—Optional. An existing document to scan. Pass it ALONE to scan that document as it currently stands — that is the safe default. Combining it with `content` REPLACES the document's entire body first (see the `content` warning).
contentstringNo—Optional. Markdown to ground. On its own, it is stored as a NEW document and scanned. ⚠️ DANGER — combined with `content_id`, this REPLACES THE ENTIRE BODY of that document, exactly like update_content. It is a whole-document overwrite, never a fragment check. If you want to check one paragraph or section of an existing document, do NOT pass that fragment here with a content_id — you would destroy the rest of the document. Either pass the FULL revised document, or omit `content` entirely and scan the existing item by content_id alone.
titlestringNo—Optional. Only meaningful alongside content. When omitted the name is derived from the first line of the markdown.

Input Schema

{
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "description": "Optional. Only meaningful alongside content. When omitted the name is derived from the first line of the markdown."
    },
    "content": {
      "type": "string",
      "description": "Optional. Markdown to ground. On its own, it is stored as a NEW document and scanned. ⚠️ DANGER — combined with `content_id`, this REPLACES THE ENTIRE BODY of that document, exactly like update_content. It is a whole-document overwrite, never a fragment check. If you want to check one paragraph or section of an existing document, do NOT pass that fragment here with a content_id — you would destroy the rest of the document. Either pass the FULL revised document, or omit `content` entirely and scan the existing item by content_id alone."
    },
    "content_id": {
      "type": "string",
      "format": "uuid",
      "description": "Optional. An existing document to scan. Pass it ALONE to scan that document as it currently stands — that is the safe default. Combining it with `content` REPLACES the document's entire body first (see the `content` warning)."
    }
  }
}

Output Schema

{
  "type": "object",
  "required": [
    "content_id",
    "status",
    "link_url",
    "summary"
  ],
  "properties": {
    "claims": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "refs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "link_url": {
                  "type": "string"
                },
                "context_item_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            },
            "description": "Context items supporting or contradicting this claim."
          },
          "value": {
            "type": [
              "string",
              "null"
            ]
          },
          "bucket": {
            "enum": [
              "supported",
              "conflict",
              "gap"
            ],
            "type": "string"
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "claim_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "claim_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "confidence": {
            "type": [
              "string",
              "null"
            ],
            "description": "Extraction confidence for this claim, as a decimal STRING (e.g. \"0.82\") — matching the shape the context-item claims endpoint returns."
          },
          "finding_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_excerpt": {
            "type": [
              "string",
              "null"
            ],
            "description": "The passage in the document the claim came from."
          }
        }
      },
      "description": "Every factual claim extracted from the document, with its verdict. Creator-only."
    },
    "status": {
      "enum": [
        "running",
        "complete",
        "failed",
        "none"
      ],
      "type": "string",
      "description": "running = poll get_grounding_result with this scan_id, do not re-scan. none = no scan has been run for this content yet."
    },
    "message": {
      "type": "string",
      "description": "Present when the scan is still running, or when details are withheld."
    },
    "scan_id": {
      "type": [
        "string",
        "null"
      ],
      "format": "uuid",
      "description": "The scan run. Null only if no scan has ever run for this content."
    },
    "summary": {
      "type": "object",
      "properties": {
        "gaps": {
          "type": "integer",
          "description": "Claims the library can neither support nor contradict."
        },
        "conflicts": {
          "type": "integer",
          "description": "Claims that contradict the library — the ones to act on first."
        },
        "supported": {
          "type": "integer",
          "description": "Claims the context library backs up."
        },
        "total_claims": {
          "type": "integer"
        },
        "corpus_freshness": {
          "type": [
            "object",
            "null"
          ],
          "description": "What the pre-scan freshness sweep refreshed before grounding. Free; does not count against credits.",
          "additionalProperties": true
        }
      },
      "description": "Claim counts. Present even when details_visible is false."
    },
    "findings": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "conflict or gap."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "description": "pending, acknowledged, dismissed or resolved."
          },
          "subject": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the finding is about."
          },
          "link_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opens the finding."
          },
          "severity": {
            "type": [
              "string",
              "null"
            ]
          },
          "statement": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the document says versus what the library says."
          },
          "finding_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Pass to get_ci_finding / update_ci_finding_status."
          },
          "suggested_fix": {
            "type": [
              "object",
              "null"
            ],
            "description": "The full recommended update, exactly as Marcora stored it — read this to review the exact change before calling apply_grounding_fix. The wording sits under whichever of ai_prompt, new_value, append_value or insert_value the engine wrote.",
            "additionalProperties": true
          },
          "recommendation": {
            "type": [
              "string",
              "null"
            ],
            "description": "What Marcora suggests doing."
          },
          "context_item_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The context item apply_grounding_fix will write to for this finding. null means the fix targets the content document itself rather than a library item."
          },
          "has_suggested_fix": {
            "type": "boolean",
            "description": "True when Marcora has drafted a fix for this finding."
          }
        }
      },
      "description": "Actionable conflicts and gaps. Creator-only."
    },
    "link_url": {
      "type": "string",
      "description": "Opens the document in Marcora with the grounding panel showing."
    },
    "content_id": {
      "type": "string",
      "format": "uuid",
      "description": "The content item that was scanned. In content-submission mode this is the newly created item — keep it for polling and for follow-up calls."
    },
    "corpus_items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "description": "context_item, project_brief or generation."
          },
          "link_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null for corpus entries that are not standalone context items, such as project briefs."
          },
          "context_item_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "null for entries that are not context items, such as project briefs."
          },
          "content_category": {
            "type": [
              "string",
              "null"
            ],
            "description": "company_authoritative, reference_material or unclassified — how authoritative this source is."
          }
        }
      },
      "description": "The context items this scan was actually grounded against, recorded at scan time. Creator-only."
    },
    "excluded_items": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": true
      },
      "description": "Present only when reference material was locked mid-edit and could not be included in the corpus — the grounding is honest but incomplete."
    },
    "details_visible": {
      "type": "boolean",
      "description": "False when the caller is not the content's creator — findings, claims and corpus_items are then omitted."
    }
  },
  "description": "The grounding envelope. check_content_grounding and get_grounding_result return exactly this shape, so one handler works for both."
}

Instructions

When to use: the user wants to know whether a document is accurate and consistent with what their company has already said - "check this against our context", "is this on-message", "fact-check this draft". It is also the natural next step after you draft something for them.

Runs a grounding scan on a document: it extracts the document's factual claims and sorts each one into supported (the context library backs it), conflict (the library says something different), or gap (the library has nothing on it). You get back the claims, the findings, and the context it was checked against.

This closes the loop for agent-driven writing - draft, ground, review, apply, re-ground - without leaving the conversation.

Three entry modes

  • content_id alone - scan a document that already exists in Marcora. The safe default.
  • content alone - hand over markdown; Marcora stores it as a new document and scans it. The new content_id comes back in the response.
  • content_id + content - replaces that document's entire body with the markdown you pass, then re-scans. This is the revise-and-re-ground path.

Passing neither is an error.

:warning: content together with content_id is a whole-document overwrite

It replaces the document's ENTIRE body - identical to update_content.

This is never a "check this section" operation. If a user asks you to ground one paragraph or section of a document that already exists, do not pass that fragment with its content_id. You would replace the whole document with the fragment and destroy the rest of it - silently, with no error and no warning.

  • To check part of an existing document: pass content_id alone and scan the document as it stands.
  • To revise and re-check: pass the full revised document, not a fragment.

Timing - read this before calling

This waits up to about 20 seconds inline. If the scan finishes inside that window you get the full result straight back. Otherwise you get status: "running" with a scan_id.

A fresh scan usually needs 120-150 seconds. When you get running, poll get_grounding_result with that scan_id every 15-30 seconds. Do not call check_content_grounding again - that starts a second, redundant scan.

:warning: Poll by scan_id, never content_id

When polling a running scan, pass the scan_id you were handed. Polling get_grounding_result by content_id returns the document's previous completed scan marked complete - so you would read a stale result and believe the new scan had already finished. Nothing errors; the answer is just quietly the wrong one.

Re-scanning an unchanged document is fast (a few seconds), because unchanged claims are reused.

Requirements

Grounding requires the Command plan with an active subscription and available Studio Credits.

Parameters

Parameter Type Required Description
content_id string (uuid) No* Existing document to scan. Pass it alone to scan the document as it stands - the safe default
content string No* Markdown to ground. Alone, stored as a new document. With content_id, replaces that document's entire body - pass the full document, never a fragment
title string No Only meaningful with content. Omit and the title is taken from the first line

* One of content_id or content is required.

Output

The grounding envelope: content_id, scan_id, status, link_url, summary, findings[], claims[], corpus_items[], details_visible.

Two field-level traps worth knowing:

  • confidence on each claim is a string, e.g. "0.82" - not a number.
  • details_visible: false means you are not the document's creator, so you get counts only rather than claim and finding detail.

Hand the user the link_url - it opens the document with its grounding panel.

Coverage: before you call a gap unsupported

A gap means the check found nothing in the reference library that backs a claim. That only means the claim is unsupported if the check could read the whole library. The response tells you whether it could:

  • coverage_complete (boolean): false means some context items were not read, so a claim reported as a gap may still have support in an unread item. true does not by itself mean every context item was read: excluded_items lists any item the check left out, and it can be present even when coverage_complete is true.
  • coverage_reason (string or null): why coverage is incomplete. null when coverage_complete is true.
    • library_catch_up: some context items have not been prepared for grounding yet, so this check did not use them. Re-run the check to include more of them.
    • library_extraction_failed: some context items could not be prepared, so this check could not use them.
  • excluded_items (array, present only when the check skipped at least one context item): context items skipped because they were being edited while the check ran. Each entry has id, reason (sync_lock) and source (context_item or project_brief). An item's name is never shown to anyone except the person who ran the check; everyone else, including the content's creator, gets ids only. A skipped item can appear even when coverage_complete is true, so check both fields.

Check coverage_complete (and excluded_items) before treating any gap as unsupported. A gap from an incomplete check means "not confirmed by what was checked", not "the reference library has nothing on this".

Errors

  • Provide either 'content_id' or 'content' (400) - neither was supplied.
  • Not a valid UUID (400) - malformed content_id.
  • Content not found (404) - no such document in your team.
  • ci_not_eligible (403) - the team is not on the Command plan, has no active subscription, or is out of Studio Credits.

Example prompts

  • "Ground this draft against our context library"
  • "Does this blog post contradict anything we've published?"
  • "Rewrite the pricing section and re-check it"

Links: present link_url to the user exactly as returned — copy it character for character. Never retype, shorten, or rebuild a link or the IDs inside it.

Scroll to Top