Files
lda-wf/docs/workflow_capabilities.md
T

15 KiB

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.

For the identifier rule behind source/capability names, see structural_refs.md. In short: dotted qualified names are display strings and compatibility input only; saved refs should be structural.

The short version:

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:

who owns this capability?

not:

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:

how should a graph use this thing?

instead of:

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:

context7 -> context7.default

or later:

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:

{
  "status": "needs_input",
  "message": "pick one"
}

A workflow usually wants an explicit outcome:

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:

{
  "ok": true,
  "data": {
    "items": [...]
  }
}

while the graph wants:

{
  "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:

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. 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.<artifact_id>.v<version> 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:

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.