@talkspresso/mcp-server 1.2.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 +2 -2
- package/dist/tools/appointments.js +39 -4
- package/dist/tools/earnings.js +2 -2
- 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 {
|
|
@@ -42,7 +42,7 @@ else {
|
|
|
42
42
|
const { registerSubscriptionTools } = await import('./tools/subscription.js');
|
|
43
43
|
const server = new McpServer({
|
|
44
44
|
name: 'talkspresso',
|
|
45
|
-
version: '1.
|
|
45
|
+
version: '1.3.0',
|
|
46
46
|
});
|
|
47
47
|
const apiClient = new TalkspressoClient();
|
|
48
48
|
registerAppointmentTools(server, apiClient);
|
|
@@ -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) }],
|
|
@@ -97,10 +130,12 @@ export function registerAppointmentTools(server, client) {
|
|
|
97
130
|
service_id: z.string().optional().describe('Service ID to check availability for (determines duration). Use list-services to find this.'),
|
|
98
131
|
duration: z.number().optional().describe('Duration in minutes if no service_id (default 30)'),
|
|
99
132
|
}, async (params) => {
|
|
133
|
+
const providerId = await client.getProviderId();
|
|
100
134
|
const data = await client.post('/appointments/slots', {
|
|
101
135
|
date: params.date,
|
|
102
136
|
service_id: params.service_id,
|
|
103
|
-
|
|
137
|
+
interval: params.duration || 30,
|
|
138
|
+
provider_id: providerId,
|
|
104
139
|
});
|
|
105
140
|
return {
|
|
106
141
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
package/dist/tools/earnings.js
CHANGED
|
@@ -12,8 +12,8 @@ export function registerEarningsTools(server, client) {
|
|
|
12
12
|
});
|
|
13
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
14
|
const [appointments, earnings] = await Promise.all([
|
|
15
|
-
client.get('/appointments/me', { status: 'all', limit:
|
|
16
|
-
client.get('/transaction/my', { limit:
|
|
15
|
+
client.get('/appointments/me', { status: 'all', limit: 100 }),
|
|
16
|
+
client.get('/transaction/my', { limit: 100 }),
|
|
17
17
|
]);
|
|
18
18
|
const now = new Date();
|
|
19
19
|
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
|