@talkspresso/mcp-server 1.1.0 → 1.2.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/dist/index.js +29 -1
- package/dist/tools/appointments.js +38 -0
- package/dist/tools/brew.d.ts +3 -0
- package/dist/tools/brew.js +85 -0
- package/dist/tools/calendar.d.ts +3 -0
- package/dist/tools/calendar.js +20 -0
- package/dist/tools/clients.js +16 -0
- package/dist/tools/earnings.js +25 -0
- package/dist/tools/fileLibrary.d.ts +3 -0
- package/dist/tools/fileLibrary.js +58 -0
- package/dist/tools/googleCalendar.d.ts +3 -0
- package/dist/tools/googleCalendar.js +37 -0
- package/dist/tools/live.d.ts +3 -0
- package/dist/tools/live.js +44 -0
- package/dist/tools/messaging.d.ts +3 -0
- package/dist/tools/messaging.js +52 -0
- package/dist/tools/notifications.d.ts +3 -0
- package/dist/tools/notifications.js +25 -0
- package/dist/tools/organization.d.ts +3 -0
- package/dist/tools/organization.js +68 -0
- package/dist/tools/prequalification.d.ts +3 -0
- package/dist/tools/prequalification.js +95 -0
- package/dist/tools/products.d.ts +3 -0
- package/dist/tools/products.js +86 -0
- package/dist/tools/profile.js +26 -0
- package/dist/tools/promoCodes.d.ts +3 -0
- package/dist/tools/promoCodes.js +68 -0
- package/dist/tools/recordings.d.ts +3 -0
- package/dist/tools/recordings.js +76 -0
- package/dist/tools/services.js +32 -0
- package/dist/tools/subscription.d.ts +3 -0
- package/dist/tools/subscription.js +31 -0
- package/dist/tools/testimonials.d.ts +3 -0
- package/dist/tools/testimonials.js +72 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,9 +26,23 @@ else {
|
|
|
26
26
|
const { registerServiceTools } = await import('./tools/services.js');
|
|
27
27
|
const { registerEarningsTools } = await import('./tools/earnings.js');
|
|
28
28
|
const { registerProfileTools } = await import('./tools/profile.js');
|
|
29
|
+
const { registerCalendarTools } = await import('./tools/calendar.js');
|
|
30
|
+
const { registerNotificationTools } = await import('./tools/notifications.js');
|
|
31
|
+
const { registerTestimonialTools } = await import('./tools/testimonials.js');
|
|
32
|
+
const { registerRecordingTools } = await import('./tools/recordings.js');
|
|
33
|
+
const { registerOrganizationTools } = await import('./tools/organization.js');
|
|
34
|
+
const { registerProductTools } = await import('./tools/products.js');
|
|
35
|
+
const { registerPromoCodeTools } = await import('./tools/promoCodes.js');
|
|
36
|
+
const { registerFileLibraryTools } = await import('./tools/fileLibrary.js');
|
|
37
|
+
const { registerPrequalificationTools } = await import('./tools/prequalification.js');
|
|
38
|
+
const { registerMessagingTools } = await import('./tools/messaging.js');
|
|
39
|
+
const { registerLiveTools } = await import('./tools/live.js');
|
|
40
|
+
const { registerGoogleCalendarTools } = await import('./tools/googleCalendar.js');
|
|
41
|
+
const { registerBrewTools } = await import('./tools/brew.js');
|
|
42
|
+
const { registerSubscriptionTools } = await import('./tools/subscription.js');
|
|
29
43
|
const server = new McpServer({
|
|
30
44
|
name: 'talkspresso',
|
|
31
|
-
version: '1.
|
|
45
|
+
version: '1.2.0',
|
|
32
46
|
});
|
|
33
47
|
const apiClient = new TalkspressoClient();
|
|
34
48
|
registerAppointmentTools(server, apiClient);
|
|
@@ -36,6 +50,20 @@ else {
|
|
|
36
50
|
registerServiceTools(server, apiClient);
|
|
37
51
|
registerEarningsTools(server, apiClient);
|
|
38
52
|
registerProfileTools(server, apiClient);
|
|
53
|
+
registerCalendarTools(server, apiClient);
|
|
54
|
+
registerNotificationTools(server, apiClient);
|
|
55
|
+
registerTestimonialTools(server, apiClient);
|
|
56
|
+
registerRecordingTools(server, apiClient);
|
|
57
|
+
registerOrganizationTools(server, apiClient);
|
|
58
|
+
registerProductTools(server, apiClient);
|
|
59
|
+
registerPromoCodeTools(server, apiClient);
|
|
60
|
+
registerFileLibraryTools(server, apiClient);
|
|
61
|
+
registerPrequalificationTools(server, apiClient);
|
|
62
|
+
registerMessagingTools(server, apiClient);
|
|
63
|
+
registerLiveTools(server, apiClient);
|
|
64
|
+
registerGoogleCalendarTools(server, apiClient);
|
|
65
|
+
registerBrewTools(server, apiClient);
|
|
66
|
+
registerSubscriptionTools(server, apiClient);
|
|
39
67
|
const transport = new StdioServerTransport();
|
|
40
68
|
await server.connect(transport);
|
|
41
69
|
}
|
|
@@ -92,4 +92,42 @@ export function registerAppointmentTools(server, client) {
|
|
|
92
92
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
93
93
|
};
|
|
94
94
|
});
|
|
95
|
+
server.tool('check-availability', 'Check available time slots for a specific date and service. Use this before scheduling to see when you are free.', {
|
|
96
|
+
date: z.string().describe('Date to check in YYYY-MM-DD format'),
|
|
97
|
+
service_id: z.string().optional().describe('Service ID to check availability for (determines duration). Use list-services to find this.'),
|
|
98
|
+
duration: z.number().optional().describe('Duration in minutes if no service_id (default 30)'),
|
|
99
|
+
}, async (params) => {
|
|
100
|
+
const data = await client.post('/appointments/slots', {
|
|
101
|
+
date: params.date,
|
|
102
|
+
service_id: params.service_id,
|
|
103
|
+
duration: params.duration || 30,
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
server.tool('send-test-invite', 'Send a test appointment invitation to yourself or a specific email. Great for verifying your booking flow works correctly.', {
|
|
110
|
+
email: z.string().describe('Email address to send the test invite to'),
|
|
111
|
+
name: z.string().optional().describe('Name for the test client (default "Test Client")'),
|
|
112
|
+
service_id: z.string().optional().describe('Service ID to use for the test invite. Use list-services to find this.'),
|
|
113
|
+
scheduled_date: z.string().optional().describe('Date in YYYY-MM-DD format (defaults to tomorrow)'),
|
|
114
|
+
scheduled_time: z.string().optional().describe('Time in HH:mm format, 24-hour (defaults to 10:00)'),
|
|
115
|
+
}, async (params) => {
|
|
116
|
+
// Build a test invite using the standard invite endpoint
|
|
117
|
+
const tomorrow = new Date();
|
|
118
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
119
|
+
const defaultDate = tomorrow.toISOString().split('T')[0];
|
|
120
|
+
const data = await client.post('/appointments/invite', {
|
|
121
|
+
client_name: params.name || 'Test Client',
|
|
122
|
+
client_email: params.email,
|
|
123
|
+
service_id: params.service_id,
|
|
124
|
+
scheduled_date: params.scheduled_date || defaultDate,
|
|
125
|
+
scheduled_time: params.scheduled_time || '10:00',
|
|
126
|
+
is_complimentary: true,
|
|
127
|
+
invitation_message: 'This is a test invitation to verify the booking flow.',
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
131
|
+
};
|
|
132
|
+
});
|
|
95
133
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerBrewTools(server, client) {
|
|
3
|
+
server.tool('get-brew-status', 'Check your Brew AI mentor status including Pro tier, question quota, and active conversation.', {}, async () => {
|
|
4
|
+
const data = await client.get('/guide/status');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('start-brew-conversation', 'Start a new conversation with Brew or resume your existing one. Brew is your AI business mentor.', {}, async () => {
|
|
10
|
+
const data = await client.post('/guide/start');
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
server.tool('send-brew-message', 'Send a message to Brew and get AI-powered business advice. Brew can help with pricing, services, profile optimization, and growth strategy.', {
|
|
16
|
+
conversationId: z.string().describe('The Brew conversation ID (get from start-brew-conversation)'),
|
|
17
|
+
message: z.string().describe('Your message to Brew'),
|
|
18
|
+
}, async (params) => {
|
|
19
|
+
const data = await client.post(`/guide/${params.conversationId}/message`, {
|
|
20
|
+
message: params.message,
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
server.tool('get-brew-conversation-history', 'Get the message history for a Brew conversation.', {
|
|
27
|
+
conversationId: z.string().describe('The Brew conversation ID'),
|
|
28
|
+
}, async (params) => {
|
|
29
|
+
const data = await client.get(`/guide/${params.conversationId}/history`);
|
|
30
|
+
return {
|
|
31
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
server.tool('get-brew-insights', 'Get proactive coaching insights and nudges from Brew. Shows opportunities, milestones, and reminders based on your activity.', {}, async () => {
|
|
35
|
+
const data = await client.get('/guide/insights');
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
server.tool('set-brew-goal', 'Set a business goal for Brew to help you work toward.', {
|
|
41
|
+
goal: z.string().describe('Your business goal (e.g. "Get my first 5 bookings" or "Reach $1000/month")'),
|
|
42
|
+
conversationId: z.string().optional().describe('Brew conversation ID to associate the goal with'),
|
|
43
|
+
}, async (params) => {
|
|
44
|
+
const data = await client.post('/guide/goals', params);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
server.tool('get-brew-preferences', 'Get your Brew notification preferences including intensity, channel, and sleep status.', {}, async () => {
|
|
50
|
+
const data = await client.get('/guide/preferences');
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
server.tool('update-brew-preferences', 'Update Brew notification preferences. Control how often and how Brew reaches out.', {
|
|
56
|
+
intensity: z.enum(['high', 'medium', 'low']).optional().describe('Notification intensity'),
|
|
57
|
+
channelPreference: z.enum(['email', 'in_app', 'both']).optional().describe('How to receive notifications'),
|
|
58
|
+
topicFilters: z.array(z.string()).optional().describe('Topics to filter for'),
|
|
59
|
+
}, async (params) => {
|
|
60
|
+
const data = await client.put('/guide/preferences', params);
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
server.tool('sleep-brew', 'Put Brew to sleep for a specified number of weeks. Pauses all proactive notifications.', {
|
|
66
|
+
weeks: z.number().describe('Number of weeks to sleep (1, 2, or 4)'),
|
|
67
|
+
}, async (params) => {
|
|
68
|
+
const data = await client.post('/guide/preferences/sleep', { weeks: params.weeks });
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
server.tool('wake-brew', 'Wake Brew from sleep mode and resume proactive notifications.', {}, async () => {
|
|
74
|
+
const data = await client.post('/guide/preferences/wake');
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
server.tool('get-dashboard-insight', 'Get a single focused coaching insight for your dashboard. Returns stage-appropriate advice and next action.', {}, async () => {
|
|
80
|
+
const data = await client.get('/guide/dashboard-insight');
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerCalendarTools(server, client) {
|
|
3
|
+
server.tool('get-calendar', 'Get your calendar settings including timezone, availability windows, and booking preferences. Use this to check your current availability schedule.', {}, async () => {
|
|
4
|
+
const data = await client.get('/calendar/me');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('update-calendar', 'Update your calendar settings like timezone, availability windows, booking interval, and buffer time. Use this when you want to change your availability schedule or timezone.', {
|
|
10
|
+
timezone: z.string().optional().describe('IANA timezone string (e.g., "America/New_York", "Europe/London")'),
|
|
11
|
+
availability: z.record(z.any()).optional().describe('Weekly availability object. Keys are day names (Monday-Sunday), values have is_selected, start_time, end_time.'),
|
|
12
|
+
booking_interval_days: z.number().optional().describe('How far in advance clients can book (in days)'),
|
|
13
|
+
buffer_minutes: z.number().optional().describe('Buffer time between appointments in minutes'),
|
|
14
|
+
}, async (params) => {
|
|
15
|
+
const data = await client.put('/calendar', params);
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
}
|
package/dist/tools/clients.js
CHANGED
|
@@ -18,4 +18,20 @@ export function registerClientTools(server, client) {
|
|
|
18
18
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
|
+
server.tool('get-session-history', 'Get rich session history with a specific client including session summaries, action items, and topics discussed. Use this to prep for a meeting or remember what you talked about last time.', {
|
|
22
|
+
id: z.string().describe('The client ID'),
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
const data = await client.get(`/client/${params.id}/session-history`);
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
server.tool('get-client-activity', 'Get client activity dashboard including emails sent, testimonials, pre-qualification responses, and engagement stats.', {
|
|
30
|
+
id: z.string().describe('The client ID'),
|
|
31
|
+
}, async (params) => {
|
|
32
|
+
const data = await client.get(`/client/${params.id}/activity`);
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
35
|
+
};
|
|
36
|
+
});
|
|
21
37
|
}
|
package/dist/tools/earnings.js
CHANGED
|
@@ -10,4 +10,29 @@ export function registerEarningsTools(server, client) {
|
|
|
10
10
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
11
11
|
};
|
|
12
12
|
});
|
|
13
|
+
server.tool('get-revenue-summary', 'Get a quick revenue summary: this month earnings, total bookings, new clients, and completed sessions. Use this for a "how is this month going?" check.', {}, async () => {
|
|
14
|
+
const [appointments, earnings] = await Promise.all([
|
|
15
|
+
client.get('/appointments/me', { status: 'all', limit: 200 }),
|
|
16
|
+
client.get('/transaction/my', { limit: 200 }),
|
|
17
|
+
]);
|
|
18
|
+
const now = new Date();
|
|
19
|
+
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
|
|
20
|
+
const allAppts = appointments.appointments || appointments || [];
|
|
21
|
+
const allTxns = Array.isArray(earnings) ? earnings : earnings.transactions || [];
|
|
22
|
+
const thisMonthTxns = allTxns.filter((t) => t.createdAt >= monthStart || t.created_at >= monthStart);
|
|
23
|
+
const thisMonthRevenue = thisMonthTxns
|
|
24
|
+
.filter((t) => t.transaction_type === 'payment' || t.type === 'payment')
|
|
25
|
+
.reduce((sum, t) => sum + (parseFloat(t.amount) || 0), 0);
|
|
26
|
+
const thisMonthCompleted = allAppts.filter((a) => (a.status === 'completed') && (a.start_time >= monthStart || a.createdAt >= monthStart)).length;
|
|
27
|
+
const upcomingCount = allAppts.filter((a) => a.status === 'active' || a.status === 'scheduled').length;
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
30
|
+
month: `${now.toLocaleString('default', { month: 'long' })} ${now.getFullYear()}`,
|
|
31
|
+
revenue_this_month: `$${thisMonthRevenue.toFixed(2)}`,
|
|
32
|
+
completed_sessions_this_month: thisMonthCompleted,
|
|
33
|
+
upcoming_sessions: upcomingCount,
|
|
34
|
+
total_transactions_this_month: thisMonthTxns.length,
|
|
35
|
+
}, null, 2) }],
|
|
36
|
+
};
|
|
37
|
+
});
|
|
13
38
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerFileLibraryTools(server, client) {
|
|
3
|
+
server.tool('list-files', 'Get all files in your file library. Files can be attached to products, services, or shared with clients.', {}, async () => {
|
|
4
|
+
const data = await client.get('/file-library');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('get-file', 'Get detailed information about a specific file in your library.', {
|
|
10
|
+
id: z.string().describe('The file ID'),
|
|
11
|
+
}, async (params) => {
|
|
12
|
+
const data = await client.get(`/file-library/${params.id}`);
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
server.tool('get-file-library-stats', 'Get statistics about your file library including total files, storage used, and file types.', {}, async () => {
|
|
18
|
+
const data = await client.get('/file-library/stats');
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
server.tool('get-file-library-folders', 'Get all folders in your file library for organization.', {}, async () => {
|
|
24
|
+
const data = await client.get('/file-library/folders');
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
server.tool('update-file', 'Update file metadata like name, description, or folder.', {
|
|
30
|
+
id: z.string().describe('The file ID to update'),
|
|
31
|
+
name: z.string().optional().describe('New file name'),
|
|
32
|
+
description: z.string().optional().describe('File description'),
|
|
33
|
+
folder: z.string().optional().describe('Folder to move the file into'),
|
|
34
|
+
}, async (params) => {
|
|
35
|
+
const { id, ...updateData } = params;
|
|
36
|
+
const data = await client.put(`/file-library/${id}`, updateData);
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
server.tool('delete-file', 'Delete a file from your library.', {
|
|
42
|
+
id: z.string().describe('The file ID to delete'),
|
|
43
|
+
}, async (params) => {
|
|
44
|
+
const data = await client.delete(`/file-library/${params.id}`);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
server.tool('add-file-tags', 'Add tags to a file for easier organization and search.', {
|
|
50
|
+
id: z.string().describe('The file ID'),
|
|
51
|
+
tags: z.array(z.string()).describe('Tags to add to the file'),
|
|
52
|
+
}, async (params) => {
|
|
53
|
+
const data = await client.post(`/file-library/${params.id}/tags`, { tags: params.tags });
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerGoogleCalendarTools(server, client) {
|
|
3
|
+
server.tool('get-connected-calendars', 'Get your connected Google Calendar accounts and their calendars. Shows which calendars are selected for conflict checking.', {
|
|
4
|
+
user_id: z.string().describe('Your user ID'),
|
|
5
|
+
}, async (params) => {
|
|
6
|
+
const data = await client.get(`/google-calendar/calendars/${params.user_id}`);
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
server.tool('toggle-calendar-selection', 'Select or deselect a Google Calendar for conflict checking. Selected calendars are checked when clients book.', {
|
|
12
|
+
user_id: z.string().describe('Your user ID'),
|
|
13
|
+
calendarId: z.string().describe('The Google Calendar ID to toggle'),
|
|
14
|
+
isSelected: z.boolean().describe('Whether to select (true) or deselect (false) the calendar'),
|
|
15
|
+
}, async (params) => {
|
|
16
|
+
const data = await client.put(`/google-calendar/calendars/${params.user_id}/selected`, {
|
|
17
|
+
calendarId: params.calendarId,
|
|
18
|
+
isSelected: params.isSelected,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
server.tool('check-calendar-conflicts', 'Check if a time range conflicts with your Google Calendar events. Use this before scheduling to avoid double-booking.', {
|
|
25
|
+
user_id: z.string().describe('Your user ID'),
|
|
26
|
+
startTime: z.string().describe('Start time in ISO format (e.g. 2026-02-20T10:00:00-06:00)'),
|
|
27
|
+
endTime: z.string().describe('End time in ISO format (e.g. 2026-02-20T11:00:00-06:00)'),
|
|
28
|
+
}, async (params) => {
|
|
29
|
+
const data = await client.post(`/google-calendar/check-conflicts/${params.user_id}`, {
|
|
30
|
+
startTime: params.startTime,
|
|
31
|
+
endTime: params.endTime,
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerLiveTools(server, client) {
|
|
3
|
+
server.tool('start-live-session', 'Start a new live video session (Go Live). Requires a Pro subscription. Returns a shareable link for viewers to join.', {
|
|
4
|
+
title: z.string().optional().describe('Title for the live session'),
|
|
5
|
+
}, async (params) => {
|
|
6
|
+
const data = await client.post('/live/start', { title: params.title });
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
server.tool('get-active-live-session', 'Check if you have a currently active live session. Returns session details and share URL if live.', {}, async () => {
|
|
12
|
+
const data = await client.get('/live/active');
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
server.tool('end-live-session', 'End your active live session.', {
|
|
18
|
+
slug: z.string().describe('The live session slug (short code)'),
|
|
19
|
+
}, async (params) => {
|
|
20
|
+
const data = await client.post(`/live/${params.slug}/end`);
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
server.tool('get-live-session-history', 'Get your past live session history including duration, viewer counts, and status.', {}, async () => {
|
|
26
|
+
const data = await client.get('/live/history/me');
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
server.tool('send-live-session-invite', 'Send an email invitation to someone to join your active live session.', {
|
|
32
|
+
slug: z.string().describe('The live session slug'),
|
|
33
|
+
email: z.string().describe('Email address to send the invite to'),
|
|
34
|
+
isCohost: z.boolean().optional().describe('Invite as co-host with publishing rights (default false)'),
|
|
35
|
+
}, async (params) => {
|
|
36
|
+
const data = await client.post(`/live/${params.slug}/invite`, {
|
|
37
|
+
email: params.email,
|
|
38
|
+
isCohost: params.isCohost || false,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerMessagingTools(server, client) {
|
|
3
|
+
server.tool('list-conversations', 'Get all your message conversations with clients. Returns conversations sorted by most recent message.', {}, async () => {
|
|
4
|
+
const data = await client.get('/messaging/conversations', { userType: 'provider' });
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('get-conversation-messages', 'Get messages from a specific conversation. Returns the most recent messages in chronological order.', {
|
|
10
|
+
conversation_id: z.string().describe('The conversation ID'),
|
|
11
|
+
limit: z.number().optional().describe('Number of messages to return (default 50)'),
|
|
12
|
+
}, async (params) => {
|
|
13
|
+
const queryParams = {};
|
|
14
|
+
if (params.limit)
|
|
15
|
+
queryParams.limit = String(params.limit);
|
|
16
|
+
const data = await client.get(`/messaging/conversations/${params.conversation_id}/messages`, queryParams);
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.tool('send-message', 'Send a message to a client in an existing conversation. Use list-conversations first to find the conversation ID.', {
|
|
22
|
+
conversation_id: z.string().describe('The conversation ID'),
|
|
23
|
+
message: z.string().describe('The message text to send'),
|
|
24
|
+
sender_name: z.string().describe('Your name (the provider name)'),
|
|
25
|
+
}, async (params) => {
|
|
26
|
+
const data = await client.post(`/messaging/conversations/${params.conversation_id}/messages`, {
|
|
27
|
+
senderId: 'provider',
|
|
28
|
+
senderType: 'provider',
|
|
29
|
+
senderName: params.sender_name,
|
|
30
|
+
message: params.message,
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
server.tool('get-unread-message-count', 'Get the total number of unread messages across all conversations.', {}, async () => {
|
|
37
|
+
const data = await client.get('/messaging/unread-count', { userType: 'provider' });
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
server.tool('mark-conversation-read', 'Mark all messages in a conversation as read.', {
|
|
43
|
+
conversation_id: z.string().describe('The conversation ID to mark as read'),
|
|
44
|
+
}, async (params) => {
|
|
45
|
+
const data = await client.post(`/messaging/conversations/${params.conversation_id}/read`, {
|
|
46
|
+
userType: 'provider',
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerNotificationTools(server, client) {
|
|
3
|
+
server.tool('list-notifications', 'Get all your notifications including new bookings, messages, and system alerts. Use this to check what needs your attention.', {
|
|
4
|
+
user_id: z.string().describe('Your user ID (get this from get-profile first)'),
|
|
5
|
+
}, async (params) => {
|
|
6
|
+
const data = await client.get(`/notification/${params.user_id}`);
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
server.tool('mark-notification-read', 'Mark a single notification as read.', {
|
|
12
|
+
notification_id: z.string().describe('The notification ID to mark as read'),
|
|
13
|
+
}, async (params) => {
|
|
14
|
+
const data = await client.put(`/notification/${params.notification_id}/read`);
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
server.tool('mark-all-notifications-read', 'Mark all your notifications as read. Use this to clear your notification count.', {}, async () => {
|
|
20
|
+
const data = await client.put('/notification/read-all');
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerOrganizationTools(server, client) {
|
|
3
|
+
server.tool('list-my-organizations', 'Get organizations you are an admin or member of. Use this to see your org memberships.', {}, async () => {
|
|
4
|
+
const data = await client.get('/organization/my');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('get-organization', 'Get detailed information about a specific organization by ID.', {
|
|
10
|
+
id: z.string().describe('The organization ID'),
|
|
11
|
+
}, async (params) => {
|
|
12
|
+
const data = await client.get(`/organization/${params.id}`);
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
server.tool('get-organization-members', 'Get all members of an organization. Use this to see who belongs to the org.', {
|
|
18
|
+
id: z.string().describe('The organization ID'),
|
|
19
|
+
}, async (params) => {
|
|
20
|
+
const data = await client.get(`/organization/${params.id}/members`);
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
server.tool('get-organization-stats', 'Get statistics for an organization including member count, booking count, and revenue.', {
|
|
26
|
+
id: z.string().describe('The organization ID'),
|
|
27
|
+
}, async (params) => {
|
|
28
|
+
const data = await client.get(`/organization/${params.id}/stats`);
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
server.tool('update-organization', 'Update organization settings like name, description, or branding.', {
|
|
34
|
+
id: z.string().describe('The organization ID to update'),
|
|
35
|
+
name: z.string().optional().describe('Organization name'),
|
|
36
|
+
description: z.string().optional().describe('Organization description'),
|
|
37
|
+
slug: z.string().optional().describe('URL slug for the organization page'),
|
|
38
|
+
}, async (params) => {
|
|
39
|
+
const { id, ...updateData } = params;
|
|
40
|
+
const data = await client.put(`/organization/${id}`, updateData);
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
server.tool('add-organization-member', 'Add a new member to an organization.', {
|
|
46
|
+
id: z.string().describe('The organization ID'),
|
|
47
|
+
email: z.string().describe('Email of the person to add'),
|
|
48
|
+
name: z.string().optional().describe('Name of the person'),
|
|
49
|
+
role: z.string().optional().describe('Role within the organization'),
|
|
50
|
+
}, async (params) => {
|
|
51
|
+
const { id, ...body } = params;
|
|
52
|
+
const data = await client.post(`/organization/${id}/members`, body);
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
server.tool('send-organization-invitation', 'Send an invitation email to join an organization.', {
|
|
58
|
+
id: z.string().describe('The organization ID'),
|
|
59
|
+
email: z.string().describe('Email to send the invitation to'),
|
|
60
|
+
role: z.string().optional().describe('Role for the invited person'),
|
|
61
|
+
}, async (params) => {
|
|
62
|
+
const { id, ...body } = params;
|
|
63
|
+
const data = await client.post(`/organization/${id}/invitations`, body);
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPrequalificationTools(server, client) {
|
|
3
|
+
server.tool('list-intake-questions', 'Get all your intake (prequalification) questions. These are shown to clients before booking or messaging you.', {}, async () => {
|
|
4
|
+
const data = await client.get('/prequalification/questions');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('create-intake-question', 'Create a new intake question for clients to answer before booking or messaging.', {
|
|
10
|
+
question: z.string().describe('The question text'),
|
|
11
|
+
questionType: z.enum(['text', 'textarea', 'select', 'multiselect', 'radio', 'checkbox']).optional().describe('Question type (default text)'),
|
|
12
|
+
options: z.array(z.string()).optional().describe('Answer options for select/multiselect/radio types'),
|
|
13
|
+
isRequired: z.boolean().optional().describe('Whether the question is required (default true)'),
|
|
14
|
+
placeholder: z.string().optional().describe('Placeholder text for the input'),
|
|
15
|
+
helperText: z.string().optional().describe('Helper text shown below the question'),
|
|
16
|
+
context: z.enum(['booking', 'messaging', 'both']).optional().describe('When to show: booking, messaging, or both (default both)'),
|
|
17
|
+
}, async (params) => {
|
|
18
|
+
const data = await client.post('/prequalification/questions', params);
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
server.tool('update-intake-question', 'Update an existing intake question.', {
|
|
24
|
+
id: z.string().describe('The question ID to update'),
|
|
25
|
+
question: z.string().optional().describe('Updated question text'),
|
|
26
|
+
questionType: z.enum(['text', 'textarea', 'select', 'multiselect', 'radio', 'checkbox']).optional().describe('Updated question type'),
|
|
27
|
+
options: z.array(z.string()).optional().describe('Updated answer options'),
|
|
28
|
+
isRequired: z.boolean().optional().describe('Whether the question is required'),
|
|
29
|
+
isActive: z.boolean().optional().describe('Enable or disable the question'),
|
|
30
|
+
placeholder: z.string().optional().describe('Updated placeholder text'),
|
|
31
|
+
helperText: z.string().optional().describe('Updated helper text'),
|
|
32
|
+
context: z.enum(['booking', 'messaging', 'both']).optional().describe('When to show the question'),
|
|
33
|
+
}, async (params) => {
|
|
34
|
+
const { id, ...updateData } = params;
|
|
35
|
+
const data = await client.put(`/prequalification/questions/${id}`, updateData);
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
server.tool('delete-intake-question', 'Delete an intake question.', {
|
|
41
|
+
id: z.string().describe('The question ID to delete'),
|
|
42
|
+
}, async (params) => {
|
|
43
|
+
const data = await client.delete(`/prequalification/questions/${params.id}`);
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
server.tool('reorder-intake-questions', 'Reorder your intake questions by providing the question IDs in the desired order.', {
|
|
49
|
+
questionIds: z.array(z.string()).describe('Array of question IDs in the desired order'),
|
|
50
|
+
}, async (params) => {
|
|
51
|
+
const data = await client.put('/prequalification/questions/reorder', { questionIds: params.questionIds });
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
server.tool('generate-intake-question-suggestions', 'Use AI to generate intake question suggestions based on your profile. Great for setting up intake forms quickly.', {}, async () => {
|
|
57
|
+
const data = await client.post('/prequalification/questions/ai-suggestions');
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
server.tool('generate-service-intake-questions', 'Use AI to generate intake questions tailored to a specific service or course.', {
|
|
63
|
+
serviceTitle: z.string().describe('The title of the service'),
|
|
64
|
+
serviceDescription: z.string().optional().describe('Description of the service'),
|
|
65
|
+
sessionCount: z.number().optional().describe('Number of sessions in the package'),
|
|
66
|
+
}, async (params) => {
|
|
67
|
+
const data = await client.post('/prequalification/questions/generate-for-service', params);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
server.tool('get-client-intake-responses', 'Get a specific client\'s intake question responses. Use this to review what a client shared before their session.', {
|
|
73
|
+
client_id: z.string().describe('The client ID'),
|
|
74
|
+
serviceId: z.string().optional().describe('Filter by service ID'),
|
|
75
|
+
appointmentId: z.string().optional().describe('Filter by appointment ID'),
|
|
76
|
+
}, async (params) => {
|
|
77
|
+
const queryParams = {};
|
|
78
|
+
if (params.serviceId)
|
|
79
|
+
queryParams.serviceId = params.serviceId;
|
|
80
|
+
if (params.appointmentId)
|
|
81
|
+
queryParams.appointmentId = params.appointmentId;
|
|
82
|
+
const data = await client.get(`/prequalification/responses/client/${params.client_id}`, queryParams);
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
server.tool('seed-default-intake-questions', 'Auto-generate and save default intake questions based on your profile. Useful for first-time setup.', {
|
|
88
|
+
force: z.boolean().optional().describe('Force re-seed even if questions already exist (default false)'),
|
|
89
|
+
}, async (params) => {
|
|
90
|
+
const data = await client.post('/prequalification/questions/seed-defaults', { force: params.force || false });
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerProductTools(server, client) {
|
|
3
|
+
server.tool('list-products', 'Get all your digital products (downloads, video courses, bundles). Use this to see what you have for sale.', {}, async () => {
|
|
4
|
+
const data = await client.get('/product/me');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('get-product', 'Get detailed information about a specific product including files, pricing, and sales stats.', {
|
|
10
|
+
id: z.string().describe('The product ID'),
|
|
11
|
+
}, async (params) => {
|
|
12
|
+
const data = await client.get(`/product/${params.id}`);
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
server.tool('create-product', 'Create a new digital product to sell on your profile. Supports downloads (PDFs, files), videos, and bundles.', {
|
|
18
|
+
title: z.string().describe('Product title'),
|
|
19
|
+
short_description: z.string().describe('Short description (shown in product card)'),
|
|
20
|
+
long_description: z.string().optional().describe('Full description with details'),
|
|
21
|
+
price: z.number().describe('Price in dollars (0 for free)'),
|
|
22
|
+
product_type: z.enum(['download', 'video', 'bundle']).describe('Type of product'),
|
|
23
|
+
status: z.enum(['draft', 'active']).optional().describe('Product status (default draft)'),
|
|
24
|
+
keywords: z.array(z.string()).optional().describe('Keywords for SEO and discovery'),
|
|
25
|
+
}, async (params) => {
|
|
26
|
+
const data = await client.post('/product', params);
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
server.tool('update-product', 'Update an existing product (title, price, description, status, etc.).', {
|
|
32
|
+
id: z.string().describe('The product ID to update'),
|
|
33
|
+
title: z.string().optional().describe('New title'),
|
|
34
|
+
short_description: z.string().optional().describe('New short description'),
|
|
35
|
+
long_description: z.string().optional().describe('New full description'),
|
|
36
|
+
price: z.number().optional().describe('New price in dollars'),
|
|
37
|
+
status: z.enum(['draft', 'active', 'archived']).optional().describe('Product status'),
|
|
38
|
+
keywords: z.array(z.string()).optional().describe('Updated keywords'),
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
const { id, ...updateData } = params;
|
|
41
|
+
const data = await client.put(`/product/${id}`, updateData);
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
server.tool('delete-product', 'Delete a product. This removes it from your store.', {
|
|
47
|
+
id: z.string().describe('The product ID to delete'),
|
|
48
|
+
}, async (params) => {
|
|
49
|
+
const data = await client.delete(`/product/${params.id}`);
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
server.tool('get-product-analytics', 'Get analytics for your products including views, sales, and revenue. Use this to check how your products are performing.', {}, async () => {
|
|
55
|
+
const data = await client.get('/product/analytics');
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
server.tool('list-product-purchases', 'Get all purchases across all your products. See who bought what and when.', {}, async () => {
|
|
61
|
+
const data = await client.get('/product/purchases');
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
server.tool('get-product-purchases', 'Get purchases for a specific product. See who bought it.', {
|
|
67
|
+
product_id: z.string().describe('The product ID to get purchases for'),
|
|
68
|
+
}, async (params) => {
|
|
69
|
+
const data = await client.get(`/product/${params.product_id}/purchases`);
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
server.tool('generate-product-details', 'Use AI to generate product title, description, keywords, and suggested price from a brief description. Great for quickly creating product listings.', {
|
|
75
|
+
description: z.string().describe('Brief description of what the product is about (at least 10 characters)'),
|
|
76
|
+
product_type: z.enum(['download', 'video', 'bundle']).optional().describe('Type of product (default download)'),
|
|
77
|
+
}, async (params) => {
|
|
78
|
+
const data = await client.post('/product/generate-details', {
|
|
79
|
+
description: params.description,
|
|
80
|
+
productType: params.product_type || 'download',
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
package/dist/tools/profile.js
CHANGED
|
@@ -23,4 +23,30 @@ export function registerProfileTools(server, client) {
|
|
|
23
23
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
|
+
server.tool('get-booking-link', 'Get a shareable booking link for a specific service or your general booking page. Use this when you want to send someone a link to book with you.', {
|
|
27
|
+
service_id: z.string().optional().describe('Service ID for a specific service link. If omitted, returns your general booking page.'),
|
|
28
|
+
}, async (params) => {
|
|
29
|
+
const profile = await client.get('/profile/me');
|
|
30
|
+
const handle = profile.handle || profile.website;
|
|
31
|
+
const baseUrl = 'https://app.talkspresso.com';
|
|
32
|
+
if (params.service_id) {
|
|
33
|
+
const services = await client.get('/service/me');
|
|
34
|
+
const service = (Array.isArray(services) ? services : services.services || [])
|
|
35
|
+
.find((s) => s.id === params.service_id);
|
|
36
|
+
const slug = service?.slug || params.service_id;
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
39
|
+
booking_link: `${baseUrl}/${handle}/${slug}`,
|
|
40
|
+
general_link: `${baseUrl}/${handle}`,
|
|
41
|
+
service_title: service?.title || 'Unknown service',
|
|
42
|
+
}, null, 2) }],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
47
|
+
booking_link: `${baseUrl}/${handle}`,
|
|
48
|
+
handle,
|
|
49
|
+
}, null, 2) }],
|
|
50
|
+
};
|
|
51
|
+
});
|
|
26
52
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPromoCodeTools(server, client) {
|
|
3
|
+
server.tool('list-promo-codes', 'Get all your promo codes including their status, usage count, and discount details. Use this to manage discounts and promotions.', {}, async () => {
|
|
4
|
+
const data = await client.get('/promo-code');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('get-promo-code', 'Get detailed information about a specific promo code including usage history.', {
|
|
10
|
+
id: z.string().describe('The promo code ID'),
|
|
11
|
+
}, async (params) => {
|
|
12
|
+
const data = await client.get(`/promo-code/${params.id}`);
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
server.tool('create-promo-code', 'Create a new promo code for discounts on services or products. Use this to offer promotions to clients.', {
|
|
18
|
+
code: z.string().describe('The promo code string clients will enter (e.g., "WELCOME20")'),
|
|
19
|
+
discount_type: z.enum(['percentage', 'fixed']).describe('Type of discount: percentage off or fixed dollar amount'),
|
|
20
|
+
discount_value: z.number().describe('Discount amount (e.g., 20 for 20% or $20)'),
|
|
21
|
+
max_uses: z.number().optional().describe('Maximum number of times this code can be used (unlimited if omitted)'),
|
|
22
|
+
expires_at: z.string().optional().describe('Expiration date in ISO format (no expiry if omitted)'),
|
|
23
|
+
service_ids: z.array(z.string()).optional().describe('Limit to specific service IDs (all services if omitted)'),
|
|
24
|
+
is_active: z.boolean().optional().describe('Whether the code is active (default true)'),
|
|
25
|
+
}, async (params) => {
|
|
26
|
+
const data = await client.post('/promo-code', params);
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
server.tool('update-promo-code', 'Update an existing promo code settings.', {
|
|
32
|
+
id: z.string().describe('The promo code ID to update'),
|
|
33
|
+
code: z.string().optional().describe('Updated code string'),
|
|
34
|
+
discount_type: z.enum(['percentage', 'fixed']).optional().describe('Updated discount type'),
|
|
35
|
+
discount_value: z.number().optional().describe('Updated discount amount'),
|
|
36
|
+
max_uses: z.number().optional().describe('Updated max uses'),
|
|
37
|
+
expires_at: z.string().optional().describe('Updated expiration date'),
|
|
38
|
+
is_active: z.boolean().optional().describe('Enable or disable the code'),
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
const { id, ...updateData } = params;
|
|
41
|
+
const data = await client.put(`/promo-code/${id}`, updateData);
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
server.tool('delete-promo-code', 'Permanently delete a promo code.', {
|
|
47
|
+
id: z.string().describe('The promo code ID to delete'),
|
|
48
|
+
}, async (params) => {
|
|
49
|
+
const data = await client.delete(`/promo-code/${params.id}`);
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
server.tool('toggle-promo-code-active', 'Toggle a promo code between active and inactive without deleting it.', {
|
|
55
|
+
id: z.string().describe('The promo code ID to toggle'),
|
|
56
|
+
}, async (params) => {
|
|
57
|
+
const data = await client.post(`/promo-code/${params.id}/toggle-active`);
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
server.tool('get-promo-code-analytics', 'Get analytics for all your promo codes including total usage, revenue impact, and top-performing codes.', {}, async () => {
|
|
63
|
+
const data = await client.get('/promo-code/analytics');
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerRecordingTools(server, client) {
|
|
3
|
+
server.tool('list-recordings', 'Get all your session recordings. Returns the recording library with titles, durations, transcription status, and more. Use this to browse past session recordings.', {
|
|
4
|
+
page: z.number().optional().describe('Page number (default 1)'),
|
|
5
|
+
limit: z.number().optional().describe('Results per page (default 20)'),
|
|
6
|
+
visibility: z.enum(['all', 'private', 'unlisted', 'public']).optional().describe('Filter by visibility (default all)'),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
const data = await client.get('/recordings', params);
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
server.tool('get-recording', 'Get detailed information about a specific recording including transcription, summary, key takeaways, and action items. Use this to review what happened in a past session.', {
|
|
14
|
+
id: z.string().describe('The recording ID'),
|
|
15
|
+
}, async (params) => {
|
|
16
|
+
const data = await client.get(`/recordings/${params.id}`);
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.tool('update-recording', 'Update a recording title, description, or visibility setting.', {
|
|
22
|
+
id: z.string().describe('The recording ID to update'),
|
|
23
|
+
title: z.string().optional().describe('New title for the recording'),
|
|
24
|
+
description: z.string().optional().describe('New description'),
|
|
25
|
+
visibility: z.enum(['private', 'unlisted', 'public']).optional().describe('Visibility: private (only you), unlisted (link only), public (anyone)'),
|
|
26
|
+
}, async (params) => {
|
|
27
|
+
const { id, ...updateData } = params;
|
|
28
|
+
const data = await client.put(`/recordings/${id}`, updateData);
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
server.tool('delete-recording', 'Permanently delete a recording. This cannot be undone.', {
|
|
34
|
+
id: z.string().describe('The recording ID to delete'),
|
|
35
|
+
}, async (params) => {
|
|
36
|
+
const data = await client.delete(`/recordings/${params.id}`);
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
server.tool('get-client-recordings', 'Get all recordings from sessions with a specific client. Use this to review session history with a particular client.', {
|
|
42
|
+
client_id: z.string().describe('The client ID to get recordings for'),
|
|
43
|
+
}, async (params) => {
|
|
44
|
+
const data = await client.get(`/recordings/client/${params.client_id}`);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
server.tool('get-recording-files', 'Get individual participant recording files for a session (for editing workflows like Descript). Returns signed download URLs.', {
|
|
50
|
+
id: z.string().describe('The recording ID'),
|
|
51
|
+
}, async (params) => {
|
|
52
|
+
const data = await client.get(`/recordings/${params.id}/files`);
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
server.tool('create-product-from-recording', 'Turn a session recording into a sellable digital product. Automatically generates title, description, and keywords from the recording summary.', {
|
|
58
|
+
id: z.string().describe('The recording ID to create a product from'),
|
|
59
|
+
title: z.string().optional().describe('Product title (auto-generated from recording if omitted)'),
|
|
60
|
+
description: z.string().optional().describe('Product description (auto-generated from summary if omitted)'),
|
|
61
|
+
price: z.number().describe('Price in dollars (e.g., 29 for $29)'),
|
|
62
|
+
status: z.enum(['draft', 'active']).optional().describe('Product status (default draft)'),
|
|
63
|
+
}, async (params) => {
|
|
64
|
+
const { id, ...body } = params;
|
|
65
|
+
const data = await client.post(`/recordings/${id}/create-product`, body);
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
server.tool('retry-recording-transcription', 'Retry transcription and AI summary for recordings that failed or are stuck. Use this if a recording shows "failed" or "pending" transcription status.', {}, async () => {
|
|
71
|
+
const data = await client.post('/recordings/admin/retry-transcriptions');
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
package/dist/tools/services.js
CHANGED
|
@@ -18,6 +18,14 @@ export function registerServiceTools(server, client) {
|
|
|
18
18
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
|
+
server.tool('get-service', 'Get detailed information about a specific service including pricing, duration, and logistics.', {
|
|
22
|
+
id: z.string().describe('The service ID'),
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
const data = await client.get(`/service/${params.id}`);
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
21
29
|
server.tool('update-service', 'Update an existing service', {
|
|
22
30
|
id: z.string().describe('Service ID to update'),
|
|
23
31
|
title: z.string().optional().describe('New title'),
|
|
@@ -32,4 +40,28 @@ export function registerServiceTools(server, client) {
|
|
|
32
40
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
33
41
|
};
|
|
34
42
|
});
|
|
43
|
+
server.tool('delete-service', 'Delete a service from your profile. This cannot be undone.', {
|
|
44
|
+
id: z.string().describe('The service ID to delete'),
|
|
45
|
+
}, async (params) => {
|
|
46
|
+
const data = await client.delete(`/service/${params.id}`);
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
server.tool('duplicate-service', 'Create a copy of an existing service. Useful for creating variations of popular services.', {
|
|
52
|
+
id: z.string().describe('The service ID to duplicate'),
|
|
53
|
+
}, async (params) => {
|
|
54
|
+
const data = await client.post(`/service/${params.id}/duplicate`);
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
server.tool('get-service-bookings', 'Get all bookings for a specific service. See who has booked and upcoming sessions.', {
|
|
60
|
+
id: z.string().describe('The service ID'),
|
|
61
|
+
}, async (params) => {
|
|
62
|
+
const data = await client.get(`/service/${params.id}/bookings`);
|
|
63
|
+
return {
|
|
64
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
65
|
+
};
|
|
66
|
+
});
|
|
35
67
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerSubscriptionTools(server, client) {
|
|
3
|
+
server.tool('get-my-subscription', 'Get your current subscription plan details including plan name, status, billing period, and features.', {}, async () => {
|
|
4
|
+
const data = await client.get('/subscription/me');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('get-payment-methods', 'Get your saved payment methods on file.', {}, async () => {
|
|
10
|
+
const data = await client.get('/subscription/payment-methods');
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
server.tool('get-stripe-account-link', 'Get a Stripe Connect onboarding or account link. Use this to set up or manage your payment receiving account.', {}, async () => {
|
|
16
|
+
const data = await client.get('/subscription/create-account-link');
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
server.tool('create-billing-portal-session', 'Open the Stripe billing portal to manage your subscription, update payment method, or view invoices.', {
|
|
22
|
+
return_url: z.string().optional().describe('URL to redirect back to after the portal session'),
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
const data = await client.post('/subscription/billing-portal', {
|
|
25
|
+
return_url: params.return_url,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerTestimonialTools(server, client) {
|
|
3
|
+
server.tool('list-testimonials', 'Get all your testimonials from clients. Use this when someone asks about reviews, social proof, or client feedback.', {}, async () => {
|
|
4
|
+
const data = await client.get('/testimonial');
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
server.tool('create-testimonial', 'Manually add a testimonial from a client. Use this when you have offline feedback you want to add to your profile.', {
|
|
10
|
+
author_name: z.string().describe('Name of the person giving the testimonial'),
|
|
11
|
+
author_title: z.string().optional().describe('Title or role of the person (e.g., "CEO at Acme")'),
|
|
12
|
+
content: z.string().describe('The testimonial text'),
|
|
13
|
+
rating: z.number().optional().describe('Rating from 1-5 (default 5)'),
|
|
14
|
+
}, async (params) => {
|
|
15
|
+
const data = await client.post('/testimonial', params);
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
server.tool('request-testimonial', 'Send a testimonial request email to a client. They will receive a link to submit their testimonial. Use this after completing a successful session.', {
|
|
21
|
+
client_id: z.string().describe('The client ID to request a testimonial from. Use list-clients to find this.'),
|
|
22
|
+
appointment_id: z.string().optional().describe('Optional appointment ID to reference a specific session'),
|
|
23
|
+
}, async (params) => {
|
|
24
|
+
const data = await client.post('/testimonial/request', params);
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
server.tool('approve-testimonial', 'Approve a pending testimonial submitted by a client so it appears on your profile.', {
|
|
30
|
+
id: z.string().describe('The testimonial ID to approve'),
|
|
31
|
+
}, async (params) => {
|
|
32
|
+
const data = await client.post(`/testimonial/${params.id}/approve`);
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
server.tool('reject-testimonial', 'Reject a pending testimonial so it does not appear on your profile.', {
|
|
38
|
+
id: z.string().describe('The testimonial ID to reject'),
|
|
39
|
+
}, async (params) => {
|
|
40
|
+
const data = await client.post(`/testimonial/${params.id}/reject`);
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
server.tool('toggle-featured-testimonial', 'Toggle whether a testimonial is featured (highlighted) on your profile.', {
|
|
46
|
+
id: z.string().describe('The testimonial ID to toggle featured status'),
|
|
47
|
+
}, async (params) => {
|
|
48
|
+
const data = await client.post(`/testimonial/${params.id}/toggle-featured`);
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
server.tool('update-testimonial', 'Update an existing testimonial (edit text, visibility, etc.).', {
|
|
54
|
+
id: z.string().describe('The testimonial ID to update'),
|
|
55
|
+
content: z.string().optional().describe('Updated testimonial text'),
|
|
56
|
+
is_visible: z.boolean().optional().describe('Whether the testimonial is visible on your profile'),
|
|
57
|
+
}, async (params) => {
|
|
58
|
+
const { id, ...updateData } = params;
|
|
59
|
+
const data = await client.put(`/testimonial/${id}`, updateData);
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
server.tool('delete-testimonial', 'Permanently delete a testimonial.', {
|
|
65
|
+
id: z.string().describe('The testimonial ID to delete'),
|
|
66
|
+
}, async (params) => {
|
|
67
|
+
const data = await client.delete(`/testimonial/${params.id}`);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
}
|