MCP Tools
Workflows

create_workflow

Create a reusable, multi-step workflow template for the team, with an explicit list of allowed tools. New workflows are saved Inactive and any schedule is saved Paused — it runs on its own only once the workflow is set Active and the user turns the schedule on with Resume schedule in the app.

Parameters

NameTypeRequiredDefaultDescription
namestringYes—Display name for the workflow, shown in the workflow list and passed to the agent that runs it. Required and must be non-empty — a missing or blank value is rejected. `list_workflows` searches on this name, so make it distinctive and confirm the wording with the user first.
descriptionstringNo—One or two sentences on what the workflow accomplishes. It is inserted verbatim into the prompt given to the agent that runs the workflow, so write it as orienting context, not marketing copy. Optional — stored as an empty string when omitted.
stepsarrayYes—Ordered list of the actions the workflow should perform, handed to the agent as JSON at run time. Required. Write each step so a fresh agent with no conversation history can carry it out without asking follow-up questions.
allowed_toolsarray of stringYes—REQUIRED, non-empty. Tools the workflow runner may use; an empty list is rejected.
inputsobjectNo—Object declaring the values this workflow expects at run time (for example a topic or a date range). It is stored and returned as documentation for callers and for the app UI; the agent itself receives the actual per-run values via `input_values`, not this declaration. Optional — defaults to an empty object.
tagsarray of stringNo—Free-form labels for organizing workflows. Must be an array of strings; any other value is ignored and a single blank tag is stored instead. Purely descriptive — listing and search do not filter on tags.
schedule_configobjectNo—Include only when the user explicitly asks for the workflow to run on a schedule. A non-empty object creates the schedule, which is always saved Paused — the user turns it on in the app with "Resume schedule", and it fires only while the workflow is Active. Two modes: - **Calendar mode (preferred — it is what the app's editor shows and edits):** set `hour` (integer 0–23, in **UTC**). With `frequency: "weekly"`, set `days_of_week` — an array of 1–7 distinct integers, 0=Sunday … 6=Saturday, in **UTC** — so "3 times a week" is one schedule, e.g. `[1,3,5]`. (The older single `day_of_week` is still read when `days_of_week` is absent; prefer the array.) Any frequency other than weekly runs daily at `hour`. Convert the user's local time (and weekday) to UTC yourself, and set `timezone` to the user's IANA timezone (e.g. "America/Sao_Paulo") for display. - **Interval mode (when `hour` is absent):** runs every `interval_hours` hours, or every 1 / 24 / 168 hours for hourly / daily / weekly if `interval_hours` is omitted. There is no fixed time of day, and the first run is one full interval after the user switches the schedule on. The app's editor cannot show or edit an interval schedule, so use it only when calendar mode can't express what the user needs, and say what you saved. `timezone` is display-only; the scheduler always uses UTC.

Input Schema

{
  "type": "object",
  "required": [
    "name",
    "steps",
    "allowed_tools"
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "Display name for the workflow, shown in the workflow list and passed to the agent that runs it. Required and must be non-empty — a missing or blank value is rejected. `list_workflows` searches on this name, so make it distinctive and confirm the wording with the user first."
    },
    "tags": {
      "description": "Free-form labels for organizing workflows. Must be an array of strings; any other value is ignored and a single blank tag is stored instead. Purely descriptive — listing and search do not filter on tags."
    },
    "steps": {
      "description": "Ordered list of the actions the workflow should perform, handed to the agent as JSON at run time. Required. Write each step so a fresh agent with no conversation history can carry it out without asking follow-up questions."
    },
    "inputs": {
      "description": "Object declaring the values this workflow expects at run time (for example a topic or a date range). It is stored and returned as documentation for callers and for the app UI; the agent itself receives the actual per-run values via `input_values`, not this declaration. Optional — defaults to an empty object."
    },
    "description": {
      "type": "string",
      "description": "One or two sentences on what the workflow accomplishes. It is inserted verbatim into the prompt given to the agent that runs the workflow, so write it as orienting context, not marketing copy. Optional — stored as an empty string when omitted."
    },
    "allowed_tools": {
      "description": "REQUIRED, non-empty. Tools the workflow runner may use; an empty list is rejected."
    },
    "schedule_config": {
      "type": "object",
      "properties": {
        "hour": {
          "type": "integer",
          "maximum": 23,
          "minimum": 0,
          "description": "Calendar mode: hour of day in UTC (0–23). Selects calendar mode when present."
        },
        "timezone": {
          "type": "string",
          "description": "The user's IANA timezone, for display only. Does not change when the schedule runs."
        },
        "frequency": {
          "enum": [
            "hourly",
            "daily",
            "weekly"
          ],
          "type": "string",
          "description": "\"daily\" or \"weekly\" (the app's editor options). \"hourly\" is interval mode only. Anything else is treated as daily."
        },
        "day_of_week": {
          "type": "integer",
          "maximum": 6,
          "minimum": 0,
          "description": "Calendar mode with frequency \"weekly\": a single day in UTC, 0=Sunday … 6=Saturday. Superseded by `days_of_week`, which the app now writes; still read when `days_of_week` is absent."
        },
        "days_of_week": {
          "type": "array",
          "items": {
            "type": "integer",
            "maximum": 6,
            "minimum": 0
          },
          "maxItems": 7,
          "minItems": 1,
          "description": "Calendar mode with frequency \"weekly\": the days to run on, in UTC — 0=Sunday … 6=Saturday. 1–7 distinct integers; requires an integer `hour`. This is how a multi-day cadence (\"3 times a week\" → [1,3,5]) is saved, and it is what the app's weekday picker edits. Rejected with a readable error if the values are out of range, duplicated, or `hour` is missing.",
          "uniqueItems": true
        },
        "interval_hours": {
          "type": "number",
          "description": "Interval mode only (ignored when `hour` is set): hours between runs.",
          "exclusiveMinimum": 0
        }
      },
      "description": "Include only when the user explicitly asks for the workflow to run on a schedule. A non-empty object creates the schedule, which is always saved Paused — the user turns it on in the app with \"Resume schedule\", and it fires only while the workflow is Active. Two modes:\n- **Calendar mode (preferred — it is what the app's editor shows and edits):** set `hour` (integer 0–23, in **UTC**). With `frequency: \"weekly\"`, set `days_of_week` — an array of 1–7 distinct integers, 0=Sunday … 6=Saturday, in **UTC** — so \"3 times a week\" is one schedule, e.g. `[1,3,5]`. (The older single `day_of_week` is still read when `days_of_week` is absent; prefer the array.) Any frequency other than weekly runs daily at `hour`. Convert the user's local time (and weekday) to UTC yourself, and set `timezone` to the user's IANA timezone (e.g. \"America/Sao_Paulo\") for display.\n- **Interval mode (when `hour` is absent):** runs every `interval_hours` hours, or every 1 / 24 / 168 hours for hourly / daily / weekly if `interval_hours` is omitted. There is no fixed time of day, and the first run is one full interval after the user switches the schedule on. The app's editor cannot show or edit an interval schedule, so use it only when calendar mode can't express what the user needs, and say what you saved.\n`timezone` is display-only; the scheduler always uses UTC."
    }
  }
}

