salesflare-mcp-server 1.0.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/API.md +691 -0
- package/CHANGELOG.md +49 -0
- package/CLAUDE.md +117 -0
- package/CONTRIBUTING.md +399 -0
- package/FIX_PLAN.md +70 -0
- package/INSPECTOR.md +191 -0
- package/LICENSE +21 -0
- package/PUBLISH.md +73 -0
- package/README.md +383 -0
- package/dist/auth/api-key-auth.d.ts +75 -0
- package/dist/auth/api-key-auth.d.ts.map +1 -0
- package/dist/auth/api-key-auth.js +103 -0
- package/dist/auth/oauth-auth.d.ts +81 -0
- package/dist/auth/oauth-auth.d.ts.map +1 -0
- package/dist/auth/oauth-auth.js +123 -0
- package/dist/auth/token-manager.d.ts +105 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +87 -0
- package/dist/client/salesflare-client.d.ts +219 -0
- package/dist/client/salesflare-client.d.ts.map +1 -0
- package/dist/client/salesflare-client.js +484 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/server.d.ts +39 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +140 -0
- package/dist/tools/companies.d.ts +45 -0
- package/dist/tools/companies.d.ts.map +1 -0
- package/dist/tools/companies.js +392 -0
- package/dist/tools/contacts.d.ts +45 -0
- package/dist/tools/contacts.d.ts.map +1 -0
- package/dist/tools/contacts.js +290 -0
- package/dist/tools/deals.d.ts +46 -0
- package/dist/tools/deals.d.ts.map +1 -0
- package/dist/tools/deals.js +442 -0
- package/dist/tools/pipeline.d.ts +43 -0
- package/dist/tools/pipeline.d.ts.map +1 -0
- package/dist/tools/pipeline.js +328 -0
- package/dist/tools/tasks.d.ts +44 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +406 -0
- package/dist/transport/http-transport.d.ts +36 -0
- package/dist/transport/http-transport.d.ts.map +1 -0
- package/dist/transport/http-transport.js +173 -0
- package/dist/transport/stdio-transport.d.ts +37 -0
- package/dist/transport/stdio-transport.d.ts.map +1 -0
- package/dist/transport/stdio-transport.js +129 -0
- package/dist/types/company.d.ts +223 -0
- package/dist/types/company.d.ts.map +1 -0
- package/dist/types/company.js +8 -0
- package/dist/types/contact.d.ts +166 -0
- package/dist/types/contact.d.ts.map +1 -0
- package/dist/types/contact.js +8 -0
- package/dist/types/deal.d.ts +203 -0
- package/dist/types/deal.d.ts.map +1 -0
- package/dist/types/deal.js +8 -0
- package/dist/types/pipeline.d.ts +116 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +8 -0
- package/dist/types/task.d.ts +154 -0
- package/dist/types/task.d.ts.map +1 -0
- package/dist/types/task.js +8 -0
- package/dist/utils/errors.d.ts +128 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +205 -0
- package/dist/utils/validation.d.ts +354 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +716 -0
- package/package.json +49 -0
- package/test-tasks-debug.js +21 -0
- package/test-tasks-params.js +52 -0
- package/test-tools.js +171 -0
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deal tools for Salesflare MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Implements CRUD operations for deals:
|
|
5
|
+
* - salesflare_deals_list: List deals with filtering and pagination
|
|
6
|
+
* - salesflare_deals_create: Create new deals
|
|
7
|
+
* - salesflare_deals_update: Update existing deals
|
|
8
|
+
* - salesflare_deals_delete: Delete deals
|
|
9
|
+
* - salesflare_deals_move_stage: Move deals between pipeline stages
|
|
10
|
+
*
|
|
11
|
+
* @module tools/deals
|
|
12
|
+
*/
|
|
13
|
+
import { SalesflareError, ErrorCode } from '../utils/errors.js';
|
|
14
|
+
/**
|
|
15
|
+
* Deal tool definitions with JSON schemas
|
|
16
|
+
*/
|
|
17
|
+
const dealTools = [
|
|
18
|
+
{
|
|
19
|
+
name: 'salesflare_deals_list',
|
|
20
|
+
description: 'List deals from Salesflare CRM with optional filtering and pagination. ' +
|
|
21
|
+
'Supports filtering by status (open, won, lost), pipeline_id, assigned_user_id, stage_id, ' +
|
|
22
|
+
'min_value, max_value (in cents), and search. Returns paginated results with total count ' +
|
|
23
|
+
'and has_more indicator. Deal values are displayed in human-readable format.',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
status: { type: 'string', enum: ['open', 'won', 'lost'], description: 'Filter by deal status' },
|
|
28
|
+
pipeline_id: { type: 'string', description: 'Filter by pipeline ID (UUID)' },
|
|
29
|
+
assigned_user_id: { type: 'string', description: 'Filter by assigned user ID (UUID)' },
|
|
30
|
+
stage_id: { type: 'string', description: 'Filter by stage ID (UUID)' },
|
|
31
|
+
min_value: { type: 'number', description: 'Minimum deal value in cents' },
|
|
32
|
+
max_value: { type: 'number', description: 'Maximum deal value in cents' },
|
|
33
|
+
search: { type: 'string', description: 'Free-text search across deal fields' },
|
|
34
|
+
page: { type: 'number', description: 'Page number (default: 1)' },
|
|
35
|
+
limit: { type: 'number', description: 'Items per page (default: 20, max: 100)' },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'salesflare_deals_create',
|
|
41
|
+
description: 'Create a new deal in Salesflare CRM. ' +
|
|
42
|
+
'Name, value (in dollars), and pipeline_id are required. ' +
|
|
43
|
+
'Value will be converted to cents for API storage. ' +
|
|
44
|
+
'Optional fields include currency (default USD), stage_id, close_date, ' +
|
|
45
|
+
'assigned_user_id, company_id, contact_ids, and description.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
name: { type: 'string', description: 'Deal name (required)' },
|
|
50
|
+
value: { type: 'number', description: 'Deal value in dollars (required, will be converted to cents)' },
|
|
51
|
+
currency: { type: 'string', description: 'Currency code (3-letter ISO, default: USD)' },
|
|
52
|
+
pipeline_id: { type: 'string', description: 'Pipeline ID the deal belongs to (required, UUID)' },
|
|
53
|
+
stage_id: { type: 'string', description: 'Stage ID within the pipeline (optional, UUID)' },
|
|
54
|
+
close_date: { type: 'string', description: 'Expected close date (ISO 8601 format)' },
|
|
55
|
+
assigned_user_id: { type: 'string', description: 'Assigned user ID (optional, UUID)' },
|
|
56
|
+
company_id: { type: 'string', description: 'Associated company ID (optional, UUID)' },
|
|
57
|
+
contact_ids: { type: 'array', items: { type: 'string' }, description: 'Associated contact IDs (optional, UUID array)' },
|
|
58
|
+
description: { type: 'string', description: 'Deal description' },
|
|
59
|
+
},
|
|
60
|
+
required: ['name', 'value', 'pipeline_id'],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'salesflare_deals_update',
|
|
65
|
+
description: 'Update an existing deal in Salesflare CRM. ' +
|
|
66
|
+
'Requires deal_id. All other fields are optional - only provided fields will be updated. ' +
|
|
67
|
+
'Value should be provided in dollars and will be converted to cents. ' +
|
|
68
|
+
'Status can be updated to open, won, or lost.',
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
deal_id: { type: 'string', description: 'Deal UUID to update' },
|
|
73
|
+
name: { type: 'string', description: 'Deal name' },
|
|
74
|
+
value: { type: 'number', description: 'Deal value in dollars (will be converted to cents)' },
|
|
75
|
+
currency: { type: 'string', description: 'Currency code (3-letter ISO)' },
|
|
76
|
+
pipeline_id: { type: 'string', description: 'Pipeline ID the deal belongs to' },
|
|
77
|
+
stage_id: { type: 'string', description: 'Stage ID within the pipeline' },
|
|
78
|
+
status: { type: 'string', enum: ['open', 'won', 'lost'], description: 'Deal status' },
|
|
79
|
+
close_date: { type: 'string', description: 'Expected close date (ISO 8601 format)' },
|
|
80
|
+
assigned_user_id: { type: 'string', description: 'Assigned user ID (UUID)' },
|
|
81
|
+
company_id: { type: 'string', description: 'Associated company ID (UUID)' },
|
|
82
|
+
contact_ids: { type: 'array', items: { type: 'string' }, description: 'Associated contact IDs (UUID array)' },
|
|
83
|
+
description: { type: 'string', description: 'Deal description' },
|
|
84
|
+
},
|
|
85
|
+
required: ['deal_id'],
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'salesflare_deals_delete',
|
|
90
|
+
description: 'Delete a deal from Salesflare CRM. ' +
|
|
91
|
+
'Requires deal_id. This action cannot be undone.',
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {
|
|
95
|
+
deal_id: { type: 'string', description: 'Deal UUID to delete' },
|
|
96
|
+
},
|
|
97
|
+
required: ['deal_id'],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'salesflare_deals_move_stage',
|
|
102
|
+
description: 'Move a deal to a different pipeline stage in Salesflare CRM. ' +
|
|
103
|
+
'Requires deal_id and stage_id. Returns the updated deal with new stage information.',
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
deal_id: { type: 'string', description: 'Deal UUID to move' },
|
|
108
|
+
stage_id: { type: 'string', description: 'Target stage ID (UUID)' },
|
|
109
|
+
},
|
|
110
|
+
required: ['deal_id', 'stage_id'],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* Exported deal tools array for unified registration
|
|
116
|
+
*/
|
|
117
|
+
export { dealTools };
|
|
118
|
+
/**
|
|
119
|
+
* Handle deal tool calls
|
|
120
|
+
*
|
|
121
|
+
* @param client - Salesflare API client
|
|
122
|
+
* @param name - Tool name
|
|
123
|
+
* @param args - Tool arguments
|
|
124
|
+
* @returns Tool response
|
|
125
|
+
*/
|
|
126
|
+
export async function handleDealsTool(client, name, args) {
|
|
127
|
+
switch (name) {
|
|
128
|
+
case 'salesflare_deals_list':
|
|
129
|
+
return await handleListDeals(client, args);
|
|
130
|
+
case 'salesflare_deals_create':
|
|
131
|
+
return await handleCreateDeal(client, args);
|
|
132
|
+
case 'salesflare_deals_update':
|
|
133
|
+
return await handleUpdateDeal(client, args);
|
|
134
|
+
case 'salesflare_deals_delete':
|
|
135
|
+
return await handleDeleteDeal(client, args);
|
|
136
|
+
case 'salesflare_deals_move_stage':
|
|
137
|
+
return await handleMoveDealStage(client, args);
|
|
138
|
+
default:
|
|
139
|
+
throw new SalesflareError({
|
|
140
|
+
code: ErrorCode.INVALID_INPUT,
|
|
141
|
+
message: `Unknown deal tool: ${name}`,
|
|
142
|
+
retryable: false,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Register deal-related tools with the MCP server
|
|
148
|
+
*
|
|
149
|
+
* @deprecated Use handleDealsTool instead for unified registration
|
|
150
|
+
* @param server - MCP Server instance
|
|
151
|
+
* @param client - Salesflare API client
|
|
152
|
+
*/
|
|
153
|
+
export function registerDealsTools(server, client) {
|
|
154
|
+
// This function is deprecated - use unified tool registration in server.ts
|
|
155
|
+
// Kept for backward compatibility
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Convert dollars to cents for API storage
|
|
159
|
+
* Per D-22: User inputs dollars, API stores cents
|
|
160
|
+
*/
|
|
161
|
+
function dollarsToCents(dollars) {
|
|
162
|
+
return Math.round(dollars * 100);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Convert cents to dollars for display
|
|
166
|
+
*/
|
|
167
|
+
function centsToDollars(cents) {
|
|
168
|
+
return cents / 100;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Format currency value for human-readable display
|
|
172
|
+
* Example: 1000000 cents + 'USD' → '$10,000.00'
|
|
173
|
+
*/
|
|
174
|
+
function formatCurrency(valueInCents, currency = 'USD') {
|
|
175
|
+
const dollars = centsToDollars(valueInCents);
|
|
176
|
+
// Ensure currency is a string
|
|
177
|
+
const currencyCode = (currency || 'USD').toString();
|
|
178
|
+
// Format with appropriate locale based on currency
|
|
179
|
+
let locale = 'en-US';
|
|
180
|
+
let currencySymbol = '$';
|
|
181
|
+
switch (currencyCode.toUpperCase()) {
|
|
182
|
+
case 'EUR':
|
|
183
|
+
locale = 'de-DE';
|
|
184
|
+
currencySymbol = '€';
|
|
185
|
+
break;
|
|
186
|
+
case 'GBP':
|
|
187
|
+
locale = 'en-GB';
|
|
188
|
+
currencySymbol = '£';
|
|
189
|
+
break;
|
|
190
|
+
case 'JPY':
|
|
191
|
+
locale = 'ja-JP';
|
|
192
|
+
currencySymbol = '¥';
|
|
193
|
+
break;
|
|
194
|
+
default:
|
|
195
|
+
// USD and others use US format
|
|
196
|
+
locale = 'en-US';
|
|
197
|
+
currencySymbol = '$';
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
return new Intl.NumberFormat(locale, {
|
|
201
|
+
style: 'currency',
|
|
202
|
+
currency: currencyCode.toUpperCase(),
|
|
203
|
+
}).format(dollars);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Fallback for unsupported currency codes
|
|
207
|
+
return `${currencySymbol}${dollars.toFixed(2)}`;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Handle salesflare_deals_list tool call
|
|
212
|
+
* Implements filters per D-15 to D-20
|
|
213
|
+
*/
|
|
214
|
+
async function handleListDeals(client, params) {
|
|
215
|
+
// Build query parameters from filters
|
|
216
|
+
const queryParams = {};
|
|
217
|
+
if (params.status)
|
|
218
|
+
queryParams.status = params.status;
|
|
219
|
+
if (params.pipeline_id)
|
|
220
|
+
queryParams.pipeline_id = params.pipeline_id;
|
|
221
|
+
if (params.assigned_user_id)
|
|
222
|
+
queryParams.assigned_user_id = params.assigned_user_id;
|
|
223
|
+
if (params.stage_id)
|
|
224
|
+
queryParams.stage_id = params.stage_id;
|
|
225
|
+
if (params.min_value !== undefined)
|
|
226
|
+
queryParams.min_value = params.min_value;
|
|
227
|
+
if (params.max_value !== undefined)
|
|
228
|
+
queryParams.max_value = params.max_value;
|
|
229
|
+
if (params.search)
|
|
230
|
+
queryParams.search = params.search;
|
|
231
|
+
// Pagination
|
|
232
|
+
queryParams.page = params.page || 1;
|
|
233
|
+
queryParams.limit = params.limit || 20;
|
|
234
|
+
// Call Salesflare API
|
|
235
|
+
const response = await client.get('/opportunities', { params: queryParams });
|
|
236
|
+
// Handle different response formats
|
|
237
|
+
const items = response.items || (Array.isArray(response) ? response : []);
|
|
238
|
+
const total = response.total ?? items.length;
|
|
239
|
+
const page = (response.page ?? Number(params.page)) || 1;
|
|
240
|
+
const limit = (response.limit ?? Number(params.limit)) || 20;
|
|
241
|
+
// Transform to curated response format (D-10)
|
|
242
|
+
const deals = items.map((item) => ({
|
|
243
|
+
id: item.id,
|
|
244
|
+
name: item.name,
|
|
245
|
+
value: item.value,
|
|
246
|
+
currency: item.currency || 'USD',
|
|
247
|
+
pipeline_id: item.pipeline_id,
|
|
248
|
+
stage_id: item.stage_id,
|
|
249
|
+
status: item.status,
|
|
250
|
+
close_date: item.close_date,
|
|
251
|
+
assigned_user: item.assigned_user ? {
|
|
252
|
+
id: item.assigned_user.id,
|
|
253
|
+
name: item.assigned_user.name,
|
|
254
|
+
} : undefined,
|
|
255
|
+
company: item.company ? {
|
|
256
|
+
id: item.company.id,
|
|
257
|
+
name: item.company.name,
|
|
258
|
+
} : undefined,
|
|
259
|
+
contacts: item.contacts ? item.contacts.map((c) => ({
|
|
260
|
+
id: c.id,
|
|
261
|
+
name: c.name,
|
|
262
|
+
})) : undefined,
|
|
263
|
+
description: item.description,
|
|
264
|
+
created_at: item.created_at,
|
|
265
|
+
updated_at: item.updated_at,
|
|
266
|
+
}));
|
|
267
|
+
const listResponse = {
|
|
268
|
+
deals,
|
|
269
|
+
total,
|
|
270
|
+
page,
|
|
271
|
+
limit,
|
|
272
|
+
has_more: page * limit < total,
|
|
273
|
+
};
|
|
274
|
+
// Calculate total value for summary (use first deal's currency or default to USD)
|
|
275
|
+
const totalValueCents = deals.reduce((sum, deal) => sum + (deal.value || 0), 0);
|
|
276
|
+
const currency = deals.length > 0 ? deals[0].currency : 'USD';
|
|
277
|
+
const formattedTotalValue = formatCurrency(totalValueCents, currency);
|
|
278
|
+
// Generate human-readable summary
|
|
279
|
+
const summaryText = listResponse.deals.length === 0
|
|
280
|
+
? 'No deals found matching the criteria.'
|
|
281
|
+
: `Found ${listResponse.total} deal(s) worth ${formattedTotalValue} total. ` +
|
|
282
|
+
`Showing page ${listResponse.page} with ${listResponse.deals.length} result(s).` +
|
|
283
|
+
(listResponse.has_more ? ` More pages available.` : '');
|
|
284
|
+
return {
|
|
285
|
+
content: [
|
|
286
|
+
{ type: 'text', text: summaryText },
|
|
287
|
+
{ type: 'text', text: JSON.stringify(listResponse, null, 2) },
|
|
288
|
+
],
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Handle salesflare_deals_create tool call
|
|
293
|
+
* Name, value, and pipeline_id are required per D-01
|
|
294
|
+
* Value converted from dollars to cents per D-22
|
|
295
|
+
*/
|
|
296
|
+
async function handleCreateDeal(client, params) {
|
|
297
|
+
// Convert value from dollars to cents for API
|
|
298
|
+
const valueInCents = dollarsToCents(params.value);
|
|
299
|
+
// Call Salesflare API to create deal
|
|
300
|
+
const response = await client.post('/deals', {
|
|
301
|
+
name: params.name,
|
|
302
|
+
value: valueInCents,
|
|
303
|
+
currency: params.currency || 'USD',
|
|
304
|
+
pipeline_id: params.pipeline_id,
|
|
305
|
+
stage_id: params.stage_id,
|
|
306
|
+
close_date: params.close_date,
|
|
307
|
+
assigned_user_id: params.assigned_user_id,
|
|
308
|
+
company_id: params.company_id,
|
|
309
|
+
contact_ids: params.contact_ids,
|
|
310
|
+
description: params.description,
|
|
311
|
+
});
|
|
312
|
+
// Transform to curated response format
|
|
313
|
+
const deal = {
|
|
314
|
+
id: response.id,
|
|
315
|
+
name: response.name,
|
|
316
|
+
value: response.value,
|
|
317
|
+
currency: response.currency || 'USD',
|
|
318
|
+
pipeline_id: response.pipeline_id,
|
|
319
|
+
stage_id: response.stage_id,
|
|
320
|
+
status: response.status,
|
|
321
|
+
close_date: response.close_date,
|
|
322
|
+
assigned_user: response.assigned_user ? {
|
|
323
|
+
id: response.assigned_user.id,
|
|
324
|
+
name: response.assigned_user.name,
|
|
325
|
+
} : undefined,
|
|
326
|
+
company: response.company ? {
|
|
327
|
+
id: response.company.id,
|
|
328
|
+
name: response.company.name,
|
|
329
|
+
} : undefined,
|
|
330
|
+
contacts: response.contacts ? response.contacts.map((c) => ({
|
|
331
|
+
id: c.id,
|
|
332
|
+
name: c.name,
|
|
333
|
+
})) : undefined,
|
|
334
|
+
description: response.description,
|
|
335
|
+
created_at: response.created_at,
|
|
336
|
+
updated_at: response.updated_at,
|
|
337
|
+
};
|
|
338
|
+
const formattedValue = formatCurrency(deal.value, deal.currency);
|
|
339
|
+
return {
|
|
340
|
+
content: [
|
|
341
|
+
{ type: 'text', text: `Deal created: ${deal.name} (${formattedValue})` },
|
|
342
|
+
{ type: 'text', text: JSON.stringify(deal, null, 2) },
|
|
343
|
+
],
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Transform API response to curated Deal format
|
|
348
|
+
* Shared transformation logic for create, update, and move_stage
|
|
349
|
+
*/
|
|
350
|
+
function transformDealResponse(response) {
|
|
351
|
+
return {
|
|
352
|
+
id: response.id,
|
|
353
|
+
name: response.name,
|
|
354
|
+
value: response.value,
|
|
355
|
+
currency: response.currency || 'USD',
|
|
356
|
+
pipeline_id: response.pipeline_id,
|
|
357
|
+
stage_id: response.stage_id,
|
|
358
|
+
status: response.status,
|
|
359
|
+
close_date: response.close_date,
|
|
360
|
+
assigned_user: response.assigned_user ? {
|
|
361
|
+
id: response.assigned_user.id,
|
|
362
|
+
name: response.assigned_user.name,
|
|
363
|
+
} : undefined,
|
|
364
|
+
company: response.company ? {
|
|
365
|
+
id: response.company.id,
|
|
366
|
+
name: response.company.name,
|
|
367
|
+
} : undefined,
|
|
368
|
+
contacts: response.contacts ? response.contacts.map((c) => ({
|
|
369
|
+
id: c.id,
|
|
370
|
+
name: c.name,
|
|
371
|
+
})) : undefined,
|
|
372
|
+
description: response.description,
|
|
373
|
+
created_at: response.created_at,
|
|
374
|
+
updated_at: response.updated_at,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Handle salesflare_deals_update tool call
|
|
379
|
+
* Partial update per D-25: only provided fields will be updated
|
|
380
|
+
* Value converted from dollars to cents if provided
|
|
381
|
+
*/
|
|
382
|
+
async function handleUpdateDeal(client, params) {
|
|
383
|
+
const { deal_id, ...updateData } = params;
|
|
384
|
+
// Check if at least one field is provided for update
|
|
385
|
+
const hasUpdateFields = Object.keys(updateData).length > 0;
|
|
386
|
+
if (!hasUpdateFields) {
|
|
387
|
+
return {
|
|
388
|
+
content: [
|
|
389
|
+
{ type: 'text', text: 'Error [INVALID_INPUT]: At least one field must be provided for update.' },
|
|
390
|
+
{ type: 'text', text: '{}' },
|
|
391
|
+
],
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
// Convert value from dollars to cents if provided
|
|
395
|
+
if (typeof updateData.value === 'number') {
|
|
396
|
+
updateData.value = dollarsToCents(updateData.value);
|
|
397
|
+
}
|
|
398
|
+
// Call Salesflare API to update deal
|
|
399
|
+
const response = await client.patch(`/deals/${deal_id}`, updateData);
|
|
400
|
+
// Transform to curated response format
|
|
401
|
+
const deal = transformDealResponse(response);
|
|
402
|
+
const formattedValue = formatCurrency(deal.value, deal.currency);
|
|
403
|
+
return {
|
|
404
|
+
content: [
|
|
405
|
+
{ type: 'text', text: `Deal updated: ${deal.name} (${formattedValue})` },
|
|
406
|
+
{ type: 'text', text: JSON.stringify(deal, null, 2) },
|
|
407
|
+
],
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Handle salesflare_deals_delete tool call
|
|
412
|
+
* Per D-12: Returns confirmation only, no deal data
|
|
413
|
+
*/
|
|
414
|
+
async function handleDeleteDeal(client, params) {
|
|
415
|
+
// Call Salesflare API to delete deal
|
|
416
|
+
await client.delete(`/deals/${params.deal_id}`);
|
|
417
|
+
return {
|
|
418
|
+
content: [{ type: 'text', text: 'Deal deleted successfully.' }],
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Handle salesflare_deals_move_stage tool call
|
|
423
|
+
* Wrapper around update per D-26: updates stage_id
|
|
424
|
+
* Returns updated deal with new stage per D-27
|
|
425
|
+
*/
|
|
426
|
+
async function handleMoveDealStage(client, params) {
|
|
427
|
+
// Call Salesflare API to update deal stage
|
|
428
|
+
const response = await client.patch(`/deals/${params.deal_id}`, {
|
|
429
|
+
stage_id: params.stage_id,
|
|
430
|
+
});
|
|
431
|
+
// Transform to curated response format
|
|
432
|
+
const deal = transformDealResponse(response);
|
|
433
|
+
const formattedValue = formatCurrency(deal.value, deal.currency);
|
|
434
|
+
// Get stage name if available
|
|
435
|
+
const stageName = deal.stage_id || 'new stage';
|
|
436
|
+
return {
|
|
437
|
+
content: [
|
|
438
|
+
{ type: 'text', text: `Deal moved to stage: ${stageName} (${formattedValue})` },
|
|
439
|
+
{ type: 'text', text: JSON.stringify(deal, null, 2) },
|
|
440
|
+
],
|
|
441
|
+
};
|
|
442
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline tools for Salesflare MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Implements pipeline operations:
|
|
5
|
+
* - salesflare_pipeline_list_stages: List pipeline stages
|
|
6
|
+
* - salesflare_pipeline_get_overview: Get pipeline statistics
|
|
7
|
+
*
|
|
8
|
+
* @module tools/pipeline
|
|
9
|
+
*/
|
|
10
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
12
|
+
import { SalesflareClient } from '../client/salesflare-client.js';
|
|
13
|
+
/**
|
|
14
|
+
* Pipeline tool definitions with JSON schemas
|
|
15
|
+
*/
|
|
16
|
+
declare const pipelineTools: Tool[];
|
|
17
|
+
/**
|
|
18
|
+
* Exported pipeline tools array for unified registration
|
|
19
|
+
*/
|
|
20
|
+
export { pipelineTools };
|
|
21
|
+
/**
|
|
22
|
+
* Handle pipeline tool calls
|
|
23
|
+
*
|
|
24
|
+
* @param client - Salesflare API client
|
|
25
|
+
* @param name - Tool name
|
|
26
|
+
* @param args - Tool arguments
|
|
27
|
+
* @returns Tool response
|
|
28
|
+
*/
|
|
29
|
+
export declare function handlePipelineTool(client: SalesflareClient, name: string, args: unknown): Promise<{
|
|
30
|
+
content: Array<{
|
|
31
|
+
type: string;
|
|
32
|
+
text: string;
|
|
33
|
+
}>;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Register pipeline-related tools with the MCP server
|
|
37
|
+
*
|
|
38
|
+
* @deprecated Use handlePipelineTool instead for unified registration
|
|
39
|
+
* @param server - MCP Server instance
|
|
40
|
+
* @param client - Salesflare API client
|
|
41
|
+
*/
|
|
42
|
+
export declare function registerPipelineTools(server: Server, client: SalesflareClient): void;
|
|
43
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/tools/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAGL,IAAI,EACL,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAWlE;;GAEG;AACH,QAAA,MAAM,aAAa,EAAE,IAAI,EA0BxB,CAAC;AAEF;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAe7D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAGpF"}
|