@talkspresso/mcp-server 1.1.0 → 1.3.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/client.d.ts +2 -0
- package/dist/client.js +8 -0
- package/dist/index.js +30 -2
- package/dist/tools/appointments.js +76 -3
- 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/client.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export declare class TalkspressoClient {
|
|
2
2
|
private http;
|
|
3
|
+
private _providerId;
|
|
3
4
|
constructor();
|
|
4
5
|
get<T = any>(path: string, params?: Record<string, any>): Promise<T>;
|
|
5
6
|
post<T = any>(path: string, data?: any): Promise<T>;
|
|
6
7
|
put<T = any>(path: string, data?: any): Promise<T>;
|
|
7
8
|
delete<T = any>(path: string): Promise<T>;
|
|
9
|
+
getProviderId(): Promise<string>;
|
|
8
10
|
private formatError;
|
|
9
11
|
}
|
package/dist/client.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
export class TalkspressoClient {
|
|
3
3
|
http;
|
|
4
|
+
_providerId = null;
|
|
4
5
|
constructor() {
|
|
5
6
|
const apiKey = process.env.TALKSPRESSO_API_KEY;
|
|
6
7
|
if (!apiKey) {
|
|
@@ -52,6 +53,13 @@ export class TalkspressoClient {
|
|
|
52
53
|
throw this.formatError(err);
|
|
53
54
|
}
|
|
54
55
|
}
|
|
56
|
+
async getProviderId() {
|
|
57
|
+
if (this._providerId)
|
|
58
|
+
return this._providerId;
|
|
59
|
+
const profile = await this.get('/profile');
|
|
60
|
+
this._providerId = profile.id || profile.user_id;
|
|
61
|
+
return this._providerId;
|
|
62
|
+
}
|
|
55
63
|
formatError(err) {
|
|
56
64
|
const data = err.response?.data;
|
|
57
65
|
const status = err.response?.status;
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ else if (args.includes('--help')) {
|
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
16
16
|
else if (args.includes('--version')) {
|
|
17
|
-
console.log('1.
|
|
17
|
+
console.log('1.3.0');
|
|
18
18
|
process.exit(0);
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
@@ -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.3.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
|
}
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
function trimAppointment(apt) {
|
|
3
|
+
return {
|
|
4
|
+
id: apt.id,
|
|
5
|
+
status: apt.status,
|
|
6
|
+
start_time: apt.start_time,
|
|
7
|
+
end_time: apt.end_time,
|
|
8
|
+
duration: apt.duration,
|
|
9
|
+
client_name: apt.client?.name || apt.client_name,
|
|
10
|
+
client_email: apt.client?.email || apt.client_email,
|
|
11
|
+
service_title: apt.service?.title || apt.service_title,
|
|
12
|
+
service_price: apt.service?.price,
|
|
13
|
+
is_complimentary: apt.is_complimentary,
|
|
14
|
+
invitation_sent: apt.invitation_sent,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
2
17
|
export function registerAppointmentTools(server, client) {
|
|
3
18
|
server.tool('list-appointments', 'Get your appointments with optional filters. Returns upcoming appointments by default.', {
|
|
4
19
|
status: z.enum(['upcoming', 'completed', 'all']).optional().describe('Filter by appointment status (default: upcoming)'),
|
|
@@ -6,8 +21,11 @@ export function registerAppointmentTools(server, client) {
|
|
|
6
21
|
limit: z.number().optional().describe('Number of results per page'),
|
|
7
22
|
}, async (params) => {
|
|
8
23
|
const data = await client.get('/appointments/me', params);
|
|
24
|
+
// Trim response to essential fields to avoid exceeding token limits
|
|
25
|
+
const appointments = Array.isArray(data) ? data : data?.appointments || data?.rows || [];
|
|
26
|
+
const trimmed = appointments.map(trimAppointment);
|
|
9
27
|
return {
|
|
10
|
-
content: [{ type: 'text', text: JSON.stringify(
|
|
28
|
+
content: [{ type: 'text', text: JSON.stringify(trimmed, null, 2) }],
|
|
11
29
|
};
|
|
12
30
|
});
|
|
13
31
|
server.tool('get-appointment', 'Get detailed information about a specific appointment', {
|
|
@@ -43,7 +61,7 @@ export function registerAppointmentTools(server, client) {
|
|
|
43
61
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
44
62
|
};
|
|
45
63
|
});
|
|
46
|
-
server.tool('create-appointment', 'Create an appointment
|
|
64
|
+
server.tool('create-appointment', 'Create an appointment WITHOUT sending the invitation email. Returns appointment details for review. After reviewing, use send-appointment-invite to send the email to the client.', {
|
|
47
65
|
client_name: z.string().describe('Client full name'),
|
|
48
66
|
client_email: z.string().optional().describe('Client email address (invitation sent here)'),
|
|
49
67
|
scheduled_date: z.string().describe('Date in YYYY-MM-DD format'),
|
|
@@ -53,7 +71,7 @@ export function registerAppointmentTools(server, client) {
|
|
|
53
71
|
custom_title: z.string().optional().describe('Custom session title (overrides service title)'),
|
|
54
72
|
custom_price: z.number().optional().describe('Price in dollars (required if no service_id and not complimentary)'),
|
|
55
73
|
is_complimentary: z.boolean().optional().describe('If true, session is free (default: true)'),
|
|
56
|
-
invitation_message: z.string().optional().describe('Personal message
|
|
74
|
+
invitation_message: z.string().optional().describe('Personal message to include when the invitation is sent'),
|
|
57
75
|
}, async (params) => {
|
|
58
76
|
const data = await client.post('/appointments/invite', {
|
|
59
77
|
client_name: params.client_name,
|
|
@@ -66,6 +84,21 @@ export function registerAppointmentTools(server, client) {
|
|
|
66
84
|
custom_price: params.custom_price,
|
|
67
85
|
is_complimentary: params.is_complimentary ?? true,
|
|
68
86
|
invitation_message: params.invitation_message,
|
|
87
|
+
skip_email: true,
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
content: [{ type: 'text', text: JSON.stringify({
|
|
91
|
+
...data,
|
|
92
|
+
_note: 'Appointment created. Email NOT sent yet. Use send-appointment-invite to send the invitation email after reviewing.',
|
|
93
|
+
}, null, 2) }],
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
server.tool('send-appointment-invite', 'Send the invitation email for an existing appointment. Use this after create-appointment to send the invite once the provider has reviewed the details.', {
|
|
97
|
+
id: z.string().describe('The appointment ID to send the invitation for'),
|
|
98
|
+
invitation_message: z.string().optional().describe('Personal message to include in the invitation email (overrides the one from create-appointment)'),
|
|
99
|
+
}, async (params) => {
|
|
100
|
+
const data = await client.post(`/appointments/${params.id}/resend-invite`, {
|
|
101
|
+
invitation_message: params.invitation_message,
|
|
69
102
|
});
|
|
70
103
|
return {
|
|
71
104
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
@@ -92,4 +125,44 @@ export function registerAppointmentTools(server, client) {
|
|
|
92
125
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
93
126
|
};
|
|
94
127
|
});
|
|
128
|
+
server.tool('check-availability', 'Check available time slots for a specific date and service. Use this before scheduling to see when you are free.', {
|
|
129
|
+
date: z.string().describe('Date to check in YYYY-MM-DD format'),
|
|
130
|
+
service_id: z.string().optional().describe('Service ID to check availability for (determines duration). Use list-services to find this.'),
|
|
131
|
+
duration: z.number().optional().describe('Duration in minutes if no service_id (default 30)'),
|
|
132
|
+
}, async (params) => {
|
|
133
|
+
const providerId = await client.getProviderId();
|
|
134
|
+
const data = await client.post('/appointments/slots', {
|
|
135
|
+
date: params.date,
|
|
136
|
+
service_id: params.service_id,
|
|
137
|
+
interval: params.duration || 30,
|
|
138
|
+
provider_id: providerId,
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
server.tool('send-test-invite', 'Send a test appointment invitation to yourself or a specific email. Great for verifying your booking flow works correctly.', {
|
|
145
|
+
email: z.string().describe('Email address to send the test invite to'),
|
|
146
|
+
name: z.string().optional().describe('Name for the test client (default "Test Client")'),
|
|
147
|
+
service_id: z.string().optional().describe('Service ID to use for the test invite. Use list-services to find this.'),
|
|
148
|
+
scheduled_date: z.string().optional().describe('Date in YYYY-MM-DD format (defaults to tomorrow)'),
|
|
149
|
+
scheduled_time: z.string().optional().describe('Time in HH:mm format, 24-hour (defaults to 10:00)'),
|
|
150
|
+
}, async (params) => {
|
|
151
|
+
// Build a test invite using the standard invite endpoint
|
|
152
|
+
const tomorrow = new Date();
|
|
153
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
154
|
+
const defaultDate = tomorrow.toISOString().split('T')[0];
|
|
155
|
+
const data = await client.post('/appointments/invite', {
|
|
156
|
+
client_name: params.name || 'Test Client',
|
|
157
|
+
client_email: params.email,
|
|
158
|
+
service_id: params.service_id,
|
|
159
|
+
scheduled_date: params.scheduled_date || defaultDate,
|
|
160
|
+
scheduled_time: params.scheduled_time || '10:00',
|
|
161
|
+
is_complimentary: true,
|
|
162
|
+
invitation_message: 'This is a test invitation to verify the booking flow.',
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
166
|
+
};
|
|
167
|
+
});
|
|
95
168
|
}
|
|
@@ -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: 100 }),
|
|
16
|
+
client.get('/transaction/my', { limit: 100 }),
|
|
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
|
+
}
|