@talkspresso/mcp-server 1.4.2 → 1.5.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 +2 -2
- package/dist/setup-api.d.ts +2 -0
- package/dist/setup-api.js +13 -0
- package/dist/setup.js +44 -127
- package/dist/tools/brew.js +30 -2
- package/package.json +1 -1
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.5.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.5.0',
|
|
46
46
|
});
|
|
47
47
|
const apiClient = new TalkspressoClient();
|
|
48
48
|
registerAppointmentTools(server, apiClient);
|
package/dist/setup-api.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare class SetupApiClient {
|
|
|
18
18
|
about?: string;
|
|
19
19
|
bio?: string;
|
|
20
20
|
categories?: string[];
|
|
21
|
+
profile_handle?: string;
|
|
21
22
|
}): Promise<any>;
|
|
22
23
|
createService(data: {
|
|
23
24
|
title: string;
|
|
@@ -26,6 +27,7 @@ export declare class SetupApiClient {
|
|
|
26
27
|
duration: number;
|
|
27
28
|
type: string;
|
|
28
29
|
}): Promise<any>;
|
|
30
|
+
checkHandleAvailability(handle: string): Promise<boolean>;
|
|
29
31
|
updateCalendar(data: {
|
|
30
32
|
timezone?: string;
|
|
31
33
|
availability?: Record<string, any>;
|
package/dist/setup-api.js
CHANGED
|
@@ -73,6 +73,19 @@ export class SetupApiClient {
|
|
|
73
73
|
throw this.formatError(err);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
async checkHandleAvailability(handle) {
|
|
77
|
+
try {
|
|
78
|
+
await this.http.get('/profile/check_handle_availability', {
|
|
79
|
+
params: { profile_handle: handle },
|
|
80
|
+
});
|
|
81
|
+
return true; // 200 = available
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
if (err.response?.status === 409)
|
|
85
|
+
return false; // taken
|
|
86
|
+
return false; // assume taken on error
|
|
87
|
+
}
|
|
88
|
+
}
|
|
76
89
|
async updateCalendar(data) {
|
|
77
90
|
try {
|
|
78
91
|
const response = await this.http.put('/calendar', data);
|
package/dist/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { confirm, input, password as passwordPrompt
|
|
2
|
+
import { confirm, input, password as passwordPrompt } from '@inquirer/prompts';
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { homedir } from 'os';
|
|
@@ -49,40 +49,6 @@ function mcpEntry(apiKey) {
|
|
|
49
49
|
env: { TALKSPRESSO_API_KEY: apiKey },
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
const SERVICE_PRESETS = [
|
|
53
|
-
{ name: '1:1 Video Call (30 min, $100)', value: { title: '1:1 Video Call', description: 'A private 30-minute video session.', price: 100, duration: 30, type: 'video_call' } },
|
|
54
|
-
{ name: '1:1 Video Call (60 min, $200)', value: { title: '1:1 Video Call', description: 'A private 60-minute video session.', price: 200, duration: 60, type: 'video_call' } },
|
|
55
|
-
{ name: 'Group Workshop (60 min, $50)', value: { title: 'Group Workshop', description: 'A 60-minute interactive group session.', price: 50, duration: 60, type: 'workshop' } },
|
|
56
|
-
{ name: 'Custom (I\'ll set it up)', value: 'custom' },
|
|
57
|
-
{ name: 'Skip for now', value: 'skip' },
|
|
58
|
-
];
|
|
59
|
-
const AVAILABILITY_PRESETS = [
|
|
60
|
-
{ name: 'Weekdays 9 AM - 5 PM', value: 'weekdays-9-5' },
|
|
61
|
-
{ name: 'Weekdays 10 AM - 6 PM', value: 'weekdays-10-6' },
|
|
62
|
-
{ name: 'Every day 9 AM - 9 PM', value: 'everyday-9-9' },
|
|
63
|
-
{ name: 'Skip for now', value: 'skip' },
|
|
64
|
-
];
|
|
65
|
-
function buildAvailability(preset) {
|
|
66
|
-
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
|
67
|
-
const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'];
|
|
68
|
-
const make = (selectedDays, start, end) => {
|
|
69
|
-
const result = {};
|
|
70
|
-
for (const day of days) {
|
|
71
|
-
result[day] = {
|
|
72
|
-
is_selected: selectedDays.includes(day),
|
|
73
|
-
start_time: start,
|
|
74
|
-
end_time: end,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
};
|
|
79
|
-
switch (preset) {
|
|
80
|
-
case 'weekdays-9-5': return make(weekdays, '09:00', '17:00');
|
|
81
|
-
case 'weekdays-10-6': return make(weekdays, '10:00', '18:00');
|
|
82
|
-
case 'everyday-9-9': return make(days, '09:00', '21:00');
|
|
83
|
-
default: return null;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
52
|
export async function runSetup() {
|
|
87
53
|
process.on('SIGINT', () => {
|
|
88
54
|
console.log(`\n\n ${chalk.dim('Setup cancelled. Run')} npx @talkspresso/mcp-server --setup ${chalk.dim('anytime.')}\n`);
|
|
@@ -92,7 +58,7 @@ export async function runSetup() {
|
|
|
92
58
|
// ── Welcome ──────────────────────────────────────────
|
|
93
59
|
console.log(LOGO);
|
|
94
60
|
console.log(` ${chalk.white.bold('Manage your business with AI.')}`);
|
|
95
|
-
console.log(` ${chalk.dim("Let's
|
|
61
|
+
console.log(` ${chalk.dim("Let's connect your account. Takes about 60 seconds.")}\n`);
|
|
96
62
|
// ── Account ──────────────────────────────────────────
|
|
97
63
|
let accessToken;
|
|
98
64
|
let userName;
|
|
@@ -170,89 +136,40 @@ export async function runSetup() {
|
|
|
170
136
|
console.log(` ${chalk.dim('Create one manually at')} ${chalk.cyan('app.talkspresso.com/settings/api-keys')}\n`);
|
|
171
137
|
process.exit(1);
|
|
172
138
|
}
|
|
173
|
-
// ──
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
await api.updateProfile({
|
|
184
|
-
expert_title: expertTitle || undefined,
|
|
185
|
-
about: about || undefined,
|
|
186
|
-
});
|
|
187
|
-
console.log(` ${chalk.green('✓')} Profile updated\n`);
|
|
188
|
-
}
|
|
189
|
-
catch {
|
|
190
|
-
console.log(` ${chalk.yellow('!')} Could not update profile. You can update it later.\n`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
// ── First Service ────────────────────────────────────
|
|
194
|
-
console.log(chalk.white.bold(' Create your first offering\n'));
|
|
195
|
-
console.log(` ${chalk.dim('This is what people will book with you.')}\n`);
|
|
196
|
-
const serviceChoice = await select({
|
|
197
|
-
message: 'Pick a starting template:',
|
|
198
|
-
choices: SERVICE_PRESETS,
|
|
199
|
-
});
|
|
200
|
-
if (serviceChoice === 'custom') {
|
|
201
|
-
const title = await input({ message: 'Service title:' });
|
|
202
|
-
const description = await input({ message: 'Short description:' });
|
|
203
|
-
const priceStr = await input({ message: 'Price in dollars (0 for free):' });
|
|
204
|
-
const durationStr = await input({ message: 'Duration in minutes:' });
|
|
205
|
-
const type = await select({
|
|
206
|
-
message: 'Service type:',
|
|
207
|
-
choices: [
|
|
208
|
-
{ name: '1:1 Video Call', value: 'video_call' },
|
|
209
|
-
{ name: 'Group Session', value: 'group_session' },
|
|
210
|
-
{ name: 'Workshop', value: 'workshop' },
|
|
211
|
-
{ name: 'Webinar', value: 'webinar' },
|
|
212
|
-
],
|
|
139
|
+
// ── Handle / Vanity URL ────────────────────────────
|
|
140
|
+
let profileHandle = '';
|
|
141
|
+
const defaultHandle = userName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
142
|
+
console.log(` ${chalk.dim('Your booking page will be:')} ${chalk.cyan(`app.talkspresso.com/`)}${chalk.cyan.bold('<your-handle>')}\n`);
|
|
143
|
+
let handleAttempts = 0;
|
|
144
|
+
while (handleAttempts < 5) {
|
|
145
|
+
const handle = await input({
|
|
146
|
+
message: 'Choose your handle:',
|
|
147
|
+
default: handleAttempts === 0 ? defaultHandle : undefined,
|
|
213
148
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
duration: parseInt(durationStr) || 30,
|
|
220
|
-
type,
|
|
221
|
-
});
|
|
222
|
-
console.log(` ${chalk.green('✓')} Service "${title}" created\n`);
|
|
149
|
+
const cleaned = handle.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
150
|
+
if (!cleaned || cleaned.length < 3) {
|
|
151
|
+
console.log(` ${chalk.red('✗')} Handle must be at least 3 characters.\n`);
|
|
152
|
+
handleAttempts++;
|
|
153
|
+
continue;
|
|
223
154
|
}
|
|
224
|
-
|
|
225
|
-
|
|
155
|
+
const available = await api.checkHandleAvailability(cleaned);
|
|
156
|
+
if (available) {
|
|
157
|
+
profileHandle = cleaned;
|
|
158
|
+
console.log(` ${chalk.green('✓')} ${chalk.cyan(`app.talkspresso.com/${cleaned}`)} is yours!\n`);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(` ${chalk.red('✗')} "${cleaned}" is taken. Try another.\n`);
|
|
163
|
+
handleAttempts++;
|
|
226
164
|
}
|
|
227
165
|
}
|
|
228
|
-
|
|
166
|
+
// Save handle to profile
|
|
167
|
+
if (profileHandle) {
|
|
229
168
|
try {
|
|
230
|
-
|
|
231
|
-
await api.createService(preset);
|
|
232
|
-
console.log(` ${chalk.green('✓')} Service "${preset.title}" created ($${preset.price}, ${preset.duration} min)\n`);
|
|
233
|
-
}
|
|
234
|
-
catch (err) {
|
|
235
|
-
console.log(` ${chalk.yellow('!')} Could not create service: ${err.message}. You can create one later.\n`);
|
|
169
|
+
await api.updateProfile({ profile_handle: profileHandle });
|
|
236
170
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
console.log(chalk.white.bold(' Set your availability\n'));
|
|
240
|
-
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
241
|
-
console.log(` ${chalk.dim(`Detected timezone: ${timezone}`)}\n`);
|
|
242
|
-
const availPreset = await select({
|
|
243
|
-
message: 'When are you available for sessions?',
|
|
244
|
-
choices: AVAILABILITY_PRESETS,
|
|
245
|
-
});
|
|
246
|
-
if (availPreset !== 'skip') {
|
|
247
|
-
const availability = buildAvailability(availPreset);
|
|
248
|
-
if (availability) {
|
|
249
|
-
try {
|
|
250
|
-
await api.updateCalendar({ timezone, availability });
|
|
251
|
-
console.log(` ${chalk.green('✓')} Availability set\n`);
|
|
252
|
-
}
|
|
253
|
-
catch {
|
|
254
|
-
console.log(` ${chalk.yellow('!')} Could not set availability. You can update it later.\n`);
|
|
255
|
-
}
|
|
171
|
+
catch {
|
|
172
|
+
// Non-fatal, handle might already be set
|
|
256
173
|
}
|
|
257
174
|
}
|
|
258
175
|
// ── Configure Claude Desktop ─────────────────────────
|
|
@@ -295,16 +212,12 @@ export async function runSetup() {
|
|
|
295
212
|
}
|
|
296
213
|
}
|
|
297
214
|
// ── Success ──────────────────────────────────────────
|
|
298
|
-
console.log(chalk.green.bold('\n You\'re
|
|
215
|
+
console.log(chalk.green.bold('\n You\'re connected!\n'));
|
|
299
216
|
const done = [];
|
|
300
217
|
done.push(`Account: ${userEmail}`);
|
|
301
218
|
done.push(`API key saved`);
|
|
302
|
-
if (
|
|
303
|
-
done.push(`
|
|
304
|
-
if (serviceChoice !== 'skip')
|
|
305
|
-
done.push('First service created');
|
|
306
|
-
if (availPreset !== 'skip')
|
|
307
|
-
done.push('Availability configured');
|
|
219
|
+
if (profileHandle)
|
|
220
|
+
done.push(`Handle: app.talkspresso.com/${profileHandle}`);
|
|
308
221
|
if (configuredDesktop)
|
|
309
222
|
done.push('Claude Desktop configured');
|
|
310
223
|
if (configuredCode)
|
|
@@ -312,15 +225,19 @@ export async function runSetup() {
|
|
|
312
225
|
for (const item of done) {
|
|
313
226
|
console.log(` ${chalk.green('✓')} ${item}`);
|
|
314
227
|
}
|
|
315
|
-
console.log(`\n ${chalk.bold('
|
|
228
|
+
console.log(`\n ${chalk.bold('Now the fun part:')}\n`);
|
|
316
229
|
if (configuredDesktop || configuredCode) {
|
|
317
|
-
console.log(` 1. ${chalk.white('Restart Claude')} (
|
|
318
|
-
console.log(` 2. ${chalk.white('
|
|
319
|
-
console.log(
|
|
320
|
-
console.log(`
|
|
230
|
+
console.log(` 1. ${chalk.white('Restart Claude')} (quit and reopen)`);
|
|
231
|
+
console.log(` 2. ${chalk.white('Say:')} ${chalk.cyan('"Help me set up my Talkspresso business"')}`);
|
|
232
|
+
console.log();
|
|
233
|
+
console.log(` ${chalk.dim('Brew, your AI business advisor, will:')}`);
|
|
234
|
+
console.log(` ${chalk.dim(' - Ask about what you do')}`);
|
|
235
|
+
console.log(` ${chalk.dim(' - Suggest sessions and pricing for your niche')}`);
|
|
236
|
+
console.log(` ${chalk.dim(' - Create your services and set up your availability')}`);
|
|
237
|
+
console.log(` ${chalk.dim(' - Get your booking page ready to share')}`);
|
|
321
238
|
}
|
|
322
239
|
else {
|
|
323
|
-
console.log(`
|
|
240
|
+
console.log(` Run ${chalk.cyan('npx @talkspresso/mcp-server --setup')} to connect to Claude.`);
|
|
324
241
|
}
|
|
325
|
-
console.log(`\n ${chalk.dim('
|
|
242
|
+
console.log(`\n ${chalk.dim('Your entire business, built through conversation.')}\n`);
|
|
326
243
|
}
|
package/dist/tools/brew.js
CHANGED
|
@@ -5,11 +5,24 @@ export function registerBrewTools(server, client) {
|
|
|
5
5
|
const data = await client.get('/guide/status');
|
|
6
6
|
return formatMcpResponse(data);
|
|
7
7
|
});
|
|
8
|
-
server.tool('start-brew-conversation',
|
|
8
|
+
server.tool('start-brew-conversation', `Start a new conversation with Brew or resume your existing one. Brew is your AI business mentor on Talkspresso.
|
|
9
|
+
|
|
10
|
+
IMPORTANT FOR NEW USERS: If the user just set up their account or says "help me set up my business", start a Brew conversation first. Brew will detect they are new and guide them through:
|
|
11
|
+
1. Understanding what they do and who they serve
|
|
12
|
+
2. Suggesting personalized session types and pricing for their niche
|
|
13
|
+
3. Creating their first services (use confirm-brew-action to execute proposals)
|
|
14
|
+
4. Setting up availability and profile
|
|
15
|
+
5. Getting their booking page ready to share
|
|
16
|
+
|
|
17
|
+
Brew knows the user's full context (profile, services, bookings, stage) and gives niche-specific advice.`, {}, async () => {
|
|
9
18
|
const data = await client.post('/guide/start');
|
|
10
19
|
return formatMcpResponse(data);
|
|
11
20
|
});
|
|
12
|
-
server.tool('send-brew-message',
|
|
21
|
+
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.
|
|
22
|
+
|
|
23
|
+
When Brew proposes an action (like creating a service or updating availability), the response will include a write_proposal with actionData and a messageId. To execute the proposed action, call confirm-brew-action with the conversationId, actionType, and messageId.
|
|
24
|
+
|
|
25
|
+
Brew can propose these actions: create_service, update_service, convert_service_type, add_package_session, update_service_capacity, update_availability, update_profile, connect_stripe, create_appointment, cancel_appointment.`, {
|
|
13
26
|
conversationId: z.string().describe('The Brew conversation ID (get from start-brew-conversation)'),
|
|
14
27
|
message: z.string().describe('Your message to Brew'),
|
|
15
28
|
}, async (params) => {
|
|
@@ -18,6 +31,21 @@ export function registerBrewTools(server, client) {
|
|
|
18
31
|
});
|
|
19
32
|
return formatMcpResponse(data);
|
|
20
33
|
});
|
|
34
|
+
server.tool('confirm-brew-action', `Execute a proposed action from Brew. When Brew suggests creating a service, updating availability, or making other changes, it returns a write_proposal with a messageId. Call this tool to confirm and execute that action.
|
|
35
|
+
|
|
36
|
+
Supported action types: create_service, update_service, convert_service_type, add_package_session, update_service_capacity, update_availability, update_profile, connect_stripe, create_appointment, cancel_appointment.
|
|
37
|
+
|
|
38
|
+
Always confirm with the user before executing Brew's proposals.`, {
|
|
39
|
+
conversationId: z.string().describe('The Brew conversation ID'),
|
|
40
|
+
actionType: z.string().describe('The action type from the write_proposal (e.g., "create_service", "update_availability")'),
|
|
41
|
+
messageId: z.string().describe('The message ID from the write_proposal response'),
|
|
42
|
+
}, async (params) => {
|
|
43
|
+
const data = await client.post(`/guide/${params.conversationId}/confirm-action`, {
|
|
44
|
+
actionType: params.actionType,
|
|
45
|
+
messageId: params.messageId,
|
|
46
|
+
});
|
|
47
|
+
return formatMcpResponse(data);
|
|
48
|
+
});
|
|
21
49
|
server.tool('get-brew-conversation-history', 'Get the message history for a Brew conversation.', {
|
|
22
50
|
conversationId: z.string().describe('The Brew conversation ID'),
|
|
23
51
|
}, async (params) => {
|
package/package.json
CHANGED