salesforce-metadata-mcp 2.1.2 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTFORCE.md CHANGED
@@ -6,120 +6,218 @@ Complete guide for creating Agentforce agents with `salesforce-metadata-mcp`.
6
6
 
7
7
  ## Overview
8
8
 
9
- Agentforce (Einstein Copilot) agents consist of three components:
9
+ Agentforce (Einstein Copilot) agents are built from these metadata types, which must be created in order:
10
10
 
11
- 1. **Agent** — The top-level AI assistant with a persona and instructions
12
- 2. **Topics** — Areas of expertise (what types of requests the agent handles)
13
- 3. **Actions** — Concrete steps the agent takes (powered by Flows, Apex, or Prompt Templates)
11
+ 1. **AutoLaunchedFlow** — the action's implementation; must be Active with `runInMode=SystemModeWithoutSharing`
12
+ 2. **GenAiFunction** — wraps a flow as an agent action; includes LLM-facing JSON schemas
13
+ 3. **GenAiPlugin** (Topic) groups related actions; defines routing criteria and instructions
14
+ 4. **GenAiPlannerBundle** — links topics to the agent's planning engine
15
+ 5. **Bot** — the top-level agent referencing the planner bundle
16
+ 6. Activate the Bot
17
+
18
+ > **Important:** The agent type (`EinsteinCopilot` for internal employees, `ExternalCopilot` for customer-facing) is **immutable** after creation — choose carefully.
14
19
 
15
20
  ---
16
21
 
17
- ## Step 1: Create the Agent
22
+ ## Step 1: Create the Flow
23
+
24
+ The flow must be an AutoLaunchedFlow with `runInMode=SystemModeWithoutSharing` and must be **Active**.
18
25
 
19
26
  ```
20
- Create an Agentforce agent called SalesAssistant:
21
- - Label: Sales Assistant
22
- - Persona: A knowledgeable sales expert who helps reps close more deals
23
- - Tone: Professional
24
- - Instructions: Always check opportunity stage before recommending next steps. Be concise.
27
+ Create an AutoLaunchedFlow called Create_Account_Record that:
28
+ - Input variable: AccountName (String, isInput: true)
29
+ - Input variable: Industry (String, isInput: true, isRequired: false)
30
+ - Input variable: Phone (String, isInput: true, isRequired: false)
31
+ - CreateRecords element creating an Account with these fields
32
+ - Output variable: AccountId (String, isOutput: true) — set to the created record ID
25
33
  ```
26
34
 
27
- This calls `sf_create_agent` with:
35
+ ---
36
+
37
+ ## Step 2: Create Agent Actions (`sf_create_agent_action`)
38
+
39
+ Each action wraps one flow as a GenAiFunction. The tool automatically generates the required LLM-facing JSON schema files (`input/schema.json`, `output/schema.json`) — without these the LLM cannot invoke the action.
40
+
28
41
  ```json
29
42
  {
30
- "agentName": "SalesAssistant",
31
- "label": "Sales Assistant",
32
- "type": "EinsteinCopilot",
33
- "persona": "A knowledgeable sales expert who helps reps close more deals",
34
- "tone": "Neutral",
35
- "instructions": "Always check opportunity stage before recommending next steps. Be concise."
43
+ "actionName": "Create_Account",
44
+ "label": "Create Account",
45
+ "description": "Creates a new Account record with the provided company details",
46
+ "flowApiName": "Create_Account_Record",
47
+ "inputs": [
48
+ {
49
+ "name": "AccountName",
50
+ "label": "Account Name",
51
+ "description": "The name of the company or organization",
52
+ "type": "Text",
53
+ "required": true
54
+ },
55
+ {
56
+ "name": "Industry",
57
+ "label": "Industry",
58
+ "description": "The industry or business sector",
59
+ "type": "Text",
60
+ "required": false
61
+ },
62
+ {
63
+ "name": "Phone",
64
+ "label": "Phone",
65
+ "description": "The main phone number",
66
+ "type": "Text",
67
+ "required": false
68
+ }
69
+ ],
70
+ "outputs": [
71
+ {
72
+ "name": "AccountId",
73
+ "label": "Account ID",
74
+ "description": "The Salesforce ID of the created Account record",
75
+ "type": "Text"
76
+ }
77
+ ]
36
78
  }
37
79
  ```
38
80
 
81
+ > **Type matching:** The `type` field must match the flow variable's data type:
82
+ > - Flow `Currency` field → use `"type": "Currency"` (maps to `lightning__numberType`)
83
+ > - Flow `Date` field → use `"type": "Date"` (maps to `lightning__dateType`)
84
+ > - Flow `Number` field → use `"type": "Number"`
85
+ > - Flow `String`/`Text` field → use `"type": "Text"` (default)
86
+ >
87
+ > Using `"type": "Text"` for a Currency/Number field causes the LLM to send a string value that the flow rejects.
88
+
39
89
  ---
40
90
 
41
- ## Step 2: Create Topics
91
+ ## Step 3: Create Topics (`sf_create_agent_topic`)
42
92
 
43
- Topics tell the agent what kinds of user requests it can handle.
93
+ Topics define the agent's areas of expertise. Create topics **after** actions — topics reference action API names.
44
94
 
