salesforce-metadata-mcp 2.3.0 → 2.4.0
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/CHANGELOG.md +42 -0
- package/README.md +43 -3
- package/dist/index.js +4 -4
- package/dist/schemas/index.js +123 -0
- package/dist/services/salesforce.js +358 -0
- package/dist/tools/audit.js +96 -0
- package/dist/tools/data.js +33 -2
- package/dist/tools/deployment.js +22 -2
- package/dist/tools/einstein.js +79 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/integrations.js +39 -2
- package/dist/tools/ui.js +32 -2
- package/package.json +14 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.4.0] - 2026-05-28
|
|
4
|
+
|
|
5
|
+
### New Tools — 14 Additions Across 6 Categories
|
|
6
|
+
|
|
7
|
+
#### Lightning Pages & App Builder (2 new)
|
|
8
|
+
- `sf_create_lightning_app_page` — Create a Lightning App Page (FlexiPage of type AppPage) for use in Lightning Apps
|
|
9
|
+
- `sf_create_letterhead` — Create email letterheads (Letterhead metadata) for Classic email templates
|
|
10
|
+
|
|
11
|
+
#### Users & Data Management (2 new)
|
|
12
|
+
- `sf_delete_record` — Delete a single SObject record by ID via REST API
|
|
13
|
+
- `sf_send_email` — Send email from Salesforce via the emailSimple invocable action
|
|
14
|
+
|
|
15
|
+
#### Audit Trail & Monitoring (4 new)
|
|
16
|
+
- `sf_get_setup_audit_trail` — Query SetupAuditTrail for org configuration change history (last 6 months)
|
|
17
|
+
- `sf_get_login_history` — Query LoginHistory for user login activity (source IP, browser, status)
|
|
18
|
+
- `sf_get_event_logs` — Fetch and parse EventLogFile entries (Login, API, Report, Flow, Apex, LightningPageView, etc.)
|
|
19
|
+
- `sf_get_field_history` — Query {Object}History for field-level change history on a specific record
|
|
20
|
+
|
|
21
|
+
#### Deployment & Org Management (1 new)
|
|
22
|
+
- `sf_compare_orgs` — Compare metadata between two orgs using SF CLI aliases; returns components only in source, only in target, or different in both
|
|
23
|
+
|
|
24
|
+
#### Integration & Connectivity (2 new)
|
|
25
|
+
- `sf_create_certificate` — Create a self-signed Certificate (Certificate metadata) for callout signing and SSO
|
|
26
|
+
- `sf_create_event_relay` — Create an EventRelayConfig to relay Platform Events or CDC to Amazon EventBridge or another event bus
|
|
27
|
+
|
|
28
|
+
#### Einstein & AI Features (3 new)
|
|
29
|
+
- `sf_create_einstein_prediction` — Create an Einstein Prediction Builder definition (MLPredictionDefinition metadata) for binary classification or regression
|
|
30
|
+
- `sf_create_next_best_action` — Create a Next Best Action recommendation strategy (RecommendationStrategy metadata)
|
|
31
|
+
- `sf_create_einstein_bot` — Create a classic Einstein Bot with ML domain and conversation dialogs (Bot + BotVersion metadata)
|
|
32
|
+
|
|
33
|
+
### Notes on Existing Tools
|
|
34
|
+
The following tools requested in v2.4.0 were already present from earlier releases and are unchanged:
|
|
35
|
+
- Security & Permissions: `sf_create_permission_set_group`, `sf_create_muting_permission_set`, `sf_set_field_level_security`, `sf_set_org_wide_defaults`, `sf_clone_profile`, `sf_update_profile`
|
|
36
|
+
- Lightning Pages: `sf_create_lightning_record_page`, `sf_create_lightning_home_page`, `sf_update_lightning_page`, `sf_assign_lightning_page`, `sf_assign_compact_layout`
|
|
37
|
+
- Reports & Dashboards: `sf_create_report`, `sf_update_dashboard`, `sf_create_report_folder`, `sf_share_report_folder`
|
|
38
|
+
- Users & Data: `sf_create_user`, `sf_update_user`, `sf_assign_queue_member`, `sf_create_public_group`, `sf_query_records`, `sf_create_record`, `sf_update_record`, `sf_bulk_import_records`
|
|
39
|
+
- Deployment: `sf_validate_deployment`, `sf_list_metadata`
|
|
40
|
+
- Integrations: `sf_create_outbound_message`, `sf_create_auth_provider`
|
|
41
|
+
- GitHub Actions workflows: present since v2.3.0 (ci.yml, publish.yml, sf-release-monitor.yml, api-version-bump.yml)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
3
45
|
## [2.3.0] - 2026-05-28
|
|
4
46
|
|
|
5
47
|
### New Tools — 30 Additions Across 8 Categories
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# salesforce-metadata-mcp
|
|
2
2
|
|
|
3
|
-
[](https://npmjs.com/package/salesforce-metadata-mcp)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://modelcontextprotocol.io)
|
|
6
6
|
|
|
7
|
-
**The most comprehensive Salesforce MCP server.**
|
|
7
|
+
**The most comprehensive Salesforce MCP server.** 155+ tools for building, configuring, and automating Salesforce orgs directly from Claude or any MCP client — covering metadata, Apex, LWC, Agentforce agents, OmniStudio, OmniChannel, Experience Cloud, Field Service, Messaging, Einstein AI, audit trail, bulk data, users, reports, security, and more.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -46,6 +46,24 @@ See [SETUP.md](SETUP.md) for all authentication methods and detailed setup instr
|
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
+
## What's New in v2.4.0
|
|
50
|
+
|
|
51
|
+
14 new tools across 6 categories:
|
|
52
|
+
|
|
53
|
+
- **Lightning App Page** — `sf_create_lightning_app_page` for Lightning App tab pages
|
|
54
|
+
- **Letterhead** — `sf_create_letterhead` for Classic email template branding
|
|
55
|
+
- **Record Delete** — `sf_delete_record` via REST API
|
|
56
|
+
- **Email** — `sf_send_email` via the emailSimple invocable action
|
|
57
|
+
- **Audit Trail** — `sf_get_setup_audit_trail`, `sf_get_login_history`, `sf_get_event_logs`, `sf_get_field_history`
|
|
58
|
+
- **Org Comparison** — `sf_compare_orgs` using SF CLI aliases
|
|
59
|
+
- **Certificates** — `sf_create_certificate` (self-signed, for callout signing/SSO)
|
|
60
|
+
- **Event Relay** — `sf_create_event_relay` to Amazon EventBridge or event bus
|
|
61
|
+
- **Einstein AI** — `sf_create_einstein_prediction`, `sf_create_next_best_action`, `sf_create_einstein_bot`
|
|
62
|
+
|
|
63
|
+
See [CHANGELOG.md](CHANGELOG.md) for full release notes.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
49
67
|
## What's New in v2.3.0
|
|
50
68
|
|
|
51
69
|
30 new tools across 8 categories:
|
|
@@ -82,7 +100,7 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
|
|
|
82
100
|
|
|
83
101
|
---
|
|
84
102
|
|
|
85
|
-
## Tools (
|
|
103
|
+
## Tools (155+)
|
|
86
104
|
|
|
87
105
|
### Objects & Fields
|
|
88
106
|
| Tool | Description |
|
|
@@ -159,6 +177,8 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
|
|
|
159
177
|
| `sf_create_lightning_home_page` | Create a Lightning Home Page (FlexiPage) |
|
|
160
178
|
| `sf_update_lightning_page` | Update an existing Lightning Page |
|
|
161
179
|
| `sf_assign_lightning_page` | Assign a Lightning Page to an Experience site |
|
|
180
|
+
| `sf_create_lightning_app_page` | Create a Lightning App Page (FlexiPage for App tabs) |
|
|
181
|
+
| `sf_create_letterhead` | Create an email letterhead for Classic email templates |
|
|
162
182
|
|
|
163
183
|
### Apex, Visualforce & Aura
|
|
164
184
|
| Tool | Description |
|
|
@@ -199,6 +219,8 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
|
|
|
199
219
|
| `sf_create_record` | Create a single SObject record |
|
|
200
220
|
| `sf_update_record` | Update an existing SObject record by ID |
|
|
201
221
|
| `sf_bulk_import_records` | Bulk insert/upsert/update/delete via Bulk API 2.0 |
|
|
222
|
+
| `sf_delete_record` | Delete a single SObject record by ID |
|
|
223
|
+
| `sf_send_email` | Send email from Salesforce via the emailSimple action |
|
|
202
224
|
|
|
203
225
|
### Experience Cloud
|
|
204
226
|
| Tool | Description |
|
|
@@ -238,6 +260,8 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
|
|
|
238
260
|
| `sf_create_csp_setting` | Create CSP trusted sites for LWC |
|
|
239
261
|
| `sf_create_outbound_message` | Create Workflow Outbound Messages |
|
|
240
262
|
| `sf_create_auth_provider` | Create OAuth Auth Providers |
|
|
263
|
+
| `sf_create_certificate` | Create a self-signed Certificate for callout signing/SSO |
|
|
264
|
+
| `sf_create_event_relay` | Create an Event Relay to Amazon EventBridge or event bus |
|
|
241
265
|
|
|
242
266
|
### Change Sets & Deployment
|
|
243
267
|
| Tool | Description |
|
|
@@ -249,6 +273,7 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
|
|
|
249
273
|
| `sf_check_deploy_status` | Check deployment job status |
|
|
250
274
|
| `sf_retrieve_metadata` | Retrieve metadata from the org |
|
|
251
275
|
| `sf_list_metadata` | List all components of a metadata type |
|
|
276
|
+
| `sf_compare_orgs` | Compare metadata between two orgs using SF CLI aliases |
|
|
252
277
|
|
|
253
278
|
### OmniStudio
|
|
254
279
|
| Tool | Description |
|
|
@@ -270,6 +295,21 @@ See [CHANGELOG.md](CHANGELOG.md) for the full release notes.
|
|
|
270
295
|
| `sf_create_calculation_matrix` | Create a Calculation Matrix for rule-based lookups |
|
|
271
296
|
| `sf_create_calculation_procedure` | Create a Calculation Procedure with multi-step logic |
|
|
272
297
|
|
|
298
|
+
### Audit Trail & Monitoring
|
|
299
|
+
| Tool | Description |
|
|
300
|
+
|------|-------------|
|
|
301
|
+
| `sf_get_setup_audit_trail` | Query SetupAuditTrail for org configuration change history |
|
|
302
|
+
| `sf_get_login_history` | Query LoginHistory for user login activity |
|
|
303
|
+
| `sf_get_event_logs` | Fetch and parse EventLogFile entries (Login, API, Flow, Apex, etc.) |
|
|
304
|
+
| `sf_get_field_history` | Get field-level change history for a specific record |
|
|
305
|
+
|
|
306
|
+
### Einstein & AI
|
|
307
|
+
| Tool | Description |
|
|
308
|
+
|------|-------------|
|
|
309
|
+
| `sf_create_einstein_prediction` | Create an Einstein Prediction Builder definition |
|
|
310
|
+
| `sf_create_next_best_action` | Create a Next Best Action recommendation strategy |
|
|
311
|
+
| `sf_create_einstein_bot` | Create a classic Einstein Bot with dialogs |
|
|
312
|
+
|
|
273
313
|
### OmniChannel & Field Service
|
|
274
314
|
| Tool | Description |
|
|
275
315
|
|------|-------------|
|
package/dist/index.js
CHANGED
|
@@ -6,14 +6,14 @@ import { createServer } from "http";
|
|
|
6
6
|
import { registerTools } from "./tools/index.js";
|
|
7
7
|
const server = new McpServer({
|
|
8
8
|
name: "salesforce-metadata-mcp",
|
|
9
|
-
version: "2.
|
|
9
|
+
version: "2.4.0",
|
|
10
10
|
});
|
|
11
11
|
registerTools(server);
|
|
12
12
|
// ─── Transport: stdio ─────────────────────────────────────────────────────────
|
|
13
13
|
async function runStdio() {
|
|
14
14
|
const transport = new StdioServerTransport();
|
|
15
15
|
await server.connect(transport);
|
|
16
|
-
console.error("Salesforce Metadata MCP server v2.
|
|
16
|
+
console.error("Salesforce Metadata MCP server v2.4.0 running on stdio");
|
|
17
17
|
}
|
|
18
18
|
// ─── Transport: HTTP ──────────────────────────────────────────────────────────
|
|
19
19
|
function readBody(req) {
|
|
@@ -38,7 +38,7 @@ async function runHTTP() {
|
|
|
38
38
|
const url = req.url ?? "/";
|
|
39
39
|
if (url === "/health" && req.method === "GET") {
|
|
40
40
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41
|
-
res.end(JSON.stringify({ status: "ok", server: "salesforce-metadata-mcp", version: "2.
|
|
41
|
+
res.end(JSON.stringify({ status: "ok", server: "salesforce-metadata-mcp", version: "2.4.0"}));
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
if (url === "/mcp" && req.method === "POST") {
|
|
@@ -64,7 +64,7 @@ async function runHTTP() {
|
|
|
64
64
|
res.end(JSON.stringify({ error: "Not found" }));
|
|
65
65
|
});
|
|
66
66
|
httpServer.listen(port, () => {
|
|
67
|
-
console.error(`Salesforce Metadata MCP server v2.
|
|
67
|
+
console.error(`Salesforce Metadata MCP server v2.4.0 running on http://localhost:${port}/mcp`);
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
// ─── Entry point ──────────────────────────────────────────────────────────────
|
package/dist/schemas/index.js
CHANGED
|
@@ -1667,4 +1667,127 @@ export const CreateBotRoutingSchema = z.object({
|
|
|
1667
1667
|
action: z.enum(["TransferToQueue","EndChat","SetVariable"]).default("TransferToQueue"),
|
|
1668
1668
|
})).optional().describe("Conditions that trigger transfer to human agent"),
|
|
1669
1669
|
}).strict();
|
|
1670
|
+
// ─── v2.4.0 — NEW TOOLS ──────────────────────────────────────────────────────
|
|
1671
|
+
export const CreateLightningAppPageSchema = z.object({
|
|
1672
|
+
pageName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("FlexiPage API name"),
|
|
1673
|
+
label: z.string().min(1).describe("Page display label"),
|
|
1674
|
+
template: z.string().default("AppDefaultTemplate").describe("Page template, e.g. AppDefaultTemplate, OneRegion, TwoColumn_LeftSidebar"),
|
|
1675
|
+
components: z.array(FlexiComponentSchema).optional().describe("Components to add to the page"),
|
|
1676
|
+
description: z.string().optional().describe("Page description"),
|
|
1677
|
+
}).strict();
|
|
1678
|
+
export const DeleteRecordSchema = z.object({
|
|
1679
|
+
objectApiName: z.string().min(1).describe("SObject API name, e.g. 'Account'"),
|
|
1680
|
+
recordId: z.string().min(15).max(18).describe("15 or 18 character Salesforce record ID"),
|
|
1681
|
+
}).strict();
|
|
1682
|
+
export const GetSetupAuditTrailSchema = z.object({
|
|
1683
|
+
startDate: z.string().describe("Start date in ISO format, e.g. '2025-01-01'"),
|
|
1684
|
+
endDate: z.string().describe("End date in ISO format, e.g. '2025-12-31'"),
|
|
1685
|
+
createdByUsername: z.string().optional().describe("Filter by the username who made the change"),
|
|
1686
|
+
section: z.string().optional().describe("Filter by section, e.g. 'Custom Fields', 'Profiles', 'Flows', 'Apex Classes'"),
|
|
1687
|
+
limit: z.number().int().min(1).max(2000).default(100).describe("Maximum records to return"),
|
|
1688
|
+
}).strict();
|
|
1689
|
+
export const GetLoginHistorySchema = z.object({
|
|
1690
|
+
startDate: z.string().describe("Start date in ISO format, e.g. '2025-01-01'"),
|
|
1691
|
+
endDate: z.string().describe("End date in ISO format, e.g. '2025-12-31'"),
|
|
1692
|
+
username: z.string().optional().describe("Filter by Salesforce username"),
|
|
1693
|
+
status: z.string().optional().describe("Filter by login status, e.g. 'Success', 'Failed'"),
|
|
1694
|
+
limit: z.number().int().min(1).max(2000).default(100).describe("Maximum records to return"),
|
|
1695
|
+
}).strict();
|
|
1696
|
+
export const GetEventLogsSchema = z.object({
|
|
1697
|
+
eventType: z.string().describe("Event type, e.g. 'Login', 'API', 'Report', 'Flow', 'ApexExecution', 'LightningPageView', 'RestApi'"),
|
|
1698
|
+
startDate: z.string().describe("Start date in ISO format, e.g. '2025-01-01'"),
|
|
1699
|
+
endDate: z.string().describe("End date in ISO format, e.g. '2025-12-31'"),
|
|
1700
|
+
limit: z.number().int().min(1).max(50).default(10).describe("Maximum log files to fetch"),
|
|
1701
|
+
}).strict();
|
|
1702
|
+
export const GetFieldHistorySchema = z.object({
|
|
1703
|
+
objectApiName: z.string().min(1).describe("Object API name, e.g. 'Account', 'Case', 'Opportunity'"),
|
|
1704
|
+
recordId: z.string().min(15).max(18).describe("Record ID to fetch history for"),
|
|
1705
|
+
fields: z.array(z.string()).optional().describe("Optional field names to filter — returns all tracked fields if omitted"),
|
|
1706
|
+
limit: z.number().int().min(1).max(500).default(100).describe("Maximum history records to return"),
|
|
1707
|
+
}).strict();
|
|
1708
|
+
export const CompareOrgsSchema = z.object({
|
|
1709
|
+
sourceAlias: z.string().min(1).regex(/^[A-Za-z0-9_-]+$/).describe("SF CLI alias for the source org (run: sf org list to see aliases)"),
|
|
1710
|
+
targetAlias: z.string().min(1).regex(/^[A-Za-z0-9_-]+$/).describe("SF CLI alias for the target org"),
|
|
1711
|
+
metadataTypes: z.array(z.string()).default(["ApexClass","Flow","CustomObject","PermissionSet","LightningComponentBundle"]).describe("Metadata types to compare"),
|
|
1712
|
+
}).strict();
|
|
1713
|
+
export const CreateCertificateSchema = z.object({
|
|
1714
|
+
certName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Certificate API name"),
|
|
1715
|
+
label: z.string().min(1).describe("Certificate display label"),
|
|
1716
|
+
keySize: z.enum(["2048","4096"]).default("2048").describe("Key size in bits"),
|
|
1717
|
+
expirationDate: z.string().optional().describe("Expiration date in ISO format, e.g. '2030-01-01'"),
|
|
1718
|
+
privateKeyExportable: z.boolean().default(false).describe("Whether the private key can be exported"),
|
|
1719
|
+
}).strict();
|
|
1720
|
+
export const CreateEventRelaySchema = z.object({
|
|
1721
|
+
relayName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Event relay API name"),
|
|
1722
|
+
label: z.string().min(1).describe("Display label"),
|
|
1723
|
+
eventChannel: z.string().min(1).describe("Platform event or CDC channel API name, e.g. 'My_Event__e' or 'AccountChangeEvent'"),
|
|
1724
|
+
destinationType: z.enum(["AmazonEventBridge","EventBus"]).describe("Destination type for the relay"),
|
|
1725
|
+
destinationResourceName: z.string().min(1).describe("ARN or event bus name for the destination"),
|
|
1726
|
+
state: z.enum(["RUN","STOP","PAUSE"]).default("RUN").describe("Initial relay state"),
|
|
1727
|
+
description: z.string().optional().describe("Relay description"),
|
|
1728
|
+
}).strict();
|
|
1729
|
+
export const CreateLetterheadSchema = z.object({
|
|
1730
|
+
letterheadName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Letterhead API name"),
|
|
1731
|
+
label: z.string().min(1).describe("Letterhead display name"),
|
|
1732
|
+
headerColor: z.string().default("#0070D2").describe("Header background color (hex)"),
|
|
1733
|
+
headerFontColor: z.string().default("#FFFFFF").describe("Header text color"),
|
|
1734
|
+
bodyColor: z.string().default("#FFFFFF").describe("Body background color"),
|
|
1735
|
+
footerColor: z.string().default("#404040").describe("Footer background color"),
|
|
1736
|
+
footerFontColor: z.string().default("#FFFFFF").describe("Footer text color"),
|
|
1737
|
+
fontName: z.string().default("Arial").describe("Font name, e.g. 'Arial', 'Helvetica', 'Times New Roman'"),
|
|
1738
|
+
fontSize: z.number().int().default(12).describe("Font size in points"),
|
|
1739
|
+
footerText: z.string().optional().describe("Footer text content"),
|
|
1740
|
+
topLineColor: z.string().default("#0070D2").describe("Top separator line color"),
|
|
1741
|
+
bottomLineColor: z.string().default("#0070D2").describe("Bottom separator line color"),
|
|
1742
|
+
}).strict();
|
|
1743
|
+
export const SendEmailSchema = z.object({
|
|
1744
|
+
toAddresses: z.array(z.string()).min(1).describe("Recipient email addresses"),
|
|
1745
|
+
subject: z.string().min(1).describe("Email subject line"),
|
|
1746
|
+
body: z.string().optional().describe("Plain text email body"),
|
|
1747
|
+
htmlBody: z.string().optional().describe("HTML email body (takes precedence over body)"),
|
|
1748
|
+
templateName: z.string().optional().describe("Email template API name (uses template instead of body)"),
|
|
1749
|
+
whatId: z.string().optional().describe("Related record ID (e.g. Opportunity or Case ID)"),
|
|
1750
|
+
whoId: z.string().optional().describe("Contact or Lead ID"),
|
|
1751
|
+
saveAsActivity: z.boolean().default(true).describe("Save email as an Activity record"),
|
|
1752
|
+
useSignature: z.boolean().default(false).describe("Append running user's email signature"),
|
|
1753
|
+
ccAddresses: z.array(z.string()).optional().describe("CC email addresses"),
|
|
1754
|
+
}).strict();
|
|
1755
|
+
export const CreateEinsteinPredictionSchema = z.object({
|
|
1756
|
+
predictionName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Prediction API name"),
|
|
1757
|
+
label: z.string().min(1).describe("Prediction display label"),
|
|
1758
|
+
objectApiName: z.string().min(1).describe("Salesforce object to run predictions on, e.g. 'Opportunity'"),
|
|
1759
|
+
predictionType: z.enum(["BinaryClassification","Regression"]).describe("BinaryClassification for yes/no, Regression for numeric"),
|
|
1760
|
+
targetField: z.string().min(1).describe("Field API name to predict"),
|
|
1761
|
+
positiveLabel: z.string().default("Yes").describe("Label for positive outcome (BinaryClassification only)"),
|
|
1762
|
+
negativeLabel: z.string().default("No").describe("Label for negative outcome (BinaryClassification only)"),
|
|
1763
|
+
pushbackField: z.string().optional().describe("Field to write the prediction score to, e.g. 'Win_Score__c'"),
|
|
1764
|
+
description: z.string().optional().describe("Prediction description"),
|
|
1765
|
+
}).strict();
|
|
1766
|
+
export const CreateNextBestActionSchema = z.object({
|
|
1767
|
+
strategyName: z.string().min(1).max(80).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Strategy API name"),
|
|
1768
|
+
label: z.string().min(1).describe("Strategy display label"),
|
|
1769
|
+
contextObjectApiName: z.string().min(1).describe("Object that provides context, e.g. 'Account', 'Case'"),
|
|
1770
|
+
recommendations: z.array(z.object({
|
|
1771
|
+
name: z.string().min(1).describe("Recommendation developer name"),
|
|
1772
|
+
label: z.string().min(1).describe("Label shown to users"),
|
|
1773
|
+
acceptanceLabel: z.string().default("Accept").describe("Accept button label"),
|
|
1774
|
+
rejectionLabel: z.string().default("Decline").describe("Reject button label"),
|
|
1775
|
+
actionReference: z.string().optional().describe("Flow API name to execute on acceptance"),
|
|
1776
|
+
})).optional().describe("Recommendation definitions"),
|
|
1777
|
+
description: z.string().optional().describe("Strategy description"),
|
|
1778
|
+
}).strict();
|
|
1779
|
+
export const CreateEinsteinBotSchema = z.object({
|
|
1780
|
+
botName: z.string().min(1).max(40).regex(/^[A-Za-z][A-Za-z0-9_]*$/).describe("Bot API name"),
|
|
1781
|
+
label: z.string().min(1).describe("Bot display label"),
|
|
1782
|
+
defaultLocale: z.string().default("en_US").describe("Default language/locale, e.g. 'en_US', 'fr', 'de'"),
|
|
1783
|
+
description: z.string().optional().describe("Bot description"),
|
|
1784
|
+
dialogs: z.array(z.object({
|
|
1785
|
+
name: z.string().min(1).describe("Dialog developer name"),
|
|
1786
|
+
label: z.string().min(1).describe("Dialog display label"),
|
|
1787
|
+
type: z.enum(["Main","System","Rule"]).default("Main").describe("Dialog type"),
|
|
1788
|
+
isGoalStep: z.boolean().default(false).describe("Whether this dialog represents goal completion"),
|
|
1789
|
+
utterances: z.array(z.string()).optional().describe("Training utterances that trigger this dialog"),
|
|
1790
|
+
messages: z.array(z.string()).optional().describe("Bot messages to show"),
|
|
1791
|
+
})).optional().describe("Bot dialogs"),
|
|
1792
|
+
}).strict();
|
|
1670
1793
|
//# sourceMappingURL=index.js.map
|
|
@@ -3320,4 +3320,362 @@ export async function createBotRouting(auth, params) {
|
|
|
3320
3320
|
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3321
3321
|
}
|
|
3322
3322
|
}
|
|
3323
|
+
// ─── v2.4.0 — NEW SERVICE FUNCTIONS ──────────────────────────────────────────
|
|
3324
|
+
export async function createLightningAppPage(auth, params) {
|
|
3325
|
+
return createFlexiPage(auth, { ...params, pageType: "AppPage" });
|
|
3326
|
+
}
|
|
3327
|
+
export async function deleteRecord(auth, params) {
|
|
3328
|
+
try {
|
|
3329
|
+
const client = createClient(auth);
|
|
3330
|
+
await client.del(`/sobjects/${params.objectApiName}/${params.recordId}`);
|
|
3331
|
+
return { success: true, fullName: params.recordId, created: false, message: `${params.objectApiName} record ${params.recordId} deleted successfully.` };
|
|
3332
|
+
} catch (err) {
|
|
3333
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
export async function getSetupAuditTrail(auth, params) {
|
|
3337
|
+
try {
|
|
3338
|
+
const client = createClient(auth);
|
|
3339
|
+
const conditions = [];
|
|
3340
|
+
conditions.push(`CreatedDate >= ${params.startDate}T00:00:00Z`);
|
|
3341
|
+
conditions.push(`CreatedDate <= ${params.endDate}T23:59:59Z`);
|
|
3342
|
+
if (params.createdByUsername) conditions.push(`CreatedBy.Username = '${params.createdByUsername.replace(/'/g, "\\'")}'`);
|
|
3343
|
+
if (params.section) conditions.push(`Section = '${params.section.replace(/'/g, "\\'")}'`);
|
|
3344
|
+
const soql = `SELECT Id, CreatedDate, CreatedBy.Username, Section, Action, Display FROM SetupAuditTrail WHERE ${conditions.join(" AND ")} ORDER BY CreatedDate DESC LIMIT ${params.limit ?? 100}`;
|
|
3345
|
+
const resp = await client.get(`/query?q=${encodeURIComponent(soql)}`);
|
|
3346
|
+
const records = (resp.data.records ?? []).map((r) => ({
|
|
3347
|
+
date: r.CreatedDate,
|
|
3348
|
+
username: r.CreatedBy?.Username ?? "",
|
|
3349
|
+
section: r.Section,
|
|
3350
|
+
action: r.Action,
|
|
3351
|
+
display: r.Display,
|
|
3352
|
+
}));
|
|
3353
|
+
return { success: true, totalSize: resp.data.totalSize, records, message: `${records.length} setup audit trail record(s) returned.` };
|
|
3354
|
+
} catch (err) {
|
|
3355
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
export async function getLoginHistory(auth, params) {
|
|
3359
|
+
try {
|
|
3360
|
+
const client = createClient(auth);
|
|
3361
|
+
const conditions = [];
|
|
3362
|
+
conditions.push(`LoginTime >= ${params.startDate}T00:00:00Z`);
|
|
3363
|
+
conditions.push(`LoginTime <= ${params.endDate}T23:59:59Z`);
|
|
3364
|
+
if (params.username) conditions.push(`Username = '${params.username.replace(/'/g, "\\'")}'`);
|
|
3365
|
+
if (params.status) conditions.push(`Status = '${params.status.replace(/'/g, "\\'")}'`);
|
|
3366
|
+
const soql = `SELECT Id, LoginTime, Username, SourceIp, Browser, Platform, Status, LoginType FROM LoginHistory WHERE ${conditions.join(" AND ")} ORDER BY LoginTime DESC LIMIT ${params.limit ?? 100}`;
|
|
3367
|
+
const resp = await client.get(`/query?q=${encodeURIComponent(soql)}`);
|
|
3368
|
+
const records = (resp.data.records ?? []).map((r) => ({
|
|
3369
|
+
loginTime: r.LoginTime,
|
|
3370
|
+
username: r.Username,
|
|
3371
|
+
sourceIp: r.SourceIp,
|
|
3372
|
+
browser: r.Browser,
|
|
3373
|
+
platform: r.Platform,
|
|
3374
|
+
status: r.Status,
|
|
3375
|
+
loginType: r.LoginType,
|
|
3376
|
+
}));
|
|
3377
|
+
return { success: true, totalSize: resp.data.totalSize, records, message: `${records.length} login history record(s) returned.` };
|
|
3378
|
+
} catch (err) {
|
|
3379
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
export async function getEventLogs(auth, params) {
|
|
3383
|
+
try {
|
|
3384
|
+
const client = createClient(auth);
|
|
3385
|
+
const soql = `SELECT Id, EventType, LogFile, LogDate, LogFileLength FROM EventLogFile WHERE EventType = '${params.eventType.replace(/'/g, "\\'")}' AND LogDate >= ${params.startDate}T00:00:00Z AND LogDate <= ${params.endDate}T23:59:59Z ORDER BY LogDate DESC LIMIT ${params.limit ?? 10}`;
|
|
3386
|
+
const resp = await client.get(`/query?q=${encodeURIComponent(soql)}`);
|
|
3387
|
+
const logFiles = resp.data.records ?? [];
|
|
3388
|
+
if (logFiles.length === 0) {
|
|
3389
|
+
return { success: true, totalSize: 0, logs: [], message: `No event log files found for type '${params.eventType}' in the specified date range.` };
|
|
3390
|
+
}
|
|
3391
|
+
const logs = [];
|
|
3392
|
+
for (const logFile of logFiles.slice(0, 3)) {
|
|
3393
|
+
if (!logFile.LogFile) continue;
|
|
3394
|
+
try {
|
|
3395
|
+
const csvResp = await fetchWithTimeout(`${auth.instanceUrl}${logFile.LogFile}`, {
|
|
3396
|
+
method: "GET",
|
|
3397
|
+
headers: { Authorization: `Bearer ${auth.accessToken}` },
|
|
3398
|
+
}, 30_000);
|
|
3399
|
+
if (csvResp.ok) {
|
|
3400
|
+
const csvText = await csvResp.text();
|
|
3401
|
+
const lines = csvText.split("\n").filter(l => l.trim());
|
|
3402
|
+
const headers = lines[0]?.split(",").map(h => h.replace(/"/g, "").trim()) ?? [];
|
|
3403
|
+
const rows = lines.slice(1, 21).map(line => {
|
|
3404
|
+
const values = line.split(",").map(v => v.replace(/"/g, "").trim());
|
|
3405
|
+
return Object.fromEntries(headers.map((h, i) => [h, values[i] ?? ""]));
|
|
3406
|
+
});
|
|
3407
|
+
logs.push({ logDate: logFile.LogDate, eventType: logFile.EventType, logFileLength: logFile.LogFileLength, entries: rows });
|
|
3408
|
+
}
|
|
3409
|
+
} catch {
|
|
3410
|
+
logs.push({ logDate: logFile.LogDate, eventType: logFile.EventType, logFileLength: logFile.LogFileLength, entries: [], note: "Could not fetch log content." });
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
return { success: true, totalSize: resp.data.totalSize, logs, message: `${logs.length} event log file(s) returned.` };
|
|
3414
|
+
} catch (err) {
|
|
3415
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
export async function getFieldHistory(auth, params) {
|
|
3419
|
+
try {
|
|
3420
|
+
const client = createClient(auth);
|
|
3421
|
+
const historyObject = `${params.objectApiName}History`;
|
|
3422
|
+
const fieldFilter = params.fields && params.fields.length > 0
|
|
3423
|
+
? ` AND Field IN (${params.fields.map(f => `'${f.replace(/'/g, "\\'")}'`).join(",")})`
|
|
3424
|
+
: "";
|
|
3425
|
+
const soql = `SELECT Id, Field, OldValue, NewValue, CreatedDate, CreatedBy.Username FROM ${historyObject} WHERE ParentId = '${params.recordId}'${fieldFilter} ORDER BY CreatedDate DESC LIMIT ${params.limit ?? 100}`;
|
|
3426
|
+
const resp = await client.get(`/query?q=${encodeURIComponent(soql)}`);
|
|
3427
|
+
const records = (resp.data.records ?? []).map((r) => ({
|
|
3428
|
+
date: r.CreatedDate,
|
|
3429
|
+
field: r.Field,
|
|
3430
|
+
oldValue: r.OldValue,
|
|
3431
|
+
newValue: r.NewValue,
|
|
3432
|
+
changedBy: r.CreatedBy?.Username ?? "",
|
|
3433
|
+
}));
|
|
3434
|
+
return { success: true, totalSize: resp.data.totalSize, records, message: `${records.length} field history record(s) returned.` };
|
|
3435
|
+
} catch (err) {
|
|
3436
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
export async function compareOrgs(params) {
|
|
3440
|
+
const { execSync: exec } = await import("child_process");
|
|
3441
|
+
function getAuthForAlias(alias) {
|
|
3442
|
+
if (!/^[A-Za-z0-9_-]+$/.test(alias)) throw new Error(`Invalid org alias: ${alias}`);
|
|
3443
|
+
let raw;
|
|
3444
|
+
try {
|
|
3445
|
+
raw = exec(`sf org display --target-org ${alias} --json`, { encoding: "utf-8", timeout: 30_000, env: { PATH: process.env["PATH"] ?? "" } });
|
|
3446
|
+
} catch (e) {
|
|
3447
|
+
throw new Error(`SF CLI failed for alias '${alias}': ${e instanceof Error ? sanitizeError(e.message) : "unknown error"}`);
|
|
3448
|
+
}
|
|
3449
|
+
const parsed = JSON.parse(raw);
|
|
3450
|
+
const accessToken = parsed?.result?.accessToken;
|
|
3451
|
+
const instanceUrl = parsed?.result?.instanceUrl;
|
|
3452
|
+
if (!accessToken || !instanceUrl) throw new Error(`No credentials returned for alias '${alias}'.`);
|
|
3453
|
+
return { instanceUrl: instanceUrl.replace(/\/$/, ""), accessToken };
|
|
3454
|
+
}
|
|
3455
|
+
try {
|
|
3456
|
+
const sourceAuth = getAuthForAlias(params.sourceAlias);
|
|
3457
|
+
const targetAuth = getAuthForAlias(params.targetAlias);
|
|
3458
|
+
const metadataTypes = params.metadataTypes ?? ["ApexClass","Flow","CustomObject","PermissionSet","LightningComponentBundle"];
|
|
3459
|
+
const results = { onlyInSource: [], onlyInTarget: [], differentInBoth: [], same: [] };
|
|
3460
|
+
for (const mdType of metadataTypes) {
|
|
3461
|
+
const [sourceList, targetList] = await Promise.all([
|
|
3462
|
+
listMetadataType(sourceAuth, mdType),
|
|
3463
|
+
listMetadataType(targetAuth, mdType),
|
|
3464
|
+
]);
|
|
3465
|
+
if (!sourceList.success || !targetList.success) continue;
|
|
3466
|
+
const sourceMap = new Map(sourceList.items.map(i => [i.fullName, i.lastModifiedDate]));
|
|
3467
|
+
const targetMap = new Map(targetList.items.map(i => [i.fullName, i.lastModifiedDate]));
|
|
3468
|
+
for (const [name, sourceDate] of sourceMap) {
|
|
3469
|
+
if (!targetMap.has(name)) {
|
|
3470
|
+
results.onlyInSource.push({ type: mdType, fullName: name, lastModified: sourceDate });
|
|
3471
|
+
} else {
|
|
3472
|
+
const targetDate = targetMap.get(name);
|
|
3473
|
+
if (sourceDate !== targetDate) {
|
|
3474
|
+
results.differentInBoth.push({ type: mdType, fullName: name, sourceLastModified: sourceDate, targetLastModified: targetDate });
|
|
3475
|
+
} else {
|
|
3476
|
+
results.same.push({ type: mdType, fullName: name });
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
for (const [name, targetDate] of targetMap) {
|
|
3481
|
+
if (!sourceMap.has(name)) {
|
|
3482
|
+
results.onlyInTarget.push({ type: mdType, fullName: name, lastModified: targetDate });
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
return { success: true, sourceAlias: params.sourceAlias, targetAlias: params.targetAlias,
|
|
3487
|
+
summary: { onlyInSource: results.onlyInSource.length, onlyInTarget: results.onlyInTarget.length, different: results.differentInBoth.length, same: results.same.length },
|
|
3488
|
+
onlyInSource: results.onlyInSource, onlyInTarget: results.onlyInTarget, differentInBoth: results.differentInBoth,
|
|
3489
|
+
message: `Comparison complete. Source-only: ${results.onlyInSource.length}, Target-only: ${results.onlyInTarget.length}, Different: ${results.differentInBoth.length}, Same: ${results.same.length}` };
|
|
3490
|
+
} catch (err) {
|
|
3491
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
export async function createCertificate(auth, params) {
|
|
3495
|
+
try {
|
|
3496
|
+
const xml = `<met:metadata xsi:type="met:Certificate" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3497
|
+
<met:fullName>${x(params.certName)}</met:fullName>
|
|
3498
|
+
<met:masterLabel>${x(params.label)}</met:masterLabel>
|
|
3499
|
+
<met:keySize>${x(params.keySize ?? "2048")}</met:keySize>
|
|
3500
|
+
<met:privateKeyExportable>${params.privateKeyExportable ? "true" : "false"}</met:privateKeyExportable>
|
|
3501
|
+
${params.expirationDate ? `<met:expirationDate>${x(params.expirationDate)}</met:expirationDate>` : ""}
|
|
3502
|
+
</met:metadata>`;
|
|
3503
|
+
return await upsertMetadata(auth, xml);
|
|
3504
|
+
} catch (err) {
|
|
3505
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
export async function createEventRelay(auth, params) {
|
|
3509
|
+
try {
|
|
3510
|
+
const xml = `<met:metadata xsi:type="met:EventRelayConfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3511
|
+
<met:fullName>${x(params.relayName)}</met:fullName>
|
|
3512
|
+
<met:label>${x(params.label)}</met:label>
|
|
3513
|
+
<met:eventChannel>${x(params.eventChannel)}</met:eventChannel>
|
|
3514
|
+
<met:destinationType>${x(params.destinationType)}</met:destinationType>
|
|
3515
|
+
<met:destinationResourceName>${x(params.destinationResourceName)}</met:destinationResourceName>
|
|
3516
|
+
<met:state>${x(params.state ?? "RUN")}</met:state>
|
|
3517
|
+
${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
|
|
3518
|
+
</met:metadata>`;
|
|
3519
|
+
return await upsertMetadata(auth, xml);
|
|
3520
|
+
} catch (err) {
|
|
3521
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
export async function createLetterhead(auth, params) {
|
|
3525
|
+
try {
|
|
3526
|
+
const xml = `<met:metadata xsi:type="met:Letterhead" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3527
|
+
<met:fullName>${x(params.letterheadName)}</met:fullName>
|
|
3528
|
+
<met:available>true</met:available>
|
|
3529
|
+
<met:backgroundColor>${x(params.bodyColor ?? "#FFFFFF")}</met:backgroundColor>
|
|
3530
|
+
<met:bodyColor>${x(params.bodyColor ?? "#FFFFFF")}</met:bodyColor>
|
|
3531
|
+
<met:description>${x(params.footerText ?? "")}</met:description>
|
|
3532
|
+
<met:footer>
|
|
3533
|
+
<met:backgroundColor>${x(params.footerColor ?? "#404040")}</met:backgroundColor>
|
|
3534
|
+
<met:color>${x(params.footerFontColor ?? "#FFFFFF")}</met:color>
|
|
3535
|
+
<met:fontFace>${x(params.fontName ?? "Arial")}</met:fontFace>
|
|
3536
|
+
<met:fontSize>${params.fontSize ?? 12}</met:fontSize>
|
|
3537
|
+
<met:height>60</met:height>
|
|
3538
|
+
<met:horizontalAlignment>Center</met:horizontalAlignment>
|
|
3539
|
+
<met:verticalAlignment>Bottom</met:verticalAlignment>
|
|
3540
|
+
</met:footer>
|
|
3541
|
+
<met:header>
|
|
3542
|
+
<met:backgroundColor>${x(params.headerColor ?? "#0070D2")}</met:backgroundColor>
|
|
3543
|
+
<met:color>${x(params.headerFontColor ?? "#FFFFFF")}</met:color>
|
|
3544
|
+
<met:fontFace>${x(params.fontName ?? "Arial")}</met:fontFace>
|
|
3545
|
+
<met:fontSize>${params.fontSize ?? 12}</met:fontSize>
|
|
3546
|
+
<met:height>60</met:height>
|
|
3547
|
+
<met:horizontalAlignment>Center</met:horizontalAlignment>
|
|
3548
|
+
<met:verticalAlignment>Middle</met:verticalAlignment>
|
|
3549
|
+
</met:header>
|
|
3550
|
+
<met:name>${x(params.label)}</met:name>
|
|
3551
|
+
<met:topLine>
|
|
3552
|
+
<met:color>${x(params.topLineColor ?? "#0070D2")}</met:color>
|
|
3553
|
+
<met:height>3</met:height>
|
|
3554
|
+
<met:style>Solid</met:style>
|
|
3555
|
+
</met:topLine>
|
|
3556
|
+
<met:bottomLine>
|
|
3557
|
+
<met:color>${x(params.bottomLineColor ?? "#0070D2")}</met:color>
|
|
3558
|
+
<met:height>3</met:height>
|
|
3559
|
+
<met:style>Solid</met:style>
|
|
3560
|
+
</met:bottomLine>
|
|
3561
|
+
</met:metadata>`;
|
|
3562
|
+
return await upsertMetadata(auth, xml);
|
|
3563
|
+
} catch (err) {
|
|
3564
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
export async function sendEmail(auth, params) {
|
|
3568
|
+
try {
|
|
3569
|
+
const client = createClient(auth);
|
|
3570
|
+
const emailBody = params.htmlBody || params.body || "";
|
|
3571
|
+
const payload = {
|
|
3572
|
+
inputs: [{
|
|
3573
|
+
emailAddresses: params.toAddresses.join(","),
|
|
3574
|
+
emailSubject: params.subject,
|
|
3575
|
+
emailBody,
|
|
3576
|
+
saveAsActivity: params.saveAsActivity ?? true,
|
|
3577
|
+
senderAddress: "",
|
|
3578
|
+
...(params.whoId && { targetObjectId: params.whoId }),
|
|
3579
|
+
...(params.whatId && { whatId: params.whatId }),
|
|
3580
|
+
...(params.ccAddresses?.length && { ccAddresses: params.ccAddresses.join(",") }),
|
|
3581
|
+
}],
|
|
3582
|
+
};
|
|
3583
|
+
const resp = await client.post("/actions/standard/emailSimple", payload);
|
|
3584
|
+
const output = Array.isArray(resp.data) ? resp.data[0] : resp.data;
|
|
3585
|
+
if (output?.isSuccess === false) {
|
|
3586
|
+
const errMsg = output?.errors?.map((e) => e.message).join("; ") ?? "Email action failed.";
|
|
3587
|
+
return { success: false, message: errMsg };
|
|
3588
|
+
}
|
|
3589
|
+
return { success: true, fullName: "sendEmail", created: false, message: `Email sent to ${params.toAddresses.join(", ")}.` };
|
|
3590
|
+
} catch (err) {
|
|
3591
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
export async function createEinsteinPrediction(auth, params) {
|
|
3595
|
+
try {
|
|
3596
|
+
const xml = `<met:metadata xsi:type="met:MLPredictionDefinition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3597
|
+
<met:fullName>${x(params.predictionName)}</met:fullName>
|
|
3598
|
+
<met:label>${x(params.label)}</met:label>
|
|
3599
|
+
<met:active>false</met:active>
|
|
3600
|
+
<met:negativeLabel>${x(params.negativeLabel ?? "No")}</met:negativeLabel>
|
|
3601
|
+
<met:positiveLabel>${x(params.positiveLabel ?? "Yes")}</met:positiveLabel>
|
|
3602
|
+
<met:predictionType>${x(params.predictionType)}</met:predictionType>
|
|
3603
|
+
<met:status>Draft</met:status>
|
|
3604
|
+
${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
|
|
3605
|
+
${params.pushbackField ? `<met:pushbackField>
|
|
3606
|
+
<met:fieldName>${x(params.pushbackField)}</met:fieldName>
|
|
3607
|
+
<met:objectName>${x(params.objectApiName)}</met:objectName>
|
|
3608
|
+
</met:pushbackField>` : ""}
|
|
3609
|
+
</met:metadata>`;
|
|
3610
|
+
return await upsertMetadata(auth, xml);
|
|
3611
|
+
} catch (err) {
|
|
3612
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
export async function createNextBestAction(auth, params) {
|
|
3616
|
+
try {
|
|
3617
|
+
const recsXml = (params.recommendations ?? []).map(rec => `
|
|
3618
|
+
<met:recommendationDefinitions>
|
|
3619
|
+
<met:developerName>${x(rec.name)}</met:developerName>
|
|
3620
|
+
<met:label>${x(rec.label)}</met:label>
|
|
3621
|
+
<met:acceptanceLabel>${x(rec.acceptanceLabel ?? "Accept")}</met:acceptanceLabel>
|
|
3622
|
+
<met:rejectionLabel>${x(rec.rejectionLabel ?? "Decline")}</met:rejectionLabel>
|
|
3623
|
+
${rec.actionReference ? `<met:actionReference>${x(rec.actionReference)}</met:actionReference>` : ""}
|
|
3624
|
+
</met:recommendationDefinitions>`).join("");
|
|
3625
|
+
const xml = `<met:metadata xsi:type="met:RecommendationStrategy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3626
|
+
<met:fullName>${x(params.strategyName)}</met:fullName>
|
|
3627
|
+
<met:label>${x(params.label)}</met:label>
|
|
3628
|
+
<met:contextObjectName>${x(params.contextObjectApiName)}</met:contextObjectName>
|
|
3629
|
+
${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
|
|
3630
|
+
${recsXml}
|
|
3631
|
+
</met:metadata>`;
|
|
3632
|
+
return await upsertMetadata(auth, xml);
|
|
3633
|
+
} catch (err) {
|
|
3634
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
export async function createEinsteinBot(auth, params) {
|
|
3638
|
+
try {
|
|
3639
|
+
const mlIntentsXml = (params.dialogs ?? []).map(d => `
|
|
3640
|
+
<met:mlIntents>
|
|
3641
|
+
<met:developerName>${x(d.name)}</met:developerName>
|
|
3642
|
+
<met:label>${x(d.label)}</met:label>
|
|
3643
|
+
${(d.utterances ?? []).map(u => `<met:mlIntentUtterances><met:utterance>${x(u)}</met:utterance></met:mlIntentUtterances>`).join("")}
|
|
3644
|
+
</met:mlIntents>`).join("");
|
|
3645
|
+
const dialogsXml = (params.dialogs ?? [{ name: "Welcome", label: "Welcome", type: "Main", isGoalStep: false, messages: ["Hello! How can I help you today?"] }]).map(d => `
|
|
3646
|
+
<met:botDialogs>
|
|
3647
|
+
${(d.messages ?? ["Hello!"]).map((msg, i) => `
|
|
3648
|
+
<met:botSteps>
|
|
3649
|
+
<met:conversationStepType>Message</met:conversationStepType>
|
|
3650
|
+
<met:botMessage>${x(msg)}</met:botMessage>
|
|
3651
|
+
<met:stepIdentifier>${x(d.name)}_step${i + 1}</met:stepIdentifier>
|
|
3652
|
+
</met:botSteps>`).join("")}
|
|
3653
|
+
<met:developerName>${x(d.name)}</met:developerName>
|
|
3654
|
+
<met:isGoalStep>${d.isGoalStep ? "true" : "false"}</met:isGoalStep>
|
|
3655
|
+
<met:label>${x(d.label)}</met:label>
|
|
3656
|
+
<met:showInFooterMenu>false</met:showInFooterMenu>
|
|
3657
|
+
</met:botDialogs>`).join("");
|
|
3658
|
+
const botXml = `<met:metadata xsi:type="met:Bot" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3659
|
+
<met:fullName>${x(params.botName)}</met:fullName>
|
|
3660
|
+
<met:label>${x(params.label)}</met:label>
|
|
3661
|
+
<met:defaultLocale>${x(params.defaultLocale ?? "en_US")}</met:defaultLocale>
|
|
3662
|
+
${params.description ? `<met:description>${x(params.description)}</met:description>` : ""}
|
|
3663
|
+
<met:mlDomain>
|
|
3664
|
+
<met:developerName>${x(params.botName)}_MLDomain</met:developerName>
|
|
3665
|
+
<met:label>${x(params.label)} ML Domain</met:label>
|
|
3666
|
+
${mlIntentsXml}
|
|
3667
|
+
</met:mlDomain>
|
|
3668
|
+
</met:metadata>`;
|
|
3669
|
+
const botResult = await upsertMetadata(auth, botXml);
|
|
3670
|
+
if (!botResult.success) return botResult;
|
|
3671
|
+
const versionXml = `<met:metadata xsi:type="met:BotVersion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
3672
|
+
<met:fullName>${x(params.botName)}.v1</met:fullName>
|
|
3673
|
+
${dialogsXml}
|
|
3674
|
+
</met:metadata>`;
|
|
3675
|
+
const versionResult = await upsertMetadata(auth, versionXml);
|
|
3676
|
+
return { success: versionResult.success, fullName: params.botName, created: true, message: versionResult.success ? `Einstein Bot '${params.botName}' created with ${(params.dialogs ?? []).length || 1} dialog(s).` : versionResult.message };
|
|
3677
|
+
} catch (err) {
|
|
3678
|
+
return { success: false, message: sanitizeError(err instanceof Error ? err.message : String(err)) };
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3323
3681
|
//# sourceMappingURL=salesforce.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GetSetupAuditTrailSchema, GetLoginHistorySchema, GetEventLogsSchema, GetFieldHistorySchema,
|
|
3
|
+
} from "../schemas/index.js";
|
|
4
|
+
import { getAuth, getSetupAuditTrail, getLoginHistory, getEventLogs, getFieldHistory } from "../services/salesforce.js";
|
|
5
|
+
import { resultContent } from "./utils.js";
|
|
6
|
+
|
|
7
|
+
export function registerAuditTools(server) {
|
|
8
|
+
server.registerTool("sf_get_setup_audit_trail", {
|
|
9
|
+
title: "Get Setup Audit Trail",
|
|
10
|
+
description: `Queries the SetupAuditTrail object to see who made what configuration changes to the org, and when. Covers the last 6 months of setup activity.
|
|
11
|
+
|
|
12
|
+
Returns records with: date, username, section, action, display (human-readable description)
|
|
13
|
+
|
|
14
|
+
section filter examples: 'Custom Fields', 'Profiles', 'Flows', 'Apex Classes', 'Permission Sets', 'Connected Apps', 'Users'
|
|
15
|
+
|
|
16
|
+
Useful for:
|
|
17
|
+
- Security audits (who changed profiles or permissions)
|
|
18
|
+
- Debugging unexpected configuration changes
|
|
19
|
+
- Compliance reporting on org configuration changes`,
|
|
20
|
+
inputSchema: GetSetupAuditTrailSchema,
|
|
21
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
22
|
+
}, async (params) => {
|
|
23
|
+
const auth = await getAuth();
|
|
24
|
+
const result = await getSetupAuditTrail(auth, params);
|
|
25
|
+
return resultContent(result);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
server.registerTool("sf_get_login_history", {
|
|
29
|
+
title: "Get Login History",
|
|
30
|
+
description: `Queries LoginHistory to see user login activity — who logged in, from where, and whether they succeeded.
|
|
31
|
+
|
|
32
|
+
Returns records with: loginTime, username, sourceIp, browser, platform, status, loginType
|
|
33
|
+
|
|
34
|
+
status values: 'Success', 'Failed', 'No Password', 'Blocked', 'No Cookie'
|
|
35
|
+
loginType values: 'Application', 'API', 'SAML', 'OAuth', 'LightningLogin', 'Chatter'
|
|
36
|
+
|
|
37
|
+
Useful for:
|
|
38
|
+
- Security monitoring (failed logins, unusual IP addresses)
|
|
39
|
+
- Compliance auditing (who accessed the org and when)
|
|
40
|
+
- Investigating suspicious account activity
|
|
41
|
+
|
|
42
|
+
Note: LoginHistory covers the past 6 months.`,
|
|
43
|
+
inputSchema: GetLoginHistorySchema,
|
|
44
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
45
|
+
}, async (params) => {
|
|
46
|
+
const auth = await getAuth();
|
|
47
|
+
const result = await getLoginHistory(auth, params);
|
|
48
|
+
return resultContent(result);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
server.registerTool("sf_get_event_logs", {
|
|
52
|
+
title: "Get Event Log Files",
|
|
53
|
+
description: `Queries EventLogFile for detailed activity logs. Event logs capture granular org activity for security monitoring and performance analysis.
|
|
54
|
+
|
|
55
|
+
Common eventType values:
|
|
56
|
+
- Login — login attempts and results
|
|
57
|
+
- API — SOAP/REST API calls
|
|
58
|
+
- Report — report executions
|
|
59
|
+
- Flow — Flow runs and executions
|
|
60
|
+
- ApexExecution — Apex code executions
|
|
61
|
+
- LightningPageView — Lightning page views
|
|
62
|
+
- RestApi — REST API requests
|
|
63
|
+
- VisualforceRequest — Visualforce page requests
|
|
64
|
+
- URI — general HTTP requests
|
|
65
|
+
- LightningError — Lightning component errors
|
|
66
|
+
|
|
67
|
+
Returns parsed CSV log entries (up to 20 rows per log file, up to 3 files per call).
|
|
68
|
+
|
|
69
|
+
Requires Event Monitoring add-on OR Agentforce debug logs to be enabled.`,
|
|
70
|
+
inputSchema: GetEventLogsSchema,
|
|
71
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
72
|
+
}, async (params) => {
|
|
73
|
+
const auth = await getAuth();
|
|
74
|
+
const result = await getEventLogs(auth, params);
|
|
75
|
+
return resultContent(result);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
server.registerTool("sf_get_field_history", {
|
|
79
|
+
title: "Get Field History for a Record",
|
|
80
|
+
description: `Queries the {Object}History object to retrieve a field-level change history for a specific record. Shows what changed, when, the old and new values, and who made the change.
|
|
81
|
+
|
|
82
|
+
Returns records with: date, field, oldValue, newValue, changedBy
|
|
83
|
+
|
|
84
|
+
objectApiName: the SObject with history tracking enabled, e.g. 'Account', 'Opportunity', 'Case'
|
|
85
|
+
recordId: the specific record to retrieve history for
|
|
86
|
+
|
|
87
|
+
Note: Field history tracking must be enabled for the object and for each field you want to track (Setup → Object Manager → {Object} → Fields & Relationships → Field History Tracking). History is retained for up to 18 months.`,
|
|
88
|
+
inputSchema: GetFieldHistorySchema,
|
|
89
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
90
|
+
}, async (params) => {
|
|
91
|
+
const auth = await getAuth();
|
|
92
|
+
const result = await getFieldHistory(auth, params);
|
|
93
|
+
return resultContent(result);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=audit.js.map
|
package/dist/tools/data.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CreateUserSchema, UpdateUserSchema, AssignQueueMemberSchema, CreatePublicGroupSchema, QueryRecordsSchema, CreateRecordSchema, UpdateRecordSchema, BulkImportRecordsSchema, } from "../schemas/index.js";
|
|
2
|
-
import { getAuth, createUser, updateUser, assignQueueMember, createPublicGroup, queryRecords, createRecord, updateRecord, bulkImportRecords, } from "../services/salesforce.js";
|
|
1
|
+
import { CreateUserSchema, UpdateUserSchema, AssignQueueMemberSchema, CreatePublicGroupSchema, QueryRecordsSchema, CreateRecordSchema, UpdateRecordSchema, BulkImportRecordsSchema, DeleteRecordSchema, SendEmailSchema, } from "../schemas/index.js";
|
|
2
|
+
import { getAuth, createUser, updateUser, assignQueueMember, createPublicGroup, queryRecords, createRecord, updateRecord, bulkImportRecords, deleteRecord, sendEmail, } from "../services/salesforce.js";
|
|
3
3
|
import { resultContent } from "./utils.js";
|
|
4
4
|
export function registerDataTools(server) {
|
|
5
5
|
server.registerTool("sf_create_user", {
|
|
@@ -82,5 +82,36 @@ export function registerDataTools(server) {
|
|
|
82
82
|
const result = await bulkImportRecords(auth, params);
|
|
83
83
|
return resultContent(result);
|
|
84
84
|
});
|
|
85
|
+
server.registerTool("sf_delete_record", {
|
|
86
|
+
title: "Delete SObject Record",
|
|
87
|
+
description: `Deletes a single SObject record by record ID via the Salesforce REST API. The deletion is permanent and cannot be undone (the record goes to the Recycle Bin for objects that support it, from where it can be undeleted within 15 days).
|
|
88
|
+
|
|
89
|
+
Provide the object API name and the 15 or 18 character record ID. For bulk deletions (100+ records), use sf_bulk_import_records with operation='delete'.`,
|
|
90
|
+
inputSchema: DeleteRecordSchema,
|
|
91
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
92
|
+
}, async (params) => {
|
|
93
|
+
const auth = await getAuth();
|
|
94
|
+
const result = await deleteRecord(auth, params);
|
|
95
|
+
return resultContent(result);
|
|
96
|
+
});
|
|
97
|
+
server.registerTool("sf_send_email", {
|
|
98
|
+
title: "Send Email via Salesforce",
|
|
99
|
+
description: `Sends an email from Salesforce using the emailSimple invocable action. The email is sent from the running user's email address through Salesforce's email infrastructure (respects org email deliverability settings).
|
|
100
|
+
|
|
101
|
+
toAddresses: one or more recipient email addresses
|
|
102
|
+
body / htmlBody: email body content (htmlBody takes precedence)
|
|
103
|
+
templateName: use an existing email template instead of providing body text
|
|
104
|
+
whatId: related record ID (e.g. Opportunity, Case) — links the email as an activity
|
|
105
|
+
whoId: Contact or Lead ID — links the email to the person record
|
|
106
|
+
saveAsActivity: saves the email as an EmailMessage activity (default: true)
|
|
107
|
+
|
|
108
|
+
Note: Salesforce email limits apply (daily email limits based on org edition). Mass emails should use list email features instead.`,
|
|
109
|
+
inputSchema: SendEmailSchema,
|
|
110
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
111
|
+
}, async (params) => {
|
|
112
|
+
const auth = await getAuth();
|
|
113
|
+
const result = await sendEmail(auth, params);
|
|
114
|
+
return resultContent(result);
|
|
115
|
+
});
|
|
85
116
|
}
|
|
86
117
|
//# sourceMappingURL=data.js.map
|
package/dist/tools/deployment.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CreateOutboundChangeSetSchema, AddToChangeSetSchema, DeployMetadataSchema, CheckDeployStatusSchema, RetrieveMetadataSchema, ValidateDeploymentSchema, ListMetadataSchema, } from "../schemas/index.js";
|
|
2
|
-
import { getAuth, listMetadataForTool } from "../services/salesforce.js";
|
|
1
|
+
import { CreateOutboundChangeSetSchema, AddToChangeSetSchema, DeployMetadataSchema, CheckDeployStatusSchema, RetrieveMetadataSchema, ValidateDeploymentSchema, ListMetadataSchema, CompareOrgsSchema, } from "../schemas/index.js";
|
|
2
|
+
import { getAuth, listMetadataForTool, compareOrgs } from "../services/salesforce.js";
|
|
3
3
|
import { buildGenericDeployZip, deployZip, pollDeployStatus, checkDeployStatus, retrieveMetadata, } from "../services/deployment.js";
|
|
4
4
|
import { createOutboundChangeSet, addComponentsToChangeSet, } from "../services/tooling.js";
|
|
5
5
|
import { resultContent } from "./utils.js";
|
|
@@ -121,5 +121,25 @@ export function registerDeploymentTools(server) {
|
|
|
121
121
|
const result = await listMetadataForTool(auth, params.metadataType);
|
|
122
122
|
return resultContent(result);
|
|
123
123
|
});
|
|
124
|
+
server.registerTool("sf_compare_orgs", {
|
|
125
|
+
title: "Compare Metadata Between Two Orgs",
|
|
126
|
+
description: `Compares metadata components of specified types between two Salesforce orgs using their SF CLI aliases. Returns components that exist only in the source, only in the target, or differ between both.
|
|
127
|
+
|
|
128
|
+
Requires the Salesforce CLI to be installed and both org aliases to be authenticated (run: sf org list to see available aliases).
|
|
129
|
+
|
|
130
|
+
sourceAlias / targetAlias: SF CLI org aliases (letters, numbers, hyphens, underscores only)
|
|
131
|
+
metadataTypes: list of metadata types to compare — defaults to common types (ApexClass, Flow, CustomObject, PermissionSet, LightningComponentBundle)
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
- onlyInSource: components in source that don't exist in target
|
|
135
|
+
- onlyInTarget: components in target that don't exist in source
|
|
136
|
+
- differentInBoth: components that exist in both but have different lastModifiedDate
|
|
137
|
+
- summary: counts for each category`,
|
|
138
|
+
inputSchema: CompareOrgsSchema,
|
|
139
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
140
|
+
}, async (params) => {
|
|
141
|
+
const result = await compareOrgs(params);
|
|
142
|
+
return resultContent(result);
|
|
143
|
+
});
|
|
124
144
|
}
|
|
125
145
|
//# sourceMappingURL=deployment.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CreateEinsteinPredictionSchema, CreateNextBestActionSchema, CreateEinsteinBotSchema,
|
|
3
|
+
} from "../schemas/index.js";
|
|
4
|
+
import { getAuth, createEinsteinPrediction, createNextBestAction, createEinsteinBot } from "../services/salesforce.js";
|
|
5
|
+
import { resultContent } from "./utils.js";
|
|
6
|
+
|
|
7
|
+
export function registerEinsteinTools(server) {
|
|
8
|
+
server.registerTool("sf_create_einstein_prediction", {
|
|
9
|
+
title: "Create Einstein Prediction (ML Prediction Definition)",
|
|
10
|
+
description: `Creates an Einstein Prediction Builder prediction definition (MLPredictionDefinition metadata type). Predictions analyze historical Salesforce data to score or classify records automatically.
|
|
11
|
+
|
|
12
|
+
predictionType:
|
|
13
|
+
- BinaryClassification: predict a yes/no outcome (e.g. Will this opportunity close? Is this lead likely to convert?)
|
|
14
|
+
- Regression: predict a numeric value (e.g. Expected revenue, likelihood score)
|
|
15
|
+
|
|
16
|
+
targetField: the field the prediction is based on (e.g. 'IsWon' for BinaryClassification on Opportunity)
|
|
17
|
+
pushbackField: an existing custom field to write the prediction score to automatically
|
|
18
|
+
|
|
19
|
+
IMPORTANT: Einstein Prediction Builder requires an Einstein Analytics license or the Einstein Platform add-on. If the org lacks this license, the metadata deployment will succeed but the prediction cannot be trained or activated. This tool creates the definition — training happens in Setup → Einstein → Prediction Builder.
|
|
20
|
+
|
|
21
|
+
The prediction is created in Draft status. Activate it from Setup after training is complete.`,
|
|
22
|
+
inputSchema: CreateEinsteinPredictionSchema,
|
|
23
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
24
|
+
}, async (params) => {
|
|
25
|
+
const auth = await getAuth();
|
|
26
|
+
const result = await createEinsteinPrediction(auth, params);
|
|
27
|
+
return resultContent(result);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
server.registerTool("sf_create_next_best_action", {
|
|
31
|
+
title: "Create Next Best Action Strategy",
|
|
32
|
+
description: `Creates a Next Best Action (NBA) recommendation strategy (RecommendationStrategy metadata type). NBA strategies surface contextual recommendations to agents and customers on record pages, communities, and chatbots.
|
|
33
|
+
|
|
34
|
+
A strategy defines:
|
|
35
|
+
- contextObjectApiName: the record type that provides context (e.g. 'Account', 'Case', 'Opportunity')
|
|
36
|
+
- recommendations: a list of actions the agent can offer, each with Accept/Decline buttons and an optional Flow to execute on acceptance
|
|
37
|
+
|
|
38
|
+
NBA strategies can be displayed via:
|
|
39
|
+
- Einstein Next Best Action component on a Lightning Record Page
|
|
40
|
+
- OmniScripts and FlexCards
|
|
41
|
+
- Service Console
|
|
42
|
+
|
|
43
|
+
After creating, add the "Einstein Next Best Action" Lightning component to a record page and configure it to use this strategy.`,
|
|
44
|
+
inputSchema: CreateNextBestActionSchema,
|
|
45
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
46
|
+
}, async (params) => {
|
|
47
|
+
const auth = await getAuth();
|
|
48
|
+
const result = await createNextBestAction(auth, params);
|
|
49
|
+
return resultContent(result);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
server.registerTool("sf_create_einstein_bot", {
|
|
53
|
+
title: "Create Einstein Bot (Classic)",
|
|
54
|
+
description: `Creates a classic Einstein Bot (Bot + BotVersion metadata types) with one or more conversation dialogs. Classic Einstein Bots handle chat and messaging channels via rule-based and ML-powered conversation flows.
|
|
55
|
+
|
|
56
|
+
Note: For AI-first agents using large language models, use sf_create_agent (Agentforce/Einstein Service Agent) instead. Classic Einstein Bots are best suited for:
|
|
57
|
+
- Structured FAQ automation
|
|
58
|
+
- Simple data collection workflows
|
|
59
|
+
- Channels that don't support Agentforce (SMS, WhatsApp via classic routing)
|
|
60
|
+
|
|
61
|
+
Each dialog defines:
|
|
62
|
+
- name/label: the dialog identifier
|
|
63
|
+
- utterances: training phrases that trigger this dialog
|
|
64
|
+
- messages: bot responses shown to the user
|
|
65
|
+
- type: Main (user-facing), System (internal), Rule (condition-based)
|
|
66
|
+
|
|
67
|
+
The bot is created with an ML domain for intent classification. After creation:
|
|
68
|
+
1. Train the bot in Setup → Einstein Bots → {BotName} → Train
|
|
69
|
+
2. Activate the bot
|
|
70
|
+
3. Connect it to a messaging channel or chat button`,
|
|
71
|
+
inputSchema: CreateEinsteinBotSchema,
|
|
72
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
73
|
+
}, async (params) => {
|
|
74
|
+
const auth = await getAuth();
|
|
75
|
+
const result = await createEinsteinBot(auth, params);
|
|
76
|
+
return resultContent(result);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=einstein.js.map
|
package/dist/tools/index.js
CHANGED
|
@@ -14,6 +14,8 @@ import { registerReportTools } from "./reports.js";
|
|
|
14
14
|
import { registerDataTools } from "./data.js";
|
|
15
15
|
import { registerOmniStudioTools } from "./omnistudio.js";
|
|
16
16
|
import { registerOmniChannelTools } from "./omnichannel.js";
|
|
17
|
+
import { registerAuditTools } from "./audit.js";
|
|
18
|
+
import { registerEinsteinTools } from "./einstein.js";
|
|
17
19
|
export function registerTools(server) {
|
|
18
20
|
registerMetadataTools(server);
|
|
19
21
|
registerObjectTools(server);
|
|
@@ -31,5 +33,7 @@ export function registerTools(server) {
|
|
|
31
33
|
registerDataTools(server);
|
|
32
34
|
registerOmniStudioTools(server);
|
|
33
35
|
registerOmniChannelTools(server);
|
|
36
|
+
registerAuditTools(server);
|
|
37
|
+
registerEinsteinTools(server);
|
|
34
38
|
}
|
|
35
39
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CreateConnectedAppSchema, CreateExternalDataSourceSchema, CreateExternalObjectSchema, CreateRemoteSiteSettingSchema, CreateCspSettingSchema, CreateOutboundMessageSchema, CreateAuthProviderSchema, } from "../schemas/index.js";
|
|
2
|
-
import { getAuth, createConnectedApp, createExternalDataSource, createExternalObject, createRemoteSiteSetting, createCspSetting, createOutboundMessage, createAuthProvider, } from "../services/salesforce.js";
|
|
1
|
+
import { CreateConnectedAppSchema, CreateExternalDataSourceSchema, CreateExternalObjectSchema, CreateRemoteSiteSettingSchema, CreateCspSettingSchema, CreateOutboundMessageSchema, CreateAuthProviderSchema, CreateCertificateSchema, CreateEventRelaySchema, } from "../schemas/index.js";
|
|
2
|
+
import { getAuth, createConnectedApp, createExternalDataSource, createExternalObject, createRemoteSiteSetting, createCspSetting, createOutboundMessage, createAuthProvider, createCertificate, createEventRelay, } from "../services/salesforce.js";
|
|
3
3
|
import { resultContent } from "./utils.js";
|
|
4
4
|
export function registerIntegrationTools(server) {
|
|
5
5
|
server.registerTool("sf_create_connected_app", {
|
|
@@ -112,5 +112,42 @@ export function registerIntegrationTools(server) {
|
|
|
112
112
|
const result = await createAuthProvider(auth, params);
|
|
113
113
|
return resultContent(result);
|
|
114
114
|
});
|
|
115
|
+
server.registerTool("sf_create_certificate", {
|
|
116
|
+
title: "Create Self-Signed Certificate",
|
|
117
|
+
description: `Creates a self-signed certificate in Salesforce (Certificate metadata type). Certificates are used for:
|
|
118
|
+
- Signing outbound callouts (mutual TLS / client certificate authentication)
|
|
119
|
+
- Signing SAML assertions for SSO
|
|
120
|
+
- Encrypting/decrypting data in Named Credentials
|
|
121
|
+
|
|
122
|
+
keySize: 2048 (standard) or 4096 (high security)
|
|
123
|
+
expirationDate: optional ISO date for the certificate expiry (e.g. '2030-01-01')
|
|
124
|
+
privateKeyExportable: set true only if you need to export the private key (not recommended for production)
|
|
125
|
+
|
|
126
|
+
After creation, the certificate can be referenced in Named Credentials and Connected Apps.`,
|
|
127
|
+
inputSchema: CreateCertificateSchema,
|
|
128
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
129
|
+
}, async (params) => {
|
|
130
|
+
const auth = await getAuth();
|
|
131
|
+
const result = await createCertificate(auth, params);
|
|
132
|
+
return resultContent(result);
|
|
133
|
+
});
|
|
134
|
+
server.registerTool("sf_create_event_relay", {
|
|
135
|
+
title: "Create Event Relay Configuration",
|
|
136
|
+
description: `Creates an EventRelayConfig that relays Salesforce Platform Events or Change Data Capture events to an external event bus (Amazon EventBridge or another Salesforce event bus).
|
|
137
|
+
|
|
138
|
+
eventChannel: the Platform Event or CDC channel to relay, e.g. 'MyEvent__e', 'AccountChangeEvent', or 'data/ChangeEvents' for all CDC
|
|
139
|
+
destinationType: AmazonEventBridge or EventBus
|
|
140
|
+
destinationResourceName: ARN for Amazon EventBridge (e.g. 'arn:aws:events:us-east-1:123456789:event-bus/my-bus') or target event bus name
|
|
141
|
+
|
|
142
|
+
state: RUN (immediately start relaying), STOP (create but don't relay), PAUSE (temporarily paused)
|
|
143
|
+
|
|
144
|
+
Requires Event Relay entitlement in the org. For Amazon EventBridge, the AWS partner event source must be set up first.`,
|
|
145
|
+
inputSchema: CreateEventRelaySchema,
|
|
146
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
147
|
+
}, async (params) => {
|
|
148
|
+
const auth = await getAuth();
|
|
149
|
+
const result = await createEventRelay(auth, params);
|
|
150
|
+
return resultContent(result);
|
|
151
|
+
});
|
|
115
152
|
}
|
|
116
153
|
//# sourceMappingURL=integrations.js.map
|
package/dist/tools/ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CreateLightningAppSchema, CreateTabSchema, CreateCompactLayoutSchema, CreateListViewSchema, CreateEmailTemplateSchema, CreateStaticResourceSchema, CreateCustomNotificationTypeSchema, CreateReportTypeSchema, CreateDashboardSchema, UpdatePageLayoutSchema, AssignPageLayoutSchema, CreateLightningRecordPageSchema, CreateLightningHomePageSchema, UpdateLightningPageSchema, AssignLightningPageSchema, AssignCompactLayoutSchema, } from "../schemas/index.js";
|
|
2
|
-
import { getAuth, createLightningApp, createTab, createCompactLayout, createListView, createEmailTemplate, createCustomNotificationType, createReportType, updatePageLayout, assignPageLayout, createFlexiPage, updateFlexiPage, assignFlexiPage, assignCompactLayout, } from "../services/salesforce.js";
|
|
1
|
+
import { CreateLightningAppSchema, CreateTabSchema, CreateCompactLayoutSchema, CreateListViewSchema, CreateEmailTemplateSchema, CreateStaticResourceSchema, CreateCustomNotificationTypeSchema, CreateReportTypeSchema, CreateDashboardSchema, UpdatePageLayoutSchema, AssignPageLayoutSchema, CreateLightningRecordPageSchema, CreateLightningHomePageSchema, UpdateLightningPageSchema, AssignLightningPageSchema, AssignCompactLayoutSchema, CreateLightningAppPageSchema, CreateLetterheadSchema, } from "../schemas/index.js";
|
|
2
|
+
import { getAuth, createLightningApp, createTab, createCompactLayout, createListView, createEmailTemplate, createCustomNotificationType, createReportType, updatePageLayout, assignPageLayout, createFlexiPage, updateFlexiPage, assignFlexiPage, assignCompactLayout, createLightningAppPage, createLetterhead, } from "../services/salesforce.js";
|
|
3
3
|
import { buildStaticResourceZip, deployZip, pollDeployStatus, } from "../services/deployment.js";
|
|
4
4
|
import { API_VERSION } from "../services/salesforce.js";
|
|
5
5
|
import { resultContent } from "./utils.js";
|
|
@@ -261,5 +261,35 @@ export function registerUiTools(server) {
|
|
|
261
261
|
const result = await assignCompactLayout(auth, params);
|
|
262
262
|
return resultContent(result);
|
|
263
263
|
});
|
|
264
|
+
server.registerTool("sf_create_lightning_app_page", {
|
|
265
|
+
title: "Create Lightning App Page (FlexiPage)",
|
|
266
|
+
description: `Creates a Lightning App Page (FlexiPage of type AppPage) for use in Lightning Apps. App Pages appear as tabs in a Lightning App and can display dashboards, lists, and custom components.
|
|
267
|
+
|
|
268
|
+
template options: AppDefaultTemplate (single region), OneRegion, TwoColumn_LeftSidebar, TwoColumn_RightSidebar, ThreeColumn
|
|
269
|
+
|
|
270
|
+
After creating, assign the page to a Lightning App via App Manager in Setup, or use the Lightning App Builder to activate it.`,
|
|
271
|
+
inputSchema: CreateLightningAppPageSchema,
|
|
272
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
273
|
+
}, async (params) => {
|
|
274
|
+
const auth = await getAuth();
|
|
275
|
+
const result = await createLightningAppPage(auth, params);
|
|
276
|
+
return resultContent(result);
|
|
277
|
+
});
|
|
278
|
+
server.registerTool("sf_create_letterhead", {
|
|
279
|
+
title: "Create Email Letterhead",
|
|
280
|
+
description: `Creates an email letterhead (Letterhead metadata type) for use with Classic email templates. Letterheads define the visual branding of email templates — header/footer colors, fonts, separator lines, and logo placement.
|
|
281
|
+
|
|
282
|
+
After creating a letterhead, reference it by API name when creating email templates (sf_create_email_template with htmlValue that includes the letterhead).
|
|
283
|
+
|
|
284
|
+
headerColor/footerColor/bodyColor: hex color values (e.g. '#0070D2')
|
|
285
|
+
fontName: font face, e.g. 'Arial', 'Helvetica', 'Times New Roman'
|
|
286
|
+
footerText: optional static text shown in the footer`,
|
|
287
|
+
inputSchema: CreateLetterheadSchema,
|
|
288
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
289
|
+
}, async (params) => {
|
|
290
|
+
const auth = await getAuth();
|
|
291
|
+
const result = await createLetterhead(auth, params);
|
|
292
|
+
return resultContent(result);
|
|
293
|
+
});
|
|
264
294
|
}
|
|
265
295
|
//# sourceMappingURL=ui.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "salesforce-metadata-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "The most comprehensive Salesforce MCP server:
|
|
3
|
+
"version": "2.4.0",
|
|
4
|
+
"description": "The most comprehensive Salesforce MCP server: 155+ tools covering custom objects, flows, Apex, LWC, page layouts, permissions, profiles, users, reports, dashboards, Experience Cloud, OmniStudio, OmniChannel, Agentforce, Einstein AI, audit trail, and more — everything a Salesforce admin, advanced admin and developer needs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
7
7
|
"type": "module",
|
|
@@ -70,7 +70,18 @@
|
|
|
70
70
|
"messaging",
|
|
71
71
|
"live-chat",
|
|
72
72
|
"skill-routing",
|
|
73
|
-
"presence"
|
|
73
|
+
"presence",
|
|
74
|
+
"einstein",
|
|
75
|
+
"next-best-action",
|
|
76
|
+
"audit-trail",
|
|
77
|
+
"login-history",
|
|
78
|
+
"lightning-page",
|
|
79
|
+
"flexipage",
|
|
80
|
+
"app-builder",
|
|
81
|
+
"letterhead",
|
|
82
|
+
"soql",
|
|
83
|
+
"github-actions",
|
|
84
|
+
"ci-cd"
|
|
74
85
|
],
|
|
75
86
|
"dependencies": {
|
|
76
87
|
"@modelcontextprotocol/sdk": "1.29.0",
|