@talkspresso/mcp-server 1.3.0 → 1.3.2

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 CHANGED
@@ -1,3 +1,9 @@
1
+ export declare function formatMcpResponse(data: any): {
2
+ content: Array<{
3
+ type: 'text';
4
+ text: string;
5
+ }>;
6
+ };
1
7
  export declare class TalkspressoClient {
2
8
  private http;
3
9
  private _providerId;
package/dist/client.js CHANGED
@@ -1,4 +1,36 @@
1
1
  import axios from 'axios';
2
+ const MAX_RESPONSE_CHARS = 50000;
3
+ export function formatMcpResponse(data) {
4
+ const json = JSON.stringify(data, null, 2);
5
+ if (json.length <= MAX_RESPONSE_CHARS) {
6
+ return { content: [{ type: 'text', text: json }] };
7
+ }
8
+ // Response too large -- if it's an array, trim items and note how many were cut
9
+ if (Array.isArray(data)) {
10
+ let trimmed = [...data];
11
+ let result = JSON.stringify(trimmed, null, 2);
12
+ while (result.length > MAX_RESPONSE_CHARS && trimmed.length > 1) {
13
+ trimmed = trimmed.slice(0, Math.ceil(trimmed.length * 0.7));
14
+ result = JSON.stringify(trimmed, null, 2);
15
+ }
16
+ const note = `\n\n--- Showing ${trimmed.length} of ${data.length} results. Use pagination (page/limit) to see more. ---`;
17
+ return { content: [{ type: 'text', text: result + note }] };
18
+ }
19
+ // Object with an array property (e.g. { appointments: [...], totalCount: 50 })
20
+ for (const key of Object.keys(data)) {
21
+ if (Array.isArray(data[key]) && data[key].length > 5) {
22
+ const truncated = { ...data, [key]: data[key].slice(0, 20) };
23
+ const result = JSON.stringify(truncated, null, 2);
24
+ if (result.length <= MAX_RESPONSE_CHARS) {
25
+ const note = `\n\n--- Showing 20 of ${data[key].length} ${key}. Use pagination to see more. ---`;
26
+ return { content: [{ type: 'text', text: result + note }] };
27
+ }
28
+ }
29
+ }
30
+ // Last resort: hard truncate
31
+ const truncated = json.slice(0, MAX_RESPONSE_CHARS);
32
+ return { content: [{ type: 'text', text: truncated + '\n\n--- Response truncated (exceeded size limit). Try a more specific query. ---' }] };
33
+ }
2
34
  export class TalkspressoClient {
3
35
  http;
4
36
  _providerId = null;
@@ -56,7 +88,7 @@ export class TalkspressoClient {
56
88
  async getProviderId() {
57
89
  if (this._providerId)
58
90
  return this._providerId;
59
- const profile = await this.get('/profile');
91
+ const profile = await this.get('/profile/me');
60
92
  this._providerId = profile.id || profile.user_id;
61
93
  return this._providerId;
62
94
  }
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.3.0');
17
+ console.log('1.3.2');
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.3.0',
45
+ version: '1.3.2',
46
46
  });
47
47
  const apiClient = new TalkspressoClient();
48
48
  registerAppointmentTools(server, apiClient);
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  function trimAppointment(apt) {
3
4
  return {
4
5
  id: apt.id,
@@ -24,31 +25,23 @@ export function registerAppointmentTools(server, client) {
24
25
  // Trim response to essential fields to avoid exceeding token limits
25
26
  const appointments = Array.isArray(data) ? data : data?.appointments || data?.rows || [];
26
27
  const trimmed = appointments.map(trimAppointment);
27
- return {
28
- content: [{ type: 'text', text: JSON.stringify(trimmed, null, 2) }],
29
- };
28
+ return formatMcpResponse(trimmed);
30
29
  });
31
30
  server.tool('get-appointment', 'Get detailed information about a specific appointment', {
32
31
  id: z.string().describe('The appointment ID'),
33
32
  }, async (params) => {
34
33
  const data = await client.get(`/appointments/${params.id}`);
35
- return {
36
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
37
- };
34
+ return formatMcpResponse(data);
38
35
  });
39
36
  server.tool('get-pending-bookings', 'Get all pending bookings that need your approval', {}, async () => {
40
37
  const data = await client.get('/appointments/pending');
41
- return {
42
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
43
- };
38
+ return formatMcpResponse(data);
44
39
  });
45
40
  server.tool('approve-appointment', 'Approve a pending booking request', {
46
41
  id: z.string().describe('The appointment ID to approve'),
47
42
  }, async (params) => {
48
43
  const data = await client.post(`/appointments/${params.id}/approve`);
49
- return {
50
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
51
- };
44
+ return formatMcpResponse(data);
52
45
  });
53
46
  server.tool('decline-appointment', 'Decline a pending booking request', {
54
47
  id: z.string().describe('The appointment ID to decline'),
@@ -57,9 +50,7 @@ export function registerAppointmentTools(server, client) {
57
50
  const data = await client.post(`/appointments/${params.id}/decline`, {
58
51
  decline_reason: params.decline_reason,
59
52
  });
60
- return {
61
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
62
- };
53
+ return formatMcpResponse(data);
63
54
  });
64
55
  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.', {
65
56
  client_name: z.string().describe('Client full name'),
@@ -86,12 +77,10 @@ export function registerAppointmentTools(server, client) {
86
77
  invitation_message: params.invitation_message,
87
78
  skip_email: true,
88
79
  });
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
- };
80
+ return formatMcpResponse({
81
+ ...data,
82
+ _note: 'Appointment created. Email NOT sent yet. Use send-appointment-invite to send the invitation email after reviewing.',
83
+ });
95
84
  });
