marcora-mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited marcora-mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The companion skill to the Marcora MCP server.
You are connected to Marcora, a product-marketing context platform for go-to-market teams. Marcora stores brand and product context, generates marketing content with AI, and organizes work into projects. This skill teaches you the object model, the workflow patterns, and the gotchas. The MCP tool definitions already document each tool's parameters and outputs — don't restate them. This skill covers everything the tool schemas can't: which tool to reach for, in what order, with what user intent, and what to do when things look ambiguous.
Mindset: Marcora is a context-first platform. Every piece of content draws on layered context (Brand Foundation → Reference Library → Project Context → per-generation collections). Your job before generating anything is to (1) understand what the user wants, (2) confirm the right context will be in scope, (3) state your plan in one sentence, (4) call the tool. Never silently guess between two tools that look similar — confirm.
Apply this skill when the user's request involves Marcora: one of its tools, one of its objects, or a marcora.ai link. You may already have relevant context in your awareness — a list of blueprints the user mentioned earlier, a project they're currently working on, content they just generated. Use what you already have; only call discovery tools (marcora:list_*) to fill genuine gaps. Don't re-list what you already know.
If the user says not to use Marcora for a task, don't call any marcora:* tool.
If the user hands you a Marcora URL, the UUID in the path is the object id — use it directly; don't web_browse the page (the marcora.ai domain means this is Marcora-tool territory).
app.marcora.ai/library/<uuid> and app.marcora.ai/canvas/<uuid> are the same Content document (saved view vs. editor view) → get_content(content_id=<uuid>) to read it, update_content(content_id=<uuid>, …) to revise it.app.marcora.ai/project/<uuid> → get_project.(A `/canvas/<uuid>` link is occasionally a blueprint draft rather than a finished document — only matters if `get_content` comes back empty.)
The Marcora MCP server is hosted; the user's MCP client connects directly. You do nothing for setup. Every tool call runs as the authenticated user against their active team — auth is implicit. If a call returns an auth error, tell the user to reconnect in Marcora's integration settings; don't try to recover.
These are Marcora's core nouns. Internalize them before calling any tool.
marcora:create_content. Two ways to create one with the same tool. The default: you write the piece yourself from the team's context (get_relevant_context) and pass content only, which saves your text verbatim. The alternative is Marcora's own writer: pass instructions (Quick by default: one model, sync, about 45 s to 3½ min; generation_mode: "multi_model" writes two drafts and a synthesis, async, 3–5 min), or instructions + blueprint_uuid for blueprint-driven generation (Multi-model by default, async, 3–5 min, returns a generation_id to poll). Use instructions only when the user asks Marcora to write it, a Blueprint is used, or a plan is being fulfilled.A document's title comes from its first heading — there is no title parameter. On the content path, start the markdown with # <Title> on the first line. On the instructions path, state the wanted title inside the instructions text. Never send content and instructions together (that is rejected), not even to carry a title. The title keeps following the first heading unless someone locks it with update_content name_override.
owner / editor / viewer) and a separate Collaborator role for project-only stakeholders.create_project — project_brief_instructions (Marcora writes the brief from your prompt) or project_brief_content (your finished text, saved as-is) — or on an existing project via update_project(project_brief_id=<content uuid>). The latter handles attachment automatically: if the content isn't yet in the project, the tool attaches it AND sets it as the brief in one call.add_context with no project_id. Filtered by relevancy at generation time.add_context with project_id. Always pulled in for that project's generations.collection_ids or dimension_option_ids on create_content. Not persisted as reusable context.marcora:get_brand_foundation. Always pulled into every content generation. You don't need to read it manually before generating.dimension_option_ids to shape generation for an audience.create_workflow, update_workflow, run_workflow, get_workflow, list_workflows, get_workflow_runs). See the Workflows chapter below for the output-destination, scheduling, and dedup patterns.create_plan, produced into a real Content document by produce_plan. Private to its creator by default. See the Content Plans & Playbooks chapter.instantiate_playbook, optionally anchored to a date. Team-visible by default. See the Content Plans & Playbooks chapter.project_id) and may be generated from a Blueprint (blueprint_uuid).project_brief block instead.in_progress (being generated or edited) → ready (final).pending → gathering context → processing → completed (or failed). Poll marcora:get_generation_status until completed.active or archived. Project visibility: team or private.When marcora:create_content runs inside a project, Marcora automatically layers (these are the in-app labels — quote them when explaining context):
collection_ids. A project can have default collections.Outside a project, only layers 1, 2, and 4 apply.
Implication: don't repeat brand voice in your prompt (Layer 1 has it). Don't re-explain a project's strategic angle (Layer 3 has the brief). Your prompt's job is the one-off signal for this document — through dimension_option_ids (audience) or one-time collection_ids.
The five workflows you'll handle 80% of the time. Two more surfaces — Workflows and Content Plans & Playbooks — have their own chapters below. Long-tail recipes (community-blueprint imports, exports, sharing, project rename/archive) live in references/workflows.md.
Goal. Produce a piece of content for the user, optionally inside a project, optionally targeting an audience.
The default: you write it. When the user asks you to write, draft or create something (and, optionally, to save it to Marcora), write it yourself from the team's context, then save it with content. Marcora's own writer (instructions) is for three cases only: (a) the user asks Marcora to write or generate it, (b) a Blueprint is used (the user names one or asks for a template), or (c) a plan is being fulfilled. Do not go looking for a blueprint on every request, and do not hand a plain "write X" to the generator.
Preconditions. None hard-required. If the user mentioned an initiative and you don't already know the project, fetch it first.
Steps — you write it (the default).
marcora:list_projects. If they want the piece scoped to it, keep the project_id.marcora:get_relevant_context with a prompt describing the piece and include_brand_foundation: true on the first call of the conversation. Pass project_id when the piece belongs to a project (the first call returns the project's brief — read it; your draft must not contradict it). One response gives you Reference Library chunks and the team's Brand Foundation (company overview, brand voice, writing style, writing examples).marcora:get_content (find them with list_content) and write from them.marcora:create_content with content only. Start content with # <Title> on the first line; add project_id and category_id where relevant. content cannot be combined with instructions or blueprint_uuid, and reference_content_ids is rejected with it.Steps — Marcora writes it (the user asks Marcora to write it, a Blueprint is used, or a plan is being fulfilled).
marcora:list_blueprints (returns your published blueprints under a blueprints array) and propose a fitting one.marcora:list_community_blueprints (the Blueprint Exchange). If something there fits, propose it: "I don't see a matching template in your library, but '\[name]' on the Blueprint Exchange looks like a fit — want me to import it?" If they say yes: marcora:get_community_blueprint_details to confirm fit → marcora:import_community_blueprint → use the returned UUID as the blueprint_uuid in step 4.marcora:list_projects. If the user mentioned an initiative, propose scoping to it.marcora:list_targeting_dimensions. Pick option IDs.generation_mode: "multi_model") is async and takes 3–5 min. Quick costs 1–2 Studio Credits, Multi-model 6–7.marcora:create_content with instructions + blueprint_uuid (if blueprint) + project_id + dimension_option_ids + optional collection_ids for one-off context. Do not pre-fetch context with get_relevant_context — the instructions path pulls all relevant context internally, including the project's brief when project_id is set. (This holds only when Marcora writes via instructions; when you draft the content yourself you DO fetch context first — see "Writing the content yourself?" in Workflow 5 and the pitfall below.)generation_id): poll marcora:get_generation_status every ~30s, surface progress to the user every minute. When status == completed, the response includes content.link_url.Validation. Before saving, sanity-check that content is not combined with blueprint_uuid or instructions (mutually exclusive — pick one mode).
Output to user. "Done — your case study is ready: [link]. Want me to share it externally, export to Word, or refine?"
Narrow exception to "don't pre-fetch context" (Marcora-writes path only). If the user asks Marcora to write about something narrow and specific that probably isn't in the standard Reference Library (a particular customer name, a specific incident, a niche internal initiative), one targeted marcora:get_relevant_context call up front is reasonable — purely so you can ask "I don't see source material on X yet — want to add some before I generate?" Skip the pre-check for broad topics (brand voice, common positioning, generic blog ideas). The model pulls what it needs at generation time.
Goal. Make a specific Content item the strategic anchor of a project.
Preconditions. A project (you have the project_id) and a Content item (you have its UUID). Both must exist; the user must have editor or owner access to the team.
Steps.
marcora:list_projects to resolve it from the name.marcora:list_content and disambiguate with the user.marcora:update_project(project_id, project_brief_id=<content_uuid>). The tool handles BOTH cases automatically: if the content is already in the project's documents → pins it as the brief; if not → attaches it AND sets it as the brief in one call.Validation. None required after the call — the tool returns success: true with the updated project record.
Output to user. "Brief set: [project link]."
To edit the brief (not change which doc IS the brief): use update_content on the brief's content_id. Discover it via get_project(project_id).project_brief.content_id (project_brief is null when the project has no brief) or, when the user just created the project, take it directly from the create_project response. Read the current brief before you rewrite it — get_content(content_id) for the full body — because update_content replaces the body in full.
Pitfalls — this is the founding misfire that motivated this skill:
get_content and re-create it via create_content(project_id=...) to "put it in the project." That creates a duplicate with a fresh UUID, orphaned from the original. Attachment is a relationship, not a copy. update_project handles it.get_project first to check if the doc is in the project. update_project handles both states. (If the project already has a brief and the user is replacing it, it is worth reading the old one first — get_project then get_content — so nothing it settled is lost without the user knowing. That is a read for the user's benefit, not an attachment check.)add_context to set a brief — add_context creates a Context item, which is a different object than a Content item used as a brief.Goal. Before you draft, revise, assess, critique or answer questions about work in a project, know what the project has already decided.
The brief is the project's authoritative statement of premise, scope and the structural decisions already taken. The project's other documents and context items may be older than it or contradict it — the brief wins. Work produced without reading it is likely to contradict decisions the user has already made.
Two tools hand you the brief — you only need it once per project per conversation:
project_brief block (null when there is no brief). Its entry in documents is flagged is_project_brief: true and sorted first.project_brief block, as the first key of the response, when the project has a brief. include_project_brief defaults to true.Steps.
content_intro. If truncated is true, it is only the opening excerpt — call marcora:get_content(content_id) for the full body before doing the work. (This is always a legitimate use of get_content.)get_relevant_context call for the same project in the same conversation, pass include_project_brief: false — you already have it. If you got the brief from get_project first, the first get_relevant_context call for that project already counts as a later call. The same goes for a brief your environment has already put in your instructions for that project.include_project_brief at its default for your first call on it.When you don't need to read it yourself. Handing off to create_content with instructions + project_id — Marcora layers the brief in internally (Layer 3 of the context model above). Read it when you are the one reasoning about the project.
Output to user. When the brief shapes your answer, say so in a phrase ("per the project brief, the launch leads with …") so the user can see which decisions you worked from.
Goal. Persist a reference document (brand guidelines, persona research, competitor analysis, product spec, customer interview) so future generations can draw on it.
Preconditions. None.
Steps.
collection_ids or dimension_option_ids on create_content instead.marcora:list_context_collections. Use existing collection if a fit; otherwise marcora:create_context_collection.marcora:add_context with name and the body, plus optional collection_id (top-level) or project_id (project-scoped). Pick the body argument based on what you have — provide exactly one of these three (zero or more than one → 400):web_browse/web_fetch it into your conversation first just to forward the bytes.content_type: "webpage"): the URL is stored so it can be re-pulled later via update_context(refresh_webpage=true) or the app's refresh button. Use this for the customer's own pages and anything you'll want to keep current. Dedupes by URL: re-adding a tracked URL updates that item in place and overwrites its stored content with the fresh fetch (so add_context is marked destructive). Admin/editor only — collaborators are rejected.Import wait. import_url and connected_webpage_url imports wait up to about 25 seconds. If the page loads in that time the result has import_status: "ready" (the body is not in the result; get_context_item returns it). If the page can't be read, the call returns an error and nothing is added. If the import is still running after 25 seconds, the result has import_status: "processing": poll get_context_item until it is ready.
Plan capacity. When the team's plan limits context items, the add_context result carries capacity (used, limit, remaining); on a plan with no limit it is absent. At the limit, a call that would create an item (content, import_url or a new web page) returns an error that states the limit; deleting an item makes room. Re-adding a connected_webpage_url the team already tracks still refreshes it.
Output to user. "Added: [link]. Want to use this in a content generation now?"
Goal. Set up a workstream container for an initiative.
Preconditions. None hard-required. If you don't already know the user's projects: marcora:list_projects to avoid duplicates.
Steps.
project_brief_instructions, or their own finished text via project_brief_content) or set up empty (and add a brief later via Workflow 2). Both paths are fine.marcora:create_project with name, optional visibility (team default | private), optional project_brief_instructions or project_brief_content (if both are sent, project_brief_content wins; project_brief_instructions uses Studio Credits). When a brief is created, the response includes project_brief: {name, content_id} — save the content_id so the user can edit the brief later via update_content.Output to user. "Project created: [link]."
Goal. Answer the user's question about what's in their library, or help them ideate using their existing context.
Preconditions. None.
Pick the right discovery tool based on intent:
marcora:get_relevant_context. Returns the passages most relevant to the question, with sources. Best when the user has a question that needs content, not a list.marcora:list_context_items. Returns names + intros + IDs, newest first. Set reference_library_only=true to scope to top-level Reference Library items only (i.e. items not in any project or collection). An optional search only re-orders the list by similarity (each item gains a relevance_score); it never filters, so the whole library comes back.marcora:get_context_item(context_item_id). Returns full markdown + metadata + link.marcora:list_content. Returns every piece the user can see, newest first; an optional search re-orders it by similarity to the query and cuts nothing. Use get_relevant_context when you want the reference material that is relevant to a question.Steps (RAG path).
marcora:get_relevant_context with a descriptive prompt. Optionally broaden with project_id or collection_ids — these are additive (they add that project's / those collections' items on top of the general library, they don't restrict to only them). This is the only legitimate use of this tool besides the narrow Workflow 1 sourcing-check.sources[] array — one entry per parent context item, each with its context_item_id, name, content_type, a link_url deep-link (and source_url for webpage items), and the chunk IDs from that item. Use sources to cite/link what you surface. Each source also carries content_category (company_authoritative outranks reference_material when they disagree) and is_stale (treat a stale item's claims with caution).project_brief block ahead of the chunks. Read it first, and weigh the chunks against it — see "Working inside a project" above. Pass include_project_brief: false on later calls for the same project.context_rag_ids (excludes already-returned chunks), or offer to add new context.marcora:get_context_item(context_item_id) — get_relevant_context only returns chunks, not the whole item.Writing the content yourself? (This is the default for new content.) When you draft with your own model and then save it via the content parameter of create_content (or update_content) — rather than letting Marcora generate from instructions — call marcora:get_relevant_context(prompt, include_brand_foundation=true) first and write from what it returns. You get Reference Library RAG chunks and the team's Brand Foundation (company overview, brand voice, writing style, writing examples) in one response — so you write on-brand without a separate get_brand_foundation call. Those content-save paths store your text verbatim and consult no context on their own, so this fetch is the only thing that grounds your draft. Don't set the flag when handing off via instructions (that path pulls Brand Foundation in automatically). When paginating, set it true on the first page only. If you are writing for a project, pass its project_id too: the first call returns the project's brief, and your draft must not contradict it.
Steps (browse path).
marcora:list_context_items (default returns everything the user can see; pass reference_library_only=true for just orphan items in the top-level Reference Library). Items in private collections / private projects the user is not in are filtered out automatically.marcora:list_context_collections if the user is asking about collection-level organization, or marcora:get_project(project_id).context_items for one project's items.marcora:get_context_item(context_item_id).Output to user. A summary, not a JSON dump. Offer next steps: drill into a specific item (get_context_item), add new context, generate something based on what was found.
Goal. Check whether a document's factual claims hold up against the team's own context library, and fix the ones that don't.
Preconditions. Command plan with credits. A document to check — either already in Marcora, or markdown you're holding.
When to reach for it. After drafting anything factual, or when the user asks "is this accurate", "does this contradict anything we've said", "check this against our context". It is the natural second beat after Workflow 1.
Steps.
marcora:check_content_grounding — content_id alone to scan an existing document, content alone to store-and-scan new markdown.status: "running", poll marcora:get_grounding_result({scan_id}) every 15–30s. Poll with `scan_id`. Polling with content_id returns the last completed scan, which during your run is the previous one — you'd report stale findings as fresh. Never re-call check_content_grounding to check progress.coverage_complete is false, or excluded_items is present, the check did not read every context item, so a gap may still have support. Say so: describe those gaps as "not yet confirmed", not "unsupported". coverage_reason: "library_catch_up" means some context items have not been prepared yet; re-run the check to include more of them. library_extraction_failed means some could not be prepared. Then review findings[] with the user. Each carries the full suggested_fix and the context_item_id it would write to. Hand over link_url.marcora:apply_grounding_fix({finding_ids: [...]}) for what they approve. Use context_item_overrides to redirect a fix.marcora:get_generation_status({generation_id}) with the UUID generation_id from jobs[]. Findings whose fixes land in the same document (the same context item, or the same content document when context_item_id is null) are applied together in one run and share one generation_id: poll each distinct generation_id once, and its document_updated covers every finding in that run. Brand Foundation findings are not grouped. `document_updated` is the honest outcome: false means the recommendation was already covered and nothing was written. Report that distinction.⚠️ The one way to lose data here. content + content_id replaces the document's entire body, exactly like update_content. To ground part of an existing document, pass content_id alone. Never pass a paragraph alongside a content_id — the rest of the document is gone.
apply_grounding_fix also applies Context Intelligence health-audit recommendations from list_ci_findings. Full recipe: references/workflows.md Recipe I.
A workflow lets the user describe a multi-step process once and run it reliably afterwards — manually on demand, on a schedule, or both — without re-explaining the steps each time.
Mindset: a workflow is a reusable, named process. Some are scheduled (a daily digest, a weekly competitor sweep); many are not (a launch playbook, a customer-onboarding routine run on demand). Both are first-class — don't assume "workflow = recurring scheduled task."
since_last_run input binding.If intent is ambiguous, ask: "Do you want to run this once, or set it up as a reusable process you can run again later — manually, on a schedule, or both?"
Workflow vs. Playbook — pick the right surface. A Playbook (below) produces a batch of content plans — an ordered set of things to write, landing on the plans board for a human to produce. A Workflow runs an agent through arbitrary steps (search, summarize, create content, send an email) in a background session. "Save this content sequence as a template" → playbook. "Every Monday, sweep competitor blogs and email me a digest" → workflow.
(Not available in ChatGPT, where these six tools aren't offered; set workflows up in the Marcora app there. Every other client sees them.)
name, steps, description, inputs, allowed_tools, tags, optional schedule_config. Saves the workflow Inactive and any schedule Paused; the response carries a next_step saying what will and won't run.allowed_tools and tags, plus its triggers (including the schedule, if any) and latest run, and run_state (one sentence covering both switches) and schedule (its read-back, when it has one). Call before update_workflow to avoid clobbering unknown fields, and before saying whether a workflow runs.status, search, pagination). Call with search: before creating to spot duplicate names. The list does not show schedules — status: "active" in it does not mean a workflow is running.status accepts "active", "inactive" or "archived" (soft-delete); anything else is refused and nothing is saved. It cannot edit a schedule or switch one On. When the call changes the status to Active or Inactive, the response carries a next_step.allowed_tools. Only an Active workflow runs; the schedule plays no part in a manual run. Inspect .status: "running" = success, "failed" = check .error_reason.run_id for single-run detail (step logs + tool-call logs); omit for a paginated list.create_workflow only after the user agrees.create_content, add_context, create_project, update_context, create_external_share, or connected apps: send an email (Gmail), post a message (Slack, Teams, Discord), create a task (Google Tasks, Asana, Linear), or write to Google Docs, Sheets or Notion.agent_hint for non-obvious guidance. Tool names in step descriptions render as chips — write them in canonical SCREAMING_SNAKE_CASE.allowed_tools is missing or empty — even summary-only workflows need read tools spelled out (e.g. web_search, web_browse).run_workflow) needs only Active.update_workflow status:"active" and describe the state after that call (its next_step), not the state create_workflow reported.schedule_config entirely for manual/on-demand workflows.{"frequency": "daily"|"weekly", "hour": <0-23 UTC>, "days_of_week": [<0=Sun…6=Sat, UTC>], "timezone": "<the user's IANA zone>"}. days_of_week takes 1–7 distinct days, so "3 times a week" is ONE schedule ([1,3,5]) — use it rather than approximating with an interval. (The older single day_of_week is still read when the array is absent.) Convert the user's local time and weekdays to UTC yourself; timezone is display-only. This is the shape the app's schedule editor shows and edits.hour and pass interval_hours (or rely on the 1h / 24h / 168h default for hourly / daily / weekly). It runs every N hours with no fixed time of day, the first run landing one interval after the user switches the schedule On. The app's editor cannot display or edit it — use it only when the calendar shape can't express the need.update_workflow silently ignores schedule_config and still returns success. Tell the user the schedule is Paused, hand them the workflow's link_url exactly as returned, and ask them to review it and click Resume schedule. Quote schedule.summary when you describe what was saved.since_last_run input binding (Marcora computes the window from the last successful run — don't compute it yourself), match schedule cadence to lookback, and write source entity IDs into downstream artifacts so a future run can tell what it already processed. Raise this proactively if the user doesn't.The runner agent's FINAL message becomes the run's summary (rendered as markdown on the run-detail page). Instruct it to: format in markdown, lead with a one-line conclusion, and link back to anything created (most Marcora tools return a url/link — include it). For summary-only workflows, the summary IS the output — make it complete.
Setting the run's status: tell the runner to start its final message with one of these prefixes — Workflow complete: <md> → succeeded · Partial completion: <md> → succeeded (partial) · SKIP: <reason> → skipped · FAIL: <reason> → failed. With no prefix, the final message is used as the run summary as-is.
"paused" workflow status.update_workflow status:"archived". Restore with status:"inactive" or status:"active".list_workflows search:"<name>" first if re-creating is possible.link_url.create_workflow/update_workflow.The plans board is Marcora's content pipeline: a queue of ideas/intents (plans) that move through stages and get produced into real Content. Playbooks are reusable, ordered templates of plan items you can stamp out as a batch.
Mindset: a plan is intent, Content is output. Creating a plan doesn't write anything —produce_plandoes. Keep the two straight:create_contentwrites or saves a document now;create_planrecords "we should write X" for later.
Suggested → Accepted → In_Process → Complete, plus Dismissed (terminal). Transitions go through update_plan target_stage: (use the UNDERSCORE form In_Process). Only these are allowed: Suggested→Accepted/Dismissed · Accepted→In_Process/Dismissed · In_Process→Complete/Accepted/Dismissed · Complete→Accepted (re-open, clears produced content)/Dismissed. There is no `delete_plan` — dismiss with target_stage:"Dismissed".
The starting stage is set automatically from `source`, you don't control it directly: cora_requested / playbook → Accepted (actionable now); user_added / cora_proactive / workflow → Suggested (awaits user accept). Set source:"cora_requested" when the user explicitly asked; source:"cora_proactive" when you're surfacing an unprompted suggestion. Never pass source:"workflow" or "playbook" from an interactive session.
Plans are `private` by default — the creator's ideas queue, invisible to teammates (a teammate's private plans return NotFound and never appear in their list_plans). Assigning a plan to another member (assigned_to) auto-promotes it to `team` — assignment is a communication act, even over an explicit private. Only the plan's creator can change visibility; mention the change to the user before sending it. Playbooks default to `team`; instantiate_playbook inherits the playbook's visibility onto the plans it creates.
title is required. Optional executable params (prompt, blueprint_id, project_id, category_id, due_date, reference_document_ids, context_collection_ids, targeting_dimension_ids, assigned_to, visibility). Dedupe first: call list_plans with a project_id filter before creating; if a matching Accepted/Suggested plan exists, offer to update_plan it instead. When creating several in one turn, correlate them with source_metadata.batch_id and deep-link the filtered view.plan_uuid with all linked params. Always call before `update_plan` to avoid overwriting with stale values. _produced_content null = no content yet.stage (single-value array, UNDERSCORE form), project_id, assignee_scope (me default | created_by_me | all_visible). Current limitations: due_before, due_after and search_text are accepted but not yet applied, and for stage and source only the first value is used — pass single-value arrays.get_plan. reference_document_ids / context_collection_ids / targeting_dimension_ids are full-replace when non-empty; [] is ignored, so they can't be cleared. null clears blueprint_id / due_date but is ignored for project_id / category_id. Server-managed fields (source, produced_content_id, timestamps, etc.) are rejected as immutable.update_plan target_stage:"Accepted" first). ⚠️ Consumes Studio Credits and takes 1–5 min — confirm before producing a plan the user didn't explicitly ask to produce. The plan's prompt, targeting, context collections, and project are used as generation inputs — set them via update_plan BEFORE producing.generation_id; poll `get_generation_status`. A plan with a blueprint → path:"blueprint"; without a blueprint → path:"freeform". On completion Marcora links the produced content and flips the plan to In_Process (then Complete when the content reaches ready).get_playbook for items. Use before instantiate_playbook/update_playbook to find the right id.name + optional ordered items (each item becomes one plan on instantiation). Defaults visibility:"team". Optionally set `anchor_date` (YYYY-MM-DD) when the template is built around a real date — it persists on the playbook and becomes the default anchor at instantiation.plan_ids; their title/description/prompt/blueprint/category copy into ordered items. Use this (vs create_playbook) when the user liked a batch they already ran.items is provided it FULLY REPLACES the items and their order; omit items to leave them. visibility change is creator-only. Pass `anchor_date` to set the reference date, or null to clear it."playbook", inheriting the playbook's visibility). This is a distinct bulk action — it does NOT create/edit the playbook. Optional project_id, assigned_to, category_id, and `anchor_date`: each item's offset_days is applied to the anchor to compute that plan's due date (e.g. "instantiate my launch playbook anchored to next Monday"). If anchor_date is omitted, the playbook's persisted anchor is used.Playbook responses carry links — hand them to the user, not raw ids. Every playbook read/write tool returnsanchor_date(persistedYYYY-MM-DD, ornull) and a `link_url` that opens the playbook in Marcora.instantiate_playbookreturns the created cycle (run, with its ownlink_url→app.marcora.ai/runs/{run_id}) plus aplans[]array where each plan has its own `link_url` →app.marcora.ai/plans/{plan_uuid}. Share the cycle link to hand off the whole batch.
list_plans (find it) → update_plan target_stage:"Accepted" → produce_plan → poll get_generation_status → hand the user the produced content's link.create_playbook_from_plans(plan_ids) → later instantiate_playbook(anchor_date=…) to redeploy the sequence.create_playbook(name, items) → instantiate_playbook when ready to deploy.| If the user wants… | Call this | Not this — because… |
|---|---|---|
| To write a new document (any kind) | Write it yourself from marcora:get_relevant_context(include_brand_foundation=true), then marcora:create_content with content | add_context creates a reference item, not a document. Use instructions only when the user asks Marcora to write it, a Blueprint is used, or a plan is being fulfilled. |
| To generate from a template they name (or ask for) | marcora:create_content with instructions + blueprint_uuid | get_blueprint only fetches details; it doesn't generate. |
| To save text as a document (yours or the user's) | marcora:create_content with content only | Don't add blueprint_uuid or instructions — incompatible. |
| To pin a Content item as a project's strategic anchor | marcora:update_project(project_brief_id=…) | add_context creates a Context item, NOT a brief. Different objects. |
| To attach an existing Content item to a project (no brief intent) | marcora:update_project(project_brief_id=…) (which auto-attaches), OR have the user attach in-app | Don't create_content(project_id=…) to "duplicate" it into the project — orphaned copy. |
| To add reference material reusable across all projects | marcora:add_context (no project_id) | A Context Collection is just a folder; you still need add_context to put items in it. |
| To add reference material specific to one project | marcora:add_context(project_id=…) | update_project(project_brief_id=…) would make it the brief — only one of those per project. |
| To edit the name, content, or location of an existing context item | marcora:update_context | add_context would create a duplicate. Note: collection_id and project_id are full-replace on every call — pass null to clear. Use marcora:list_context_items to find the ID, or marcora:get_context_item to confirm the current collection_id / project_id values before the full-replace update. To replace the body from a URL with a one-off snapshot, pass import_url instead of content — backend extracts the markdown server-side. |
| To track a web page as context so it can be refreshed later | marcora:add_context(connected_webpage_url=<url>) | This creates a real webpage item with a stored, refreshable URL — import_url only takes a one-off snapshot that cannot be refreshed. Admin/editor only; dedupes by URL. |
| To refresh a tracked web-page item after its source page changed | marcora:update_context(context_item_id, refresh_webpage=true) | Re-pulls from the stored URL (the app's refresh button). Only works on items created via connected_webpage_url. Find which items are refreshable via the source_url field on list_context_items / get_context_item. Don't web_browse + update_context(content=…) — that's a blind overwrite, not a tracked refresh. |
To edit an existing Content document — change the body, name, stage (ready / in_progress), visibility, category, or single-project assignment | marcora:update_content | update_context operates on Context items, not Content documents — different object. update_project(project_brief_id=…) only changes a project's brief pointer, not the document body or fields. update_content is partial-update (omit a field = leave alone) and replaces the body in full when content is supplied — call get_content first if you need to splice into the existing markdown. Setting name_override LOCKS the title so it won't auto-resync from the body's first header on future edits. |
| To have Marcora's in-editor AI assistant edit / extend a document — or answer a question about it — with the reply streaming live into the document's sidebar | marcora:ask_content_assistant | update_content is a manual full-body replace — you compute and supply the new markdown. ask_content_assistant hands the request to Marcora's own Content Assistant: it loads the document + brand/reference context, decides whether to edit or just reply, and streams the result live to the user in the app. It's async — returns a generation_id to poll via get_generation_status. One run per document at a time: a second call on the same document fails until the first run finishes, so wait for a terminal status or combine requests into one prompt. It is NOT the general Marcora Agent. |
| To save a URL (blog post, competitor page, Google Doc export, presigned link) as a one-off context snapshot | marcora:add_context with import_url=<url> | Don't web_browse/web_fetch the URL just to paste the markdown into content — Marcora extracts the page itself and avoids the round-trip through your conversation. Use connected_webpage_url instead if you want the URL kept and refreshable (see the web-page rows below). |
| To read a project's brief (its premise and settled decisions) | marcora:get_project → project_brief, or the project_brief block on your first marcora:get_relevant_context(project_id=…) call; then marcora:get_content(content_id) when truncated is true | update_project only sets which document is the brief — it never returns the brief. list_context_items / relevancy search never surface it: the brief is a document, not a context item. |
| To know what content already exists about a topic | marcora:get_relevant_context for context, OR marcora:list_content for a content list | create_content would generate something new — wrong tool for "what already exists." |
| To browse what's in the user's context library (full inventory) | marcora:list_context_items | get_relevant_context returns the passages relevant to a question, not the item list. Use list_context_items for the catalog view. Pass reference_library_only=true to scope to just the top-level Reference Library. |
| To read the full markdown of a specific context item | marcora:get_context_item(context_item_id) | list_context_items only returns content_intro (a truncation). get_relevant_context returns matched passages. Use this to open one item whose ID you already have. |
| To find the passages in the library that are relevant to a question | marcora:get_relevant_context | It scores each passage on its own and against its whole document, drops weak matches and returns the top 10 with their sources. list_context_items(search=…) and list_content(search=…) only re-order a full listing: they cut nothing, so the response is as large as the library. Open a surfaced item in full with get_context_item(context_item_id). |
| To read the team's Brand Foundation (company overview, brand voice, writing style, writing examples) | marcora:get_brand_foundation | get_relevant_context searches the Reference Library, not Brand Foundation. Auto-pulled into create_content when Marcora writes via instructions. When you write it yourself, get_relevant_context(include_brand_foundation=true) returns it together with the context in one call. |
| To change one of the four Brand Foundation elements | marcora:update_brand_foundation | Brand Foundation lives at the team level, not as Context items — update_context won't touch it. Always full-replace; fetch first with get_brand_foundation to confirm what's being replaced. Hand the user the returned link_url — never build a Brand Foundation URL yourself. |
To find a teammate's numeric user_id (to assign a plan/content to them) | marcora:get_team_info | get_current_user_info is only you. get_team_info lists every team you're in + each member's numeric user_id — the value assigned_to / update_plan(assigned_to=…) expects. Pending invites show user_id: null (can't be assigned yet). |
| To switch which team you're working in | marcora:set_active_team | Changes your active team for all subsequent calls. ⚠️ Global — it applies everywhere for the account (app tabs, Marcora agent sessions, other clients). Tell the user first; capture the returned previous_team_id and switch back when done. |
link_url (or any URL field), copy it character for character into your reply. Never retype an id, shorten a URL, or rebuild one from a pattern — a single wrong character in a UUID gives the user a dead link that still looks right.update_project(project_brief_id=...) — it auto-attaches.get_relevant_context(include_brand_foundation=true) → you write → create_content with content. The content path stores your text verbatim and consults no context, so if you skip the context call, your draft is off-brand and ignores the Reference Library. Marcora's generator (instructions) is for three cases: the user asks Marcora to write it, a Blueprint is used, or a plan is being fulfilled. On that path, don't pre-fetch: the instructions path already pulls in Brand Foundation (so you don't need marcora:get_brand_foundation either), Reference Library via relevancy scoring, Project Context if project_id is set, and any collection_ids you pass, so fetching first is wasted work. Other legitimate uses of the fetch tools: the narrow Workflow-1 sourcing-check (specific customer / incident not likely in the library) and direct user Q&A about brand voice or library contents.link_url. get_content is for three cases only: (a) the user later asks a question that requires reading the body to answer, (b) you need the markdown to feed convert_markdown_to_word_doc, or (c) a project_brief block came back with truncated: true and you are about to work in that project — read the full brief first.include_project_brief defaults to true; after the first get_relevant_context call for a project (or once you have the brief from get_project), pass false for that project.create_content returns a generation_id immediately. Without polling, the user thinks nothing happened. Poll get_generation_status every ~30s; surface progress every minute.create_content with instructions (Quick, no blueprint) returns the full content directly, but the wait is real (about 45 s to 3½ min). Tell the user before calling, and allow a long timeout. use_extended_thinking: false is faster.content cannot combine with blueprint_uuid either.options array.name="" is a safe no-op rather than a clobber. There's intentionally no way to clear a project name through this tool.name_override locks the title (has_custom_name=true) and there's no un-lock path in this tool — let the next plain content write recompute the auto-name if needed. The tool rejects non-editable document types (e.g. the documents that back the context-item editor in the app) — those are managed by separate sync flows and would corrupt the linked context item if edited here.generation_id immediately, and the reply (plus any document edits) stream live into the document's AI Assistant sidebar for a user who has it open. Poll get_generation_status for the result (flow_type: ai_assistant, terminal status complete) — it returns the document's current state + the latest assistant reply you are allowed to see, not a frozen snapshot. If that reply used sources you can't open, assistant_summary reads "This reply used sources you can't open" instead of the reply text; the run still succeeded, so tell the user rather than retrying. Reach for it (vs update_content) when you want Marcora's assistant to make the edit with full brand context and live streaming rather than computing the new body yourself. The assistant decides whether to edit the doc or just reply, unless you pass chat_only_mode: true. One run per document at a time: while a run is in progress a second ask_content_assistant call on the same document fails. A run that may edit the document also holds it, so nobody can edit it in the app until the run ends; a chat_only_mode: true run doesn't hold it. Wait for get_generation_status to reach a terminal status before sending the nex~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.