Flowline
Reference

MCP tutorial — author a flow and run a QA suite with your AI assistant

This is a hands-on, end-to-end walkthrough. For each step you'll see the natural-language ask you'd type to your assistant, the tool call it makes (JSON arguments), and the result it gets back. By the end you'll have authored a PIN-entry flow, defined two scenarios, run a regression suite against a build, recorded results, filed a bug, and read analytics — entirely through conversation.

Reference for every tool, its arguments, and what's intentionally not exposed: see MCP setup & tool reference.

Using the hosted MCP (remote)

If you're connecting to a deployed instance rather than a local checkout:

  1. Sign in to the web app and create an MCP access token in your profile.
  2. Add the hosted endpoint to your assistant with the token as a bearer header (see the "Remote / hosted MCP" section of the setup reference).
  3. Start your session by asking the assistant to "list my workspaces and select the one" — this runs list_workspaces then select_workspace so the rest of the session reads and writes the right place.

Everything else in this tutorial works the same; an open editor merges your changes within 15 seconds.

Prerequisites

  1. Start the app/API: npm run dev (serves the REST API on http://127.0.0.1:8787).
  2. Pick the workspace to author in: open it in the web app, or ask the assistant to select it (which workspace a session uses).
  3. Connect your assistant to the MCP server (see the setup guide), then talk to it.

Throughout, ids like proj_…, flow_…, nd_…, vs_…, suite_…, sr_… are illustrative — your assistant carries the real ids returned by each call into the next one, so you never have to copy them.


1. Create a project

You: "Create a new project called Smart Locker."

// create_project
{ "name": "Smart Locker" }
// result
{ "id": "proj_8f2a", "name": "Smart Locker", "flows": [] }

2. Author a flow from a spec

You: "In that project, build a PIN-entry flow: an idle screen that starts PIN entry, a PIN screen with correct and wrong branches, ending in Cell opens or Account locked."

// create_flow
{
  "projectId": "proj_8f2a",
  "spec": {
    "name": "PIN entry",
    "entry": "idle",
    "points": [
      { "key": "idle", "title": "Idle screen", "branches": ["start"] },
      { "key": "pin",  "title": "Enter PIN",   "branches": ["correct", "wrong"] }
    ],
    "ends": [
      { "key": "ok",     "outcome": "Cell opens" },
      { "key": "locked", "outcome": "Account locked" }
    ],
    "edges": [
      { "from": "idle", "branch": "start",   "to": "pin" },
      { "from": "pin",  "branch": "correct", "to": "ok" },
      { "from": "pin",  "branch": "wrong",   "to": "locked" }
    ]
  }
}
// result
{ "flowId": "flow_1c7d", "nodeCount": 4, "edgeCount": 3, "warnings": [] }

The flow now renders in the canvas. The point/end keys become the real node ids — fetch them any time with get_flow.

3. Refine the flow

You: "Add a locked out branch on the PIN screen that also leads to Account locked, and reword that outcome to Account locked for 30 min."

// add_branch
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "nodeId": "pin", "branch": "locked out" }
// add_edge
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "from": "pin", "to": "locked", "branch": "locked out" }
// update_end_outcome
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "nodeId": "locked", "outcome": "Account locked for 30 min" }
// result (add_edge)
{ "edgeId": "edge_44b1", "warnings": [] }

4. Define two scenarios (value sets)

You: "Add two scenarios: Correct PIN and Wrong PIN three times."

// create_scenario
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "name": "Correct PIN" }
// result
{ "scenarioId": "vs_a1", "name": "Correct PIN" }
// create_scenario
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "name": "Wrong PIN three times" }
// result
{ "scenarioId": "vs_b2", "name": "Wrong PIN three times" }

Set field values and expected outcomes

You: "For Correct PIN, the PIN field is 4321 and it should end with the cell opening. For Wrong PIN three times, the PIN is 0000 and the expected outcome is the 30-minute lockout."

// set_scenario_value  (PIN field on the "pin" screen)
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "scenarioId": "vs_a1",
  "nodeId": "pin", "fieldId": "pin", "value": "4321" }
// set_scenario_expected_outcome
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "scenarioId": "vs_a1", "outcome": "Cell opens" }
// set_scenario_value
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "scenarioId": "vs_b2",
  "nodeId": "pin", "fieldId": "pin", "value": "0000" }
// set_scenario_expected_outcome
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "scenarioId": "vs_b2", "outcome": "Account locked for 30 min" }

Tip: set_scenario_expected_note adds a free-form per-screen expectation (e.g. "lockout banner is red") that shows read-only during guided runs.

5. Build a regression suite

You: "Create a PIN regression suite containing both scenarios, in that order."