96
85
  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
86
  id: z.string().describe('The appointment ID to send the invitation for'),
@@ -100,17 +89,13 @@ export function registerAppointmentTools(server, client) {
100
89
  const data = await client.post(`/appointments/${params.id}/resend-invite`, {
101
90
  invitation_message: params.invitation_message,
102
91
  });
103
- return {
104
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
105
- };
92
+ return formatMcpResponse(data);
106
93
  });
107
94
  server.tool('cancel-appointment', 'Cancel an appointment', {
108
95
  id: z.string().describe('The appointment ID to cancel'),
109
96
  }, async (params) => {
110
97
  const data = await client.post(`/appointments/${params.id}/cancel`);
111
- return {
112
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
113
- };
98
+ return formatMcpResponse(data);
114
99
  });
115
100
  server.tool('reschedule-appointment', 'Reschedule an appointment to a new date and time', {
116
101
  id: z.string().describe('The appointment ID to reschedule'),
@@ -121,9 +106,7 @@ export function registerAppointmentTools(server, client) {
121
106
  start_time: params.start_time,
122
107
  end_time: params.end_time,
123
108
  });
124
- return {
125
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
126
- };
109
+ return formatMcpResponse(data);
127
110
  });
128
111
  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
112
  date: z.string().describe('Date to check in YYYY-MM-DD format'),
@@ -137,9 +120,7 @@ export function registerAppointmentTools(server, client) {
137
120
  interval: params.duration || 30,
138
121
  provider_id: providerId,
139
122
  });
140
- return {
141
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
142
- };
123
+ return formatMcpResponse(data);
143
124
  });
144
125
  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
126
  email: z.string().describe('Email address to send the test invite to'),
@@ -161,8 +142,6 @@ export function registerAppointmentTools(server, client) {
161
142
  is_complimentary: true,
162
143
  invitation_message: 'This is a test invitation to verify the booking flow.',
163
144
  });
164
- return {
165
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
166
- };
145
+ return formatMcpResponse(data);
167
146
  });
168
147
  }