45
- ```
46
- Add a topic called OrderManagement to the SalesAssistant agent:
47
- - Label: Order Management
48
- - Description: Handles all questions about customer orders, quotes, and order status
49
- - Scope: User questions about creating orders, checking order status, updating order quantities
50
- - Instructions: 1. Identify the order or account. 2. Check current status. 3. Take appropriate action.
95
+ ```json
96
+ {
97
+ "topicName": "Account_Management",
98
+ "label": "Account Management",
99
+ "description": "Handle requests to create, update, or look up Account records in Salesforce CRM",
100
+ "scope": "This topic covers creating new company/account records, updating existing accounts, and looking up account information",
101
+ "instructions": [
102
+ "Collect the required company name from the user",
103
+ "Ask for optional details: industry, phone, website",
104
+ "Use the Create Account action to create the record",
105
+ "Confirm success by sharing the record ID with the user"
106
+ ],
107
+ "actions": ["Create_Account"]
108
+ }
51
109
  ```
52
110
 
53
111
  ---
54
112
 
55
- ## Step 3: Create a Flow for the Action
113
+ ## Step 4: Create Planner Bundle (`sf_create_agent_planner`)
114
+
115
+ The planner bundle is the **critical link** between the Bot and its topics. Without it, the agent has 0 visible topics and cannot route any requests.
56
116
 
57
- First, create the Flow that the agent will invoke:
117
+ Create the planner **after** all topics exist.
58
118
 
119
+ ```json
120
+ {
121
+ "plannerName": "CRM_Agent_Planner",
122
+ "label": "CRM Agent Planner",
123
+ "description": "Routes user requests to the appropriate CRM action topics",
124
+ "topicNames": ["Account_Management", "Lead_Management", "Opportunity_Management"]
125
+ }
59
126
  ```
60
- Create an AutoLaunchedFlow called Get_Account_Orders that:
61
- - Takes an input variable accountId (String, isInput: true)
62
- - Queries related Order__c records using GetRecords
63
- - Returns them in an output variable orders (SObject collection, isOutput: true)
127
+
128
+ ---
129
+
130
+ ## Step 5: Create Agent (`sf_create_agent`)
131
+
132
+ Create the Bot referencing the planner bundle name.
133
+
134
+ ```json
135
+ {
136
+ "agentName": "CRM_Record_Creator",
137
+ "label": "CRM Record Creator",
138
+ "description": "Creates and manages CRM records based on user requests",
139
+ "type": "EinsteinCopilot",
140
+ "plannerName": "CRM_Agent_Planner"
141
+ }
64
142
  ```
65
143
 
144
+ Agent types:
145
+ - `EinsteinCopilot` — internal employee-facing agent (shown in Lightning sidebar)
146
+ - `ExternalCopilot` — customer-facing Agentforce Service Agent (for Experience Cloud / messaging)
147
+
66
148
  ---
67
149
 
68
- ## Step 4: Link the Flow as an Agent Action
150
+ ## Step 6: Activate the Agent (`sf_activate_agent`)
69
151
 
152
+ ```json
153
+ {
154
+ "agentApiName": "CRM_Record_Creator"
155
+ }
70
156
  ```
71
- Create an agent action called GetOrders for the SalesAssistant agent's OrderManagement topic:
72
- - Type: Flow
73
- - Reference: Get_Account_Orders
74
- - Description: Retrieves all orders for a given account
75
- - Map input: accountId → {!Agent.Topic.Entities.accountId}
157
+
158
+ ---
159
+
160
+ ## Deactivating for Changes
161
+
162
+ You must deactivate an agent before modifying its topics, actions, or planner:
163
+
164
+ ```json
165
+ { "agentApiName": "CRM_Record_Creator" }
76
166
  ```
77
167
 
168
+ After making changes, re-activate with `sf_activate_agent`.
169
+
78
170
  ---
79
171
 
80
172
  ## End-to-End Example
81
173
 
82
- Full conversation to create a support agent:
174
+ Full prompt sequence to create a CRM Record Creator agent:
83
175
 
84
176
  ```