Output Schema

{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "id",
    "name",
    "status",
    "team_id",
    "created_at",
    "link_url"
  ],
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid",
      "description": "Workflow UUID. Use as workflow_id in other workflow tools."
    },
    "name": {
      "type": "string"
    },
    "tags": {
      "type": "array"
    },
    "steps": {
      "type": "array"
    },
    "inputs": {
      "type": "object"
    },
    "status": {
      "enum": [
        "inactive",
        "active",
        "archived"
      ],
      "type": "string"
    },
    "team_id": {
      "type": "integer"
    },
    "link_url": {
      "type": "string",
      "format": "uri",
      "description": "Direct URL to view this workflow in Marcora."
    },
    "schedule": {
      "type": "object",
      "properties": {
        "summary": {
          "type": "string",
          "description": "Plain-language description of exactly what was saved (times in UTC). Quote it to the user."
        },
        "is_enabled": {
          "type": "boolean",
          "description": "Always false on create: the schedule is Paused, and does not fire until the user clicks \"Resume schedule\" in the app — and even then only while the workflow is Active."
        },
        "trigger_id": {
          "type": "string",
          "format": "uuid"
        },
        "schedule_config": {
          "type": "object"
        }
      },
      "description": "Present only when schedule_config created a schedule. Read back from the saved schedule."
    },
    "next_step": {
      "type": "string",
      "description": "Always present. What will and won't run, across both switches — the workflow's status (Active / Inactive) and its schedule (On / Paused / none) — computed from what was saved, with the words to use. Follow it and lead your reply with it."
    },
    "created_at": {
      "type": "integer"
    },
    "updated_at": {
      "type": "integer"
    },
    "description": {
      "type": "string"
    },
    "allowed_tools": {
      "type": "array"
    },
    "created_by_user_id": {
      "type": "integer"
    }
  }
}

