MCP Response Contract
Structured JSON shape returned by POST /api/mcp/v1/invoke and consumed by @visualq/mcp.
Every tool invoked via POST /api/mcp/v1/invoke (or hosted POST /api/mcp) returns the same top-level JSON shape. The MCP client forwards this to the IDE agent as structured content.
Success response
{
"ok": true,
"tool": "get_run_failures",
"summary": "3 of 12 checks failed.",
"data": {
"runId": "run_abc",
"failed": 3,
"total": 12,
"failures": [
{
"scenarioLabel": "Homepage",
"viewport": "desktop",
"mismatchPercent": 4.2
}
]
},
"warnings": [],
"nextActions": [
{
"label": "Inspect Homepage desktop",
"tool": "get_diff_stats",
"args": {
"scenarioLabel": "Homepage",
"viewport": "desktop"
}
}
]
}Fields
| Field | Type | Description |
|---|---|---|
ok | boolean | true when the tool executed successfully |
tool | string | Tool name echoed from the request |
summary | string | One-line human-readable result for the agent |
data | object | array | null | Tool-specific payload |
warnings | string[] | Non-fatal issues (empty when none) |
nextActions | array | Suggested follow-up tool calls for the agent |
nextActions entries
| Field | Type | Description |
|---|---|---|
label | string | Short description shown to the agent |
tool | string | Tool name to call next |
args | object | Optional pre-filled arguments |
get_run_failures automatically populates up to five nextActions pointing at get_diff_stats for each failed scenario.
Error response
{
"ok": false,
"tool": "approve_vrt_results",
"summary": "confirm must be true to execute write tool approve_vrt_results",
"data": null,
"warnings": [],
"nextActions": [],
"error": {
"code": "confirm_required",
"message": "confirm must be true to execute write tool approve_vrt_results"
},
"recoverable": true
}Error fields
| Field | Type | Description |
|---|---|---|
error.code | string | Machine-readable error category |
error.message | string | Human-readable explanation |
recoverable | boolean | Whether retrying with different args may succeed |
Common error codes
| Code | Typical cause |
|---|---|
validation_error | Missing or invalid arguments |
confirm_required | Write tool without confirm: true |
scope_denied | API key scope insufficient |
plan_gate | Feature not on current billing plan |
rate_limit | Too many invoke calls (see retryAfterMs on 429 responses) |
project_resolution_error | Project or environment not found |
tool_error | Executor or downstream failure |
pipeline_blocked | FRT scenario pipeline could not complete (missing startPath, empty goal, etc.) |
save_failed | FRT feature save or compile failed after pipeline |
http_error | MCP client received non-JSON HTTP body (timeout, gateway error) — see error.message for status snippet |
not_found | Unknown tool name |
create_frt_scenario success variants
data.resolved | Meaning |
|---|---|
existing | frt_find_scenarios resolve-first matched an existing feature — no duplicate created |
created | New feature persisted |
When the user goal mentions tracking payload verification, the service strips that clause, creates the click scenario, and adds nextActions for tracking_get_plan and run_tracking.
For JIRA tracking proof (e.g. BN-470), use tracking_prove_jira_ticket — one async call that resolves ticket intent semantically. Poll get_job_status until status: completed, then read result.jiraMarkdown and result.proofVerdict. Do not manually chain frt_find_scenarios for proof workflows.
tracking_prove_jira_ticket proof fields
| Field | Meaning |
|---|---|
proofVerdict | proven = eventStatus: pass and scenario.matchesTicketIntent: true; failed otherwise |
proofOutcome | { proven, headline, reasons } — agent must quote headline (OUI/NON) to the user |
jiraMarkdown | Paste verbatim into the JIRA comment — do not paraphrase |
warnings | e.g. intent-only proof (generic scenario), reused audit cache |
nextActions | On failure: create FRT scenario, re-prove, inspect proof — agent must propose these |
matchesTicketIntent | Semantic intent match (preferred over literal repro strings) |
When proofVerdict is failed, the invoke response returns ok: false with error.code: proof_failed but still includes full data for the failure comment.
Async flow: first response { jobId, status: "queued" } → poll get_job_status → result contains the proof object.
HTTP status mapping
| Status | When |
|---|---|
| 200 | ok: true |
| 400 | Validation or confirm gate |
| 403 | Scope or plan gate |
| 404 | Unknown tool |
| 422 | ok: false business/tool error |
| 429 | Rate limit (retryAfterMs included in body) |
CI tools
Tools routed through /api/ci/* (run_vrt, run_perf, get_run_status, etc.) return CI API shapes, not this contract. Only invoke tools use ToolResponse.
Async invoke tools return { jobId, status: "queued" } in data — poll with get_job_status.