85
- 1. Create an Agentforce agent called SupportAgent with:
86
- - Persona: "A friendly and efficient customer support representative"
87
- - Tone: Formal
88
- - Company: Acme Corp
89
-
90
- 2. Add a topic CaseManagement to SupportAgent:
91
- - Description: Handles customer support cases, status inquiries, and escalations
92
- - Scope: Questions about case status, creating new cases, escalating urgent issues
93
-
94
- 3. Create an AutoLaunchedFlow called Create_Support_Case with:
95
- - Input variables: subject (String), description (String), contactId (String)
96
- - A CreateRecords element creating a Case with these fields
97
- - Output variable: caseId (String)
98
-
99
- 4. Create an agent action CreateCase for SupportAgent.CaseManagement:
100
- - Type: Flow
101
- - Reference: Create_Support_Case
102
- - Description: Creates a new support case for the customer
177
+ 1. Create AutoLaunchedFlow "Create_Account_Record":
178
+ - Input: AccountName (String, required), Industry (String), Phone (String)
179
+ - CreateRecords element → Account with those fields
180
+ - Output: AccountId (String)
181
+
182
+ 2. Create agent action "Create_Account":
183
+ - flowApiName: Create_Account_Record
184
+ - inputs: AccountName (Text, required), Industry (Text), Phone (Text)
185
+ - outputs: AccountId (Text)
186
+
187
+ 3. Create agent topic "Account_Management":
188
+ - description: "Handle requests to create Account records"
189
+ - scope: "Creating new company or organization accounts in Salesforce"
190
+ - instructions: ["Ask for company name", "Collect optional fields", "Call Create Account action", "Confirm the record ID"]
191
+ - actions: ["Create_Account"]
192
+
193
+ 4. Create planner "CRM_Agent_Planner":
194
+ - topicNames: ["Account_Management"]
195
+
196
+ 5. Create agent "CRM_Record_Creator":
197
+ - type: EinsteinCopilot
198
+ - plannerName: CRM_Agent_Planner
199
+
200
+ 6. Activate "CRM_Record_Creator"
103
201
  ```
104
202
 
105
203
  ---
106
204
 
107
- ## Testing Your Agent
205
+ ## Debugging
108
206
 
109
- After creating all components:
207
+ If the agent routes correctly but never invokes actions (agent says "I can't do that right now"):
110
208
 
111
- 1. **Activate the agent** in Setup Einstein Copilot Your Agent Activate
112
- 2. **Open Copilot** in any Salesforce page (the lightning bolt icon)
113
- 3. **Test a prompt:** "Show me all orders for Acme Corp"
209
+ 1. **Check schema files exist** Retrieve the GenAiFunction from your org. If you see `The Input LightningTypeBundle schema for action 'X' could not be found`, the schema files are missing. Use `sf_create_agent_action` to redeploy (it now generates schema files automatically).
114
210
 
115
- The agent should route to the OrderManagement topic and invoke the GetOrders action.
116
-
117
- ---
211
+ 2. **Check type mapping** If the action is invoked but the flow fails with "field in incorrect format", the `type` in your action inputs doesn't match the flow variable type. A Currency flow variable needs `"type": "Currency"`, not `"type": "Text"`.
118
212
 
119
- ## Tips
213
+ 3. **Check ConversationDefinitionEventLog** — Run SOQL:
214
+ ```sql
215
+ SELECT EventLabel, EventTarget, EventDetails
216
+ FROM ConversationDefinitionEventLog
217
+ WHERE LogDate = TODAY
218
+ ORDER BY EventDate DESC
219
+ LIMIT 50
220
+ ```
221
+ Look for `TopicClassificationSuccess` (routing worked) vs `ActionExecuted` (action ran).
120
222
 
121
- - **Be specific in topic descriptions** — the AI uses them to route requests
122
- - **Use clear action descriptions** — help the agent know when to invoke each action
123
- - **Start with Flows** — they're easiest to create and debug
124
- - **Test with narrow prompts first** — gradually expand scope
125
- - **Use variables consistently** — name them meaningfully for better AI reasoning
223
+ 4. **Verify planner exists** — If `TopicClassificationSuccess` never appears, the GenAiPlannerBundle may be missing. Use `sf_create_agent_planner` to create it.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.1.3] - 2026-05-28
4
+
5
+ ### Bug Fixes — Agentforce Action Invocation
6
+
7
+ This release fixes critical bugs that prevented Agentforce agents from invoking actions. Agents would correctly route to topics (TopicClassificationSuccess) but never call actions (no ActionExecuted events).
8
+
9
+ #### Root Cause: Missing GenAiFunction Schema Files
10
+
11
+ `sf_create_agent_action` was deploying GenAiFunction metadata without the required `input/schema.json` and `output/schema.json` bundle files. The Agentforce LLM runtime needs these JSON schemas to construct the tool call specification sent to the LLM. Without them, the LLM cannot invoke actions — it replies with messages like "I can't do that directly right now."
12
+
13
+ **Fix:** `sf_create_agent_action` now deploys a complete zip bundle containing:
14
+ - `genAiFunctions/<Name>/<Name>.genAiFunction-meta.xml`
15
+ - `genAiFunctions/<Name>/input/schema.json` — LLM-facing input parameter schema
16
+ - `genAiFunctions/<Name>/output/schema.json` — LLM-facing output parameter schema
17
+
18
+ Schema files use the correct Salesforce LightningTypeBundle format with `lightning:type`, `lightning:isPII`, `copilotAction:isUserInput`, `copilotAction:isDisplayable`, and `copilotAction:isUsedByPlanner` fields.
19
+
20
+ #### Flow Variable Type Mismatch Fixed
21
+
22
+ Flow variables of type `Currency`, `Number`, `Date`, and `DateTime` must use matching `lightning__numberType` or `lightning__dateType` in the schema, not `lightning__textType`. Using text type caused the LLM to send string values like `"5000"` which Flow rejected with "Amount field provided in incorrect format."
23
+
24
+ **Fix:** Added a `type` field to action parameters (`Text`, `Number`, `Currency`, `Boolean`, `Date`, `DateTime`, `TextArea`) that maps correctly to the corresponding `lightning:type` in the schema.
25
+
26
+ #### `sf_create_agent_topic` Was Creating Wrong Metadata Type
27
+
28
+ The tool was deploying `BotVersion` XML instead of `GenAiPlugin` XML.
29
+
30
+ **Fix:** Replaced `buildBotVersionXml` with `buildGenAiPluginXml` that produces correct `GenAiPlugin` metadata with `pluginType`, `scope`, `canEscalate`, step-by-step `genAiPluginInstructions`, and `genAiFunctions` references.
31
+
32
+ #### Added Missing Tools
33
+
34
+ - `sf_create_agent_planner` — Creates a `GenAiPlannerBundle` that links topics to the agent. This is the critical link between the Bot and its topics. Without it, the agent has 0 visible topics and cannot route any requests. Was missing entirely from v2.0.0.
35
+ - `sf_activate_agent` — Activates an agent via REST API after configuration changes.
36
+ - `sf_deactivate_agent` — Deactivates an agent (required before modifying topics/actions).
37
+
38
+ #### API Version Updated
39
+
40
+ Updated from `62.0` to `66.0` (current Salesforce API version for Agentforce metadata).
41
+
42
+ #### Schema Corrections (`sf_create_agent`)
43
+
44
+ - Removed invalid fields: `persona`, `tone`, `instructions`, `company` (not part of Bot metadata)
45
+ - Fixed `type` enum from `["Default", "EinsteinCopilot"]` to `["EinsteinCopilot", "ExternalCopilot"]`
46
+ - Added `agentTemplate: AiCopilot__AgentforceAgent` to Bot XML (required for proper action invocation wiring)
47
+
48
+ #### Correct Creation Order Now Enforced
49
+
50
+ The tool descriptions now document and enforce the correct metadata creation order:
51
+ 1. Create Flows (`sf_create_flow`) — AutoLaunchedFlows with `runInMode=SystemModeWithoutSharing`
52
+ 2. Create Actions (`sf_create_agent_action`) — GenAiFunction + schema files
53
+ 3. Create Topics (`sf_create_agent_topic`) — GenAiPlugin referencing actions
54
+ 4. Create Planner (`sf_create_agent_planner`) — GenAiPlannerBundle linking all topics
55
+ 5. Create Agent (`sf_create_agent`) — Bot referencing the planner
56
+ 6. Activate Agent (`sf_activate_agent`)
57
+
58
+ ---
59
+
3
60
  ## [2.0.0] - 2026-05-22
4
61
 
5
62
  ### Major Release — 60+ Tools
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- #!/usr/bin/env node
2
1
  export {};
3
2
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
File without changes
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -858,37 +858,39 @@ export const CreateExperiencePageSchema = z.object({
858
858
  }).strict();
859
859
  // ─── AGENTFORCE ───────────────────────────────────────────────────────────────
860
860
  export const CreateAgentSchema = z.object({
861
- agentName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Agent API name, e.g. 'SupportAgent'"),
862
- label: z.string().min(1).max(255).describe("Agent display name"),
863
- description: z.string().max(1000).optional().describe("Agent description shown to users"),
864
- type: z.enum(["Default", "EinsteinCopilot"]).default("EinsteinCopilot").describe("Agent type"),
865
- company: z.string().max(255).optional().describe("Company name for the agent's context"),
866
- persona: z.string().max(5000).optional().describe("Agent persona description, e.g. 'A helpful customer service representative'"),
867
- tone: z.enum(["Formal", "Neutral", "Casual"]).default("Neutral").describe("Communication tone"),
868
- instructions: z.string().max(10000).optional().describe("System-level instructions for the agent"),
861
+ agentName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Agent API name, e.g. 'CRM_Record_Creator'. IMMUTABLE after creation."),
862
+ label: z.string().min(1).max(255).describe("Agent display label, e.g. 'CRM Record Creator'"),
863
+ description: z.string().max(1000).optional().describe("Agent description"),
864
+ type: z.enum(["EinsteinCopilot", "ExternalCopilot"]).default("EinsteinCopilot").describe("Bot type: 'EinsteinCopilot' for internal employee agents (shown in Lightning sidebar), 'ExternalCopilot' for customer-facing Agentforce Service Agents. CANNOT be changed after creation."),
869
865
  }).strict();
870
866
  export const CreateAgentTopicSchema = z.object({
871
- agentName: z.string().min(1).max(80).describe("Parent agent API name"),
872
- topicName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Topic API name, e.g. 'OrderManagement'"),
873
- label: z.string().min(1).max(255).describe("Topic label"),
874
- description: z.string().min(1).max(5000).describe("What this topic covers"),
875
- scope: z.string().min(1).max(5000).describe("Scope of this topic what kind of requests it handles"),
876
- instructions: z.string().max(10000).optional().describe("Step-by-step instructions for handling this topic"),
877
- actions: z.array(z.string().max(80)).optional().describe("Action API names to associate with this topic"),
878
- }).strict();
867
+ topicName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Topic API name, e.g. 'Create_Account_Topic'. Used as the GenAiPlugin developer name."),
868
+ label: z.string().min(1).max(255).describe("Topic display label, e.g. 'Create Account Topic'"),
869
+ description: z.string().min(1).max(5000).describe("Routing description — the LLM uses this to decide which topic handles a user request. Be specific, e.g. 'Use this topic when the user wants to create, add, or make a new Account or company record'"),
870
+ scope: z.string().min(1).max(5000).describe("What this topic covers in detail, e.g. 'Create new Account records with company name, industry, phone, and website'"),
871
+ instructions: z.array(z.string().max(2000)).optional().describe("Ordered step-by-step instructions for the agent, e.g. ['Ask the user for the account name', 'Call the Create Account action', 'Confirm success to the user']"),
872
+ actions: z.array(z.string().max(80)).optional().describe("Action API names (GenAiFunction developer names) to associate, e.g. ['Create_Account']. Create actions first with sf_create_agent_action."),
873
+ }).strict();
874
+ const AgentParamSchema = z.object({
875
+ name: z.string().max(80).describe("Parameter API name matching the flow variable name, e.g. 'AccountName'"),
876
+ label: z.string().max(255).describe("Human-readable label, e.g. 'Account Name'"),
877
+ description: z.string().max(1000).optional().describe("Description shown to the LLM, e.g. 'The name of the company or organization'"),
878
+ type: z.enum(["Text", "Number", "Currency", "Boolean", "Date", "DateTime", "TextArea"]).default("Text").describe("Data type — must match the flow variable type: 'Currency'/'Number' for numeric fields, 'Date' for date fields, 'Boolean' for checkboxes, 'Text' for everything else"),
879
+ required: z.boolean().default(true).describe("Whether this input is required"),
880
+ });
879
881
  export const CreateAgentActionSchema = z.object({
880
- agentName: z.string().min(1).max(80).describe("Parent agent API name"),
881
- topicName: z.string().min(1).max(80).describe("Parent topic API name"),
882
- actionName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Action API name"),
883
- label: z.string().min(1).max(255).describe("Action label"),
884
- description: z.string().min(1).max(5000).describe("What this action does"),
885
- type: z.enum(["Flow", "ApexClass", "PromptTemplate", "DataCategoryGroup", "ExternalService"])
886
- .describe("Action type"),
887
- reference: z.string().min(1).max(255).describe("API name of the Flow, Apex class, or Prompt Template to invoke"),
888
- inputs: z.array(z.object({
889
- name: z.string().max(255).describe("Input parameter name"),
890
- value: z.string().max(1000).describe("Value or reference, e.g. '{!Agent.Topic.Entities.accountName}'"),
891
- })).optional().describe("Input parameter mappings"),
882
+ actionName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Action API name (GenAiFunction developer name), e.g. 'Create_Account'. Used to reference this action from topics."),
883
+ label: z.string().min(1).max(255).describe("Action display label, e.g. 'Create Account'"),
884
+ description: z.string().min(1).max(5000).describe("What this action does — the LLM uses this to decide when to invoke it. Be specific, e.g. 'Creates a new Account record in Salesforce with the given company name, industry, phone, and website'"),
885
+ flowApiName: z.string().min(1).max(255).describe("API name of the AutoLaunchedFlow to invoke, e.g. 'Create_Account_Record'. The flow must be Active and have runInMode=SystemModeWithoutSharing."),
886
+ inputs: z.array(AgentParamSchema).optional().describe("Flow input variables. Each input becomes a parameter the LLM collects from the user. Type MUST match the flow variable's data type."),
887
+ outputs: z.array(AgentParamSchema.omit({ required: true })).optional().describe("Flow output variables returned to the agent after execution, e.g. the created record ID"),
888
+ }).strict();
889
+ export const CreateAgentPlannerSchema = z.object({
890
+ plannerName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Planner API name, e.g. 'CRM_Creator_Planner'. NOTE: Names are permanently reserved even after deletion — use a unique name."),
891
+ label: z.string().min(1).max(255).describe("Planner display label, e.g. 'CRM Creator Planner'"),
892
+ description: z.string().max(1000).optional().describe("Planner description"),
893
+ topicNames: z.array(z.string().min(1).max(80)).min(1).describe("Topic API names (GenAiPlugin developer names) to include, e.g. ['Create_Account_Topic', 'Create_Lead_Topic']. Topics must already exist."),
892
894
  }).strict();
893
895
  // ─── MCP SERVER MANAGEMENT ───────────────────────────────────────────────────
894
896
  export const CreateMcpServerSchema = z.object({
@@ -64,6 +64,102 @@ export async function buildStaticResourceZip(resourceName, content, contentType,
64
64
  const buffer = await zip.generateAsync({ type: "nodebuffer" });
65
65
  return buffer.toString("base64");
66
66
  }
67
+ export async function buildGenAiActionZip(params, apiVersion) {
68
+ const zip = new JSZip();
69
+ const functionName = params.actionName;
70
+ const packageXml = buildPackageXml([{ name: "GenAiFunction", members: [functionName] }], apiVersion);
71
+ zip.file("package.xml", packageXml);
72
+ // Build mappingAttributes XML
73
+ const inputsXml = (params.inputs ?? []).map(inp => `
74
+ <mappingAttributes>
75
+ <description>${escapeXml(inp.description ?? inp.label)}</description>
76
+ <label>${escapeXml(inp.label)}</label>
77
+ <name>${escapeXml(inp.name)}</name>
78
+ <parameterName>${escapeXml(inp.name)}</parameterName>
79
+ <parameterType>input</parameterType>
80
+ </mappingAttributes>`).join("\n");
81
+ const outputsXml = (params.outputs ?? []).map(out => `
82
+ <mappingAttributes>
83
+ <description>${escapeXml(out.description ?? out.label)}</description>
84
+ <label>${escapeXml(out.label)}</label>
85
+ <name>${escapeXml(out.name)}</name>
86
+ <parameterName>${escapeXml(out.name)}</parameterName>
87
+ <parameterType>output</parameterType>
88
+ </mappingAttributes>`).join("\n");
89
+ const functionXml = `<?xml version="1.0" encoding="UTF-8"?>
90
+ <GenAiFunction xmlns="http://soap.sforce.com/2006/04/metadata">
91
+ <description>${escapeXml(params.description)}</description>
92
+ <invocationTarget>${escapeXml(params.flowApiName)}</invocationTarget>
93
+ <invocationTargetType>flow</invocationTargetType>
94
+ <isConfirmationRequired>false</isConfirmationRequired>
95
+ <masterLabel>${escapeXml(params.label)}</masterLabel>
96
+ ${inputsXml}
97
+ ${outputsXml}
98
+ </GenAiFunction>`;
99
+ zip.file(`genAiFunctions/${functionName}/${functionName}.genAiFunction-meta.xml`, functionXml);
100
+ // Build input schema JSON
101
+ const inputSchemaProps = {};
102
+ const requiredInputs = [];
103
+ for (const inp of (params.inputs ?? [])) {
104
+ inputSchemaProps[inp.name] = {
105
+ "title": inp.label,
106
+ "description": inp.description ?? inp.label,
107
+ "lightning:type": lightningTypeFor(inp.type ?? "Text"),
108
+ "lightning:isPII": false,
109
+ "copilotAction:isUserInput": true
110
+ };
111
+ if (inp.required !== false) {
112
+ requiredInputs.push(inp.name);
113
+ }
114
+ }
115
+ const inputSchema = {
116
+ "required": requiredInputs.length > 0 ? requiredInputs : undefined,
117
+ "unevaluatedProperties": false,
118
+ "properties": inputSchemaProps,
119
+ "lightning:type": "lightning__objectType"
120
+ };
121
+ if (!inputSchema.required) {
122
+ delete inputSchema.required;
123
+ }
124
+ zip.file(`genAiFunctions/${functionName}/input/schema.json`, JSON.stringify(inputSchema, null, 2));
125
+ // Build output schema JSON
126
+ const outputSchemaProps = {};
127
+ for (const out of (params.outputs ?? [])) {
128
+ outputSchemaProps[out.name] = {
129
+ "title": out.label,
130
+ "description": out.description ?? out.label,
131
+ "lightning:type": lightningTypeFor(out.type ?? "Text"),
132
+ "lightning:isPII": false,
133
+ "copilotAction:isDisplayable": true,
134
+ "copilotAction:isUsedByPlanner": true
135
+ };
136
+ }
137
+ const outputSchema = {
138
+ "unevaluatedProperties": false,
139
+ "properties": outputSchemaProps,
140
+ "lightning:type": "lightning__objectType"
141
+ };
142
+ zip.file(`genAiFunctions/${functionName}/output/schema.json`, JSON.stringify(outputSchema, null, 2));
143
+ const buffer = await zip.generateAsync({ type: "nodebuffer" });
144
+ return buffer.toString("base64");
145
+ }
146
+ function escapeXml(s) {
147
+ return String(s ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
148
+ }
149
+ function lightningTypeFor(sfType) {
150
+ const t = sfType.toLowerCase();
151
+ if (t === "currency" || t === "number" || t === "double" || t === "integer" || t === "percent")
152
+ return "lightning__numberType";
153
+ if (t === "boolean" || t === "checkbox")
154
+ return "lightning__booleanType";
155
+ if (t === "date")
156
+ return "lightning__dateType";
157
+ if (t === "datetime")
158
+ return "lightning__dateTimeType";
159
+ if (t === "textarea" || t === "longtextarea" || t === "richtext")
160
+ return "lightning__textAreaType";
161
+ return "lightning__textType";
162
+ }
67
163
  export async function buildGenericDeployZip(components, apiVersion) {
68
164
  const zip = new JSZip();
69
165
  const typeMap = new Map();
@@ -1,5 +1,5 @@
1
1
  import { execSync } from "child_process";
2
- export const API_VERSION = "62.0";
2
+ export const API_VERSION = "66.0";
3
3
  // ─── Token cache ──────────────────────────────────────────────────────────────
4
4
  let cachedToken = null;
5
5
  const TOKEN_TTL_MS = 55 * 60 * 1000;
@@ -1212,26 +1212,50 @@ function buildBotXml(params) {
1212
1212
  <met:fullName>${x(params.agentName)}</met:fullName>
1213
1213
  <met:label>${x(params.label)}</met:label>
1214
1214
  ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
1215
- <met:type>${x(params.type)}</met:type>
1216
- <met:status>Active</met:status>
1217
- ${params.company ? `<met:company>${x(params.company)}</met:company>` : ""}
1218
- ${params.persona ? `<met:persona>${x(params.persona)}</met:persona>` : ""}
1219
- <met:tone>${x(params.tone)}</met:tone>
1220
- ${params.instructions ? `<met:systemPrompt>${x(params.instructions)}</met:systemPrompt>` : ""}
1215
+ <met:agentTemplate>AiCopilot__AgentforceAgent</met:agentTemplate>
1216
+ <met:agentType>EinsteinServiceAgent</met:agentType>
1217
+ <met:botSource>None</met:botSource>
1218
+ <met:logPrivateConversationData>false</met:logPrivateConversationData>
1219
+ <met:richContentEnabled>true</met:richContentEnabled>
1220
+ <met:sessionTimeout>0</met:sessionTimeout>
1221
+ <met:type>${x(params.type ?? "EinsteinCopilot")}</met:type>
1221
1222
  </met:metadata>`;