Instructions

Create a new workflow template for the user's current team. New workflows are saved Inactive (status: "inactive"); set one Active with update_workflow once the user confirms.

Input roles:

  • name: Human-readable name. Confirm with the user before creating.
  • description: One or two sentences. Becomes part of the runner's system prompt.
  • steps: Ordered list. Each step should be specific enough that a fresh agent can do it without follow-up questions.
  • inputs: Declare what the workflow needs (e.g., topic, date_range). For scheduled runs these are resolved from trigger bindings.
  • allowed_tools: REQUIRED, non-empty. The exact set of tools the workflow runner is permitted to use. A workflow cannot be created without an explicit allowlist — an empty list would let the runner inherit the agent's full tool set. Prefer tight allowlists, especially for scheduled runs.
  • tags: Optional.
  • schedule_config: Include ONLY if the user explicitly wants the workflow to run on a schedule. See the schedule_config input for its two modes; prefer the calendar mode (hour, plus days_of_week for weekly).

Two switches, two vocabularies — never mix them. The workflow's status is Active or Inactive. Its schedule, if it has one, is On or Paused. Never call a schedule "active" or "inactive", never call a workflow "paused" or "on" — in any language. "Active" does not mean running; it only means the workflow is allowed to run.

What actually runs needs BOTH switches — describe the pair that exists when you finish:

  • Inactive → nothing runs, by any route (manual runs are refused too).
  • Active, no schedule → runs only when started manually; never starts by itself.
  • Active, schedule Paused → manual runs work; it won't run on its schedule until the user turns the schedule on with Resume schedule in the app.
  • Active, schedule On → runs on its schedule.
  • Inactive, schedule On → nothing runs until the workflow is set Active.

Schedules are always saved Paused. A schedule created here does not fire until the user turns it on in the Marcora app with Resume schedule. No MCP tool can turn it on — update_workflow SILENTLY IGNORES schedule_config and still returns success, so a schedule "enabled" that way is still Paused. And the schedule is only one of the two switches: it never fires while the workflow is Inactive.

  • The response always carries a next_step that states what will and won't run, computed from what was actually saved. Follow it, and lead your reply with it. When a schedule was saved it also carries schedule (is_enabled: false = Paused, plus a plain-language summary of exactly what was saved) and link_url for the user to review it and click Resume schedule.
  • If you then call update_workflow (for example to set the workflow Active), describe the state after THAT call — its next_step — not this one. Activating a workflow whose schedule is Paused still leaves it not running on its schedule; saying "it's inactive, go activate it" after you activated it is just as false.
  • "Created and active" misled a real customer into thinking their workflow was running. Never say or imply the workflow will run on its own unless it is Active AND its schedule is On.
  • The app's schedule editor offers two shapes: Daily at a set time, or Weekly on one or more days at a set time (it has a weekday picker, so Mon/Wed/Fri is a single schedule). It still cannot set a second time of day or an every-N-hours interval, so never promise the user either of those in the app.
  • A cadence of "3 times a week", "every weekday", "Mondays and Thursdays" is expressible exactly — use weekly with days_of_week (e.g. [1,3,5]) and one hour. Pick the days with the user's intent in mind and say which ones you chose; do not fall back to an interval for these.
  • If the user asks for something the two shapes genuinely can't express (e.g. "twice a day", "every 36 hours"), save the closest schedule you can, then tell the user exactly what you saved (quote schedule.summary) and that it is an approximation of what they asked for. Never present an approximation as the schedule they requested.

Usage patterns:

  • New workflows start Inactive; nothing runs until the workflow is set Active.
  • Before creating, check list_workflows with a search: filter for duplicate names.
  • For scheduled workflows that process entities (e.g., "new content items since last run"), set up a since_last_run input binding via the trigger.
  • The returned id is a UUID string. Use it as workflow_id in get_workflow / update_workflow / run_workflow / get_workflow_runs.
  • 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