@@ -1,16 +1,13 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerBrewTools(server, client) {
3
4
  server.tool('get-brew-status', 'Check your Brew AI mentor status including Pro tier, question quota, and active conversation.', {}, async () => {
4
5
  const data = await client.get('/guide/status');
5
- return {
6
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
7
- };
6
+ return formatMcpResponse(data);
8
7
  });
9
8
  server.tool('start-brew-conversation', 'Start a new conversation with Brew or resume your existing one. Brew is your AI business mentor.', {}, async () => {
10
9
  const data = await client.post('/guide/start');
11
- return {
12
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
13
- };
10
+ return formatMcpResponse(data);
14
11
  });
15
12
  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
13
  conversationId: z.string().describe('The Brew conversation ID (get from start-brew-conversation)'),
@@ -19,38 +16,28 @@ export function registerBrewTools(server, client) {
19
16
  const data = await client.post(`/guide/${params.conversationId}/message`, {
20
17
  message: params.message,
21
18
  });
22
- return {
23
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
24
- };
19
+ return formatMcpResponse(data);
25
20
  });
26
21
  server.tool('get-brew-conversation-history', 'Get the message history for a Brew conversation.', {
27
22
  conversationId: z.string().describe('The Brew conversation ID'),
28
23
  }, async (params) => {
29
24
  const data = await client.get(`/guide/${params.conversationId}/history`);
30
- return {
31
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
32
- };
25
+ return formatMcpResponse(data);
33
26
  });
34
27
  server.tool('get-brew-insights', 'Get proactive coaching insights and nudges from Brew. Shows opportunities, milestones, and reminders based on your activity.', {}, async () => {
35
28
  const data = await client.get('/guide/insights');
36
- return {
37
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
38
- };
29
+ return formatMcpResponse(data);
39
30
  });
40
31
  server.tool('set-brew-goal', 'Set a business goal for Brew to help you work toward.', {
41
32
  goal: z.string().describe('Your business goal (e.g. "Get my first 5 bookings" or "Reach $1000/month")'),
42
33
  conversationId: z.string().optional().describe('Brew conversation ID to associate the goal with'),
43
34
  }, async (params) => {
44
35
  const data = await client.post('/guide/goals', params);
45
- return {
46
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
47
- };
36
+ return formatMcpResponse(data);
48
37
  });
49
38
  server.tool('get-brew-preferences', 'Get your Brew notification preferences including intensity, channel, and sleep status.', {}, async () => {
50
39
  const data = await client.get('/guide/preferences');
51
- return {
52
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
53
- };
40
+ return formatMcpResponse(data);
54
41
  });
55
42
  server.tool('update-brew-preferences', 'Update Brew notification preferences. Control how often and how Brew reaches out.', {
56
43
  intensity: z.enum(['high', 'medium', 'low']).optional().describe('Notification intensity'),
@@ -58,28 +45,20 @@ export function registerBrewTools(server, client) {
58
45
  topicFilters: z.array(z.string()).optional().describe('Topics to filter for'),
59
46
  }, async (params) => {
60
47
  const data = await client.put('/guide/preferences', params);
61
- return {
62
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
63
- };
48
+ return formatMcpResponse(data);
64
49
  });
65
50
  server.tool('sleep-brew', 'Put Brew to sleep for a specified number of weeks. Pauses all proactive notifications.', {
66
51
  weeks: z.number().describe('Number of weeks to sleep (1, 2, or 4)'),
67
52
  }, async (params) => {
68
53
  const data = await client.post('/guide/preferences/sleep', { weeks: params.weeks });
69
- return {
70
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
71
- };
54
+ return formatMcpResponse(data);
72
55
  });
73
56
  server.tool('wake-brew', 'Wake Brew from sleep mode and resume proactive notifications.', {}, async () => {
74
57
  const data = await client.post('/guide/preferences/wake');
75
- return {
76
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
77
- };
58
+ return formatMcpResponse(data);
78
59
  });
79
60
  server.tool('get-dashboard-insight', 'Get a single focused coaching insight for your dashboard. Returns stage-appropriate advice and next action.', {}, async () => {
80
61
  const data = await client.get('/guide/dashboard-insight');
81
- return {
82
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
83
- };
62
+ return formatMcpResponse(data);
84
63
  });
85
64
  }
@@ -1,10 +1,9 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerCalendarTools(server, client) {
3
4
  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
5
  const data = await client.get('/calendar/me');
5
- return {
6
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
7
- };
6
+ return formatMcpResponse(data);
8
7
  });
9
8
  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
