Outputs
Reference for the 8 Outputs MCP tools: list_output_templates, get_story_output, list_story_outputs, add_story_output, regenerate_story_output, request_story_output_claim_check, accept_story_output_draft, discard_story_output_draft.
list_output_templates
List the org's output templates (the article/post shapes an add-an-output picker offers). Deliberately unpaginated -- a newsroom's templates number in the tens. newsdeskId narrows to templates scoped to that desk PLUS every template scoped to no desk at all -- it is the add-an-output picker's own predicate, not strict equality, so a caller wanting only the desk-scoped rows must filter the response itself. type and isActive narrow further. Each row carries newsdeskName alongside the raw newsdeskId -- null for a desk-less template, and also null (rather than a failure) when the credential lacks newsdesk:read.
read-only · idempotent · closed-world
newsdeskIdstring— Narrow to templates scoped to this desk, plus every template scoped to no desktypestring— one ofweb_article,x_post,instagram_post,tiktok_post,facebook_post,linkedin_post,short_form_video— Narrow to one template typeisActiveboolean— Narrow to active (true) or retired (false) templates
get_story_output
Get one of a story's outputs by id, in full -- content, generatedContent, editedContent, candidateContent and previousContent each carry their body (a short-form video's scenes, voice-over lines included, with storyboardDurationMs and storyboardBand giving the total against the template's band). Carries url, a link to the output in the web app, and claimCheck -- whether the article's claims were checked against the story's research: state (none, pending, checking, ready, failed or outdated), openCount (findings still open, which hold back a CMS push), and, once ready, the trace of each claim's verdict and where it is used, the figure findings and any acceptances; candidateClaimCheck is the same for a pending regenerated draft (null with no draft). list_story_outputs is the cheaper call for polling a pending output or seeing what a story has; come here once you need the actual text.
read-only · idempotent · closed-world
storyIdstring(required) — Story identifieroutputIdstring(required) — Story output identifier
list_story_outputs
List a story's outputs, newest request first, each carrying url. content, generatedContent, editedContent, candidateContent and previousContent all have an article's body, featuredImage and images dropped on every row -- an article row keeps headline, standfirst, byline and wordCount, and a post row, which has no body, keeps its whole text; a short-form video row keeps its ordered scenes (kind, durationMs, caption) without the voice-over lines, with storyboardDurationMs and storyboardBand giving the total against the template's band; status, isStale, templateName, contentVersion, cmsPushCount and candidateInstructions stay on every row. This is the call to make while polling a pending output for ready, or to see what a story has; get_story_output is where the body lives.
read-only · idempotent · closed-world
storyIdstring(required) — Story identifier
add_story_output
Ask for a new output -- whatever type its template produces -- on an enriched story from one output template, and know that this is NOT idempotent: a repeat call is not refused, it mints a SECOND output and spends a second capable-model generation on the org's bill. Retrying after a timeout therefore duplicates the output rather than recovering the first one -- read the returned existing list before retrying. Returns immediately with { created, existing }: created is the new row, status "pending" and carrying no content yet, and existing is the story's other outputs in list_story_outputs' body-elided shape (null, not a failure, when the credential lacks story:read). Generation runs out of band and takes tens of seconds -- poll get_story_output with created.id until its status is "ready", then read its content. Refused, each with its own distinct reason, when the story is not enriched, and when the template is inactive. Needs a user credential, so an interactive MCP connection: a static API key authenticates as a service and there is no user to record as the output's creator. Use list_output_templates to find an outputTemplateId.
additive · closed-world
storyIdstring(required) — Story identifieroutputTemplateIdstring(required) — Output template identifier
regenerate_story_output
Queue a fresh draft of an output a story already has, optionally with one-off instructions steering just this run. Retrying is safe and does not buy a second generation: a repeat call while the run is still queued folds into that one run (replacing its instructions), and a call once the run is under way is refused as a conflict, as is a call while a regenerated draft is still waiting for review. Nothing on the output is overwritten by this -- the new draft lands in candidateContent, and content, generatedContent and editedContent stay exactly as they are until somebody resolves it. Generation runs out of band and takes tens of seconds -- poll get_story_output until candidateContent is non-null (status returns to "ready"), read the draft there, then call accept_story_output_draft to keep it or discard_story_output_draft to throw it away. Until one of those two runs, this output cannot be regenerated again. Needs a user credential, so an interactive MCP connection: a static API key authenticates as a service and there is no user to record as having asked for the draft.
additive · idempotent · closed-world
storyIdstring(required) — Story identifieroutputIdstring(required) — Story output identifierinstructionsstring— One-off steering for this run only, e.g. "tighten to 500 words"; never stored on the output or inherited by the next regeneration
request_story_output_claim_check
Queue a check of an output's claims against the story's research: every claim the text relies on is traced to where it is used, and figures and statements the research does not support are flagged. The check runs out of band and takes tens of seconds -- poll get_story_output until claimCheck.state (or candidateClaimCheck.state for subject "candidate") is neither "pending" nor "checking", then read the findings there. Use it when push_article_to_cms is refused with reason outdated or never_checked, then push again (a check that comes back failed does not hold the push back: it goes through, recorded as published unchecked); a refusal with reason open_findings is not cleared by re-checking, it needs a person to accept or fix the findings, so stop and leave it for one. Pass subject "candidate" to check a pending regenerated draft instead of the article. Retrying is safe: a repeat call while a run for the same text is in flight changes nothing. Refused while the output is still generating, for subject "candidate" when no draft is waiting, and when the org's spending cap has stopped paid work. No tool here accepts a finding: that stays with a person. Needs a user credential, so an interactive MCP connection: a static API key authenticates as a service and there is no user to record as having asked for the check.
additive · idempotent · closed-world
storyIdstring(required) — Story identifieroutputIdstring(required) — Story output identifiersubjectstring— Check the pending regenerated draft instead of the article
accept_story_output_draft
Keep the regenerated draft waiting on an output: it becomes the output's content. Nothing here undoes that -- the text it replaces is kept one deep as previousContent, which the next accept overwrites, and any edit on the output is cleared because what it amended is no longer on file. contentVersion advances, so a CMS connection the output was already filed to accepts it again. A repeat call is refused as a conflict once no draft is waiting, which makes retrying after a timeout safe. The draft comes from regenerate_story_output and lands out of band tens of seconds after that call -- poll get_story_output until candidateContent is non-null and read it there before accepting. Needs a user credential, so an interactive MCP connection: a static API key authenticates as a service and there is no user to record as having replaced the output.
destructive · idempotent · closed-world
storyIdstring(required) — Story identifieroutputIdstring(required) — Story output identifier
discard_story_output_draft
Throw away the regenerated draft waiting on an output. The draft is gone for good -- nothing restores it, and only its headline, standfirst, byline and a word count of its body survive, in the audit trail (a post's own audit entry keeps its full text instead, having no headline, standfirst or byline) -- while the output itself, its edit and its contentVersion are untouched, so nothing a CMS push would file changes. A repeat call is refused as a conflict once no draft is waiting, which makes retrying after a timeout safe. The draft comes from regenerate_story_output and lands out of band tens of seconds after that call -- poll get_story_output until candidateContent is non-null and read it there before deciding; discarding is also what frees the output to be regenerated again. Needs a user credential, so an interactive MCP connection: a static API key authenticates as a service and the audit trail would have nobody to name for the deletion.
destructive · idempotent · closed-world
storyIdstring(required) — Story identifieroutputIdstring(required) — Story output identifier