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:
- Sign in to the web app and create an MCP access token in your profile.
- Add the hosted endpoint to your assistant with the token as a bearer header (see the "Remote / hosted MCP" section of the setup reference).
- Start your session by asking the assistant to "list my workspaces and select
the
one" — this runslist_workspacesthenselect_workspaceso 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
- Start the app/API:
npm run dev(serves the REST API onhttp://127.0.0.1:8787). - Pick the workspace to author in: open it in the web app, or ask the assistant to select it (which workspace a session uses).
- 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_noteadds 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
- Pick / build the suite —
create_suite+set_suite_scenarios, orduplicate_suiteto fork an existing one and tweak its scenario list. - Start the run —
start_suite_runwith theenvironment,buildVersion, andtestDate(optionally areleaselabel for grouping releases that span several builds). - Execute — for each scenario, record
set_suite_resultwithpass,fail,blocked,skipped, orretest, and an optionalassignee. Open a bug on failures withfile_bug(tagsuiteRunId+buildVersionso it shows up under the run). - Close —
finish_suite_runstampsfinishedAt.
The agent records manual outcomes via
set_suite_result. Stepping a flow card-by-card in the player (and capturing a fullRun) stays in the UI — see "what's intentionally not exposed" in the reference.
Tracking progress
list_suite_runs(optionallysuiteId-filtered) returns each run'ssummary:total, per-status counts,passRate, andprogress(0→1, how many scenarios have a non-untestedresult). Ask "which runs are still in progress?" and the assistant filters onprogress < 1/done === false.get_suite_rundrills into a single run's per-scenario results and assignees.list_bugswith asuiteRunIdshows exactly the bugs raised in that cycle.
Filtering by build / release & interpreting analytics
get_suite_analyticsreturns two series:byBuild— pass rate perbuildVersion. The trend you watch build-over-build; a dip flags a regression.byRelease— pass rate perreleaselabel (runs with no release fall under"(no release)"). Use this to roll several builds up into one release.
latestFailinglists the scenarios that failed in the most recent run — your "fix these first" list. Each entry pairs with the bug you filed viafile_bug(matched onsuiteRunId).- To compare environments, start separate runs per
environment(e.g.stagingvsproduction) and read each run's summary.