9
  timezone: z.string().optional().describe('IANA timezone string (e.g., "America/New_York", "Europe/London")'),
@@ -13,8 +12,6 @@ export function registerCalendarTools(server, client) {
13
12
  buffer_minutes: z.number().optional().describe('Buffer time between appointments in minutes'),
14
13
  }, async (params) => {
15
14
  const data = await client.put('/calendar', params);
16
- return {
17
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
18
- };
15
+ return formatMcpResponse(data);
19
16
  });
20
17
  }
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerClientTools(server, client) {
3
4
  server.tool('list-clients', 'Get your list of clients with optional search', {
4
5
  search: z.string().optional().describe('Search clients by name or email'),
@@ -6,32 +7,24 @@ export function registerClientTools(server, client) {
6
7
  limit: z.number().optional().describe('Number of results per page'),
7
8
  }, async (params) => {
8
9
  const data = await client.get('/client/my', params);
9
- return {
10
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
11
- };
10
+ return formatMcpResponse(data);
12
11
  });
13
12
  server.tool('get-client', 'Get detailed information about a client including their booking history', {
14
13
  id: z.string().describe('The client ID'),
15
14
  }, async (params) => {
16
15
  const data = await client.get(`/client/${params.id}/appointments`);
17
- return {
18
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
19
- };
16
+ return formatMcpResponse(data);
20
17
  });
21
18
  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
19
  id: z.string().describe('The client ID'),
23
20
  }, async (params) => {
24
21
  const data = await client.get(`/client/${params.id}/session-history`);
25
- return {
26
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
27
- };
22
+ return formatMcpResponse(data);
28
23
  });
29
24
  server.tool('get-client-activity', 'Get client activity dashboard including emails sent, testimonials, pre-qualification responses, and engagement stats.', {
30
25
  id: z.string().describe('The client ID'),
31
26
  }, async (params) => {
32
27
  const data = await client.get(`/client/${params.id}/activity`);
33
- return {
34
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
35
- };
28
+ return formatMcpResponse(data);
36
29
  });