1222
1223
  }
1223
- function buildBotVersionXml(params) {
1224
- const actionsXml = (params.actions ?? []).map(a => `
1225
- <met:botActions>
1226
- <met:botActionName>${x(a)}</met:botActionName>
1227
- </met:botActions>`).join("\n");
1228
- return `<met:metadata xsi:type="met:BotVersion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1229
- <met:fullName>${x(params.agentName)}.${x(params.topicName)}</met:fullName>
1230
- <met:label>${x(params.label)}</met:label>
1224
+ function buildGenAiPluginXml(params) {
1225
+ const instructionsXml = (params.instructions ?? []).map((instr, i) => `
1226
+ <met:genAiPluginInstructions>
1227
+ <met:description>${x(instr)}</met:description>
1228
+ <met:developerName>instruction_${i}</met:developerName>
1229
+ <met:masterLabel>instruction_${i}</met:masterLabel>
1230
+ <met:sortOrder>${i}</met:sortOrder>
1231
+ </met:genAiPluginInstructions>`).join("\n");
1232
+ const functionsXml = (params.actions ?? []).map(a => `
1233
+ <met:genAiFunctions>
1234
+ <met:functionName>${x(a)}</met:functionName>
1235
+ </met:genAiFunctions>`).join("\n");
1236
+ return `<met:metadata xsi:type="met:GenAiPlugin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1237
+ <met:fullName>${x(params.topicName)}</met:fullName>
1238
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
1231
1239
  <met:description>${x(params.description)}</met:description>
1232
1240
  <met:scope>${x(params.scope)}</met:scope>
1233
- ${params.instructions ? `<met:instructions>${x(params.instructions)}</met:instructions>` : ""}
1234
- ${actionsXml}
1241
+ <met:pluginType>Topic</met:pluginType>
1242
+ <met:canEscalate>false</met:canEscalate>
1243
+ <met:language>en_US</met:language>
1244
+ ${instructionsXml}
1245
+ ${functionsXml}
1246
+ </met:metadata>`;
1247
+ }
1248
+ function buildGenAiPlannerBundleXml(params) {
1249
+ const pluginsXml = params.topicNames.map(t => `
1250
+ <met:genAiPlugins>
1251
+ <met:genAiPluginName>${x(t)}</met:genAiPluginName>
1252
+ </met:genAiPlugins>`).join("\n");
1253
+ return `<met:metadata xsi:type="met:GenAiPlannerBundle" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
1254
+ <met:fullName>${x(params.plannerName)}</met:fullName>
1255
+ <met:masterLabel>${x(params.label)}</met:masterLabel>
1256
+ ${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
1257
+ <met:plannerType>AiCopilot__ReAct</met:plannerType>
1258
+ ${pluginsXml}
1235
1259
  </met:metadata>`;
1236
1260
  }
1237
1261
  function buildMatchingRuleXml(params) {
@@ -1474,6 +1498,33 @@ export async function createAgent(auth, params) {
1474
1498
  return upsertMetadata(auth, buildBotXml(params));
1475
1499
  }
1476
1500
  export async function createAgentTopic(auth, params) {
1477
- return upsertMetadata(auth, buildBotVersionXml(params));
1501
+ return upsertMetadata(auth, buildGenAiPluginXml(params));
1502
+ }
1503
+ export async function createAgentPlanner(auth, params) {
1504
+ return upsertMetadata(auth, buildGenAiPlannerBundleXml(params));
1505
+ }
1506
+ export async function activateAgent(auth, agentApiName) {
1507
+ try {
1508
+ const resp = await fetchWithTimeout(`${auth.instanceUrl}/services/data/v${API_VERSION}/connect/einstein/copilot/${agentApiName}/activate`, { method: "POST", headers: { "Authorization": `Bearer ${auth.accessToken}`, "Content-Type": "application/json" } }, 30_000);
1509
+ if (resp.ok)
1510
+ return { success: true, message: `Agent '${agentApiName}' activated successfully.` };
1511
+ const body = await resp.text().catch(() => "");
1512
+ return { success: false, message: `Activation failed (HTTP ${resp.status}): ${body}` };
1513
+ }
1514
+ catch (err) {
1515
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
1516
+ }
1517
+ }
1518
+ export async function deactivateAgent(auth, agentApiName) {
1519
+ try {
1520
+ const resp = await fetchWithTimeout(`${auth.instanceUrl}/services/data/v${API_VERSION}/connect/einstein/copilot/${agentApiName}/deactivate`, { method: "POST", headers: { "Authorization": `Bearer ${auth.accessToken}`, "Content-Type": "application/json" } }, 30_000);
1521
+ if (resp.ok)
1522
+ return { success: true, message: `Agent '${agentApiName}' deactivated successfully.` };
1523
+ const body = await resp.text().catch(() => "");
1524
+ return { success: false, message: `Deactivation failed (HTTP ${resp.status}): ${body}` };
1525
+ }
1526
+ catch (err) {
1527
+ return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
1528
+ }
1478
1529
  }
1479
1530
  //# sourceMappingURL=salesforce.js.map
@@ -1,10 +1,21 @@
1
- import { CreateAgentSchema, CreateAgentTopicSchema, CreateAgentActionSchema } from "../schemas/index.js";
2
- import { getAuth, createAgent, createAgentTopic } from "../services/salesforce.js";
1
+ import { CreateAgentSchema, CreateAgentTopicSchema, CreateAgentActionSchema, CreateAgentPlannerSchema } from "../schemas/index.js";
2
+ import { getAuth, createAgent, createAgentTopic, createAgentPlanner, activateAgent, deactivateAgent, API_VERSION } from "../services/salesforce.js";
3
+ import { buildGenAiActionZip, deployZip, pollDeployStatus } from "../services/deployment.js";
3
4
  import { resultContent } from "./utils.js";
4
5
  export function registerAgentforceTools(server) {
5
6
  server.registerTool("sf_create_agent", {
6
7
  title: "Create Agentforce Agent",
7
- description: `Creates an Agentforce Agent (Einstein Copilot) in Salesforce using the Bot metadata type. An agent is an AI assistant that can understand natural language, reason about user intent, and take actions using topics and linked flows/actions. Specify the agent's persona, tone, and system-level instructions to shape its behavior and communication style.`,
8
+ description: `Creates an Agentforce Agent (Einstein Copilot / Service Agent) in Salesforce using the Bot metadata type.
9
+
10
+ IMPORTANT: Follow this exact creation order for a fully working agent:
11
+ 1. Create flows (sf_create_flow) — the AutoLaunchedFlows that perform actions
12
+ 2. Create agent actions (sf_create_agent_action) — link each flow as a GenAiFunction
13
+ 3. Create agent topics (sf_create_agent_topic) — create GenAiPlugin topics referencing the actions
14
+ 4. Create agent planner (sf_create_agent_planner) — create GenAiPlannerBundle linking all topics
15
+ 5. Create agent (sf_create_agent) — create the Bot referencing the planner
16
+ 6. Activate the agent (sf_activate_agent)
17
+
18
+ The agent type is IMMUTABLE after creation — choose carefully (EinsteinCopilot for internal, ExternalCopilot for customer-facing).`,
8
19
  inputSchema: CreateAgentSchema,
9
20
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
10
21
  }, async (params) => {
@@ -14,22 +25,20 @@ export function registerAgentforceTools(server) {
14
25
  label: params.label,
15
26
  description: params.description,
16
27
  type: params.type,
17
- company: params.company,
18
- persona: params.persona,
19
- tone: params.tone,
20
- instructions: params.instructions,
21
28
  });
22
29
  return resultContent(result);
23
30
  });