// create_suite
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "name": "PIN regression" }
// result
{ "suiteId": "suite_77" }
// set_suite_scenarios
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteId": "suite_77",
  "scenarioIds": ["vs_a1", "vs_b2"] }
// result
{ "suiteId": "suite_77", "scenarioIds": ["vs_a1", "vs_b2"] }

Every id in scenarioIds must exist — an unknown id is rejected before anything is saved.

6. Start a suite run against a build

You: "Start a run of the PIN regression suite on staging, build 1.4.0, dated today."

// start_suite_run
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteId": "suite_77",
  "environment": "staging", "buildVersion": "1.4.0", "testDate": "2026-06-19" }
// result
{ "suiteRunId": "sr_01" }

The run starts with one untested result per suite scenario.

7. Record results

You: "Correct PIN passed. Wrong PIN three times failed — it opened the cell instead of locking out."

// set_suite_result
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteRunId": "sr_01",
  "scenarioId": "vs_a1", "status": "pass" }
// set_suite_result
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteRunId": "sr_01",
  "scenarioId": "vs_b2", "status": "fail", "assignee": "qa@example.com" }

You: "How's the run looking?"

// get_suite_run
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteRunId": "sr_01" }
// result (trimmed)
{
  "id": "sr_01", "suiteId": "suite_77", "environment": "staging",
  "buildVersion": "1.4.0", "testDate": "2026-06-19",
  "results": [
    { "scenarioId": "vs_a1", "status": "pass" },
    { "scenarioId": "vs_b2", "status": "fail",
      "assignee": { "id": "qa@example.com", "name": "qa@example.com" } }
  ],
  "summary": { "total": 2, "pass": 1, "fail": 1, "passRate": 0.5, "done": true, "progress": 1 }
}

8. File a bug on the failure

You: "File a high-severity bug for the failure, tagged to this run and build."

// file_bug
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d",
  "title": "Wrong PIN x3 opens the cell instead of locking out",
  "expected": "Account locked for 30 min", "actual": "Cell opened",
  "severity": "high", "status": "open",
  "suiteRunId": "sr_01", "buildVersion": "1.4.0", "valueSetId": "vs_b2" }
// result
{ "bugId": "bug_91" }

9. Finish the run

You: "Mark the run finished."

// finish_suite_run
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteRunId": "sr_01" }
// result
{ "suiteRunId": "sr_01", "finishedAt": "2026-06-19T17:42:03.118Z" }

10. Read analytics

You: "Show me the pass-rate trend for the PIN regression suite."

// get_suite_analytics
{ "projectId": "proj_8f2a", "flowId": "flow_1c7d", "suiteId": "suite_77" }
// result
{
  "byBuild":   [{ "label": "1.4.0", "passRate": 0.5, "total": 2 }],
  "byRelease": [{ "label": "(no release)", "passRate": 0.5, "total": 2 }],
  "latestFailing": [{ "scenarioId": "vs_b2", "status": "fail" }]
}

After the next build, start another run with buildVersion: "1.4.1", record results, and byBuild grows into a trend you can chart.


Management guide

How a QA lead runs and tracks cycles through the assistant.

Running a cycle

  1. Pick / build the suite — create_suite + set_suite_scenarios, or duplicate_suite to fork an existing one and tweak its scenario list.
  2. Start the run — start_suite_run with the environment, buildVersion, and testDate (optionally a release label for grouping releases that span several builds).
  3. Execute — for each scenario, record set_suite_result with pass, fail, blocked, skipped, or retest, and an optional assignee. Open a bug on failures with file_bug (tag suiteRunId + buildVersion so it shows up under the run).
  4. Close — finish_suite_run stamps finishedAt.

The agent records manual outcomes via set_suite_result. Stepping a flow card-by-card in the player (and capturing a full Run) stays in the UI — see "what's intentionally not exposed" in the reference.

Tracking progress

  • list_suite_runs (optionally suiteId-filtered) returns each run's summary: total, per-status counts, passRate, and progress (0→1, how many scenarios have a non-untested result). Ask "which runs are still in progress?" and the assistant filters on progress < 1 / done === false.
  • get_suite_run drills into a single run's per-scenario results and assignees.
  • list_bugs with a suiteRunId shows exactly the bugs raised in that cycle.

Filtering by build / release & interpreting analytics

  • get_suite_analytics returns two series:
    • byBuild — pass rate per buildVersion. The trend you watch build-over-build; a dip flags a regression.
    • byRelease — pass rate per release label (runs with no release fall under "(no release)"). Use this to roll several builds up into one release.
  • latestFailing lists the scenarios that failed in the most recent run — your "fix these first" list. Each entry pairs with the bug you filed via file_bug (matched on suiteRunId).
  • To compare environments, start separate runs per environment (e.g. staging vs production) and read each run's summary.

Safety notes

See Driving the tool with MCP → Safety notes.