# Workflow Capabilities This document separates the things an MCP-facing platform can expose from the things a workflow should usually consume. For the short operator/client workflow using these concepts, see [`wf_mcp_operator_manual.md`](wf_mcp_operator_manual.md). For the identifier rule behind source/capability names, see [`structural_refs.md`](structural_refs.md). In short: dotted qualified names are display strings and compatibility input only; saved refs should be structural. The short version: ```text raw capability != workflow capability ``` An MCP tool may be callable and still be a poor workflow node until someone wraps it into a cleaner workflow-facing contract. ## Core Terms ### Source A source is a named owner of capabilities. Examples: - `everything.default`: an upstream MCP connection source - `wf.std`: the local workflow standard library, including reusable nodes and reducers - `wf.mcp`: local workflow helpers for interacting with MCP backends - `wf.admin`: privileged control-plane capabilities A source is **not** defined by one protocol. MCP connection sources commonly own tools, prompts, and resources. Local sources may own only node specs, or node specs plus documentation prompts/resources, or only privileged admin tools. The source answers: ```text who owns this capability? ``` not: ```text what protocol transported it? ``` ### Raw Capability A raw capability is what a source directly provides. Examples: - an upstream MCP tool - an upstream MCP prompt - an upstream MCP resource - a local admin tool - a local standard-library helper Raw capabilities are useful for direct inspection and direct invocation, but their interface is shaped by the provider. That provider-facing interface may not be pleasant or safe for workflow composition. ### Workflow Capability A workflow capability is a workflow-facing `NodeSpec`. Today, a `NodeSpec` has: - one input schema - one output schema - one or more named outcomes It does **not** currently support a different output schema per outcome. The workflow capability answers: ```text how should a graph use this thing? ``` instead of: ```text how did the original provider happen to expose this thing? ``` ### Wrapper / Adapter Artifact A wrapper artifact is a saved reusable bridge from a raw capability to a workflow capability. In storage it is not a second artifact family: it is a `WorkflowArtifact` with `kind="wrapper"`. Examples: - convert a raw `isError` result into workflow outcomes such as `ok` and `error` - map a provider-specific `status` field into workflow outcomes such as `needs_input`, `done`, and `failed` - strip a provider result envelope and expose only the data a graph should use - normalize awkward parameter names or output shapes for repeated workflow use A wrapper artifact is useful when a human or LLM has learned once how to make a provider capability workflow-friendly and should not have to rediscover that interpretation every time. Expected properties: - saved - inspectable - reusable - dependency-aware - directly testable before use in a graph ### Workflow Artifact A workflow artifact is a saved graph. It may depend on: - workflow capabilities from local sources - generated workflow wrappers around upstream tools - saved wrapper artifacts authored earlier - other saved workflow artifacts later, once graph-as-node is real ### Deployment A deployment binds a saved workflow artifact to concrete runtime sources. This is where logical source names can resolve to concrete accounts or connections, for example: ```text context7 -> context7.default ``` or later: ```text crm -> salesforce.work ``` ## Why Raw MCP Tools Are Not Automatically Good Workflow Nodes MCP tools are general callable capabilities. Workflow nodes need contracts that compose well inside graphs. Common mismatch examples: ### Status Encoded In Output A provider may return: ```json { "status": "needs_input", "message": "pick one" } ``` A workflow usually wants an explicit outcome: ```text needs_input ``` so the graph can branch without every downstream node re-parsing provider status strings. ### Error Encoded By Transport Convention An MCP tool call has protocol-level success/error handling. A workflow often wants errors represented as explicit graph outcomes that must be wired. ### Provider Envelopes A provider may return: ```json { "ok": true, "data": { "items": [...] } } ``` while the graph wants: ```json { "items": [...] } ``` MCP text content blocks are a common provider-envelope case. When an MCP tool returns exactly one text content block, the SDK keeps the raw `content` list and also exposes a convenience `text` field. Wrapper hints prefer `text` so a string state field can map the actual text without writing the raw content-block list. Multiple content blocks or non-text content still require explicit wrapper decisions. ### Human-Friendly Versus Graph-Friendly Inputs A raw tool may be good for interactive human use but awkward for stateful graph composition. A wrapper can expose the small stable interface the graph actually needs. ## Generated Versus Authored Workflow Capabilities Some workflow capabilities can be generated mechanically: - a simple MCP tool whose result already maps cleanly to one output schema and `ok` / `error` outcomes Others should be authored and saved: - tools with domain-specific status fields - tools whose raw shape is too provider-centric - tools whose result needs durable semantic interpretation The platform should support both. ## Capability Steps In Drafts A capability-backed draft step records its selected capability in `use`, plus metadata, canonical input bindings, output bindings, and routes. Creation can set these common fields in one revision-checked operation: ```bash wf draft add capability report --revision 3 --step publish \ --capability local.report.publish \ --description "Publish report" --retry 2 --timeout-seconds 30 \ --input state.report.title=request.title \ --value request.format='"markdown"' --route ok=__end__ ``` Focused update changes only fields explicitly supplied by the caller. Omitted metadata is preserved; explicit null through JSON-RPC/MCP, or the matching CLI `--clear-*` flag, removes that override. Supplying canonical input bindings replaces the complete ordered list atomically. This update preserves `use`, routes, and outputs. Use their dedicated operations, or remove/add when changing the selected capability. The transport operation names are: - JSON-RPC: `workflow.draft_workspaces.add_step_from_capability` - JSON-RPC: `workflow.draft_workspaces.update_capability_step` - MCP: `wf.workflow.add_step_from_capability` - MCP: `wf.workflow.update_capability_step` ## Authoring Loop A client authoring workflows, including an LLM client, should be able to: 1. inspect available sources 2. inspect raw capabilities 3. inspect existing workflow capabilities and saved wrappers 4. call a workflow capability directly once 5. inspect the normalized output and outcome 6. author a workflow draft 7. validate or patch the draft 8. save the compiled workflow artifact Drafts are the preferred authoring format for this loop. See [`workflow_drafts.md`](workflow_drafts.md). Raw workflow plans remain an escape hatch for advanced clients and compiler outputs. Saved wrapper artifacts can be called with a deployment id when they use logical source names. The deployment supplies the concrete source bindings for that test call, matching the way `run_deployment` resolves a full saved workflow. Reusable wrapper and workflow artifacts should be authored against logical source names by default. If an author discovers a concrete capability such as `everything.default.echo`, the saved artifact should normally depend on a logical reference such as `everything.echo` plus a required capability entry. The deployment is responsible for binding `everything` to `everything.default`, `everything.work`, or any other compatible concrete source. This is especially important for LLM-authored workflows. The LLM should not need to infer dependency metadata by parsing formatted names, and a saved artifact should not accidentally become tied to the first account used during exploration. That direct-call surface is different from: - calling the raw upstream MCP tool - running a full workflow artifact - using privileged admin tools It exists so authors can test the workflow-facing contract before composing it. The workflow-facing MCP surface now has dedicated discovery tools for the authoring loop: - `wf.workflow.list_capabilities` - lists compact paged enabled planner-visible workflow-ready node spec summaries, with optional query/source filtering - also includes saved wrapper artifacts under source id `workflow` - includes the owning `source_id`, outcomes, and top-level input/output field names, but not full schemas - `wf.workflow.inspect_capability` - returns one full workflow capability contract with schemas and outcomes - includes `wrapper_hints`, a conservative scaffold for creating a wrapper draft from the inspected capability - `wf.workflow.create_draft_workspace_from_capability` - inspects one workflow capability, applies its `wrapper_hints`, and creates a patchable draft workspace - returns the hints it used so clients can immediately patch uncertain maps, schemas, or routes by revision - `wf.workflow.call_capability` - executes one such capability once for direct testing - returns `qualified_name`, `source_id`, `kind`, optional `deployment_id`, `outcome`, `output`, and `diagnostics` These are authoring-plane tools. They do not replace the privileged `wf.admin.list_sources` source inventory, and older planner-catalog projections may remain while callers migrate to the workflow-facing surface. Recommended discovery order: 1. Use `wf.admin.list_sources` to find capability owners and preview source contents. 2. Use `wf.workflow.list_capabilities` with `source_id` or `query` to find workflow-ready node specs. 3. Use `wf.workflow.inspect_capability` only for the selected capability's full schema contract. 4. Use `wf.workflow.call_capability` with a plain input object to test the selected contract once before composing it into a draft. For the copy-less wrapper authoring path, use: 1. `wf.workflow.inspect_capability` to inspect the source capability and review `wrapper_hints`. 2. `wf.workflow.create_draft_workspace_from_capability` to create a patchable draft workspace from those hints. 3. Focused patch helpers such as `wf.workflow.set_step_input_bindings`, `wf.workflow.set_step_output_bindings`, `wf.workflow.set_workflow_output_bindings`, their compatibility map adapters, and `wf.workflow.set_draft_route` to fix low-confidence hints or explicit `missing_decisions`. JSON-RPC clients use `workflow.draft_workspaces.set_workflow_output_bindings` for the same canonical replacement. 4. `wf.workflow.validate_draft_workspace` to refresh diagnostics. 5. `wf.workflow.create_wrapper_from_workspace` to save the wrapper artifact. 6. `wf.workflow.call_capability` with `workflow..v` to test the saved wrapper. See `examples/mcp_wrapper_authoring_flow.py` for the same flow through the Python handler layer. ## Wrapper Authoring Hints `wf.workflow.inspect_capability` returns `wrapper_hints` for planner-visible capabilities. These hints are scaffolding for draft creation, not semantic guarantees. Declared capability outcomes are authoritative and are preserved by default. Boolean output fields may appear as `outcome_candidates` when they have control-like names such as `success`, `error`, `approved`, or `has_more`, but they are never wired automatically. A wrapper author must explicitly confirm whether those fields should become routing conditions. `confidence` is intentionally coarse: - `high`: simple object input/output schemas and no missing decisions. - `medium`: usable scaffold with candidate decisions, such as boolean outcome candidates. - `low`: missing or nested output choices require explicit authoring. `missing_decisions` is a typed list of decisions the author should resolve before saving a wrapper. MCP clients should show these prominently rather than treating the scaffold as complete. `create_draft_workspace_from_capability` also returns `next_actions`. This is advisory guidance for clients that cannot easily read the full docs. It summarizes whether the scaffold is safe-looking enough to validate, which tool to call next, and concrete patch examples for common missing decisions. `patch_examples` may include top-level output projection bindings, which use `path` / `target` (not step-level `source` / `target`). `next_actions.can_save_now` is not enforced. A caller can still save a low confidence draft, but the field exists to make that risk explicit. `next_actions` is advisory guidance, not validation authority. It gives MCP clients a compact "what should I call next?" pointer, while diagnostics, artifact validation, deployment validation, and runtime status remain the source of truth. Deployment validation and run lifecycle responses also expose `next_actions`. For runnable deployments this points to `wf.workflow.run_deployment`; for unrunnable deployments it points back to validation after the caller repairs bindings, sources, or schema drift. Failed runs never suggest reading an unbounded trace; trace guidance always uses a bounded `trace_range`. ## Relationship To Capability Sources Sources own capability kinds: ```text tools node_specs reducers prompts resources ``` Possible later additions may include full workflow artifacts as first-class projected capability kinds, but they should not erase the raw versus workflow-facing distinction. Saved wrapper artifacts are already projected as workflow capabilities because they have a node-like callable boundary today. Examples: - `everything.default.tools["search"]` - raw upstream capability - `everything.default.node_specs["everything.default.search"]` - generated workflow-facing wrapper, if the raw tool maps cleanly - `user.crm.lookup_customer` - saved authored wrapper around a raw upstream tool, if the original contract needed interpretation ## Current System Truth Today: - `wf_platform.CapabilitySource` already owns buckets for tools, node specs, prompts, and resources - connection sources represent upstream MCP snapshots - `wf.std` owns local reusable workflow node specs and reducers - `wf.mcp` owns workflow-facing MCP runtime helpers - discovered upstream tools can already become workflow node specs - saved artifacts can be tagged with `kind="workflow"` or `kind="wrapper"` - `wf.workflow.call_capability` can execute one planner-visible workflow capability directly and return normalized `outcome` / `output` - `wf.workflow.list_capabilities` and `wf.workflow.inspect_capability` project saved wrapper artifacts as workflow capabilities under source id `workflow` Not yet implemented: - per-outcome output schemas - graph-as-node for saved workflows These are separate next steps. The current model should leave room for them without pretending they already exist.