37
30
  }
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerEarningsTools(server, client) {
3
4
  server.tool('get-earnings', 'Get your earnings and transaction history', {
4
5
  transaction_type: z.string().optional().describe('Filter by transaction type (e.g., payment, refund)'),
@@ -6,9 +7,7 @@ export function registerEarningsTools(server, client) {
6
7
  limit: z.number().optional().describe('Number of results per page'),
7
8
  }, async (params) => {
8
9
  const data = await client.get('/transaction/my', params);
9
- return {
10
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
11
- };
10
+ return formatMcpResponse(data);
12
11
  });
13
12
  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
13
  const [appointments, earnings] = await Promise.all([
@@ -25,14 +24,12 @@ export function registerEarningsTools(server, client) {
25
24
  .reduce((sum, t) => sum + (parseFloat(t.amount) || 0), 0);
26
25
  const thisMonthCompleted = allAppts.filter((a) => (a.status === 'completed') && (a.start_time >= monthStart || a.createdAt >= monthStart)).length;
27
26
  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
- };
27
+ return formatMcpResponse({
28
+ month: `${now.toLocaleString('default', { month: 'long' })} ${now.getFullYear()}`,
29
+ revenue_this_month: `$${thisMonthRevenue.toFixed(2)}`,
30
+ completed_sessions_this_month: thisMonthCompleted,
31
+ upcoming_sessions: upcomingCount,
32
+ total_transactions_this_month: thisMonthTxns.length,
33
+ });
37
34
  });
38
35
  }
@@ -1,30 +1,23 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerFileLibraryTools(server, client) {
3
4
  server.tool('list-files', 'Get all files in your file library. Files can be attached to products, services, or shared with clients.', {}, async () => {
4
5
  const data = await client.get('/file-library');
5
- return {
6
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
7
- };
6
+ return formatMcpResponse(data);
8
7
  });
9
8
  server.tool('get-file', 'Get detailed information about a specific file in your library.', {
10
9
  id: z.string().describe('The file ID'),
11
10
  }, async (params) => {
12
11
  const data = await client.get(`/file-library/${params.id}`);
13
- return {
14
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
15
- };
12
+ return formatMcpResponse(data);
16
13
  });
17
14
  server.tool('get-file-library-stats', 'Get statistics about your file library including total files, storage used, and file types.', {}, async () => {
18
15
  const data = await client.get('/file-library/stats');
19
- return {
20
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
21
- };
16
+ return formatMcpResponse(data);
22
17
  });
23
18
  server.tool('get-file-library-folders', 'Get all folders in your file library for organization.', {}, async () => {
24
19
  const data = await client.get('/file-library/folders');
25
- return {
26
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
27
- };
20
+ return formatMcpResponse(data);
28
21
  });
29
22
  server.tool('update-file', 'Update file metadata like name, description, or folder.', {
30
23
  id: z.string().describe('The file ID to update'),
@@ -34,25 +27,19 @@ export function registerFileLibraryTools(server, client) {
34
27
  }, async (params) => {
35
28
  const { id, ...updateData } = params;
36
29
  const data = await client.put(`/file-library/${id}`, updateData);
37
- return {
38
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
39
- };
30
+ return formatMcpResponse(data);
40
31
  });
41
32
  server.tool('delete-file', 'Delete a file from your library.', {
42
33
  id: z.string().describe('The file ID to delete'),
43
34
  }, async (params) => {
44
35
  const data = await client.delete(`/file-library/${params.id}`);
45
- return {
46
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
47
- };
36
+ return formatMcpResponse(data);
48
37
  });
49
38
  server.tool('add-file-tags', 'Add tags to a file for easier organization and search.', {
50
39
  id: z.string().describe('The file ID'),
51
40
  tags: z.array(z.string()).describe('Tags to add to the file'),
52
41
  }, async (params) => {
53
42
  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
- };
43
+ return formatMcpResponse(data);
57
44
  });
58
45
  }
@@ -1,12 +1,11 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerGoogleCalendarTools(server, client) {
3
4
  server.tool('get-connected-calendars', 'Get your connected Google Calendar accounts and their calendars. Shows which calendars are selected for conflict checking.', {
4
5
  user_id: z.string().describe('Your user ID'),
5
6
  }, async (params) => {
6
7
  const data = await client.get(`/google-calendar/calendars/${params.user_id}`);
7
- return {
8
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
9
- };
8
+ return formatMcpResponse(data);
10
9
  });
11
10
  server.tool('toggle-calendar-selection', 'Select or deselect a Google Calendar for conflict checking. Selected calendars are checked when clients book.', {
12
11
  user_id: z.string().describe('Your user ID'),
@@ -17,9 +16,7 @@ export function registerGoogleCalendarTools(server, client) {
17
16
  calendarId: params.calendarId,
18
17
  isSelected: params.isSelected,
19
18
  });
20
- return {
21
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
22
- };
19
+ return formatMcpResponse(data);
23
20
  });
24
21
  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
22
  user_id: z.string().describe('Your user ID'),
@@ -30,8 +27,6 @@ export function registerGoogleCalendarTools(server, client) {
30
27
  startTime: params.startTime,
31
28
  endTime: params.endTime,
32
29
  });
33
- return {
34
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
35
- };
30
+ return formatMcpResponse(data);
36
31
  });
37
32
  }
@@ -1,32 +1,25 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerLiveTools(server, client) {
3
4
  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
5
  title: z.string().optional().describe('Title for the live session'),
5
6
  }, async (params) => {
6
7
  const data = await client.post('/live/start', { title: params.title });
7
- return {
8
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
9
- };
8
+ return formatMcpResponse(data);
10
9
  });
11
10
  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
11
  const data = await client.get('/live/active');
13
- return {
14
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
15
- };
12
+ return formatMcpResponse(data);
16
13
  });
17
14
  server.tool('end-live-session', 'End your active live session.', {
18
15
  slug: z.string().describe('The live session slug (short code)'),
19
16
  }, async (params) => {
20
17
  const data = await client.post(`/live/${params.slug}/end`);
21
- return {
22
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
23
- };
18
+ return formatMcpResponse(data);
24
19
  });
