4.4 KiB
Example: Apex Invocable source
A complete walkthrough of the flow when the payload source is an Apex @InvocableMethod class that already exists in the project (source = apex). This is the fallback source — when the action is deployed to a reachable org, prefer action (describe it by name via the Actions REST API; see action-name-source-prompt.md). Use apex when no org is reachable or the describe 404s.
The prompt
I have an MCP server tool backed by the
GetAccountSummaryTestApex invocable action. Build a widget that renders its output so the account summary shows up as a rich card.
Phase 1 — Input selection
- Source:
apex(the prompt names an Apex Invocable class). - Tool API name:
getAccountSummary(from the class / invocable labelGet Account Summary).
Phase 2 — Payload discovery
Read references/mcp-tool-output-discovery.md, then locate .../classes/GetAccountSummaryTest.cls.
The invocable method:
@InvocableMethod(label='Get Account Summary')
global static List<GetAccountSummaryResponse> getAccountSummary(
List<GetAccountSummaryRequest> requests
) { ... }
- Response class =
GetAccountSummaryResponse(theList<...>element type) → payload source. - Request class =
GetAccountSummaryRequest→ excluded (tool input). private class OpportunityMetrics→ excluded (internal helper, not part of the invocable schema).
Enumerate @InvocableVariable fields on GetAccountSummaryResponse and map to CLT types:
| Field | Apex type | CLT lightning:type |
|---|---|---|
| status | String | lightning__textType |
| message | String | lightning__textType |
| accountId | Id | lightning__textType |
| accountName | String | lightning__textType |
| accountDescription | String | lightning__textType |
| accountIndustry | String | lightning__textType |
| accountPhone | String | lightning__textType |
| accountWebsite | String | lightning__textType |
| contactCount | Integer | lightning__integerType |
| opportunityCount | Integer | lightning__integerType |
| largestOpportunityId | Id | lightning__textType |
| largestOpportunityName | String | lightning__textType |
| largestOpportunityAmount | Decimal | lightning__numberType |
| totalOpportunityAmount | Decimal | lightning__numberType |
payloadFields = the 14 rows above.
Phase 3 — Build plan (abridged)
MCP Tool Widget Build Plan: getAccountSummaryWidget
PLAN: Render the GetAccountSummary MCP tool output as an account-summary card.
TOOL / SOURCE:
Tool API name: getAccountSummary
Payload source: Apex Invocable class GetAccountSummaryTest
Response class FQN: GetAccountSummaryTest.GetAccountSummaryResponse
LIGHTNING TYPES:
Response CLT: getAccountSummaryResponse (14 payload properties)
Envelope CLT: getAccountSummary
Renderer (default, bundle root): .../lightningTypes/getAccountSummary/renderer.json
Envelope: actionName (text), isSuccess (boolean), outputValues (c__getAccountSummaryResponse)
WIDGET: getAccountSummaryWidget
Renderer binding: each attribute → {!$attrs.outputValues.<field>}
Properties omitted: status, message (envelope-status text, not rendered on the card)
GENERATION ORDER: response CLT → widget → envelope CLT
Proceed unless the next reply pushes back.
Phase 4 — Generation order
- Response CLT
getAccountSummaryResponse—lightning__objectType, all 14payloadFields(1:1 with the response class's@InvocableVariablefields — the response CLT always models the complete response, includingstatus/message). - Envelope CLT
getAccountSummary—actionName,isSuccess,outputValues→c__getAccountSummaryResponse. - Widget
getAccountSummaryWidget— flat schema over the 12 rendered payload fields (14 minus the twoProperties omitted:status fields); body binds{!$attrs.accountName}etc. - Default renderer at
lightningTypes/getAccountSummary/renderer.json—definition: @widget/c/getAccountSummaryWidget, each attribute{!$attrs.outputValues.<field>}.
Phase 5 — Validation
clt-reference-integrity: envelopeoutputValues→c__getAccountSummaryResponse, response CLT exists, no$schema/items→ pass.renderer-wires-widget: bundle-root renderer present, definition@widget/c/getAccountSummaryWidget, every widget prop bound as{!$attrs.outputValues.<prop>}→ pass.field-trace: INVENTED empty; OMITTED =status, message(both inProperties omitted:) → pass.