# Test Maze — full reference for AI assistants Source: https://testmaze.com/ · Generated 2026-09-16 from the live MCP tool registry. Test Maze is the verifier for AI coding agents. It connects to Claude Code, Cursor, Cline, Gemini CLI, Codex CLI and any Model Context Protocol (MCP) client. The coding agent writes the code and runs the tests; Test Maze keeps the features, user stories and test cases, records every test result against the exact git commit, and returns a deterministic pass/fail verdict computed by fixed rules (never by an AI). It also offers exploratory testing with the agent's own browser, coverage gap analysis, regression baselines, acceptance-criterion waivers and code-quality checks. Test Maze never clones or scans the repository. - Connect: create an MCP token in a Test Maze workspace, run `npx -y @testmaze/mcp init ` in the project folder (stores the token in .env.testmaze, git-ignored), then `claude mcp add tm --scope project -- npx -y @testmaze/mcp`. - The build → verify loop: project.initialize → feature.implement → feature.verify → testrun.create / testrun.record_results → pdlc.verify. - Verdicts: "pass" (at least one case passed and none failed), "fail" (a case failed, or a frozen regression-baseline case is missing or failing) or "in-progress". Waived acceptance criteria are excluded. nextStep says ship, repair_code, repair_test or add_coverage. - Data: Test Maze receives only what the agent sends in tool calls — test artefacts, run results, git identifiers (sha, branch, clean working tree), optional screenshots, and code snippets only for explicit code-quality checks. Every call is visible on the Agent Sessions page of the workspace. - Pricing: free Basic plan; paid plans and AI credits for teams. Bring-your-own AI provider keys are stored AES-256-GCM encrypted. # MCP tools (55) You do not call these tools yourself: you ask your coding agent in plain English and it picks the tools. Kinds: read (only looks things up), write (changes workspace data), workflow (starts a guided multi-step job), verdict (deterministic pass/fail grading). ## Sessions (progress tracker) A session is an optional tracker for one piece of work as it moves plan → write tests → code → verify → ship. Read where a session is and what it expects next. ### Check where a PDLC session is in the loop — `pdlc.status` URL: https://testmaze.com/tools/pdlc-status/ Kind: read Shows which step a PDLC session has reached. A PDLC session is an optional tracker of where you are in the product loop: plan → write tests → code → verify → ship. It is opened by project.initialize and moved forward by feature.implement, feature.verify and pdlc.verify when you pass them its sessionId. Returns `state`: INTAKE (just started), PLAN (feature planned), AUTHOR (writing tests), CODE (writing code), VERIFY (grading), REPAIR (fixing a broken test), SHIP (ready to release) or DONE; plus sessionId, spaceId and updatedAt. `prdId`, `planId` and `currentStep` are reserved and currently always null. Read-only: it never changes the state. Use it to resume after a break and decide which loop tool to call next. Example requests to your agent: - "Where did we get to with the password reset feature?" - "What step of the plan-test-code-ship loop am I on?" Inputs: - `sessionId` (string, required): PDLC session id, e.g. "pdlc…": the `sessionId` returned by project.initialize, or an `id` from pdlc.list. Must belong to the connected workspace. ### List PDLC sessions — `pdlc.list` URL: https://testmaze.com/tools/pdlc-list/ Kind: read Lists the PDLC sessions in the connected workspace, most recently updated first, up to 50. A PDLC session is an optional tracker of where a piece of work is in the loop: plan → write tests → code → verify → ship; project.initialize opens one. Returns `count` and `sessions` with id, state, planId, prdId (both currently always null) and updatedAt. Use it to find a sessionId you lost, then pass it to pdlc.status or the loop tools. Read-only; takes no parameters. Example requests to your agent: - "What work sessions do I have open in Test Maze?" - "Find the session we started yesterday so we can pick it up again" Inputs: - None. ## Test cases A test case is one check of your app: steps to follow and the result you expect. Create, find, update, archive, delete or waive them here. ### List test cases — `case.list` URL: https://testmaze.com/tools/case-list/ Kind: read Lists the test cases in the connected workspace, 20 per page, sorted by caseId. A test case is one written check of the app: steps to follow and the result to expect. Call it before case.create or case.create_batch so you do not write duplicates, and to find the case you want to read, update, waive or delete. Each row has two ids: `id` (internal, e.g. "AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi") is what every other tool takes, while `caseId` (e.g. "GenTC-0001") is the human-readable label shown in the app. Returns { items: [{ id, uri, caseId, title, status, acceptanceCriterionLabel, isWaived, severity, automationStatus }], page, totalPages, totalItems }. Both ACTIVE and INACTIVE (archived) cases are listed; there is no status filter. Read-only. Use testcase.get for the steps of one case. Example requests to your agent: - "What test cases do we already have for login?" - "List all the tests in this project" - "Is there already a test for password reset?" Inputs: - `title` (string, optional): Case-insensitive text matched against the title OR the human caseId, e.g. "checkout" or "GenTC-0012". Omit to list everything. - `page` (integer, optional): Page number, starting at 1 (default 1). Each page holds up to 20 cases; check totalPages in the result. ### Get one test case — `testcase.get` URL: https://testmaze.com/tools/testcase-get/ Kind: read Reads one test case in full: title, description, pre-condition, steps (in order), expected result, post-condition, priority, status, acceptance-criterion label, waiver details (isWaived, waivedReason, waivedBy, waivedAt), severity, automationStatus, the stored Playwright script if any (playwrightSnippet), the last recorded verdict (lastVerdict, lastVerdictAt) and its tags. Use it before case.update so you can resend the full step list, or to show a user what a test actually checks. Takes the internal `id` from case.list, not the human caseId. Read-only; a case from another workspace is refused. Example requests to your agent: - "Show me the steps of the checkout test" - "What exactly does GenTC-0004 check?" - "Open the password reset test case" Inputs: - `caseId` (string, required): Internal test case id: the `id` field from case.list (e.g. "AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"). Despite the parameter name, this is NOT the human caseId like "GenTC-0001"; passing that returns "not found". ### Create a test case — `case.create` URL: https://testmaze.com/tools/case-create/ Kind: write Creates one test case in the connected workspace: a written check of the app with steps to follow and the result to expect, for example "Guest can check out without an account". Call case.list first to avoid duplicates; to create several cases, or to file them under a feature, use case.create_batch instead (this tool does not attach the case to any feature). At least one step is required (via `steps` or `stepPosition`), otherwise the call fails with "Missing Steps". A human-readable caseId such as "GenTC-0007" is assigned for you. Returns { success, message, data: { id }, uri }; keep `data.id`, the internal id every other tool takes. Next, include it in a run with testrun.create or in a plan with testplan.create. Example requests to your agent: - "Write a test case for signing up with an email address" - "Add a test that checks a guest can check out without an account" - "Create a test for the password reset email" Inputs: - `title` (string, required): Short name of what is being checked, e.g. "Guest can check out without an account". - `description` (string, optional): Optional longer explanation of the scenario and why it matters, in plain language. - `priority` (enum, optional) — one of: P0, P1, P2, P3: How important the case is. P0 = must never break (core flow), P1 = high, P2 = normal, P3 = trivial. - `preCondition` (string, optional): System state required BEFORE the test runs (auth, seed data, feature flags). Concrete enough that a reader can reproduce the starting state, e.g. "Logged out; cart contains 1 item". - `expectedResult` (string, optional): The observable result a tester checks at the end of the steps — final URL, success/error message, key field on the entity. One concise sentence, e.g. "Order confirmation page shows an order number". - `postCondition` (string, optional): System state AFTER the test completes — what persisted, what side-effects fired (emails, queue messages, webhooks), what needs cleanup. Distinct from expectedResult: this is the system snapshot, not the UI assertion. Set to "No persistent state change." when the test is read-only. - `steps` (string[], optional): The steps in order, one plain instruction per string, e.g. ["Open /cart", "Click Checkout", "Choose Continue as guest", "Submit the payment form"]. Positions are numbered from 0 for you. Ignored when stepPosition is given. Send steps or stepPosition: a case with no steps is refused. - `stepPosition` (object[], optional): Alternative to `steps` when you want to set positions yourself: [{ "stepText": "Open /cart", "position": 0 }, { "stepText": "Click Checkout", "position": 1 }]. Takes precedence over `steps`. Most callers should just use `steps`. - `tagData` (any[], optional): Optional custom tags to attach. Each item is { "tagId": "", "id": "" }, e.g. [{ "tagId": "AAct-…", "id": "AActv-…" }] for Module = Checkout. Items without tagId are skipped. The ids come from the custom tags set up in the Test Maze app; no MCP tool lists them today, so omit this unless the user gives you the ids. - `status` (enum, optional) — one of: ACTIVE, INACTIVE: TestCase lifecycle status. ACTIVE is the default and means the case is part of the library and can be added to suites/runs. INACTIVE soft-archives the case — listings and joins skip it but data isn't deleted. Anything else gets rejected; the listing queries only filter on these two values. - `acceptanceCriterionLabel` (string, optional): Set when this case proves one acceptance criterion (AC) of a feature — one testable promise the feature makes, like "a guest can check out without an account". Use the AC's label, e.g. "AC1" or "AC3.2". Only cases with a label can be waived with case.waive_ac. - `severity` (enum, optional) — one of: blocker, critical, major, minor, trivial: How bad it is for users if this check fails: blocker (app unusable / release must stop), critical (core feature broken), major (important but has a workaround), minor, trivial (cosmetic). Defaults to "major". Stored for people reading the case; pdlc.verify does not weight failures by severity today. - `automationStatus` (enum, optional) — one of: manual, planned, automated, flaky, deprecated: Whether the case has an automated (Playwright) script. manual = checked by hand, no script (default); planned = script not written yet; automated = has a runnable script; flaky = script sometimes fails for reasons unrelated to the app and needs fixing; deprecated = script no longer maintained. A label only. ### Update a test case — `case.update` URL: https://testmaze.com/tools/case-update/ Kind: write Changes an existing test case, for example to fill in the steps and expected result of a draft, or to archive it with status INACTIVE. Get the internal `id` from case.list (read the case with testcase.get if you need its current content). Send only what you want to change: every field you leave out keeps its stored value, including the steps, the human caseId label (e.g. "GenTC-0001"), the owner and the creator. If you send `steps`, that list replaces all existing steps, so include the unchanged ones too. Returns { success, message, data } with the updated fields. Example requests to your agent: - "Fill in the missing steps for the checkout test" - "Change the expected result of the login test to show the dashboard" - "Archive the old coupon test, we removed that feature" Inputs: - `caseId` (string, required): Internal test case id: the `id` field from case.list (e.g. "AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"). Despite the parameter name, this is NOT the human caseId like "GenTC-0001". - `title` (string, optional): New title, e.g. "Guest can check out without an account". Omit to keep the current title. - `description` (string, optional): New longer explanation of the scenario. Omit to keep the current one. - `priority` (enum, optional) — one of: P0, P1, P2, P3: How important the case is. P0 = must never break (core flow), P1 = high, P2 = normal, P3 = trivial. Omit to keep. - `preCondition` (string, optional): Same as on case.create. System state required BEFORE the test runs. Omit to keep. - `expectedResult` (string, optional): Same as on case.create. The observable assertion at the end of the steps. Omit to keep. - `postCondition` (string, optional): Same as on case.create. System state AFTER completion — persistence + side-effects. Required for CI hygiene; declare "No persistent state change." for read-only cases. - `steps` (string[], optional): The COMPLETE step list in order, one instruction per string, e.g. ["Open /login", "Enter email and password", "Click Sign in"]. It replaces all existing steps. Omitting it deletes the current steps, so resend them (from testcase.get) even when you only change another field. - `status` (enum, optional) — one of: ACTIVE, INACTIVE: ACTIVE = in the library and usable in suites and runs. INACTIVE = archived: hidden from pickers but not deleted. The safe alternative to case.delete. Omit to keep. - `severity` (enum, optional) — one of: blocker, critical, major, minor, trivial: How bad a failure would be: blocker, critical, major, minor, trivial (see case.create). Omit to keep. - `automationStatus` (enum, optional) — one of: manual, planned, automated, flaky, deprecated: Automation label: manual, planned, automated, flaky, deprecated (see case.create). Omit to keep. ### Create several test cases at once — `case.create_batch` URL: https://testmaze.com/tools/case-create-batch/ Kind: write Creates up to 200 test cases in one call and can file them all under a feature or user story. Use it when you turn a feature's acceptance criteria into tests (an acceptance criterion, AC, is one testable promise the feature makes) or when saving the drafts from exploration.to_cases. Call case.list first to avoid duplicates. Each case is created on its own, not all-or-nothing: a bad body does not stop the others. A unique human caseId (e.g. "GenTC-0012") is assigned to each case, even when other writers create cases at the same time. Returns { success, message, data: { created: [{ id }], failed: [{ index, title, error }] } }; success is true only when nothing failed. Fix and resend only the failed bodies (index points into `bodies`). Next, run the cases with testrun.create. Example requests to your agent: - "Write test cases for every acceptance criterion of the checkout feature" - "Save these exploration drafts as test cases under the login feature" - "Create tests for the password reset flow: happy path, expired link and wrong email" Inputs: - `suiteId` (string, optional): Optional id of the feature, sub-feature or user story to file every created case under (the `id` from feature.list, feature.create or userstory.create, e.g. "AAts-…"). Cases are appended after the ones already there. Omit to create unfiled cases. - `bodies` (any[], required): The cases to create, 1 to 200. Each body takes the same fields as case.create: title (required), steps (required: an array of strings, or stepPosition [{ "stepText", "position" }]; a body without steps fails with "Missing Steps"), and optional description, preCondition, expectedResult, postCondition, priority (P0-P3), status (ACTIVE/INACTIVE, default ACTIVE), acceptanceCriterionLabel, severity, automationStatus, tagData [{ "tagId", "id" }]. Leave caseId out; it is assigned. Example: [{ "title": "AC1: guest checkout succeeds", "acceptanceCriterionLabel": "AC1", "priority": "P0", "steps": ["Open /cart", "Click Checkout", "Choose Continue as guest", "Pay with test card 4242 4242 4242 4242"], "expectedResult": "Order confirmation page shows an order number" }]. ### Waive an acceptance criterion — `case.waive_ac` URL: https://testmaze.com/tools/case-waive-ac/ Kind: write Marks an acceptance-criterion test case as waived: a deliberate, recorded decision that this promise does not have to be proven for now (for example "Apple Pay is out of scope for the beta"). An acceptance criterion (AC) is one testable promise a feature makes, like "a guest can check out without an account". A reason is required because a waiver is an exception someone must be able to review later: the reason is stored with who waived it and when (waivedReason, waivedBy, waivedAt). Only cases with an acceptanceCriterionLabel can be waived; others return success: false. pdlc.verify leaves waived cases out of grading: a waived case that fails in a run does not fail the verdict (it is counted under `waived`) and is not treated as a regression-baseline break. Only waive when the user agrees; undo with case.unwaive_ac. Returns { success, message, data } with the updated case. Example requests to your agent: - "We are skipping the Apple Pay criterion for the beta, mark it as waived" - "Waive AC3 on checkout, the legal team said it is not needed yet" - "Accept that the export-to-PDF criterion is out of scope for this release" Inputs: - `caseId` (string, required): Internal test case id: the `id` from case.list (e.g. "AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"), not the human caseId like "GenTC-0001". The case must have an acceptanceCriterionLabel. - `reason` (string, required): Why this criterion is being waived, 1 to 2000 characters, specific enough for a reviewer, e.g. "Apple Pay is out of scope for the beta; revisit before GA (agreed with product on 2026-09-15)". ### Delete a test case — `case.delete` URL: https://testmaze.com/tools/case-delete/ Kind: write Permanently deletes one test case. This cannot be undone. Use it to clean up duplicates or drafts nobody wants. It is refused when the case has history: if it was ever part of a test run ("Test case is already used in test run") or is filed under a feature or suite ("Deletion failed. Test case is already in use."). To retire a case that has history, archive it instead with case.update and status INACTIVE (resend its steps). Takes the internal `id` from case.list. Returns { success, message }. For many ids at once use case.delete_batch. Example requests to your agent: - "Delete that duplicate login test you just made" - "Remove the test case for the old coupon page" - "Get rid of GenTC-0031, it was a mistake" Inputs: - `caseId` (string, required): Internal test case id: the `id` from case.list (e.g. "AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"), not the human caseId like "GenTC-0001". ### Delete several test cases — `case.delete_batch` URL: https://testmaze.com/tools/case-delete-batch/ Kind: write Permanently deletes up to 200 test cases in one call. This cannot be undone. Same rules as case.delete for each id: a case that was ever part of a test run, or is filed under a feature or suite, is refused (archive those with case.update and status INACTIVE instead), and ids from another workspace are refused. One failure does not stop the rest. Returns { success, message, deleted, failed, results: [{ id, success, message? }] }; success is true only when every id was deleted. Confirm the list with the user before calling. Example requests to your agent: - "Clean up all the duplicate test cases you created" - "Delete these five draft tests" - "Remove every test case for the feature we dropped" Inputs: - `caseIds` (string[], required): Internal test case ids to delete, 1 to 200: the `id` values from case.list, e.g. ["AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"], not human caseIds like "GenTC-0001". ### Remove a waiver — `case.unwaive_ac` URL: https://testmaze.com/tools/case-unwaive-ac/ Kind: write Undoes case.waive_ac: the acceptance criterion (a testable promise the feature makes) must be proven again. Clears isWaived, waivedReason, waivedBy and waivedAt on the case. Use it when a waived item comes back into scope. Takes the internal `id` from case.list (cases with isWaived: true are the waived ones). Returns { success, message, data, unwaivedBy }. Example requests to your agent: - "Apple Pay is back in scope, remove the waiver" - "Un-waive the export criterion on checkout" - "We need to test AC3 again after all" Inputs: - `caseId` (string, required): Internal test case id: the `id` from case.list (e.g. "AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"), not the human caseId like "GenTC-0001". ## Test runs A test run records the results of running a set of test cases against a specific version of your code (git commit and branch). Create runs, record pass/fail per case and read them back. ### List test runs — `testrun.list` URL: https://testmaze.com/tools/testrun-list/ Kind: read Lists the test runs in the connected workspace, newest first, 20 per page, optionally filtered by name. A test run is one execution of a set of test cases, with a Pass / Fail / Not Executed result per case. Use it to find a recent run to grade with pdlc.verify, or to decide whether a fresh run is needed. Returns { items: [{ id, uri, name, status, verdict, gitSha, branch, workingTreeClean, releaseId, pdlcSessionId, startDate, endDate }], page, totalPages, totalItems }. `status` is the run's lifecycle (e.g. ACTIVE), not its outcome. `verdict` is a count summary { passed, failed, blocked, skipped, pending, total, passRate } (passRate is 0-100, or null when nothing was executed), not a ship decision; call pdlc.verify for the deterministic pass/fail verdict. Read-only. Example requests to your agent: - "Did the last test run pass?" - "Show me the recent test runs" - "Find the run we did for the checkout release" Inputs: - `title` (string, optional): Case-insensitive text to look for in the run name, e.g. "checkout". Omit to list all runs. - `page` (integer, optional): Page number, starting at 1 (default 1). Each page holds up to 20 runs, newest first; check totalPages. ### Get one test run — `testrun.get` URL: https://testmaze.com/tools/testrun-get/ Kind: read Reads the summary of one test run in the connected workspace: { id, uri, name, buildVersion, description, startDate, endDate, status, gitSha, branch, workingTreeClean, releaseId, frozen, numberOfTestCases }. A run from another workspace is reported as not in the active space. It does not include per-case results or a pass/fail decision; for those call pdlc.verify with the same testRunId (read-only, deterministic). Get the id from testrun.list or from the testrun.create result. Read-only. Example requests to your agent: - "How many tests were in yesterday's run?" - "Show me the details of the release 2.0 test run" - "What build did the last run test?" Inputs: - `testRunId` (string, required): Test run id: the `id` from testrun.list or testrun.create (e.g. "AAtr-kzqd-mwpe-rtya-hbnc-xufo-lgsi"). ### Record test results on a run — `testrun.record_results` URL: https://testmaze.com/tools/testrun-record-results/ Kind: write Saves the outcome of each test case onto a test run that already exists: Pass, Fail or Not Executed, plus optional details (what actually happened, the error text, a note, a screenshot). Use it after testrun.create was called without results and the tests have since been carried out (by you, an external runner or a person). Each case must already be part of the run. Each row is saved on its own: one bad row does not stop the rest, and fields you leave out keep their current values. Every recorded row is stamped with you as executor and the current time. Returns { success, message, updated, failed, results: [{ caseId, success, message?, affected?, mediaId?, evidenceWarning? }] }. NEXT: call pdlc.verify({ testRunId }) to get the deterministic verdict (pass / fail / in-progress) and the recommended next step. Example requests to your agent: - "I ran the checkout tests: 4 passed, the coupon one failed. Record that" - "Save the Playwright results to the test run" - "Mark the login test as failed with this screenshot" Inputs: - `testRunId` (string, required): The run to record onto: the `id` returned by testrun.create or listed by testrun.list (e.g. "AAtr-kzqd-mwpe-rtya-hbnc-xufo-lgsi"). Must belong to the connected workspace. - `results` (object[], required): One entry per test case, 1 to 500. Example: [{ "caseId": "AAtc-kzqd-…", "status": "Pass" }, { "caseId": "AAtc-mwpe-…", "status": "Fail", "actualResult": "No confirmation page", "issues": "Timeout 5000ms exceeded waiting for locator('#pay')" }]. ### Create a test run — `testrun.create` URL: https://testmaze.com/tools/testrun-create/ Kind: write Creates a test run: one execution of a chosen set of test cases, where each case gets a result (Pass, Fail or Not Executed). Two ways to use it: (a) you already ran the tests, so pass `runTestCaseList` with each case's result, then call pdlc.verify; or (b) schedule first with `runTestCaseSelection` (or runTestCaseList without statuses), run the tests, then call testrun.record_results, then pdlc.verify. Get test case ids from case.list. Run names must be unique in the workspace. If the workspace has regression baselines (runs frozen with regression.freeze_run), include their cases too: pdlc.verify fails a run that is missing them. Pass the git fields (gitSha, branch, workingTreeClean) when grading code for the verifier loop; all three or none. They tie the verdict to the exact code that was tested, so a pass cannot be mistaken for approval of different or uncommitted code; they are stored on the run and returned by testrun.get, testrun.list and pdlc.verify. Returns { success, message, id, uri }; `id` is the testRunId for the next tool. Example requests to your agent: - "Run the checkout tests against my current commit and tell me if it is ready to ship" - "Record a test run for release 2.0 with these results" - "Set up a test run with all the login test cases" Inputs: - `name` (string, required): Run name, unique within the workspace, e.g. "Checkout verify 2026-09-15 a1b2c3d". A name that already exists is refused; including the date or short commit SHA avoids clashes. - `description` (string, optional): Optional note on what this run covers, e.g. "Guest checkout after the payment form refactor". - `buildVersion` (string, optional): Optional version or build label of the app under test, e.g. "1.4.0" or "build 512". - `startDate` (string, optional): Optional date/time the run starts, ISO 8601, e.g. "2026-09-15" or "2026-09-15T10:00:00Z". - `endDate` (string, optional): Optional date/time the run ends, ISO 8601, e.g. "2026-09-15T10:20:00Z". - `releaseId` (string, optional): Optional id of the release this run belongs to (the `id` from release.list or release.create). - `gitSha` (string, optional): Full 40-character commit SHA of the code under test, from `git rev-parse HEAD`, e.g. "a1b2c3d4e5f60718293a4b5c6d7e8f9012345678". Requires branch and workingTreeClean too. - `branch` (string, optional): Git branch of the code under test, from `git rev-parse --abbrev-ref HEAD`, e.g. "feature/guest-checkout". Requires gitSha and workingTreeClean too. - `workingTreeClean` (boolean, optional): true when there were no uncommitted changes while testing (`git status --porcelain` prints nothing), false otherwise. false means the tested code may differ from gitSha. Requires gitSha and branch too. - `runTestCaseList` (object[], optional): The test cases in the run, with optional results. Example: [{ "id": "AAtc-kzqd-…", "status": "Pass" }, { "id": "AAtc-mwpe-…", "status": "Fail", "issues": "Timeout 5000ms exceeded waiting for locator('#pay')" }]. Send this or runTestCaseSelection (one is required; if both are sent, runTestCaseSelection wins and these results are ignored). - `runTestCaseSelection` (object, optional): Schedule cases without results: { "selectedIds": ["AAtc-kzqd-…", "AAtc-mwpe-…"] }. Every case starts as not executed; record outcomes later with testrun.record_results. Takes precedence over runTestCaseList. ## Product & connection Your workspace describes one product: its vision, the problem it solves and who it's for. Check which workspace this connection is using, and read or update that description. ### Check which workspace this connection uses — `project.whoami` URL: https://testmaze.com/tools/project-whoami/ Kind: read Tells you which Test Maze workspace this connection reads from and writes to, which user your changes are credited to, and which access token was used. A workspace holds one product: its features, test cases, test runs, releases and metrics. Call this FIRST in a new session, and again whenever you are unsure (after switching project folders or re-running `npx @testmaze/mcp init`). Show the workspace name to the user and get a yes before creating or changing anything, because every write lands in this workspace. Returns `space` {id, name, description, lifecycleStage, repoUrl, defaultBranch, uri}, `user` {id, name, email}, `token` {id, name} (null when no token was used) and a one-line `hint`. If `space.name` is null the workspace could not be loaded (the token may belong to a deleted workspace). Read-only. Next: product.get for the full product context. Example requests to your agent: - "Which Test Maze workspace am I connected to?" - "Before you add anything, check you are pointed at the right project" - "Who will these changes show up as?" Inputs: - None. ### Get the product details for this workspace — `product.get` URL: https://testmaze.com/tools/product-get/ Kind: read Reads the product description stored on the connected workspace. In Test Maze the "product" is the workspace itself, so there is exactly one per connection and no id to pass. Use it at the start of planning work (writing features, user stories or test cases) so you know what the app is for and who uses it. Returns id, name, description, vision, problemStatement, targetUsers, productOwnerId, lifecycleStage (discovery, beta, live or sunset), launchedAt, sunsetAt, defaultBranch, repoUrl and status. Empty fields come back null. Read-only. If the key fields are empty, fill them in with product.update (or project.initialize to draft them from the repo). Example requests to your agent: - "What does Test Maze know about my app so far?" - "Load the product context before we plan the next feature" Inputs: - None. ### Update the product details for this workspace — `product.update` URL: https://testmaze.com/tools/product-update/ Kind: write Edits the product description stored on the connected workspace (the "product" is the workspace itself). Pass only the fields you want to change; anything you leave out stays as it is. Typical use: after reading the repo or talking to the user, record the vision, the problem the app solves, who it is for and where it stands (lifecycleStage). Call project.whoami first to confirm you are editing the right workspace, and product.get to see the current values. Setting `name` renames the workspace for everyone; if that name is already taken nothing is saved and you get success: false with a message. Setting launchedAt or sunsetAt to an empty string clears the date. Returns {success, message, data: the saved workspace, uri}. Example requests to your agent: - "Save this product vision and target audience to Test Maze" - "Mark the app as in beta" - "Set the repo URL and default branch for this project" Inputs: - `name` (string, optional): New workspace name, shown to everyone in the workspace. Example: "Recipe Box". Must not already be in use. - `description` (string, optional): One or two sentences on what the app is. Example: "A web app for saving and sharing family recipes." - `vision` (string, optional): Where the product is heading, in a sentence or two. Example: "Every family cookbook, online and searchable." - `problemStatement` (string, optional): The user problem the app solves. Example: "Handwritten recipes get lost and are hard to share." - `targetUsers` (string, optional): Who the app is for, as free text. Example: "Home cooks and families who share recipes across generations." - `productOwnerId` (string, optional): User id of the person who owns product decisions. Your own id is `user.id` from project.whoami. - `lifecycleStage` (enum, optional) — one of: discovery, beta, live, sunset: Where the whole product stands. discovery = still exploring the idea, not built for real users yet; beta = usable by early users, still changing; live = generally available (the default for new workspaces); sunset = being wound down. - `launchedAt` (string, optional): When the product launched, as an ISO 8601 date or date-time. Example: "2026-03-01". Empty string clears it. - `sunsetAt` (string, optional): When the product was or will be retired, as an ISO 8601 date or date-time. Example: "2027-01-31". Empty string clears it. - `defaultBranch` (string, optional): Main git branch of the app repository. Example: "main". - `repoUrl` (string, optional): Git repository URL of the app. Example: "https://github.com/acme/recipe-box" or "git@github.com:acme/recipe-box.git". ## Features & user stories Describe what you're building: features, smaller sub-features and user stories ("as a …, I want …, so that …"). Each is stored as a test suite that holds the test cases proving it works. ### List features and user stories — `feature.list` URL: https://testmaze.com/tools/feature-list/ Kind: read Lists the features, sub-features, user stories and regression suites in the connected workspace. In Test Maze all four are stored as test suites (a named group of test cases), told apart by `type`: feature = a capability of the product ("Checkout"); sub-feature = a smaller part of a feature ("Apply a coupon"); user-story = one user need inside a feature, written as "As a ..., I want ..., so that ..."; regression = a plain group of tests with no product meaning. Call this before feature.create or userstory.create so you do not create duplicates, and to find the `id` other tools need. Returns 20 rows per page, newest first: {items: [{id, uri, title, type, description, lifecycleStage, parentFeatureId, releaseId}], page, totalPages, totalItems}. Read-only. Example requests to your agent: - "What features do we already have in Test Maze?" - "Is there already a feature for checkout?" - "Show me the user stories we have written" Inputs: - `type` (enum, optional) — one of: feature, sub-feature, user-story, regression: Only return one kind. feature = product capability; sub-feature = part of a feature; user-story = one user need under a feature; regression = plain test group. Omit to list all kinds. - `title` (string, optional): Case-insensitive text to match anywhere in the title. Example: "checkout" also matches "Guest Checkout". - `page` (integer, optional): Page number, starting at 1 (default 1). Each page holds 20 rows; use totalPages from the result to know when to stop. ### Create a feature — `feature.create` URL: https://testmaze.com/tools/feature-create/ Kind: write Creates a feature: a named capability of the product, such as "Checkout" or "Password reset". It is stored as a test suite with type=feature, so test cases can be attached to it later. Call project.whoami first to confirm the workspace, and feature.list with a title filter to make sure it does not already exist: titles must be unique across all suites in the workspace (exact match), and a duplicate returns an error. A new feature starts in lifecycle stage "authoring". Returns the saved suite plus `suiteId` (also as `id`), `uri` and `nextSteps`. Next: add test cases with case.create_batch using that suiteId (cases created without it are not attached to the feature), add user stories with userstory.create, or track success with featuremetric.create. Note: passing parentFeatureId records the parent but the new suite is still type=feature, not sub-feature. Example requests to your agent: - "Add a feature for guest checkout" - "Create a Password reset feature and write its tests" - "Set up a feature for the new search page, planned for the June release" Inputs: - `title` (string, required): Feature name, short and unique in the workspace. Example: "Guest checkout". - `description` (string, optional): What the feature does and why, in plain words. Example: "Lets shoppers pay without creating an account." Defaults to empty. - `priority` (enum, optional) — one of: P0, P1, P2, P3: How important it is. P0 = critical, must ship; P1 = high; P2 = normal (default); P3 = nice to have. - `parentFeatureId` (string, optional): Optional id of a bigger feature this one belongs to (the `id` from feature.list). Stored as a link only; the type stays feature. - `featureOwnerId` (string, optional): User id of the person responsible for the feature. Your own id is `user.id` from project.whoami. - `releaseId` (string, optional): Id of the release, sprint or milestone this feature is planned for (the `id` from release.list). Not checked for existence. - `targetReleaseDate` (string, optional): Date the feature should ship, as YYYY-MM-DD. Example: "2026-06-30". - `rolloutPercentage` (number, optional): Share of users who get the feature, 0 to 100. Example: 25 for a gradual rollout to a quarter of users. Informational only. - `featureFlagKey` (string, optional): Key of the feature flag that switches this feature on in your app, if you use one. Example: "guest-checkout". Informational only. ### Create a user story under a feature — `userstory.create` URL: https://testmaze.com/tools/userstory-create/ Kind: write Creates a user story: one specific thing a user needs from a feature, written in three parts. Example for a "Checkout" feature: asA "returning shopper", iWant "to pay with a saved card", soThat "I can check out in one click". It is stored as a test suite with type=user-story under its parent feature, so the tests that prove the story works can be attached to it. Find or create the parent first (feature.list, feature.create) and pass its id as parentFeatureId. Titles must be unique across all suites in the workspace. A new story starts in lifecycle stage "authoring". Returns the saved suite plus `suiteId` (also as `id`), `uri` and `nextSteps`. Next: call case.create_batch with that suiteId to add its acceptance criteria as test cases (an acceptance criterion is one testable promise, like "a saved card is charged without re-entering the number"). Example requests to your agent: - "Write a user story for paying with a saved card" - "Break the checkout feature into user stories" - "As a shopper I want to track my order, add that as a story" Inputs: - `title` (string, required): Short story name, unique in the workspace. Example: "Pay with a saved card". - `description` (string, optional): Extra detail or context for the story. Defaults to empty. - `parentFeatureId` (string, required): Id of the feature (or sub-feature) this story belongs to: the `id` or `suiteId` from feature.list or feature.create. - `asA` (string, required): Who the user is (the "As a ..." part). Example: "returning shopper". - `iWant` (string, required): What they want to do (the "I want ..." part). Example: "to pay with a saved card". - `soThat` (string, required): Why it matters to them (the "so that ..." part). Example: "I can check out in one click". - `storyPoints` (integer, optional): Rough size of the work, a whole number from 1 (tiny) to 13 (large). Teams often use 1, 2, 3, 5, 8, 13. Optional. - `assigneeId` (string, optional): User id of the person building the story. Your own id is `user.id` from project.whoami. - `priority` (enum, optional) — one of: P0, P1, P2, P3: How important it is. P0 = critical, must ship; P1 = high; P2 = normal (default); P3 = nice to have. ### Move a feature or story to a new stage — `feature.set_lifecycle` URL: https://testmaze.com/tools/feature-set-lifecycle/ Kind: write Records where a feature, sub-feature or user story is in its life. The stages, in usual order: authoring = being written up and planned (every new feature and story starts here); in-progress = being built; verifying = built, tests are being run against it; live = released to users; deprecated = retired or replaced. Any stage can be set from any other; nothing is checked or triggered automatically, so move it when the real work moves (for example to verifying when coding is done, to live after the release ships). The suite must belong to the connected workspace. Returns {success, message, data: the updated suite}. Get the id from feature.list. Example requests to your agent: - "Checkout is built, mark it as being verified" - "The saved-card story is live now" - "Retire the old search feature" Inputs: - `suiteId` (string, required): Id of the feature, sub-feature or user story (the `id` from feature.list). - `stage` (enum, required) — one of: authoring, in-progress, verifying, live, deprecated: New stage. authoring = being written up; in-progress = being built; verifying = tests being run; live = released to users; deprecated = retired. ### Plan a feature into a release — `feature.set_release` URL: https://testmaze.com/tools/feature-set-release/ Kind: write Links a feature (or user story) to the release, sprint or milestone it is planned to ship in, or removes that link. Use it when the plan changes, for example moving "Guest checkout" from Sprint 23 to Sprint 24. Get the feature id from feature.list and the release id from release.list (create one with release.create if needed). A suite has at most one release; setting a new one replaces the old. Pass releaseId: null to unlink. The feature must belong to the connected workspace; the release id is stored as given and is not checked, so take it from release.list. Returns {success, message, data: the updated suite}. Example requests to your agent: - "Put guest checkout into the June release" - "Move the search feature to next sprint" - "Take password reset out of this release" Inputs: - `suiteId` (string, required): Id of the feature or user story to link (the `id` from feature.list). - `releaseId` (string | null, required): Id of the release, sprint or milestone (the `id` from release.list), or null to remove the link. ## Test plans A test plan is a named bundle of test cases you run together, like a smoke test before every deploy or a full regression pass before a release. ### List test plans — `testplan.list` URL: https://testmaze.com/tools/testplan-list/ Kind: read Lists the test plans in the connected workspace, 20 per page, optionally filtered by name. A test plan is a named bundle of test cases you want to run together, such as a quick smoke check before every deploy or a full regression pass before a release. Call it before testplan.create so you do not create a duplicate (plan names must be unique in the workspace). Returns { items: [{ id, uri, name, description, status, kind, priority }], page, totalPages, totalItems }. Read-only. Example requests to your agent: - "Do we already have a smoke test plan?" - "Show me all the test plans in this project" - "Find the release checklist plan we made last week" Inputs: - `title` (string, optional): Case-insensitive text to look for in the plan name, e.g. "smoke" matches "Checkout smoke". Omit to list all plans. - `page` (integer, optional): Page number, starting at 1 (default 1). Each page holds up to 20 plans; check totalPages in the result. ### Create a test plan — `testplan.create` URL: https://testmaze.com/tools/testplan-create/ Kind: write Creates a test plan: a named, reusable bundle of existing test cases you want to run together (for example a "Checkout smoke" plan with the five most important checkout cases). Call testplan.list first, because a plan with the same name in the workspace is refused, and case.list to get the test case ids to include. Returns { success, message, id, uri } with the new plan id. A plan does not run anything by itself: to execute its cases, pass the same test case ids to testrun.create. Example requests to your agent: - "Group the login and checkout tests into a smoke test plan" - "Create a regression plan with every payment test case" - "Make a release acceptance plan for version 2.0" Inputs: - `name` (string, required): Plan name, unique within the workspace, e.g. "Checkout smoke". A name that already exists is refused. - `description` (string, optional): Optional plain-language note on what the plan covers and when to run it, e.g. "Run before every deploy to production". - `kind` (enum, optional) — one of: smoke, sanity, security, regression, release-acceptance, custom: What kind of bundle this is. smoke = a few fast checks that the app basically works; sanity = a quick check of one area after a change; security = security-focused checks; regression = the broad set that proves nothing that used to work is broken; release-acceptance = the checks a release must pass before shipping; custom = anything else. Defaults to "custom". Used to filter plan listings. - `status` (enum, optional) — one of: ACTIVE, INACTIVE: Lifecycle status. ACTIVE = in use and shown in pickers; INACTIVE = archived, kept but hidden from pickers. When omitted the plan is stored as active. - `priority` (enum, optional) — one of: P0, P1, P2, P3: Optional plan priority, P0 = most important, P3 = least. Returned by testplan.list. - `testCaseIds` (string[], required): Test cases to include, at least one. Use the internal `id` from case.list (e.g. ["AAtc-kzqd-mwpe-rtya-hbnc-xufo-lgsi"]), not the human caseId like "GenTC-0001". ## Releases Group work into releases, sprints or milestones, then mark them shipped or cancelled. ### List releases, sprints and milestones — `release.list` URL: https://testmaze.com/tools/release-list/ Kind: read Lists the releases, sprints and milestones in the connected workspace, newest first. All three are time-boxed buckets you plan features into, told apart by `kind`: release = a version you ship to users ("v2.0", "June release"); sprint = a short, fixed work cycle, usually 1 to 2 weeks ("Sprint 23"); milestone = a named goal or checkpoint that is not a shipment ("Beta cohort 4", "Investor demo"). Call it before release.create to avoid duplicates, to find the `id` for feature.set_release or testrun.create, or to pick the open one before release.ship. Returns {items: [{id, uri, name, kind, status, startDate, targetDate, shippedAt}], totalItems}. status is planned, active, shipped or cancelled. Not paginated. Read-only. Example requests to your agent: - "What releases do we have planned?" - "Which sprint are we in right now?" - "Show me everything we have shipped so far" Inputs: - None. ### Create a release, sprint or milestone — `release.create` URL: https://testmaze.com/tools/release-create/ Kind: write Creates a time-boxed bucket to plan work into. Pick the kind: release = a version you ship to users ("v2.0"); sprint = a short fixed work cycle ("Sprint 23", usually 1 to 2 weeks); milestone = a named goal that is not a shipment ("Public beta"). Call project.whoami to confirm the workspace and release.list first, since duplicate names are not blocked. It starts with status "planned". Returns {success, data: the saved release including its `id`, uri}. Next: link features with feature.set_release, pass the id to testrun.create to tag test runs with it, and call release.ship when it goes out. Example requests to your agent: - "Create a v2.0 release targeting the end of June" - "Start Sprint 24 from Monday for two weeks" - "Add a milestone for the public beta" Inputs: - `name` (string, required): Display name, up to 128 characters. Examples: "v2.0", "Sprint 24", "Public beta". - `kind` (enum, optional) — one of: release, sprint, milestone: release (default) = a version shipped to users; sprint = a short fixed work cycle; milestone = a named goal or checkpoint that is not a shipment. - `startDate` (string, optional): When work starts, as YYYY-MM-DD. Example: "2026-06-01". - `targetDate` (string, optional): When it is meant to ship or end, as YYYY-MM-DD. Example: "2026-06-30". - `releaseNotesUrl` (string, optional): Link to the release notes or changelog, up to 255 characters. Example: "https://github.com/acme/app/releases/tag/v2.0". ### Mark a release as shipped — `release.ship` URL: https://testmaze.com/tools/release-ship/ Kind: write Records that a release, sprint or milestone is done and out: sets status to "shipped" and stamps shippedAt with the current time. Use it once the user confirms the release went live. It does not check test results, deploy anything or change the linked features, so run pdlc.verify (or check the latest test runs) first if the user wants a go/no-go, and move finished features to "live" with feature.set_lifecycle. Calling it again re-stamps shippedAt. The release must belong to the connected workspace. Returns {success, data: the updated release}. Example requests to your agent: - "We just shipped v2.0, record it" - "Close out Sprint 23 as done" Inputs: - `releaseId` (string, required): Id of the release, sprint or milestone (the `id` from release.list). ### Cancel a release — `release.cancel` URL: https://testmaze.com/tools/release-cancel/ Kind: write Marks a release, sprint or milestone as cancelled, for when the plan is dropped and it will not ship. Only the status changes: linked features keep their link (move them with feature.set_release) and nothing is deleted. No tool sets it back to planned, so confirm with the user first. The release must belong to the connected workspace. Returns {success, data: the updated release}. Example requests to your agent: - "Cancel the v2.1 release, we are not doing it" - "Drop the investor demo milestone" Inputs: - `releaseId` (string, required): Id of the release, sprint or milestone to cancel (the `id` from release.list). ## Success metrics Track whether the product and each feature actually succeed: product KPIs (e.g. weekly active users), per-feature metrics (e.g. checkout conversion) and the measurements recorded against them. ### List product KPIs — `productkpi.list` URL: https://testmaze.com/tools/productkpi-list/ Kind: read Lists the product KPIs in the connected workspace, newest first. A KPI (key performance indicator) is a number that tells you whether the whole product is doing well, such as weekly active users or monthly revenue. For numbers about one feature (like checkout conversion rate) use featuremetric.list instead. Call it before productkpi.create to avoid duplicates, or to find the `id` for metric.observe. Returns {items: [{id, uri, name, unit, direction, targetValue, status}], totalItems, page, pageSize}. direction is higher-better or lower-better; status is active or archived. Read-only. Recorded values over time are in the resource testmaze://metric-observations/{spaceId}/product/{id}. Example requests to your agent: - "What KPIs are we tracking for the product?" - "Are we already measuring weekly active users?" Inputs: - `page` (integer, optional): Page number, starting at 1 (default 1). - `pageSize` (integer, optional): Rows per page, 1 to 100 (default 20). ### List per-feature success metrics — `featuremetric.list` URL: https://testmaze.com/tools/featuremetric-list/ Kind: read Lists the success metrics attached to features in the connected workspace, newest first. A feature metric is a number that shows whether one feature is working for users, such as checkout conversion rate for a "Checkout" feature. For whole-product numbers (like weekly active users) use productkpi.list. Use it to see what is measured for a feature, or to find the `id` for metric.observe. Returns {items: [{id, uri, featureId, name, unit, direction, baseline, target, status}], totalItems, page, pageSize}. Gotcha: the featureId filter is applied only to the rows on the requested page, and totalItems then counts just those matches, so with many metrics use pageSize 100 and check each page. Read-only. Recorded values over time are in the resource testmaze://metric-observations/{spaceId}/feature/{id}. Example requests to your agent: - "How are we measuring whether checkout is working?" - "List the success metrics for the onboarding feature" Inputs: - `featureId` (string, optional): Only show metrics for this feature: its `id` from feature.list. Filters within the returned page only. - `page` (integer, optional): Page number, starting at 1 (default 1). - `pageSize` (integer, optional): Rows per page, 1 to 100 (default 20). ### Create a product KPI — `productkpi.create` URL: https://testmaze.com/tools/productkpi-create/ Kind: write Defines a new product KPI (key performance indicator): one number that shows whether the whole product is succeeding. Example: name "Weekly active users", unit "users", direction higher-better, targetValue "5000". Use this for product-wide numbers and featuremetric.create for numbers about a single feature (like checkout conversion rate). Call project.whoami to confirm the workspace and productkpi.list first, since duplicate names are not blocked. This only defines the KPI; record actual values over time with metric.observe. New KPIs are always saved with status "active". Returns {success, data: the saved KPI including its `id`, uri}. Example requests to your agent: - "Track weekly active users with a goal of 5,000" - "Add a KPI for monthly recurring revenue" - "We want churn under 3 percent, set that up as a KPI" Inputs: - `name` (string, required): KPI name, up to 128 characters. Examples: "Weekly active users", "Monthly recurring revenue", "Churn rate". - `description` (string, optional): How the KPI is defined, in plain words. Example: "Distinct users who signed in at least once in the last 7 days." - `unit` (string, required): What the numbers measure, free text up to 32 characters. Examples: "users", "percent", "usd", "seconds", "count". - `direction` (enum, required) — one of: higher-better, lower-better: Which way is good. higher-better = bigger numbers are good (active users, conversion rate); lower-better = smaller numbers are good (page load seconds, churn rate, error count). - `targetValue` (string, optional): The goal to reach. A plain number in a string: digits and an optional decimal point, no commas, symbols or units. It is stored as a number, so "5,000" or "5%" is rejected. Examples: "5000" users, "3" percent churn. - `measurementMethod` (string, optional): How the number is collected, free text up to 32 characters. Default "manual" (someone records values with metric.observe). Other examples: "integration:posthog", "integration:amplitude", "sql". A label only; nothing is collected automatically. - `measurementConfig` (object, optional): Optional free-form JSON object describing where the data comes from; stored as-is, not acted on. Example: {"tool": "posthog", "event": "checkout_completed", "window": "7d"}. - `ownerId` (string, optional): User id of the person accountable for the KPI. Your own id is `user.id` from project.whoami. - `status` (enum, optional) — one of: active, archived: Currently ignored: new KPIs are always saved as "active". (archived = no longer tracked.) ### Create a success metric for a feature — `featuremetric.create` URL: https://testmaze.com/tools/featuremetric-create/ Kind: write Defines how you will tell whether one feature is working for users. Example for a "Checkout" feature: name "Checkout conversion rate", unit "percent", direction higher-better, baseline "42" (where it is today), target "55" (where you want it). The baseline is the starting value before the change; the target is the goal. Use productkpi.create instead for product-wide numbers like weekly active users. featureId must be a suite of type feature or sub-feature (from feature.list); a user story or regression suite is rejected. New metrics start as "planned" unless you pass status. The feature must be in the connected workspace. This only defines the metric; record real values with metric.observe. Returns {success, data: the saved metric including its `id`, uri}. Example requests to your agent: - "How will we know guest checkout worked? Track conversion rate from 42% to 55%" - "Add a success metric for onboarding completion" - "Measure average search time for the new search feature, it should go down" Inputs: - `featureId` (string, required): Id of the feature or sub-feature to measure (the `id` from feature.list). User stories are not accepted. - `name` (string, required): Metric name, up to 128 characters. Examples: "Checkout conversion rate", "Time to first recipe saved". - `description` (string, optional): How the metric is calculated. Example: "Orders placed divided by checkout page visits, per week." - `unit` (string, required): What the numbers measure, free text up to 32 characters. Examples: "users", "percent", "usd", "seconds", "count". - `direction` (enum, required) — one of: higher-better, lower-better: Which way is good. higher-better = bigger numbers are good (active users, conversion rate); lower-better = smaller numbers are good (page load seconds, churn rate, error count). - `baseline` (string, optional): The value today, before the feature ships, to compare against. A plain number in a string: digits and an optional decimal point, no commas, symbols or units. It is stored as a number, so "5,000" or "5%" is rejected. Example: "42". - `target` (string, optional): The value that would count as success. A plain number in a string: digits and an optional decimal point, no commas, symbols or units. It is stored as a number, so "5,000" or "5%" is rejected. Example: "55". - `measurementMethod` (string, optional): How the number is collected, free text up to 32 characters. Default "manual" (someone records values with metric.observe). Other examples: "integration:posthog", "integration:amplitude", "sql". A label only; nothing is collected automatically. - `measurementConfig` (object, optional): Optional free-form JSON object describing where the data comes from; stored as-is, not acted on. Example: {"tool": "posthog", "event": "checkout_completed", "window": "7d"}. - `status` (enum, optional) — one of: planned, instrumented, measuring, hit, missed, abandoned: Where tracking stands (default planned). planned = defined, not yet tracked; instrumented = the app now sends the data; measuring = values are being collected; hit = target reached; missed = target not reached; abandoned = no longer tracked. ### Record a metric value — `metric.observe` URL: https://testmaze.com/tools/metric-observe/ Kind: write Records one measured value for a product KPI or a feature metric at a point in time, building up its history. Example: weekly active users was 4200 on 2026-09-14. Set metricType to "product" for a KPI (id from productkpi.list) or "feature" for a feature metric (id from featuremetric.list); a mismatched type, or a metric from another workspace, is reported as not found. Use it when the user shares a number from analytics, or after pulling one yourself. Each call adds a new row; nothing is overwritten. It does not change the metric's status or check it against the target. Returns {success, data: the saved observation}. Read the history from the resource testmaze://metric-observations/{spaceId}/{metricType}/{metricId}. Example requests to your agent: - "Log 4,200 weekly active users for this week" - "Checkout conversion was 48% yesterday, record it" Inputs: - `metricType` (enum, required) — one of: product, feature: product = the id is a product KPI (productkpi.list); feature = the id is a feature metric (featuremetric.list). - `metricId` (string, required): Id of the KPI or feature metric being measured (the `id` from productkpi.list or featuremetric.list). - `value` (string, required): The measured value. A plain number in a string: digits and an optional decimal point, no commas, symbols or units. It is stored as a number, so "5,000" or "5%" is rejected. Examples: "4200", "48.5". - `observedAt` (string, optional): When the value was true, as an ISO 8601 date or date-time. Example: "2026-09-14T00:00:00Z". Defaults to now. - `source` (string, optional): Where the number came from, free text up to 32 characters. Default "manual". Examples: "posthog", "stripe-dashboard". - `notes` (string, optional): Any context worth keeping. Example: "Dip due to the holiday weekend." ## Media Screenshots, PRDs and other files attached to test cases, runs and features. ### List uploaded files and screenshots — `media.list` URL: https://testmaze.com/tools/media-list/ Kind: read Lists files stored in the connected workspace, such as screenshots taken during test runs, newest first. Omit hasTestRun to list every file; true returns only files linked to BOTH a test case and a test run (evidence of what a test saw when it ran); false returns the rest (files not tied to a test run, such as ones attached only to a test case or a feature). Use it to find a screenshot to show the user or to check what evidence a run left behind. Returns {items: [{id, uri, path, type, size, mediaClass, testCaseId, testRunId, testSuiteId}], totalItems}: path is the public URL of the file, type is its MIME type, size is in bytes, mediaClass is screenshot, video, document or attachment. Not paginated. Read-only. Example requests to your agent: - "Show me the screenshots from the last test run" - "What files have we uploaded that are not tied to a test run?" Inputs: - `hasTestRun` (boolean, optional): Omit for every file. true = only files linked to both a test case and a test run (run evidence); false = files not linked to a test run (or not linked to a test case). ### Upload a file (base64) and attach it to a test — `media.upload_url` URL: https://testmaze.com/tools/media-upload-url/ Kind: write Uploads a file you already have, such as a screenshot of a bug, a short screen recording or a spec document, and optionally attaches it to a test case, test run or feature. Despite the name it does not fetch a URL: send the file bytes as base64 text. Linking decides where the file shows up: testCaseId attaches it to that test case (for example a screenshot of the expected screen); testRunId marks it as evidence from that test run (pass testCaseId too so it is tied to the case that produced it, which is also what media.list returns by default); testSuiteId attaches it to a feature or user story (for example a design mock or a spec). Linked ids are not checked, so take them from the matching list tool. Size: keep it small, ideally a few MB. Base64 makes the payload about a third bigger than the file, the HTTP connection rejects requests over 100 MB, and uploads count toward the workspace storage allowance (refused on the Basic plan; 1 GB total on Gold, 5 GB on Platinum), failing with "Plan exhausted" when over. Returns {success, message, data: {id, path (public URL), type, size, testCaseId, testRunId, testSuiteId, ...}, uri}. Example requests to your agent: - "Attach this screenshot of the broken checkout page to the checkout test" - "Save the screen recording as evidence for the last test run" - "Upload the PRD for the search feature to Test Maze" Inputs: - `base64` (string, required): The file contents as plain base64 text, with no "data:image/png;base64," prefix (a prefix corrupts the file). Example start of a PNG: "iVBORw0KGgoAAAANSUhEUg...". - `mimetype` (string, required): MIME type of the file; also sets its file extension. Examples: "image/png", "image/jpeg", "image/gif", "video/webm", "application/pdf", "text/markdown", "application/json". - `testCaseId` (string, optional): Attach to this test case: its internal `id` from case.list (not the human caseId like TC-0001). - `testRunId` (string, optional): Mark as evidence from this test run: the `id` from testrun.list. Pair with testCaseId for per-case evidence. - `testSuiteId` (string, optional): Attach to this feature, user story or suite: the `id` from feature.list. ## Guided workflows Start here. Each workflow tool kicks off a multi-step job (set up the product, plan a feature, turn a plan into tests, grade a run) and tells your agent exactly what to do next. ### Start the build-and-verify loop for this repo — `project.initialize` URL: https://testmaze.com/tools/project-initialize/ Kind: workflow Step 1 of the Test Maze loop: project.initialize → feature.implement → feature.verify → testrun.create (or testrun.record_results) → pdlc.verify. It returns what the connected workspace already knows about the product (id, name, description, vision, lifecycleStage) and opens a new PDLC session. A PDLC session is an optional tracker of where you are in the product loop: plan → write tests → code → verify → ship (states INTAKE, PLAN, AUTHOR, CODE, VERIFY, REPAIR, SHIP, DONE). This tool does not read the repository itself. It returns a prompt name, not an answer: `prompt: {name: "product-init", args}`. Fetch that prompt with prompts/get using exactly those args, follow it against the repo to write a JSON product summary, then save the summary with product.update. Keep the returned `sessionId` and pass it to feature.implement, feature.verify and pdlc.verify if you want progress tracked; leaving it out is fine and everything else still works. Every call opens a brand-new session (it is not a refresh), so call it once per piece of work, not on every message. Next: product.update, then feature.implement. Example requests to your agent: - "Set up Test Maze for this project" - "Get Test Maze to understand what my app does before we start building" - "Start tracking this repo so you can test what we build" Inputs: - `repoRoot` (string, required): Absolute path to the root of the repository you are working in, e.g. "/Users/me/code/shop". The server does not read it; it is passed into the product-init prompt and saved on the session so the prompt knows where to look. ### Start a new feature and plan its tests — `feature.implement` URL: https://testmaze.com/tools/feature-implement/ Kind: workflow Step 2 of the loop (project.initialize → feature.implement → feature.verify → testrun.create → pdlc.verify). Creates an empty feature (a test suite of type "feature") in the connected workspace and hands back a planning prompt. It creates a new feature on every call, so check feature.list first to avoid duplicates. Returns `snapshot.feature.id` plus `prompt: {name: "feature-spec", args}`: fetch that prompt with prompts/get using those args and follow it to turn the idea into user stories and acceptance criteria. An acceptance criterion (AC) is one testable promise the feature makes, like "a guest can check out without an account". Then call userstory.create once per story (parentFeatureId = the feature id) and case.create_batch with each story's ACs (suiteId = that story's id). Next: feature.verify. With sessionId, the session moves from INTAKE (just started) to PLAN. If the session is in any other state, the feature is still created but the call returns an error that names the new feature id. Example requests to your agent: - "Let's build a password reset flow, plan it and write the tests first" - "Add a saved payment methods feature to the app" - "Start a new feature for guest checkout and break it into user stories" Inputs: - `title` (string, required): Short feature name as a user would say it, e.g. "Password reset". Becomes the feature suite title. - `description` (string, optional): A sentence or two about what the feature should do. Optional; defaults to empty. The feature-spec prompt expands it into stories. - `priority` (string, optional): How important the feature is: "P0" (top) to "P3" (trivial). Optional; the server defaults to "P2". - `releaseId` (string, optional): Id of the release this feature ships in (the `id` from release.list or release.create). Optional. - `sessionId` (string, optional): Optional PDLC session id (the `sessionId` returned by project.initialize, or an `id` from pdlc.list). When given, moves the session from INTAKE to PLAN; the session must be in INTAKE. ### Write out the full test cases for a feature — `feature.verify` URL: https://testmaze.com/tools/feature-verify/ Kind: workflow Step 3 of the loop (project.initialize → feature.implement → feature.verify → testrun.create → pdlc.verify). Despite the name it does not run or grade anything: it collects the acceptance-criterion test cases in one suite so you can turn them from short outlines into complete tests with steps and expected results. An acceptance criterion (AC) is one testable promise the feature makes; an AC test case is any case with an acceptanceCriterionLabel such as "AC1". Pass a feature id to get the cases of the feature and of every user story and sub-feature under it, or a story id for just that story. Returns `snapshot.acceptanceCriteria` (id, acceptanceCriterionLabel, title, description, isWaived, suiteId = the suite the case is filed under) plus `prompt: {name: "ac-to-testcase", args}`: fetch that prompt with prompts/get using those args and follow it. Then call case.update for each case, write the code that makes the ACs true, record results with testrun.create, and grade them with pdlc.verify. With sessionId the session moves from PLAN to AUTHOR (writing tests), so pass it only on the first call. Example requests to your agent: - "Write the full test steps for the password reset stories" - "Flesh out the acceptance tests for this user story before we code it" - "Turn the checkout acceptance criteria into proper test cases" Inputs: - `suiteId` (string, required): Id of the suite that holds the AC test cases. Usually a user story id (the id userstory.create returned, since feature-spec attaches ACs to stories), or the feature id if ACs were attached to the feature itself. Must belong to the connected workspace. - `sessionId` (string, optional): Optional PDLC session id (from project.initialize or pdlc.list). When given, moves the session from PLAN to AUTHOR; the session must be in PLAN, otherwise the call returns an error. ### Grade a test run and say what to fix next — `pdlc.verify` URL: https://testmaze.com/tools/pdlc-verify/ Kind: verdict Final step of the loop (project.initialize → feature.implement → feature.verify → testrun.create / testrun.record_results → pdlc.verify). Reads the results of an existing test run and returns a verdict: is it done, and if not, what to do next. It never runs tests itself; record results first. The verdict is "pass" (at least one case passed and none failed), "fail" (any case failed, or a case from a frozen regression baseline is missing or no longer passing), or "in-progress" (no case has a Pass or Fail yet). Cases whose acceptance criterion is waived (case.waive_ac) are left out of grading and counted in `waived`. It is computed by fixed rules, never by an AI, so the same results always give the same verdict. Returns `snapshot` with verdict, passed, failed, failureBuckets (failures grouped by cause, e.g. timeout, selector-not-found), waived and waivedCaseIds, reliabilityKpi, gitSha, branch, workingTreeClean, frozenRegressions (only when present) and nextStep. nextStep.action in plain words: "ship" = everything passed, release it (release.ship); "repair_code" = the app is wrong, fix the code for nextStep.caseId and re-run; "repair_test" = most failures are the test failing to find elements on the page, so fix the test (case.update) and re-run; "add_coverage" = nothing was graded yet, add or execute test cases. nextStep.hint is optional advice text that an AI may write for repair actions when the workspace has an AI key; it never changes the verdict. The response also lists `nextTools` to call. Example requests to your agent: - "Did the last test run pass? What should I fix first?" - "Check whether the checkout feature is ready to ship" - "Grade the tests I just ran and tell me if the bug is in my code or the test" Inputs: - `testRunId` (string, required): Id of the test run to grade: the `id` returned by testrun.create, or from testrun.list. Must belong to the connected workspace and already have results recorded. - `sessionId` (string, optional): Optional PDLC session id (from project.initialize or pdlc.list). When given, the session is moved forward to VERIFY and then routed by the result: ship → SHIP, repair_test → REPAIR, anything else → CODE. Works from AUTHOR, CODE, REPAIR or VERIFY. If the move is not allowed you still get the verdict, and the message says the state change was skipped. ## Coverage Find what a feature is not tested for yet: happy path, edge cases, errors, permissions, accessibility, performance, browsers and unusual data. ### Find what a feature's tests are missing — `coverage.gap_for_feature` URL: https://testmaze.com/tools/coverage-gap-for-feature/ Kind: read Checks which kinds of testing a feature or user story has no test cases for yet. Every active test case of the suite and of the user stories and sub-features under it (inactive cases are skipped) is sorted into one of 8 facets by keyword matching on its title and description, with no AI involved; a case that matches no keyword counts as happy-path. The 8 facets: happy-path (the normal success flow, e.g. "user resets password and logs in"); edge cases (boundaries, e.g. "empty email field" or "maximum length name"); error / recovery (failures and retries, e.g. "network drops during payment, retry succeeds"); permissions (wrong or missing login, e.g. "a viewer cannot delete a project"); accessibility (e.g. "the form can be completed with the keyboard only"); performance (e.g. "search returns in under 1 second with 10,000 items"); browser matrix (e.g. "date picker works in Safari"); data-shape mutations (unexpected API data, e.g. "a missing field in the response does not crash the page"). Returns totalCases, perFacet counts, `missingFacets`, `missingAcLabels` (gaps in the AC1, AC2, … numbering, e.g. AC1 and AC3 exist but not AC2), existingCases and a suggested next prompt. Read-only. Next: fetch the find-coverage-gaps prompt with prompts/get (pass this whole result as JSON in its `feature` argument), create the proposed cases with case.create_batch, then fill them in via ac-to-testcase. Example requests to your agent: - "What kinds of tests is the checkout feature missing?" - "Did we forget to test permissions or error cases for password reset?" - "Are there gaps in the acceptance criteria for this user story?" Inputs: - `featureId` (string, required): Id of the suite to check: a feature, sub-feature or user story `id` (from feature.list, feature.implement or userstory.create). Must belong to the connected workspace. Cases in its child user stories and sub-features count too. ## Regression baselines Lock in a fully passing run as the "must stay green" baseline. From then on, any case from it that breaks fails the verdict, so fixed things stay fixed. ### Lock in a passing test run as a regression baseline — `regression.freeze_run` URL: https://testmaze.com/tools/regression-freeze-run/ Kind: write Freezes a test run as a regression baseline: a set of tests that must keep passing from now on. It protects against regressions, where a new change quietly breaks something that already worked, or where a test that used to run is dropped. After freezing, every pdlc.verify in this workspace checks every test case in every frozen run: if one is missing from the run being graded, or did not pass, the verdict becomes "fail" and the case is listed under `frozenRegressions`. So graded runs need to include the frozen cases, not just the feature you are working on. Waived cases (case.waive_ac) are exempt. Refuses a run with no recorded cases or with any failing case. Cases marked Not Executed are allowed but are still frozen, so they must pass in later runs. Returns testRunId, frozenAt, frozenBy, frozenCaseCount (passing cases), gitSha and branch; freezing an already frozen run is a no-op that returns alreadyFrozen: true. Undo with regression.unfreeze_run. Example requests to your agent: - "Everything passes now, lock this in so we notice if it breaks later" - "Make the current test run the baseline that must stay green" - "Protect the login flow from regressions" Inputs: - `testRunId` (string, required): Id of the test run to freeze: the `id` from testrun.create or testrun.list. Must belong to the connected workspace and have no failing cases. - `note` (string, optional): Optional short note on what this baseline covers, up to 500 characters, e.g. "Checkout v1 launch". Saved on the run and shown by regression.list_frozen. ### Retire a regression baseline — `regression.unfreeze_run` URL: https://testmaze.com/tools/regression-unfreeze-run/ Kind: write Unfreezes a test run so its cases no longer have to keep passing. A regression baseline is a frozen run whose tests every later pdlc.verify requires to be present and passing. Use it only when the baseline is deliberately out of date, for example the feature was removed or rebuilt; do not use it just to get a failing verdict to pass. Ask the user before calling it. Requires a reason. Takes effect immediately for every later pdlc.verify in the workspace; you can freeze the run again with regression.freeze_run. Returns success and the reason; a run that was not frozen returns alreadyUnfrozen: true. Call regression.list_frozen first to find the right run. Example requests to your agent: - "We removed the old checkout, stop requiring its tests to pass" - "Retire the baseline from before the redesign" Inputs: - `testRunId` (string, required): Id of the frozen test run to unfreeze: an `id` from regression.list_frozen. Must belong to the connected workspace. - `reason` (string, required): Why this baseline no longer applies, 8 to 500 characters, e.g. "Legacy checkout removed in v2". Saved on the run (unfreezeReason, with unfrozenAt and unfrozenBy) so the decision can be reviewed later. ### List regression baselines — `regression.list_frozen` URL: https://testmaze.com/tools/regression-list-frozen/ Kind: read Lists every frozen test run (regression baseline) in the connected workspace, most recently frozen first. A baseline is a run whose tests must keep passing: every later pdlc.verify fails if any of them is missing or not passing. Use it before a release, when a verdict shows frozenRegressions, or before regression.unfreeze_run. Returns `count` and `items` with id, name, gitSha, branch, workingTreeClean, frozenAt, frozenBy and caseCount (all recorded cases in that run). Read-only; takes no parameters. Example requests to your agent: - "Which tests are locked in as must-stay-green?" - "Why does the verdict say something regressed? Show me the baselines" Inputs: - None. ## Activity Label what your agent is doing so it shows up clearly on the Agent Sessions page. ### Record what the user asked for — `pdlc.recordPrompt` URL: https://testmaze.com/tools/pdlc-recordprompt/ Kind: write Saves the message the user just typed to you onto the Agent Sessions page in Test Maze. That page is an activity timeline of every Test Maze tool call; without the prompt it only shows tool calls, with it people can see what each group of calls was trying to do. Call it once at the start of each new user request, before the other Test Maze tools for that request. It changes no test data. sessionId is optional. When omitted, the prompt joins your personal default timeline ("user-"), which is also where tool calls without a sessionId land. When you are in a PDLC session (the `sessionId` from project.initialize), pass that same id here and to the loop tools so they are grouped together. Returns recorded: true, eventId and the sessionId used. Example requests to your agent: - "Keep a log of what I ask you in Test Maze" - "Make my requests show up on the Agent Sessions page" Inputs: - `prompt` (string, required): The user's message, word for word, up to 8192 characters, e.g. "Add a password reset flow and test it". - `sessionId` (string, optional): Timeline to attach the prompt to. Use the PDLC `sessionId` from project.initialize (or pdlc.list) when you have one. Optional; defaults to your personal timeline "user-". - `branchId` (string, optional): Label for a side branch of the timeline, e.g. when retrying a different approach. Optional; defaults to "main". Leave it out unless you are deliberately forking the conversation. ## Exploratory testing Let your agent click through your app in its own browser (for example with Playwright MCP) while Test Maze keeps a verified record, suggests what to try next and turns the journey into test cases. Test Maze never opens a browser itself. ### Start exploring a web app — `exploration.start` URL: https://testmaze.com/tools/exploration-start/ Kind: write Starts an exploration session: a recorded walk through a running web app to discover its pages, links and forms, which can later become test cases. You need a browser tool on your side (for example the Playwright MCP server); Test Maze never opens a browser itself, it only keeps the record and tells you what to try next. Returns `sessionId`, `budget` and `nextActions` (the first is always "navigate to the url", actionId "a0"). Next: open the URL in your browser, then call exploration.observe. Sessions with no observe for 30 minutes are closed automatically as abandoned. Example requests to your agent: - "Explore my app at http://localhost:3000 and find all the pages" - "Click through the checkout flow on staging and record what you find" - "Crawl the signup flow and turn it into test cases" Inputs: - `url` (string, required): Start URL of the running app, e.g. "http://localhost:3000" or "https://staging.example.com/login". - `goal` (string, optional): What you want to learn or check, in plain words, e.g. "Find every page reachable from the dashboard". Stored with the session and used in generated case descriptions. - `featureId` (string, optional): Id of the feature (test suite) this exploration belongs to, from feature.list. exploration.to_cases returns it as `suiteId` so the cases land in that suite. - `name` (string, optional): Short session name for lists. Default: the first 80 characters of `goal`, or "Exploration of ". - `budget` (object, optional): Limits for the session, e.g. { "maxSteps": 30, "maxPages": 10 }. Defaults: 60 steps, 25 pages. When either is reached, observe stops suggesting actions and sets coverage.done = true. ### Report the page your browser sees and get next steps — `exploration.observe` URL: https://testmaze.com/tools/exploration-observe/ Kind: write The core of the exploration loop. After every single browser action, send what the page looks like now (`page`: url, title, html and/or accessibility snapshot) and what you just did (`performed`). Then do exactly ONE of the returned nextActions in your browser and call observe again; repeat until coverage.done is true, then call exploration.finish. Returns: `step` (verified, urlChanged, domChanged, note) — a verified step is one the server could confirm from the page: you landed on the expected URL, or the page visibly changed after a click/submit/navigate/back, or new content appeared after a hover (fill, select, scroll and press are accepted as-is; a reported error is never verified). `elements` and `forms` with a stable locator for each element — a way to find it again that survives page reloads, preferring data-testid, then id, then role + accessible name, with `stability` 0–1 and ready Playwright code in `locator.code`. `suggestedAssertions` (checks that hold on this page), `assertionResults` (for `expect`), `revealed` (elements that appeared since the last observe). `coverage` — how much of the app you have seen: pagesVisited, pagesKnownUnvisited, unvisited (up to 20 URLs), stepsUsed, errors, budget, done, reason. `nextActions` — up to 8, ranked: unvisited links first, then form fills with sample values and submits, then menus to hover, then other buttons; each has actionId, kind, target, value, why. A "hover" action means hover it, then observe again so the menu that opens can be read. Only the user who started the session can observe it, and only while it is active. Example requests to your agent: - "Keep exploring the app and tell me what pages you find" - "Log what this page looks like after I clicked Sign in" - "Check that submitting the contact form shows a success message" Inputs: - `sessionId` (string, required): The `sessionId` returned by exploration.start. - `page` (object, required): What your browser shows right now. Shape: { "url": "https://app.example.com/login", "title": "Sign in", "html": "…" } (html and/or snapshot; html gives the richest analysis). - `performed` (object, optional): The one action you just did in the browser, e.g. { "actionId": "a300", "kind": "click", "target": "role=link[name=\"Pricing\"]" }. Copy actionId, kind, target and value from the nextAction you followed; add `error` if it failed. Omit only on the very first observe after start (after opening the start URL). - `expect` (object[], optional): Up to 50 checks to judge against this page, typically right after a submit, e.g. [{ "type": "url-contains", "expected": "/dashboard" }, { "type": "element-visible", "selector": ".alert-success", "expected": true }]. Each comes back in assertionResults with passed and actual; failures are noted on the step. ### Finish an exploration session — `exploration.finish` URL: https://testmaze.com/tools/exploration-finish/ Kind: write Closes an exploration session so no more observations can be added. Call it when observe reports coverage.done, or when you decide to stop. Use status "completed" (default) when the walk is worth keeping and turning into test cases; use "abandoned" when you gave up (wrong URL, login wall, browser broke). Both keep the record. It builds a navigation tree (the visited pages arranged by URL path) and saves the URL and title checks of every visited page. Returns the summary: id, status, steps, pages, errors, verifiedShare (share of judged steps that were verified, 0–1), startedAt, endedAt. Calling it on an already closed session changes nothing and returns the summary. Only the user who started it can finish it. Next: exploration.to_cases to draft test cases, or exploration.get for the full record. Example requests to your agent: - "That's enough exploring, wrap it up" - "Stop the exploration, the login page is blocking us" Inputs: - `sessionId` (string, required): The `sessionId` returned by exploration.start. - `status` (enum, optional) — one of: completed, abandoned: "completed" (default): the exploration ran its course. "abandoned": you stopped early and the record is not meant to be used. ### Draft test cases from an exploration — `exploration.to_cases` URL: https://testmaze.com/tools/exploration-to-cases/ Kind: read Turns what an exploration session recorded into draft test cases. Nothing is saved: you get `bodies` ready for case.create_batch. Same session in, same drafts out (no AI). Only verified steps without errors become case steps. Strategy "per-path" (default): one case per run of consecutive steps whose observed page (the URL after the action) stayed the same, steps like "Fill \"#email\" with \"tester3@example.com\"" or "Submit via …"; a run with no actions produces no case. Strategy "per-page": one "Open " case per visited page. Expected results come from checks that held on that page (passed `expect` results first, then URL, title, success message, form count and heading checks). Example per-path body: { "title": "Contact us: 3 action(s)", "description": "Exploration , path through https://app.example.com/contact.", "preCondition": "Application reachable at https://app.example.com", "steps": ["Navigate to https://app.example.com/contact", "Fill \"#name\" with \"Test User 4\"", "Fill \"#email\" with \"tester4@example.com\"", "Submit via \"#send\""], "expectedResult": "\".alert-success\" is visible; URL contains \"/contact\"; Page title contains \"Contact us\"", "priority": "P2" }. Returns { strategy, sessionId, suiteId (the session featureId, if set), bodies, next }. Review and tidy the drafts (the exploration-to-cases prompt rewrites them in plain language), check case.list for duplicates, then call case.create_batch({ suiteId, bodies }). Example requests to your agent: - "Turn that exploration into test cases" - "Write test cases from the pages you just clicked through" - "Make one test case per page you visited" Inputs: - `sessionId` (string, required): Exploration session id, from exploration.start or exploration.list. Works on active or finished sessions. - `strategy` (enum, optional) — one of: per-path, per-page: "per-path" (default): one case per run of actions on a page, best for flows like login or checkout. "per-page": one "page opens" case per visited page, best for a smoke check of every page. - `maxCases` (integer, optional): Most drafts to return (1–200, default 50). ### List exploration sessions — `exploration.list` URL: https://testmaze.com/tools/exploration-list/ Kind: read Lists recent exploration sessions in the connected workspace, from every user, most recently updated first. Use it to find a session id to resume, read or turn into test cases. Each row has id, status, name, goal, featureId, startUrl, steps, pages, errors, verifiedShare (share of judged steps the server could confirm, 0–1), startedAt, lastObservationAt, endedAt and a testmaze:// uri. Next: exploration.get for the full record, or exploration.to_cases. Example requests to your agent: - "What explorations have we run so far?" - "Is there an exploration still in progress?" Inputs: - `status` (enum, optional) — one of: active, completed, abandoned, saved: Only sessions in this state. active: still running. completed: finished normally. abandoned: stopped early or idle for 30 minutes. saved: recordings made in the Test Maze web assistant. Default: all. - `limit` (integer, optional): Most sessions to return (1–100, default 20). ### Show an exploration session in full — `exploration.get` URL: https://testmaze.com/tools/exploration-get/ Kind: read Reads one exploration session from the connected workspace in full. Returns the summary fields (id, status, name, goal, startUrl, pages, errors, verifiedShare, timestamps), `steps` (the log of every observation: url, title, the action performed, verified, urlChanged, domChanged, note, revealed elements, check results), `pages` (each visited page with visits, links, form and field counts, suggested checks), `coverage` as of the last observe, and `navigationTree` (visited pages by URL path; null until the session is finished). Read-only. Example requests to your agent: - "Show me everything the last exploration found" - "Which steps failed in that exploration?" Inputs: - `sessionId` (string, required): Exploration session id, from exploration.start or exploration.list. ## Code quality Two helpers for the code your agent writes: a code-smell check (fixed rules, same code gives the same result) and design advice that ranks proven design patterns and refactorings against your problem. Backed by a built-in knowledge base. ### Check code for smells — `quality.smell_check` URL: https://testmaze.com/tools/quality-smell-check/ Kind: read Scans a file, function or diff for code smells: warning signs that code will be hard to change, such as a very long function, a function with many parameters, or the same block copy-pasted. A smell is not a bug; it is a hint to look closer. The check is fixed rules that count lines, parameters, cases and repeats (long method, long parameter list, large class, big switch or if/else chain, long call chains, duplicate blocks, commented-out or unreachable code, the same parameters travelling together). No AI runs on the server, so the same code always gives the same result. Use it before committing or when reviewing a change. Returns `findings` (smell, line, endLine, detail, confidence high/medium/low, the knowledge-base entry and `fixes`: refactorings that remove it), `summary` counts, and a `checklist` of every other smell in the knowledge base with its triggers, for the ones rules cannot measure (such as Feature Envy: a method that uses another object's data more than its own), which you judge yourself. Next: confirm each finding in context, apply the fixes, or pass the result to the code-smell-review prompt for a written review. Read-only: it never changes code. Example requests to your agent: - "Check the file I just wrote for code smells" - "Is my diff getting messy? Anything I should clean up before committing?" - "Review this function for maintainability problems" Inputs: - `code` (string, required): The code to check, pasted as text: a whole file, one function, or a unified diff (git diff output). For a diff only the added lines are checked, and finding line numbers count within those added lines, not the original file. - `language` (string, optional): Language hint, e.g. "typescript" or "python". Echoed back only; the rules work across brace languages (TS/JS/Java/C#/Go/Kotlin/PHP) and Python. - `path` (string, optional): File path, e.g. "src/orders/order.service.ts". Echoed back on the result and each finding so you can match findings to files when checking several. - `thresholds` (object, optional): Override any rule limit; leave out the rest. Raise a number to be more lenient. Example: { "longMethodLines": 50, "maxParams": 6 }. Defaults: {"longMethodLines":30,"maxParams":4,"largeClassLines":300,"chainDepth":3,"duplicateBlockLines":6,"switchCases":4,"commentRatio":0.3} ### Suggest a design for a code structure problem — `architecture.advise` URL: https://testmaze.com/tools/architecture-advise/ Kind: read Suggests ways to structure code for a design problem you describe in plain words, such as "three payment providers with different APIs", "undo for editor actions" or "one class that changes for every feature". Use it before a bigger change or when code keeps getting harder to extend. It returns a ranked shortlist (`candidates`) of design patterns (proven shapes like Strategy or Adapter, from the Gang of Four book) and refactorings (small safe changes like Extract Method, from Martin Fowler), each with name, intent, `whenToUse`, `tradeoffs`, `related` entries, a score and the words that `matched`, plus `howToDecide` guidance. Ranking is fixed keyword matching against each entry's curated triggers, no AI on the server: it narrows the options, and you (the agent) still pick one against the real code, preferring the smallest change that removes the problem. No matches means re-phrase with the symptom you see in code. Next: kb.get to read a candidate in full, or the architecture-review prompt to write up a justified recommendation. Example requests to your agent: - "How should I structure support for Stripe, PayPal and Razorpay without a giant if/else?" - "This service class keeps growing, what design would help?" - "What is a clean way to add undo to my editor?" Inputs: - `problem` (string, required): The design problem in plain language, including what you see in the code, e.g. "big switch on order type in every service, adding a type touches 6 files". - `constraints` (string, optional): Limits on the solution, e.g. "TypeScript, NestJS, no new dependencies". Matched as extra keywords together with `problem`, and echoed back; it does not filter candidates. - `kinds` (enum[], optional): Which kinds of entry to consider, e.g. ["refactoring"] for small changes only. Default: ["pattern", "refactoring"]. - `limit` (integer, optional): Most candidates to return (1–10, default 5). ### Search the code-quality guide — `kb.search` URL: https://testmaze.com/tools/kb-search/ Kind: read Searches the built-in code-quality guide (a knowledge base of design patterns, code smells and refactorings) by a symptom you notice or by a name, e.g. "same three parameters everywhere", "extract method" or "observer". Use it to put a name to a problem, then read the matching entry with kb.get. Matching is fixed keyword rules over each entry's name, intent and trigger phrases, so the same query always gives the same results. Returns `results` (ref such as "smell:long-method", kind, slug, name, family, intent, score, matched, uri) best first, and `families` (the group names per kind). Read-only. Example requests to your agent: - "What is it called when a function takes way too many arguments?" - "Look up the observer pattern" - "Find refactorings for deeply nested if statements" Inputs: - `query` (string, required): A symptom or a name, in plain words, e.g. "switch on type in many places" or "strategy". - `kinds` (enum[], optional): Which kinds of entry to search, e.g. ["smell"] to name a problem first. Default: all three kinds. - `limit` (integer, optional): Most results to return (1–20, default 8). ### Read a code-quality guide entry — `kb.get` URL: https://testmaze.com/tools/kb-get/ Kind: read Reads one entry of the code-quality guide in full: a design pattern, a code smell or a refactoring, with what it is, when to use it, how it looks, an example, trade-offs and step-by-step mechanics. Use it after kb.search, architecture.advise or quality.smell_check gave you a ref or slug. Pass either `ref` (e.g. "smell:long-method") or both `kind` and `slug` (e.g. pattern + strategy); `ref` wins if both are given. Returns name, family, intent, triggers, signals (measurable hints), sources, sections, `markdown` (the full text) and `related` entries. An unknown entry returns an error; use kb.search to find the right slug. Read-only. Example requests to your agent: - "Explain the strategy pattern with an example" - "How do I actually do an Extract Method refactoring?" Inputs: - `kind` (enum, optional) — one of: pattern, smell, refactoring: Entry kind, used together with `slug`: pattern, smell or refactoring. - `slug` (string, optional): Entry slug, used together with `kind`: lower-case with hyphens, e.g. "strategy", "long-method", "extract-method". Get it from kb.search. - `ref` (string, optional): Kind and slug in one, ":", e.g. "pattern:strategy" or "smell:long-method" (the `ref` field of search results). Alternative to kind + slug. # Resources (13) Records an agent can read directly with MCP resources/read (in Claude Code: @tm:). - `testmaze://product/{spaceId}`: Your workspace as a product: vision, the problem it solves, who it is for, lifecycle stage and repository. - `testmaze://feature/{spaceId}/{suiteId}`: One feature: its lifecycle stage, the release it belongs to and the user stories under it. - `testmaze://userstory/{spaceId}/{suiteId}`: One user story ("as a …, I want …, so that …") and the acceptance-criterion test cases that prove it. - `testmaze://case/{spaceId}/{caseId}`: One test case: steps, expected result and whether it passed the last time it ran. - `testmaze://testplan/{spaceId}/{planId}`: One test plan and the test cases it bundles. - `testmaze://testrun/{spaceId}/{runId}`: One test run: pass/fail for each case plus the git commit, branch and whether the working tree had uncommitted changes. - `testmaze://release/{spaceId}/{releaseId}`: One release, sprint or milestone and its status. - `testmaze://media/{spaceId}/{mediaId}`: One uploaded file (screenshot, PRD, …): type, size and a public link. - `testmaze://productkpi/{spaceId}/{kpiId}`: One product KPI: what is measured, the unit, the target and whether higher or lower is better. - `testmaze://featuremetric/{spaceId}/{metricId}`: One feature success metric: baseline, target and where tracking stands. - `testmaze://metric-observations/{spaceId}/{metricType}/{ownerId}`: The measurements recorded over time for one KPI or feature metric. - `testmaze://kb/{spaceId}/{kind}/{slug}`: One knowledge base entry: a design pattern, code smell or refactoring (kind is pattern, smell or refactoring), with links to related entries. - `testmaze://exploration/{spaceId}/{id}`: One exploratory-testing session: every step with its verification, the pages visited, coverage and the navigation map. # Prompts (8) Step-by-step instructions stored in Test Maze and fetched with MCP prompts/get (in Claude Code: /mcp__tm__). - `code-smell-review` — Review code for smells and plan the refactoring: Follow-up to quality.smell_check. A code smell is a sign of a design problem, like a very long function or copy-pasted logic. It asks you to confirm or dismiss each automatic finding in context, check the code against the smell checklist, and return JSON: confirmed smells with line evidence, dismissed ones with a reason, an ordered plan of named refactorings (one per step) and what to re-run afterwards. - `architecture-review` — Recommend a design pattern with a migration plan: Follow-up to architecture.advise. It compares the suggested design patterns and refactorings against the problem and your constraints, picks one (or "keep it simple" when none is justified), and returns JSON: the recommendation and why, why the runners-up lost, the trade-offs accepted, and a step-by-step migration where each step is one named refactoring. - `explore-feature` — Explore an app in your own browser and record it: Step-by-step guide for exploratory testing: you click through the app with your own browser tools (for example Playwright MCP) and Test Maze keeps the record; Test Maze never opens a browser itself. The loop is exploration.start → (act in your browser → exploration.observe after every action) → exploration.finish → exploration.to_cases → case.create_batch, which turns what you verified into saved test cases. Use it when there is a running app to try out but no written tests yet. - `exploration-to-cases` — Tidy up test cases recorded while exploring: Optional follow-up to exploration.to_cases. It rewrites the mechanically generated test cases into ones a person can read: clearer titles and steps, trivial cases merged, and every recorded step and check kept (nothing that was not observed is added). Output is JSON {"bodies": [...]} ready for case.create_batch. - `product-init` — Describe the product from its repository: Used in step 1 of the loop, after project.initialize returns this prompt name. It asks you to read the repository (README, package metadata, docs, entry points) and write one JSON object describing the product: name, description, vision, problemStatement, targetUsers, lifecycleStage (discovery, beta, live or sunset), and optionally defaultBranch and repoUrl. Save that JSON with product.update. Pass the args project.initialize returned. - `feature-spec` — Plan a feature as user stories and acceptance criteria: Used in step 2 of the loop, after feature.implement returns this prompt name. It asks you to turn a feature name into user stories ("as a …, I want …, so that …") and, for each story, acceptance criteria labelled AC1, AC2, … An acceptance criterion (AC) is one testable promise the feature makes, like "a guest can check out without an account". The criteria should cover the 8 test facets: happy-path, edge cases, error / recovery, permissions, accessibility, performance, browser matrix and data-shape mutations. Output is JSON: create each story with userstory.create, then its ACs with case.create_batch using the story id. Pass the args feature.implement returned. - `ac-to-testcase` — Write full test steps for acceptance criteria: Used in step 3 of the loop, after feature.verify returns this prompt name. It takes short acceptance-criterion test cases and asks you to write each one out in full: description, preCondition (state before the test), steps, expectedResult (what to check at the end) and postCondition (state left behind), with checks suited to the kind of test (for example a permissions test asserts a 401/403 or "Access denied", not success). Output is a JSON array with one object per case id; save each with case.update, then record a run with testrun.create and grade it with pdlc.verify. Pass the args feature.verify returned. - `find-coverage-gaps` — Propose test cases for missing kinds of testing: Follow-up to coverage.gap_for_feature. It takes that gap report and asks you to sketch only the missing test cases: at least one for each facet in missingFacets (for example a permissions case if no case tests a wrong or missing login) and one for each missing AC label in missingAcLabels (for example AC3 when AC2 and AC4 exist). Output is JSON {"bodies": [...]} with short titles, steps and expected results: create them with case.create_batch, then write them out in full with the ac-to-testcase prompt.