24
31
  server.registerTool("sf_create_agent_topic", {
25
- title: "Create Agentforce Topic",
26
- description: `Creates a Topic for an Agentforce Agent. Topics define areas of expertise — what types of user requests the agent can handle. Each topic has a description (what it covers), scope (what kinds of questions it answers), and optional step-by-step instructions for how the agent should respond. Topics are linked to Actions that the agent can execute.`,
32
+ title: "Create Agentforce Topic (GenAiPlugin)",
33
+ description: `Creates a Topic (GenAiPlugin) for an Agentforce Agent. Topics define the agent's areas of expertise — what types of user requests it handles. Each topic has a description (routing criteria), scope (what it covers), step-by-step instructions, and references to agent actions.
34
+
35
+ Create topics AFTER creating agent actions (sf_create_agent_action) since topics reference actions by API name.
36
+ Then create the planner bundle (sf_create_agent_planner) to link all topics to the agent.`,
27
37
  inputSchema: CreateAgentTopicSchema,
28
38
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
29
39
  }, async (params) => {
30
40
  const auth = await getAuth();
31
41
  const result = await createAgentTopic(auth, {
32
- agentName: params.agentName,
33
42
  topicName: params.topicName,
34
43
  label: params.label,
35
44
  description: params.description,
@@ -40,34 +49,78 @@ export function registerAgentforceTools(server) {
40
49
  return resultContent(result);
41
50
  });
42
51
  server.registerTool("sf_create_agent_action", {
43
- title: "Create Agentforce Action",
44
- description: `Creates an Agentforce Action linked to a Flow, Apex class, or Prompt Template. Actions are the concrete steps an agent takes when handling a topic. The agent decides which action to invoke based on the user's request and the topic's instructions. Flow actions are the most common — create a Flow first, then link it as an agent action.`,
52
+ title: "Create Agentforce Action (GenAiFunction)",
53
+ description: `Creates an Agentforce Action (GenAiFunction) linked to a Flow. Actions are the concrete steps an agent takes when handling a topic. The LLM invokes actions based on the topic's instructions and the user's request.
54
+
55
+ IMPORTANT: This deploys a complete GenAiFunction bundle including:
56
+ - The GenAiFunction metadata (invocationTarget, invocationTargetType, mappingAttributes)
57
+ - input/schema.json — the LLM-facing JSON schema for input parameters (REQUIRED for action invocation)
58
+ - output/schema.json — the LLM-facing JSON schema for output parameters
59
+
60
+ Without the schema files, the LLM cannot invoke the action. This tool handles all three files automatically.
61
+
62
+ Create actions BEFORE topics (topics reference actions by API name).
63
+ The referenced flow MUST exist and be Active with runInMode=SystemModeWithoutSharing.`,
45
64
  inputSchema: CreateAgentActionSchema,
46
65
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
47
66
  }, async (params) => {
48
67
  const auth = await getAuth();
49
68
  try {
50
- // Agent actions are created via the GenAiPlanner/GenAiFunctionDef metadata
51
- const { upsertMetadata, x } = await import("../services/salesforce.js");
52
- const inputsXml = (params.inputs ?? []).map((inp) => `
53
- <met:inputs>
54
- <met:name>${x(inp.name)}</met:name>
55
- <met:value>${x(inp.value)}</met:value>
56
- </met:inputs>`).join("\n");
57
- const xml = `<met:metadata xsi:type="met:GenAiFunction" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
58
- <met:fullName>${x(params.agentName)}.${x(params.topicName)}.${x(params.actionName)}</met:fullName>
59
- <met:masterLabel>${x(params.label)}</met:masterLabel>
60
- <met:description>${x(params.description)}</met:description>
61
- <met:type>${x(params.type)}</met:type>
62
- <met:functionRef>${x(params.reference)}</met:functionRef>
63
- ${inputsXml}
64
- </met:metadata>`;
65
- const result = await upsertMetadata(auth, xml);
69
+ const base64Zip = await buildGenAiActionZip({
70
+ actionName: params.actionName,
71
+ label: params.label,
72
+ description: params.description,
73
+ flowApiName: params.flowApiName,
74
+ inputs: params.inputs ?? [],
75
+ outputs: params.outputs ?? [],
76
+ }, API_VERSION);
77
+ const deployId = await deployZip(auth, base64Zip);
78
+ const result = await pollDeployStatus(auth, deployId, 120_000);
66
79
  return resultContent(result);
67
80
  }
68
81
  catch (err) {
69
82
  return resultContent({ success: false, message: err instanceof Error ? err.message : String(err) });
70
83
  }
71
84
  });
85
+ server.registerTool("sf_create_agent_planner", {
86
+ title: "Create Agentforce Planner Bundle (GenAiPlannerBundle)",
87
+ description: `Creates a GenAiPlannerBundle that connects topics to the agent's planning engine.
88
+
89
+ The planner bundle is the CRITICAL link between the Bot and its topics (GenAiPlugins). Without it, the agent will have 0 topics visible and cannot route requests or invoke actions.
90
+
91
+ Create the planner bundle AFTER creating all topics (sf_create_agent_topic) and BEFORE creating the agent (sf_create_agent).
92
+ Then reference this planner's API name when calling sf_create_agent.`,
93
+ inputSchema: CreateAgentPlannerSchema,
94
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
95
+ }, async (params) => {
96
+ const auth = await getAuth();
97
+ const result = await createAgentPlanner(auth, {
98
+ plannerName: params.plannerName,
99
+ label: params.label,
100
+ description: params.description,
101
+ topicNames: params.topicNames,
102
+ });
103
+ return resultContent(result);
104
+ });
105
+ server.registerTool("sf_activate_agent", {
106
+ title: "Activate Agentforce Agent",
107
+ description: `Activates an Agentforce Agent so it is available to users. The agent must be inactive (deactivated) before you can make configuration changes like adding/removing topics or actions. After making changes, re-activate with this tool.`,
108
+ inputSchema: { type: "object", properties: { agentApiName: { type: "string", description: "API name of the agent to activate, e.g. 'CRM_Record_Creator'" } }, required: ["agentApiName"] },
109
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
110
+ }, async (params) => {
111
+ const auth = await getAuth();
112
+ const result = await activateAgent(auth, params.agentApiName);
113
+ return resultContent(result);
114
+ });
115
+ server.registerTool("sf_deactivate_agent", {
116
+ title: "Deactivate Agentforce Agent",
117
+ description: `Deactivates an Agentforce Agent so configuration changes can be made. You must deactivate an agent before modifying its topics, actions, or planner configuration. After making changes, re-activate with sf_activate_agent.`,
118
+ inputSchema: { type: "object", properties: { agentApiName: { type: "string", description: "API name of the agent to deactivate, e.g. 'CRM_Record_Creator'" } }, required: ["agentApiName"] },
119
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
120
+ }, async (params) => {
121
+ const auth = await getAuth();
122
+ const result = await deactivateAgent(auth, params.agentApiName);
123
+ return resultContent(result);
124
+ });
72
125
  }
73
- //# sourceMappingURL=agentforce.js.map
126
+ //# sourceMappingURL=agentforce.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesforce-metadata-mcp",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "The most comprehensive Salesforce metadata and development MCP server: 60+ tools for custom objects, flows, Apex, LWC, Agentforce, deployments, and more",
5
5
  "license": "MIT",
6
6
  "private": false,