@loopops/mcp-server 3.44.0 → 3.46.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.
Files changed (2) hide show
  1. package/dist/tools/cpq.js +50 -3
  2. package/package.json +1 -1
package/dist/tools/cpq.js CHANGED
@@ -25,6 +25,15 @@ export function registerCpqTools(server, allowed) {
25
25
  .describe("Filter by Quote.Status. Omit to see open quotes (Draft + Presented)."),
26
26
  }, safeTool(async ({ status }) => trpcQuery("mcp.myQuotes", { status })));
27
27
  }
28
+ if (allowed.has("find_opportunity")) {
29
+ server.tool("find_opportunity", "List open Salesforce Opportunities for accounts matching a name (case-insensitive substring). Use this BEFORE draft_quote_from_intent when the rep gave you a customer name but not the 006... Opportunity Id. Returns a table of opp Id / account / opp name / stage / amount / close date. If exactly one match, you can call draft_quote_from_intent with that Id directly. (Alternatively, draft_quote_from_intent itself accepts accountName and resolves internally — use this tool only when you want to show the rep candidates explicitly.)", {
30
+ accountName: z
31
+ .string()
32
+ .min(2)
33
+ .max(200)
34
+ .describe("Customer account name. Case-insensitive substring match."),
35
+ }, safeTool(async ({ accountName }) => trpcQuery("mcp.findOpportunity", { accountName })));
36
+ }
28
37
  if (allowed.has("quote_show")) {
29
38
  server.tool("quote_show", "Full detail on one Quote: deal shape (tier/region/term/commit/discount), line items with per-line discount, monthly run-rate, annualized run-rate, commit utilization, and AI audit metadata if the quote was generated by an agent. Look up by Quote Id, Quote name, or Opportunity name (uses the most recently modified Quote on a matching opp).", {
30
39
  quoteId: z
@@ -42,12 +51,49 @@ export function registerCpqTools(server, allowed) {
42
51
  opportunityName,
43
52
  })));
44
53
  }
54
+ if (allowed.has("create_opportunity")) {
55
+ server.tool("create_opportunity", "Create a new Salesforce Opportunity on an existing Account. Use only after the rep confirms stage / amount / closeDate — the agent should NEVER silently create with assumed defaults. Refuses if (a) the Account doesn't exist, (b) any open Opportunity already exists on the Account (anti-duplicate guard — use the existing opp instead). Typical chain: find_opportunity returns 0 matches → agent proposes opp shape → rep confirms → create_opportunity → draft_quote_from_intent.", {
56
+ accountName: z
57
+ .string()
58
+ .min(2)
59
+ .max(200)
60
+ .describe("Customer Account name (case-insensitive substring match). Must resolve to exactly one existing Account."),
61
+ opportunityName: z
62
+ .string()
63
+ .min(3)
64
+ .max(120)
65
+ .describe("Name for the new Opportunity (e.g., 'Vercel — Loop CPQ')."),
66
+ stage: z
67
+ .string()
68
+ .min(1)
69
+ .describe("Salesforce StageName (e.g., 'Prospecting', 'Qualification', 'Value Proposition'). Must match the org's Opportunity stage picklist."),
70
+ amount: z
71
+ .number()
72
+ .positive()
73
+ .describe("Opportunity Amount in USD. The rep's commit number is a sensible default."),
74
+ closeDate: z
75
+ .string()
76
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "YYYY-MM-DD")
77
+ .describe("Expected close date (YYYY-MM-DD). Ask the rep — don't invent."),
78
+ type: z
79
+ .string()
80
+ .optional()
81
+ .describe("Opportunity Type (e.g., 'New Customer'). Optional."),
82
+ }, safeTool(async (args) => trpcMutation("mcp.createOpportunity", args)));
83
+ }
45
84
  if (allowed.has("draft_quote_from_intent")) {
46
- server.tool("draft_quote_from_intent", "Generate a Salesforce Quote from a free-form sizing intent. Claude Sonnet 4.6 parses the intent into a structured sizing payload, then the Apex Invocable CpqQuoteBuilder creates the Quote + line items with the negotiated discount applied. If the model's parse confidence is below 0.6 (a critical field is ambiguous), this tool returns a clarifying question instead of writing. Quote ships in Status = Draft; the rep approves separately.", {
85
+ server.tool("draft_quote_from_intent", "Generate a Salesforce Quote from a free-form sizing intent. Claude Sonnet 4.6 parses the intent into a structured sizing payload, then the Apex Invocable CpqQuoteBuilder creates the Quote + line items with the negotiated discount applied. Pass EITHER opportunityId OR accountName (you typically know the account name; the tool resolves internally to the single open opp. If multiple opps match the name, the tool returns a disambiguation prompt). If the model's parse confidence is below 0.6 (a critical sizing field is ambiguous), the tool returns a clarifying question instead of writing. Quote ships in Status = Draft; the rep approves separately.", {
47
86
  opportunityId: z
48
87
  .string()
49
88
  .regex(/^006/, "expected a Salesforce Opportunity Id")
50
- .describe("Salesforce Opportunity Id (starts with 006)."),
89
+ .optional()
90
+ .describe("Salesforce Opportunity Id (starts with 006). Provide this OR accountName."),
91
+ accountName: z
92
+ .string()
93
+ .min(2)
94
+ .max(200)
95
+ .optional()
96
+ .describe("Customer account name (e.g. 'Vercel'). Resolved internally to a single open opp. Provide this OR opportunityId."),
51
97
  intent: z
52
98
  .string()
53
99
  .min(20)
@@ -58,8 +104,9 @@ export function registerCpqTools(server, allowed) {
58
104
  .default(12),
59
105
  region: z.string().default("us-east-1"),
60
106
  cloudProvider: z.string().default("AWS"),
61
- }, safeTool(async ({ opportunityId, intent, termMonths, region, cloudProvider }) => trpcMutation("mcp.draftQuoteFromIntent", {
107
+ }, safeTool(async ({ opportunityId, accountName, intent, termMonths, region, cloudProvider }) => trpcMutation("mcp.draftQuoteFromIntent", {
62
108
  opportunityId,
109
+ accountName,
63
110
  intent,
64
111
  termMonths,
65
112
  region,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loopops/mcp-server",
3
- "version": "3.44.0",
3
+ "version": "3.46.0",
4
4
  "description": "Loop Operations MCP Server — AI skills for RevOps",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",