How It Works 6 min read

Driving Catalio from Your IDE over MCP

Run the full Extract and Understand loop — scan, review candidates, enrich requirements, resolve proposals — from an MCP client without opening the web app

Updated
On this page

If you live in an editor, you can drive most of Catalio from there. Catalio exposes its domain actions as MCP tools, so an MCP client (Claude Code, Claude Desktop, Cursor, or your own) can start a scan, review what it found, and enrich the specification without you switching to the browser.

This guide walks the end-to-end loop and is explicit about the places where you still need the UI.

What the loop looks like

Six steps, all reachable as tools:

  1. Point at an application and start a scan.
  2. Poll until the scan finishes.
  3. List the candidates it drafted.
  4. Confirm or dismiss each candidate.
  5. Enrich the requirements the scan produced or touched.
  6. Resolve change proposals — apply, dismiss, or restore.

Step 1: Start a scan

start_extract_scan takes an application_id and an optional stage (defaults to capabilities). It wraps the same enqueuer the web UI uses, so a colleague watching the application in the browser sees your scan appear live.

Plaintext
start_extract_scan(application_id: "…", stage: "capabilities")
→ %{status: :enqueued, application_id: "…", stage: "capabilities"}

Two things worth knowing:

  • A second call inside the dedupe window returns :already_running, not a new job. This is a distinct status rather than a silent success, so your script can tell “I started it” from “it was already going.”
  • component_ids defaults to the application’s source components, capped. If you want a narrower scan, pass the ids explicitly. An application with no source components is rejected rather than enqueuing a scan that would find nothing.

Stages without a backing scan worker (validation, rules) are rejected with a specific error naming the stage. That is deliberate: silently substituting the capability worker would give you results from a scan you did not ask for.

Step 2: Poll for completion

get_extract_status returns per-stage counts and which stage, if any, is currently running.

Plaintext
get_extract_status(application_id: "…")
→ %{counts: %{"capabilities" => 12}, running_stage: nil}

Poll until running_stage is nil. Note that a failed scan also ends with running_stage: nil — there is no pollable error field today, so a scan that dies mid-run looks like one that finished with no new candidates. If you are automating this, treat “no count change and no running stage” as inconclusive rather than as success, and check the application in the UI.

Step 3: List what it found

list_extract_candidates reads the candidates for a stage, filtered by status (detected, confirmed, or dismissed; defaults to detected).

Plaintext
list_extract_candidates(application_id: "…", stage: "capabilities", status: "detected")
→ [%{id: "…", name: "Invoice Approval", confidence: 0.82, …}, …]

Step 4: Review each candidate

Three tools cover the review decision:

Tool Effect
confirm_extract_candidate Marks the candidate confirmed and links it to an org-level capability
dismiss_extract_candidate Marks it dismissed, optionally recording a reason
undismiss_extract_candidate Returns a dismissed candidate to detected and clears the reason

confirm_extract_candidate requires a capability_id. A confirmed candidate has to point at a capability in your organization’s catalog, so create or find that capability first (list_capabilities / create_capability), then pass its id.

The dismiss reason is not just bookkeeping. It feeds back into the next scan so the detector stops re-suggesting the same thing. Recording why you rejected something is worth the extra argument.

Dismissing a candidate you already confirmed is rejected — unconfirm it first.

The confirm boundary: MCP confirm is the light path

This is the one place where the MCP surface is genuinely narrower than the UI, and it is worth being precise about.

In the web app, approving a detected capability runs a promotion flow: it can mint the org-level capability for you, carry the candidate’s description and evidence across, and wire up the links in one action. Over MCP, confirm_extract_candidate does the status flip and the link only. It does not promote.

So the MCP sequence is: create or pick the capability yourself, then confirm the candidate against it. Same end state, more steps, and you own the capability’s attributes rather than inheriting them from the candidate. If you want promotion-on-approve behavior, use the UI for that step.

Step 5: Enrich requirements

Standard authoring tools apply — list_requirements, list_requirements_filtered, get_requirement, create_requirement, update_requirement — plus a link/unlink pair for each association: link_requirement_to_policy, link_requirement_to_process, link_requirement_to_persona, and link_requirement_to_component, each with a matching unlink_requirement_from_*.

This part of the surface is essentially complete. If you can do it in the requirements UI, you can do it here.

Step 6: Resolve change proposals

Change proposals are Catalio’s suggested edits to your specification. The full lifecycle is now reachable:

Tool Effect
list_change_proposals Read an initiative’s proposals
apply_change_proposal Accept it and write the change through
dismiss_change_proposal Reject it, optionally with a reason and free-text feedback
restore_change_proposal Undo a dismissal, putting it back in the queue
delete_change_proposal Remove it entirely

dismiss_change_proposal accepts a dismissal_reason (a fixed set — not_relevant, inaccurate, duplicate, and others) and a dismissal_feedback string. Both are optional; dismissing with neither still works.

Restore clears the reason and the feedback along with the dismissal, because once a proposal is back in the queue the old rejection no longer describes it. An already-applied proposal cannot be dismissed or restored.

What stays in the UI

Two parts of the workflow are UI-first by design rather than oversight, and one is reachable only in a narrower form:

Document upload. Uploading a PDF, spec, or export means multipart file transfer, which MCP does not carry. Upload documents in the web app; everything downstream of the upload is reachable over MCP.

Interactive discovery sessions. Discovery is a guided conversation — Catalio asks follow-up questions and adapts based on your answers, with the session state driving the UI. It is led by the interface rather than by a sequence of tool calls, so there is no useful way to script it. Run discovery in the app, then work the resulting requirements from your editor.

Capability promotion, as covered above, is a third partial: reachable in a narrower form, full behavior in the UI only.

Authorization

Every tool runs as you, scoped to your organization. Catalio’s resources are tenant-isolated at the data layer, so the record a tool acts on is invisible if it belongs to another organization: the call fails as not-found rather than as a permission error. There is no way to reach across organizations by guessing an id, and no partial write happens on a rejected call.

Identifiers you pass inside a call are a separate check. confirm_extract_candidate takes a capability_id naming the capability to link the candidate to, and tenant isolation on the candidate says nothing about where that second id points. It is validated explicitly: a capability_id from another organization fails as a validation error against that field, not as not-found, and it fails before any write. The distinction matters when you are reading errors programmatically — a missing candidate and a foreign capability_id surface differently.

Your own permissions still apply within your organization: the tools go through the same policies as the UI.

Related Documentation