25
20
  server.tool('get-live-session-history', 'Get your past live session history including duration, viewer counts, and status.', {}, async () => {
26
21
  const data = await client.get('/live/history/me');
27
- return {
28
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
29
- };
22
+ return formatMcpResponse(data);
30
23
  });
31
24
  server.tool('send-live-session-invite', 'Send an email invitation to someone to join your active live session.', {
32
25
  slug: z.string().describe('The live session slug'),
@@ -37,8 +30,6 @@ export function registerLiveTools(server, client) {
37
30
  email: params.email,
38
31
  isCohost: params.isCohost || false,
39
32
  });
40
- return {
41
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
42
- };
33
+ return formatMcpResponse(data);
43
34
  });
44
35
  }
@@ -1,10 +1,9 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerMessagingTools(server, client) {
3
4
  server.tool('list-conversations', 'Get all your message conversations with clients. Returns conversations sorted by most recent message.', {}, async () => {
4
5
  const data = await client.get('/messaging/conversations', { userType: 'provider' });
5
- return {
6
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
7
- };
6
+ return formatMcpResponse(data);
8
7
  });
9
8
  server.tool('get-conversation-messages', 'Get messages from a specific conversation. Returns the most recent messages in chronological order.', {
10
9
  conversation_id: z.string().describe('The conversation ID'),
@@ -14,9 +13,7 @@ export function registerMessagingTools(server, client) {
14
13
  if (params.limit)
15
14
  queryParams.limit = String(params.limit);
16
15
  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
- };
16
+ return formatMcpResponse(data);
20
17
  });
21
18
  server.tool('send-message', 'Send a message to a client in an existing conversation. Use list-conversations first to find the conversation ID.', {
22
19
  conversation_id: z.string().describe('The conversation ID'),
@@ -29,15 +26,11 @@ export function registerMessagingTools(server, client) {
29
26
  senderName: params.sender_name,
30
27
  message: params.message,
31
28
  });
32
- return {
33
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
34
- };
29
+ return formatMcpResponse(data);
35
30
  });
36
31
  server.tool('get-unread-message-count', 'Get the total number of unread messages across all conversations.', {}, async () => {
37
32
  const data = await client.get('/messaging/unread-count', { userType: 'provider' });
38
- return {
39
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
40
- };
33
+ return formatMcpResponse(data);
41
34
  });
42
35
  server.tool('mark-conversation-read', 'Mark all messages in a conversation as read.', {
43
36
  conversation_id: z.string().describe('The conversation ID to mark as read'),
@@ -45,8 +38,6 @@ export function registerMessagingTools(server, client) {
45
38
  const data = await client.post(`/messaging/conversations/${params.conversation_id}/read`, {
46
39
  userType: 'provider',
47
40
  });
48
- return {
49
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
50
- };
41
+ return formatMcpResponse(data);
51
42
  });
52
43
  }
@@ -1,25 +1,20 @@
1
1
  import { z } from 'zod';
2
+ import { formatMcpResponse } from '../client.js';
2
3
  export function registerNotificationTools(server, client) {
3
4
  server.tool('list-notifications', 'Get all your notifications including new bookings, messages, and system alerts. Use this to check what needs your attention.', {
4
5
  user_id: z.string().describe('Your user ID (get this from get-profile first)'),
5
6
  }, async (params) => {
6
7
  const data = await client.get(`/notification/${params.user_id}`);
7
- return {
8
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
9
- };
8
+ return formatMcpResponse(data);
10
9
  });
11
10
  server.tool('mark-notification-read', 'Mark a single notification as read.', {
12
11
  notification_id: z.string().describe('The notification ID to mark as read'),
13
12
  }, async (params) => {
14
13
  const data = await client.put(`/notification/${params.notification_id}/read`);
15
- return {
16
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
17
- };
14
+ return formatMcpResponse(data);
18
15
  });
19
16
  server.tool('mark-all-notifications-read', 'Mark all your notifications as read. Use this to clear your notification count.', {}, async () => {
20
17
  const data = await client.put('/notification/read-all');
21
- return {
22
- content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
23
- };
18
+ return formatMcpResponse(data);
24
19
  });
25
20
  }