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.
Files changed (73) hide show
  1. package/API.md +691 -0
  2. package/CHANGELOG.md +49 -0
  3. package/CLAUDE.md +117 -0
  4. package/CONTRIBUTING.md +399 -0
  5. package/FIX_PLAN.md +70 -0
  6. package/INSPECTOR.md +191 -0
  7. package/LICENSE +21 -0
  8. package/PUBLISH.md +73 -0
  9. package/README.md +383 -0
  10. package/dist/auth/api-key-auth.d.ts +75 -0
  11. package/dist/auth/api-key-auth.d.ts.map +1 -0
  12. package/dist/auth/api-key-auth.js +103 -0
  13. package/dist/auth/oauth-auth.d.ts +81 -0
  14. package/dist/auth/oauth-auth.d.ts.map +1 -0
  15. package/dist/auth/oauth-auth.js +123 -0
  16. package/dist/auth/token-manager.d.ts +105 -0
  17. package/dist/auth/token-manager.d.ts.map +1 -0
  18. package/dist/auth/token-manager.js +87 -0
  19. package/dist/client/salesflare-client.d.ts +219 -0
  20. package/dist/client/salesflare-client.d.ts.map +1 -0
  21. package/dist/client/salesflare-client.js +484 -0
  22. package/dist/index.d.ts +15 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +82 -0
  25. package/dist/server.d.ts +39 -0
  26. package/dist/server.d.ts.map +1 -0
  27. package/dist/server.js +140 -0
  28. package/dist/tools/companies.d.ts +45 -0
  29. package/dist/tools/companies.d.ts.map +1 -0
  30. package/dist/tools/companies.js +392 -0
  31. package/dist/tools/contacts.d.ts +45 -0
  32. package/dist/tools/contacts.d.ts.map +1 -0
  33. package/dist/tools/contacts.js +290 -0
  34. package/dist/tools/deals.d.ts +46 -0
  35. package/dist/tools/deals.d.ts.map +1 -0
  36. package/dist/tools/deals.js +442 -0
  37. package/dist/tools/pipeline.d.ts +43 -0
  38. package/dist/tools/pipeline.d.ts.map +1 -0
  39. package/dist/tools/pipeline.js +328 -0
  40. package/dist/tools/tasks.d.ts +44 -0
  41. package/dist/tools/tasks.d.ts.map +1 -0
  42. package/dist/tools/tasks.js +406 -0
  43. package/dist/transport/http-transport.d.ts +36 -0
  44. package/dist/transport/http-transport.d.ts.map +1 -0
  45. package/dist/transport/http-transport.js +173 -0
  46. package/dist/transport/stdio-transport.d.ts +37 -0
  47. package/dist/transport/stdio-transport.d.ts.map +1 -0
  48. package/dist/transport/stdio-transport.js +129 -0
  49. package/dist/types/company.d.ts +223 -0
  50. package/dist/types/company.d.ts.map +1 -0
  51. package/dist/types/company.js +8 -0
  52. package/dist/types/contact.d.ts +166 -0
  53. package/dist/types/contact.d.ts.map +1 -0
  54. package/dist/types/contact.js +8 -0
  55. package/dist/types/deal.d.ts +203 -0
  56. package/dist/types/deal.d.ts.map +1 -0
  57. package/dist/types/deal.js +8 -0
  58. package/dist/types/pipeline.d.ts +116 -0
  59. package/dist/types/pipeline.d.ts.map +1 -0
  60. package/dist/types/pipeline.js +8 -0
  61. package/dist/types/task.d.ts +154 -0
  62. package/dist/types/task.d.ts.map +1 -0
  63. package/dist/types/task.js +8 -0
  64. package/dist/utils/errors.d.ts +128 -0
  65. package/dist/utils/errors.d.ts.map +1 -0
  66. package/dist/utils/errors.js +205 -0
  67. package/dist/utils/validation.d.ts +354 -0
  68. package/dist/utils/validation.d.ts.map +1 -0
  69. package/dist/utils/validation.js +716 -0
  70. package/package.json +49 -0
  71. package/test-tasks-debug.js +21 -0
  72. package/test-tasks-params.js +52 -0
  73. 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"}