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,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contact tools for Salesflare MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Implements CRUD operations for contacts:
|
|
5
|
+
* - salesflare_contacts_list: List contacts with filtering and pagination
|
|
6
|
+
* - salesflare_contacts_create: Create new contacts
|
|
7
|
+
* - salesflare_contacts_update: Update existing contacts
|
|
8
|
+
* - salesflare_contacts_delete: Delete contacts
|
|
9
|
+
*
|
|
10
|
+
* @module tools/contacts
|
|
11
|
+
*/
|
|
12
|
+
import { SalesflareError, ErrorCode } from '../utils/errors.js';
|
|
13
|
+
/**
|
|
14
|
+
* Contact tool definitions with Zod schemas
|
|
15
|
+
*/
|
|
16
|
+
const contactTools = [
|
|
17
|
+
{
|
|
18
|
+
name: 'salesflare_contacts_list',
|
|
19
|
+
description: 'List contacts from Salesflare CRM with optional filtering and pagination. ' +
|
|
20
|
+
'Supports filtering by email, name, company_id, tags, owner, domain, and search. ' +
|
|
21
|
+
'Returns paginated results with total count and has_more indicator.',
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
email: { type: 'string', description: 'Filter by exact email match' },
|
|
26
|
+
name: { type: 'string', description: 'Filter by name (partial match, case-insensitive)' },
|
|
27
|
+
company_id: { type: 'string', description: 'Filter by company ID (UUID)' },
|
|
28
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
|
|
29
|
+
owner: { type: 'string', description: 'Filter by owner ID or name' },
|
|
30
|
+
domain: { type: 'string', description: 'Filter by email domain (partial match)' },
|
|
31
|
+
search: { type: 'string', description: 'Free-text search across contact fields' },
|
|
32
|
+
page: { type: 'number', description: 'Page number (default: 1)' },
|
|
33
|
+
limit: { type: 'number', description: 'Items per page (default: 20, max: 100)' },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'salesflare_contacts_create',
|
|
39
|
+
description: 'Create a new contact in Salesflare CRM. ' +
|
|
40
|
+
'Email is required. Optional fields include name, phone, company_id, job_title, tags, and owner_id.',
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
name: { type: 'string', description: "Contact's full name" },
|
|
45
|
+
email: { type: 'string', description: "Contact's email address (required)" },
|
|
46
|
+
phone: { type: 'string', description: "Contact's phone number" },
|
|
47
|
+
company_id: { type: 'string', description: 'Company ID to associate (UUID)' },
|
|
48
|
+
job_title: { type: 'string', description: 'Job title at the company' },
|
|
49
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags to assign' },
|
|
50
|
+
owner_id: { type: 'string', description: 'Owner/user ID to assign (UUID)' },
|
|
51
|
+
},
|
|
52
|
+
required: ['email'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'salesflare_contacts_update',
|
|
57
|
+
description: 'Update an existing contact in Salesflare CRM. ' +
|
|
58
|
+
'Requires contact_id. All other fields are optional - only provided fields will be updated.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
contact_id: { type: 'string', description: 'Contact UUID to update' },
|
|
63
|
+
name: { type: 'string', description: "Contact's full name" },
|
|
64
|
+
email: { type: 'string', description: "Contact's email address" },
|
|
65
|
+
phone: { type: 'string', description: "Contact's phone number" },
|
|
66
|
+
company_id: { type: 'string', description: 'Company ID to associate (UUID)' },
|
|
67
|
+
job_title: { type: 'string', description: 'Job title at the company' },
|
|
68
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags to assign' },
|
|
69
|
+
owner_id: { type: 'string', description: 'Owner/user ID to assign (UUID)' },
|
|
70
|
+
},
|
|
71
|
+
required: ['contact_id'],
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'salesflare_contacts_delete',
|
|
76
|
+
description: 'Delete a contact from Salesflare CRM. ' +
|
|
77
|
+
'Requires contact_id. This action cannot be undone.',
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties: {
|
|
81
|
+
contact_id: { type: 'string', description: 'Contact UUID to delete' },
|
|
82
|
+
},
|
|
83
|
+
required: ['contact_id'],
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
/**
|
|
88
|
+
* Exported contact tools array for unified registration
|
|
89
|
+
*/
|
|
90
|
+
export { contactTools };
|
|
91
|
+
/**
|
|
92
|
+
* Handle contact tool calls
|
|
93
|
+
*
|
|
94
|
+
* @param client - Salesflare API client
|
|
95
|
+
* @param name - Tool name
|
|
96
|
+
* @param args - Tool arguments
|
|
97
|
+
* @returns Tool response
|
|
98
|
+
*/
|
|
99
|
+
export async function handleContactsTool(client, name, args) {
|
|
100
|
+
switch (name) {
|
|
101
|
+
case 'salesflare_contacts_list':
|
|
102
|
+
return await handleListContacts(client, args);
|
|
103
|
+
case 'salesflare_contacts_create':
|
|
104
|
+
return await handleCreateContact(client, args);
|
|
105
|
+
case 'salesflare_contacts_update':
|
|
106
|
+
return await handleUpdateContact(client, args);
|
|
107
|
+
case 'salesflare_contacts_delete':
|
|
108
|
+
return await handleDeleteContact(client, args);
|
|
109
|
+
default:
|
|
110
|
+
throw new SalesflareError({
|
|
111
|
+
code: ErrorCode.INVALID_INPUT,
|
|
112
|
+
message: `Unknown contact tool: ${name}`,
|
|
113
|
+
retryable: false,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Register contact-related tools with the MCP server
|
|
119
|
+
*
|
|
120
|
+
* @deprecated Use handleContactsTool instead for unified registration
|
|
121
|
+
* @param server - MCP Server instance
|
|
122
|
+
* @param client - Salesflare API client
|
|
123
|
+
*/
|
|
124
|
+
export function registerContactsTools(server, client) {
|
|
125
|
+
// This function is deprecated - use unified tool registration in server.ts
|
|
126
|
+
// Kept for backward compatibility
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Handle salesflare_contacts_list tool call
|
|
130
|
+
*/
|
|
131
|
+
async function handleListContacts(client, params) {
|
|
132
|
+
// Build query parameters from filters
|
|
133
|
+
const queryParams = {};
|
|
134
|
+
if (params.email)
|
|
135
|
+
queryParams.email = params.email;
|
|
136
|
+
if (params.name)
|
|
137
|
+
queryParams.name = params.name;
|
|
138
|
+
if (params.company_id)
|
|
139
|
+
queryParams.company_id = params.company_id;
|
|
140
|
+
if (params.tags && params.tags.length > 0)
|
|
141
|
+
queryParams.tags = params.tags.join(',');
|
|
142
|
+
if (params.owner)
|
|
143
|
+
queryParams.owner = params.owner;
|
|
144
|
+
if (params.domain)
|
|
145
|
+
queryParams.domain = params.domain;
|
|
146
|
+
if (params.search)
|
|
147
|
+
queryParams.search = params.search;
|
|
148
|
+
// Pagination
|
|
149
|
+
queryParams.page = Number(params.page) || 1;
|
|
150
|
+
queryParams.limit = Number(params.limit) || 20;
|
|
151
|
+
// Call Salesflare API
|
|
152
|
+
const response = await client.get('/contacts', { params: queryParams });
|
|
153
|
+
// Handle different response formats
|
|
154
|
+
const items = response.items || (Array.isArray(response) ? response : []);
|
|
155
|
+
const total = response.total ?? items.length;
|
|
156
|
+
const page = (response.page ?? Number(params.page)) || 1;
|
|
157
|
+
const limit = (response.limit ?? Number(params.limit)) || 20;
|
|
158
|
+
// Transform to curated response format
|
|
159
|
+
const contacts = items.map((item) => ({
|
|
160
|
+
id: item.id,
|
|
161
|
+
name: item.name,
|
|
162
|
+
email: item.email,
|
|
163
|
+
phone: item.phone,
|
|
164
|
+
company: item.company ? {
|
|
165
|
+
id: item.company.id,
|
|
166
|
+
name: item.company.name,
|
|
167
|
+
} : undefined,
|
|
168
|
+
job_title: item.job_title,
|
|
169
|
+
tags: item.tags,
|
|
170
|
+
owner: item.owner ? {
|
|
171
|
+
id: item.owner.id,
|
|
172
|
+
name: item.owner.name,
|
|
173
|
+
} : undefined,
|
|
174
|
+
created_at: item.created_at,
|
|
175
|
+
updated_at: item.updated_at,
|
|
176
|
+
}));
|
|
177
|
+
const listResponse = {
|
|
178
|
+
contacts,
|
|
179
|
+
total,
|
|
180
|
+
page,
|
|
181
|
+
limit,
|
|
182
|
+
has_more: page * limit < total,
|
|
183
|
+
};
|
|
184
|
+
// Generate human-readable summary
|
|
185
|
+
const summaryText = listResponse.contacts.length === 0
|
|
186
|
+
? 'No contacts found matching the criteria.'
|
|
187
|
+
: `Found ${listResponse.total} contact(s). Showing page ${listResponse.page} with ${listResponse.contacts.length} result(s).` +
|
|
188
|
+
(listResponse.has_more ? ` More pages available.` : '');
|
|
189
|
+
return {
|
|
190
|
+
content: [
|
|
191
|
+
{ type: 'text', text: summaryText },
|
|
192
|
+
{ type: 'text', text: JSON.stringify(listResponse, null, 2) },
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Handle salesflare_contacts_create tool call
|
|
198
|
+
*/
|
|
199
|
+
async function handleCreateContact(client, params) {
|
|
200
|
+
// Call Salesflare API to create contact
|
|
201
|
+
const response = await client.post('/contacts', {
|
|
202
|
+
name: params.name,
|
|
203
|
+
email: params.email,
|
|
204
|
+
phone: params.phone,
|
|
205
|
+
company_id: params.company_id,
|
|
206
|
+
job_title: params.job_title,
|
|
207
|
+
tags: params.tags,
|
|
208
|
+
owner_id: params.owner_id,
|
|
209
|
+
});
|
|
210
|
+
// Transform to curated response format
|
|
211
|
+
const contact = {
|
|
212
|
+
id: response.id,
|
|
213
|
+
name: response.name,
|
|
214
|
+
email: response.email,
|
|
215
|
+
phone: response.phone,
|
|
216
|
+
company: response.company ? {
|
|
217
|
+
id: response.company.id,
|
|
218
|
+
name: response.company.name,
|
|
219
|
+
} : undefined,
|
|
220
|
+
job_title: response.job_title,
|
|
221
|
+
tags: response.tags,
|
|
222
|
+
owner: response.owner ? {
|
|
223
|
+
id: response.owner.id,
|
|
224
|
+
name: response.owner.name,
|
|
225
|
+
} : undefined,
|
|
226
|
+
created_at: response.created_at,
|
|
227
|
+
updated_at: response.updated_at,
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
content: [
|
|
231
|
+
{ type: 'text', text: `Contact created: ${contact.name || 'Unnamed'} (${contact.email})` },
|
|
232
|
+
{ type: 'text', text: JSON.stringify(contact, null, 2) },
|
|
233
|
+
],
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Handle salesflare_contacts_update tool call
|
|
238
|
+
*/
|
|
239
|
+
async function handleUpdateContact(client, params) {
|
|
240
|
+
const { contact_id, ...updateData } = params;
|
|
241
|
+
// Check if at least one field is provided for update
|
|
242
|
+
const hasUpdateFields = Object.keys(updateData).length > 0;
|
|
243
|
+
if (!hasUpdateFields) {
|
|
244
|
+
return {
|
|
245
|
+
content: [
|
|
246
|
+
{ type: 'text', text: 'Error [INVALID_INPUT]: At least one field must be provided for update.' },
|
|
247
|
+
{ type: 'text', text: '{}' },
|
|
248
|
+
],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// Call Salesflare API to update contact
|
|
252
|
+
const response = await client.patch(`/contacts/${contact_id}`, updateData);
|
|
253
|
+
// Transform to curated response format
|
|
254
|
+
const contact = {
|
|
255
|
+
id: response.id,
|
|
256
|
+
name: response.name,
|
|
257
|
+
email: response.email,
|
|
258
|
+
phone: response.phone,
|
|
259
|
+
company: response.company ? {
|
|
260
|
+
id: response.company.id,
|
|
261
|
+
name: response.company.name,
|
|
262
|
+
} : undefined,
|
|
263
|
+
job_title: response.job_title,
|
|
264
|
+
tags: response.tags,
|
|
265
|
+
owner: response.owner ? {
|
|
266
|
+
id: response.owner.id,
|
|
267
|
+
name: response.owner.name,
|
|
268
|
+
} : undefined,
|
|
269
|
+
created_at: response.created_at,
|
|
270
|
+
updated_at: response.updated_at,
|
|
271
|
+
};
|
|
272
|
+
return {
|
|
273
|
+
content: [
|
|
274
|
+
{ type: 'text', text: `Contact updated: ${contact.name || 'Unnamed'} (${contact.email})` },
|
|
275
|
+
{ type: 'text', text: JSON.stringify(contact, null, 2) },
|
|
276
|
+
],
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Handle salesflare_contacts_delete tool call
|
|
281
|
+
*/
|
|
282
|
+
async function handleDeleteContact(client, params) {
|
|
283
|
+
// Call Salesflare API to delete contact
|
|
284
|
+
await client.delete(`/contacts/${params.contact_id}`);
|
|
285
|
+
return {
|
|
286
|
+
content: [
|
|
287
|
+
{ type: 'text', text: 'Contact deleted successfully.' },
|
|
288
|
+
],
|
|
289
|
+
};
|
|
290
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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 { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
14
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
15
|
+
import { SalesflareClient } from '../client/salesflare-client.js';
|
|
16
|
+
/**
|
|
17
|
+
* Deal tool definitions with JSON schemas
|
|
18
|
+
*/
|
|
19
|
+
declare const dealTools: Tool[];
|
|
20
|
+
/**
|
|
21
|
+
* Exported deal tools array for unified registration
|
|
22
|
+
*/
|
|
23
|
+
export { dealTools };
|
|
24
|
+
/**
|
|
25
|
+
* Handle deal tool calls
|
|
26
|
+
*
|
|
27
|
+
* @param client - Salesflare API client
|
|
28
|
+
* @param name - Tool name
|
|
29
|
+
* @param args - Tool arguments
|
|
30
|
+
* @returns Tool response
|
|
31
|
+
*/
|
|
32
|
+
export declare function handleDealsTool(client: SalesflareClient, name: string, args: unknown): Promise<{
|
|
33
|
+
content: Array<{
|
|
34
|
+
type: string;
|
|
35
|
+
text: string;
|
|
36
|
+
}>;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Register deal-related tools with the MCP server
|
|
40
|
+
*
|
|
41
|
+
* @deprecated Use handleDealsTool instead for unified registration
|
|
42
|
+
* @param server - MCP Server instance
|
|
43
|
+
* @param client - Salesflare API client
|
|
44
|
+
*/
|
|
45
|
+
export declare function registerDealsTools(server: Server, client: SalesflareClient): void;
|
|
46
|
+
//# sourceMappingURL=deals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deals.d.ts","sourceRoot":"","sources":["../../src/tools/deals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAGL,IAAI,EACL,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AASlE;;GAEG;AACH,QAAA,MAAM,SAAS,EAAE,IAAI,EAgGpB,CAAC;AAEF;;GAEG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,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,CAwB7D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAGjF"}
|