@speakai/mcp-server 1.0.2 → 1.0.4

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.
Files changed (2) hide show
  1. package/dist/index.js +858 -215
  2. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __export = (target, all) => {
10
13
  for (var name in all)
11
14
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -28,45 +31,32 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
31
  ));
29
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
33
 
31
- // src/index.ts
32
- var index_exports = {};
33
- __export(index_exports, {
34
+ // src/client.ts
35
+ var client_exports = {};
36
+ __export(client_exports, {
34
37
  createSpeakClient: () => createSpeakClient,
35
38
  formatAxiosError: () => formatAxiosError,
36
- registerAllTools: () => registerAllTools
39
+ speakClient: () => speakClient
37
40
  });
38
- module.exports = __toCommonJS(index_exports);
39
- var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
40
- var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
41
-
42
- // src/tools/media.ts
43
- var media_exports = {};
44
- __export(media_exports, {
45
- register: () => register
46
- });
47
- var import_zod = require("zod");
48
-
49
- // src/client.ts
50
- var import_axios = __toESM(require("axios"));
51
- var BASE_URL = process.env.SPEAK_BASE_URL ?? "https://api.speakai.co";
52
- var API_KEY = process.env.SPEAK_API_KEY ?? "";
53
- if (!API_KEY && !process.env.SPEAK_MCP_LIBRARY_MODE) {
54
- process.stderr.write(
55
- "[speak-mcp] Warning: SPEAK_API_KEY is not set. All requests will fail.\n"
56
- );
41
+ function getBaseUrl() {
42
+ return process.env.SPEAK_BASE_URL ?? "https://api.speakai.co";
43
+ }
44
+ function getApiKey() {
45
+ return process.env.SPEAK_API_KEY ?? "";
57
46
  }
58
- var accessToken = process.env.SPEAK_ACCESS_TOKEN ?? "";
59
- var refreshToken = "";
60
- var tokenExpiresAt = 0;
61
47
  async function authenticate() {
48
+ const apiKey = getApiKey();
49
+ if (!apiKey) {
50
+ throw new Error("SPEAK_API_KEY is not set. Run 'speak-mcp config set-key' or set the environment variable.");
51
+ }
62
52
  try {
63
53
  const res = await import_axios.default.post(
64
- `${BASE_URL}/v1/auth/accessToken`,
54
+ `${getBaseUrl()}/v1/auth/accessToken`,
65
55
  {},
66
56
  {
67
57
  headers: {
68
58
  "Content-Type": "application/json",
69
- "x-speakai-key": API_KEY
59
+ "x-speakai-key": apiKey
70
60
  }
71
61
  }
72
62
  );
@@ -89,12 +79,12 @@ async function refreshAccessToken() {
89
79
  }
90
80
  try {
91
81
  const res = await import_axios.default.post(
92
- `${BASE_URL}/v1/auth/refreshToken`,
82
+ `${getBaseUrl()}/v1/auth/refreshToken`,
93
83
  { refreshToken },
94
84
  {
95
85
  headers: {
96
86
  "Content-Type": "application/json",
97
- "x-speakai-key": API_KEY,
87
+ "x-speakai-key": getApiKey(),
98
88
  "x-access-token": accessToken
99
89
  }
100
90
  }
@@ -118,34 +108,6 @@ async function ensureAuthenticated() {
118
108
  }
119
109
  }
120
110
  }
121
- var speakClient = import_axios.default.create({
122
- baseURL: BASE_URL,
123
- headers: { "Content-Type": "application/json" },
124
- timeout: 6e4
125
- });
126
- speakClient.interceptors.request.use(
127
- async (config) => {
128
- await ensureAuthenticated();
129
- config.headers.set("x-speakai-key", API_KEY);
130
- config.headers.set("x-access-token", accessToken);
131
- return config;
132
- }
133
- );
134
- speakClient.interceptors.response.use(
135
- (response) => response,
136
- async (error) => {
137
- const originalRequest = error.config;
138
- if (error.response?.status === 401 && !originalRequest._retried) {
139
- originalRequest._retried = true;
140
- tokenExpiresAt = 0;
141
- await ensureAuthenticated();
142
- originalRequest.headers["x-speakai-key"] = API_KEY;
143
- originalRequest.headers["x-access-token"] = accessToken;
144
- return speakClient(originalRequest);
145
- }
146
- return Promise.reject(error);
147
- }
148
- );
149
111
  function createSpeakClient(options) {
150
112
  return import_axios.default.create({
151
113
  baseURL: options.baseUrl,
@@ -167,16 +129,59 @@ function formatAxiosError(error) {
167
129
  if (error instanceof Error) return error.message;
168
130
  return String(error);
169
131
  }
132
+ var import_axios, accessToken, refreshToken, tokenExpiresAt, speakClient;
133
+ var init_client = __esm({
134
+ "src/client.ts"() {
135
+ "use strict";
136
+ import_axios = __toESM(require("axios"));
137
+ accessToken = process.env.SPEAK_ACCESS_TOKEN ?? "";
138
+ refreshToken = "";
139
+ tokenExpiresAt = 0;
140
+ speakClient = import_axios.default.create({
141
+ headers: { "Content-Type": "application/json" },
142
+ timeout: 6e4
143
+ });
144
+ speakClient.interceptors.request.use(
145
+ async (config) => {
146
+ config.baseURL = getBaseUrl();
147
+ await ensureAuthenticated();
148
+ config.headers.set("x-speakai-key", getApiKey());
149
+ config.headers.set("x-access-token", accessToken);
150
+ return config;
151
+ }
152
+ );
153
+ speakClient.interceptors.response.use(
154
+ (response) => response,
155
+ async (error) => {
156
+ const originalRequest = error.config;
157
+ const retryCount = originalRequest._retryCount ?? 0;
158
+ if (error.response?.status === 401 && retryCount < 2) {
159
+ originalRequest._retryCount = retryCount + 1;
160
+ tokenExpiresAt = 0;
161
+ await ensureAuthenticated();
162
+ originalRequest.headers["x-speakai-key"] = getApiKey();
163
+ originalRequest.headers["x-access-token"] = accessToken;
164
+ return speakClient(originalRequest);
165
+ }
166
+ return Promise.reject(error);
167
+ }
168
+ );
169
+ }
170
+ });
170
171
 
171
172
  // src/tools/media.ts
172
- function register(server2, client) {
173
+ var media_exports = {};
174
+ __export(media_exports, {
175
+ register: () => register
176
+ });
177
+ function register(server, client) {
173
178
  const api = client ?? speakClient;
174
- server2.tool(
179
+ server.tool(
175
180
  "get_signed_upload_url",
176
181
  "Get a pre-signed S3 URL for direct media file upload. Use this before uploading a file directly to Speak AI storage.",
177
182
  {
178
183
  isVideo: import_zod.z.boolean().describe("Set true for video files, false for audio files"),
179
- filename: import_zod.z.string().describe("Original filename including extension"),
184
+ filename: import_zod.z.string().min(1).describe("Original filename including extension"),
180
185
  mimeType: import_zod.z.string().describe('MIME type of the file, e.g. "audio/mp4" or "video/mp4"')
181
186
  },
182
187
  async ({ isVideo, filename, mimeType }) => {
@@ -197,11 +202,11 @@ function register(server2, client) {
197
202
  }
198
203
  }
199
204
  );
200
- server2.tool(
205
+ server.tool(
201
206
  "upload_media",
202
207
  "Upload a media file to Speak AI by providing a publicly accessible URL. Speak AI will fetch and process the file asynchronously.",
203
208
  {
204
- name: import_zod.z.string().describe("Display name for the media file"),
209
+ name: import_zod.z.string().min(1).describe("Display name for the media file"),
205
210
  url: import_zod.z.string().describe("Publicly accessible URL of the media file (or pre-signed S3 URL)"),
206
211
  mediaType: import_zod.z.enum(["audio", "video"]).describe('Type of media: "audio" or "video"'),
207
212
  description: import_zod.z.string().optional().describe("Description of the media file"),
@@ -211,8 +216,8 @@ function register(server2, client) {
211
216
  callbackUrl: import_zod.z.string().optional().describe("Webhook callback URL for this specific upload"),
212
217
  fields: import_zod.z.array(
213
218
  import_zod.z.object({
214
- id: import_zod.z.string().describe("Custom field ID"),
215
- value: import_zod.z.string().describe("Custom field value")
219
+ id: import_zod.z.string().min(1).describe("Custom field ID"),
220
+ value: import_zod.z.string().min(1).describe("Custom field value")
216
221
  })
217
222
  ).optional().describe("Custom field values to attach to the media")
218
223
  },
@@ -232,7 +237,7 @@ function register(server2, client) {
232
237
  }
233
238
  }
234
239
  );
235
- server2.tool(
240
+ server.tool(
236
241
  "list_media",
237
242
  "List all media files in the workspace with optional filtering, pagination, and sorting.",
238
243
  {
@@ -263,11 +268,11 @@ function register(server2, client) {
263
268
  }
264
269
  }
265
270
  );
266
- server2.tool(
271
+ server.tool(
267
272
  "get_media_insights",
268
273
  "Retrieve AI-generated insights for a media file, including topics, sentiment, action items, and summaries.",
269
274
  {
270
- mediaId: import_zod.z.string().describe("Unique identifier of the media file")
275
+ mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
271
276
  },
272
277
  async ({ mediaId }) => {
273
278
  try {
@@ -285,11 +290,11 @@ function register(server2, client) {
285
290
  }
286
291
  }
287
292
  );
288
- server2.tool(
293
+ server.tool(
289
294
  "get_transcript",
290
295
  "Retrieve the full transcript for a media file, including speaker labels and timestamps.",
291
296
  {
292
- mediaId: import_zod.z.string().describe("Unique identifier of the media file")
297
+ mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
293
298
  },
294
299
  async ({ mediaId }) => {
295
300
  try {
@@ -307,15 +312,15 @@ function register(server2, client) {
307
312
  }
308
313
  }
309
314
  );
310
- server2.tool(
315
+ server.tool(
311
316
  "update_transcript_speakers",
312
317
  "Update or rename speaker labels in a media transcript.",
313
318
  {
314
- mediaId: import_zod.z.string().describe("Unique identifier of the media file"),
319
+ mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file"),
315
320
  speakers: import_zod.z.array(
316
321
  import_zod.z.object({
317
- id: import_zod.z.string().describe("Speaker identifier from the transcript"),
318
- name: import_zod.z.string().describe("Display name to assign to the speaker")
322
+ id: import_zod.z.string().min(1).describe("Speaker identifier from the transcript"),
323
+ name: import_zod.z.string().min(1).describe("Display name to assign to the speaker")
319
324
  })
320
325
  ).describe("Array of speaker ID to name mappings")
321
326
  },
@@ -338,11 +343,11 @@ function register(server2, client) {
338
343
  }
339
344
  }
340
345
  );
341
- server2.tool(
346
+ server.tool(
342
347
  "get_media_status",
343
348
  "Check the processing status of a media file (e.g. pending, transcribing, completed, failed).",
344
349
  {
345
- mediaId: import_zod.z.string().describe("Unique identifier of the media file")
350
+ mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
346
351
  },
347
352
  async ({ mediaId }) => {
348
353
  try {
@@ -360,11 +365,11 @@ function register(server2, client) {
360
365
  }
361
366
  }
362
367
  );
363
- server2.tool(
368
+ server.tool(
364
369
  "update_media_metadata",
365
370
  "Update metadata fields (name, description, tags, status) for an existing media file.",
366
371
  {
367
- mediaId: import_zod.z.string().describe("Unique identifier of the media file"),
372
+ mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file"),
368
373
  name: import_zod.z.string().optional().describe("New display name for the media"),
369
374
  description: import_zod.z.string().optional().describe("Description or notes for the media"),
370
375
  folderId: import_zod.z.string().optional().describe("Move media to this folder ID"),
@@ -389,11 +394,11 @@ function register(server2, client) {
389
394
  }
390
395
  }
391
396
  );
392
- server2.tool(
397
+ server.tool(
393
398
  "delete_media",
394
399
  "Permanently delete a media file and all associated transcripts and insights.",
395
400
  {
396
- mediaId: import_zod.z.string().describe("Unique identifier of the media file to delete")
401
+ mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file to delete")
397
402
  },
398
403
  async ({ mediaId }) => {
399
404
  try {
@@ -412,20 +417,27 @@ function register(server2, client) {
412
417
  }
413
418
  );
414
419
  }
420
+ var import_zod;
421
+ var init_media = __esm({
422
+ "src/tools/media.ts"() {
423
+ "use strict";
424
+ import_zod = require("zod");
425
+ init_client();
426
+ }
427
+ });
415
428
 
416
429
  // src/tools/text.ts
417
430
  var text_exports = {};
418
431
  __export(text_exports, {
419
432
  register: () => register2
420
433
  });
421
- var import_zod2 = require("zod");
422
- function register2(server2, client) {
434
+ function register2(server, client) {
423
435
  const api = client ?? speakClient;
424
- server2.tool(
436
+ server.tool(
425
437
  "create_text_note",
426
438
  "Create a new text note in Speak AI for analysis. The content will be analyzed for insights, topics, and sentiment.",
427
439
  {
428
- name: import_zod2.z.string().describe("Title/name for the text note"),
440
+ name: import_zod2.z.string().min(1).describe("Title/name for the text note"),
429
441
  text: import_zod2.z.string().optional().describe("Full text content to analyze"),
430
442
  description: import_zod2.z.string().optional().describe("Description for the text note"),
431
443
  folderId: import_zod2.z.string().optional().describe("ID of the folder to place the note in"),
@@ -433,8 +445,8 @@ function register2(server2, client) {
433
445
  callbackUrl: import_zod2.z.string().optional().describe("Webhook callback URL for completion notification"),
434
446
  fields: import_zod2.z.array(
435
447
  import_zod2.z.object({
436
- id: import_zod2.z.string().describe("Custom field ID"),
437
- value: import_zod2.z.string().describe("Custom field value")
448
+ id: import_zod2.z.string().min(1).describe("Custom field ID"),
449
+ value: import_zod2.z.string().min(1).describe("Custom field value")
438
450
  })
439
451
  ).optional().describe("Custom field values to attach to the text note")
440
452
  },
@@ -454,11 +466,11 @@ function register2(server2, client) {
454
466
  }
455
467
  }
456
468
  );
457
- server2.tool(
469
+ server.tool(
458
470
  "get_text_insight",
459
471
  "Retrieve AI-generated insights for a text note, including topics, sentiment, summaries, and action items.",
460
472
  {
461
- mediaId: import_zod2.z.string().describe("Unique identifier of the text note")
473
+ mediaId: import_zod2.z.string().min(1).describe("Unique identifier of the text note")
462
474
  },
463
475
  async ({ mediaId }) => {
464
476
  try {
@@ -476,7 +488,7 @@ function register2(server2, client) {
476
488
  }
477
489
  }
478
490
  );
479
- server2.tool(
491
+ server.tool(
480
492
  "reanalyze_text",
481
493
  "Trigger a re-analysis of an existing text note to regenerate insights with the latest AI models.",
482
494
  {
@@ -498,11 +510,11 @@ function register2(server2, client) {
498
510
  }
499
511
  }
500
512
  );
501
- server2.tool(
513
+ server.tool(
502
514
  "update_text_note",
503
515
  "Update an existing text note's name, content, or metadata. Updating text content will trigger re-analysis.",
504
516
  {
505
- mediaId: import_zod2.z.string().describe("Unique identifier of the text note"),
517
+ mediaId: import_zod2.z.string().min(1).describe("Unique identifier of the text note"),
506
518
  name: import_zod2.z.string().optional().describe("New name for the text note"),
507
519
  text: import_zod2.z.string().optional().describe("New text content (will trigger re-analysis)"),
508
520
  description: import_zod2.z.string().optional().describe("Updated description"),
@@ -529,20 +541,27 @@ function register2(server2, client) {
529
541
  }
530
542
  );
531
543
  }
544
+ var import_zod2;
545
+ var init_text = __esm({
546
+ "src/tools/text.ts"() {
547
+ "use strict";
548
+ import_zod2 = require("zod");
549
+ init_client();
550
+ }
551
+ });
532
552
 
533
553
  // src/tools/exports.ts
534
554
  var exports_exports = {};
535
555
  __export(exports_exports, {
536
556
  register: () => register3
537
557
  });
538
- var import_zod3 = require("zod");
539
- function register3(server2, client) {
558
+ function register3(server, client) {
540
559
  const api = client ?? speakClient;
541
- server2.tool(
560
+ server.tool(
542
561
  "export_media",
543
562
  "Export a media file's transcript or insights in various formats (pdf, docx, srt, vtt, txt, csv, md).",
544
563
  {
545
- mediaId: import_zod3.z.string().describe("Unique identifier of the media file"),
564
+ mediaId: import_zod3.z.string().min(1).describe("Unique identifier of the media file"),
546
565
  fileType: import_zod3.z.enum(["pdf", "docx", "srt", "vtt", "txt", "csv", "md"]).describe("Desired export format"),
547
566
  isSpeakerNames: import_zod3.z.boolean().optional().describe("Include speaker names in export"),
548
567
  isSpeakerEmail: import_zod3.z.boolean().optional().describe("Include speaker emails in export"),
@@ -571,7 +590,7 @@ function register3(server2, client) {
571
590
  }
572
591
  }
573
592
  );
574
- server2.tool(
593
+ server.tool(
575
594
  "export_multiple_media",
576
595
  "Export multiple media files at once, optionally merged into a single file.",
577
596
  {
@@ -605,16 +624,23 @@ function register3(server2, client) {
605
624
  }
606
625
  );
607
626
  }
627
+ var import_zod3;
628
+ var init_exports = __esm({
629
+ "src/tools/exports.ts"() {
630
+ "use strict";
631
+ import_zod3 = require("zod");
632
+ init_client();
633
+ }
634
+ });
608
635
 
609
636
  // src/tools/folders.ts
610
637
  var folders_exports = {};
611
638
  __export(folders_exports, {
612
639
  register: () => register4
613
640
  });
614
- var import_zod4 = require("zod");
615
- function register4(server2, client) {
641
+ function register4(server, client) {
616
642
  const api = client ?? speakClient;
617
- server2.tool(
643
+ server.tool(
618
644
  "get_all_folder_views",
619
645
  "Retrieve all saved views across all folders.",
620
646
  {},
@@ -634,11 +660,11 @@ function register4(server2, client) {
634
660
  }
635
661
  }
636
662
  );
637
- server2.tool(
663
+ server.tool(
638
664
  "get_folder_views",
639
665
  "Retrieve all saved views for a specific folder.",
640
666
  {
641
- folderId: import_zod4.z.string().describe("Unique identifier of the folder")
667
+ folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder")
642
668
  },
643
669
  async ({ folderId }) => {
644
670
  try {
@@ -656,11 +682,11 @@ function register4(server2, client) {
656
682
  }
657
683
  }
658
684
  );
659
- server2.tool(
685
+ server.tool(
660
686
  "create_folder_view",
661
687
  "Create a new saved view for a folder with custom filters and display settings.",
662
688
  {
663
- folderId: import_zod4.z.string().describe("Unique identifier of the folder"),
689
+ folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder"),
664
690
  name: import_zod4.z.string().optional().describe("Display name for the view"),
665
691
  filters: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("Filter configuration object")
666
692
  },
@@ -683,12 +709,12 @@ function register4(server2, client) {
683
709
  }
684
710
  }
685
711
  );
686
- server2.tool(
712
+ server.tool(
687
713
  "update_folder_view",
688
714
  "Update an existing saved view's name, filters, or display settings.",
689
715
  {
690
- folderId: import_zod4.z.string().describe("Unique identifier of the folder"),
691
- viewId: import_zod4.z.string().describe("Unique identifier of the view to update"),
716
+ folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder"),
717
+ viewId: import_zod4.z.string().min(1).describe("Unique identifier of the view to update"),
692
718
  name: import_zod4.z.string().optional().describe("New display name for the view"),
693
719
  filters: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("Updated filter configuration")
694
720
  },
@@ -711,11 +737,11 @@ function register4(server2, client) {
711
737
  }
712
738
  }
713
739
  );
714
- server2.tool(
740
+ server.tool(
715
741
  "clone_folder_view",
716
742
  "Duplicate an existing folder view.",
717
743
  {
718
- viewId: import_zod4.z.string().describe("Unique identifier of the view to clone")
744
+ viewId: import_zod4.z.string().min(1).describe("Unique identifier of the view to clone")
719
745
  },
720
746
  async (body) => {
721
747
  try {
@@ -733,7 +759,7 @@ function register4(server2, client) {
733
759
  }
734
760
  }
735
761
  );
736
- server2.tool(
762
+ server.tool(
737
763
  "list_folders",
738
764
  "List all folders in the workspace with pagination and sorting.",
739
765
  {
@@ -757,11 +783,11 @@ function register4(server2, client) {
757
783
  }
758
784
  }
759
785
  );
760
- server2.tool(
786
+ server.tool(
761
787
  "get_folder_info",
762
788
  "Get detailed information about a specific folder including its contents.",
763
789
  {
764
- folderId: import_zod4.z.string().describe("Unique identifier of the folder")
790
+ folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder")
765
791
  },
766
792
  async ({ folderId }) => {
767
793
  try {
@@ -779,11 +805,11 @@ function register4(server2, client) {
779
805
  }
780
806
  }
781
807
  );
782
- server2.tool(
808
+ server.tool(
783
809
  "create_folder",
784
810
  "Create a new folder in the workspace.",
785
811
  {
786
- name: import_zod4.z.string().describe("Display name for the new folder"),
812
+ name: import_zod4.z.string().min(1).describe("Display name for the new folder"),
787
813
  parentFolderId: import_zod4.z.string().optional().describe("ID of the parent folder for nesting")
788
814
  },
789
815
  async (body) => {
@@ -802,11 +828,11 @@ function register4(server2, client) {
802
828
  }
803
829
  }
804
830
  );
805
- server2.tool(
831
+ server.tool(
806
832
  "clone_folder",
807
833
  "Duplicate an existing folder and all of its contents.",
808
834
  {
809
- folderId: import_zod4.z.string().describe("ID of the folder to clone")
835
+ folderId: import_zod4.z.string().min(1).describe("ID of the folder to clone")
810
836
  },
811
837
  async (body) => {
812
838
  try {
@@ -824,11 +850,11 @@ function register4(server2, client) {
824
850
  }
825
851
  }
826
852
  );
827
- server2.tool(
853
+ server.tool(
828
854
  "update_folder",
829
855
  "Update a folder's name or other properties.",
830
856
  {
831
- folderId: import_zod4.z.string().describe("Unique identifier of the folder"),
857
+ folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder"),
832
858
  name: import_zod4.z.string().optional().describe("New display name for the folder")
833
859
  },
834
860
  async ({ folderId, ...body }) => {
@@ -847,11 +873,11 @@ function register4(server2, client) {
847
873
  }
848
874
  }
849
875
  );
850
- server2.tool(
876
+ server.tool(
851
877
  "delete_folder",
852
878
  "Permanently delete a folder. Media within the folder will be moved, not deleted.",
853
879
  {
854
- folderId: import_zod4.z.string().describe("Unique identifier of the folder to delete")
880
+ folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder to delete")
855
881
  },
856
882
  async ({ folderId }) => {
857
883
  try {
@@ -870,20 +896,27 @@ function register4(server2, client) {
870
896
  }
871
897
  );
872
898
  }
899
+ var import_zod4;
900
+ var init_folders = __esm({
901
+ "src/tools/folders.ts"() {
902
+ "use strict";
903
+ import_zod4 = require("zod");
904
+ init_client();
905
+ }
906
+ });
873
907
 
874
908
  // src/tools/recorder.ts
875
909
  var recorder_exports = {};
876
910
  __export(recorder_exports, {
877
911
  register: () => register5
878
912
  });
879
- var import_zod5 = require("zod");
880
- function register5(server2, client) {
913
+ function register5(server, client) {
881
914
  const api = client ?? speakClient;
882
- server2.tool(
915
+ server.tool(
883
916
  "check_recorder_status",
884
917
  "Check whether a recorder/survey is active and accepting submissions.",
885
918
  {
886
- token: import_zod5.z.string().describe("Unique token identifying the recorder")
919
+ token: import_zod5.z.string().min(1).describe("Unique token identifying the recorder")
887
920
  },
888
921
  async ({ token }) => {
889
922
  try {
@@ -899,7 +932,7 @@ function register5(server2, client) {
899
932
  }
900
933
  }
901
934
  );
902
- server2.tool(
935
+ server.tool(
903
936
  "create_recorder",
904
937
  "Create a new recorder or survey for collecting audio/video submissions.",
905
938
  {
@@ -921,7 +954,7 @@ function register5(server2, client) {
921
954
  }
922
955
  }
923
956
  );
924
- server2.tool(
957
+ server.tool(
925
958
  "list_recorders",
926
959
  "List all recorders/surveys in the workspace.",
927
960
  {
@@ -943,11 +976,11 @@ function register5(server2, client) {
943
976
  }
944
977
  }
945
978
  );
946
- server2.tool(
979
+ server.tool(
947
980
  "clone_recorder",
948
981
  "Duplicate an existing recorder including all its settings and questions.",
949
982
  {
950
- recorderId: import_zod5.z.string().describe("ID of the recorder to clone")
983
+ recorderId: import_zod5.z.string().min(1).describe("ID of the recorder to clone")
951
984
  },
952
985
  async (body) => {
953
986
  try {
@@ -963,11 +996,11 @@ function register5(server2, client) {
963
996
  }
964
997
  }
965
998
  );
966
- server2.tool(
999
+ server.tool(
967
1000
  "get_recorder_info",
968
1001
  "Get detailed information about a specific recorder including its settings and questions.",
969
1002
  {
970
- recorderId: import_zod5.z.string().describe("Unique identifier of the recorder")
1003
+ recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder")
971
1004
  },
972
1005
  async ({ recorderId }) => {
973
1006
  try {
@@ -983,11 +1016,11 @@ function register5(server2, client) {
983
1016
  }
984
1017
  }
985
1018
  );
986
- server2.tool(
1019
+ server.tool(
987
1020
  "get_recorder_recordings",
988
1021
  "List all submissions/recordings collected by a specific recorder.",
989
1022
  {
990
- recorderId: import_zod5.z.string().describe("Unique identifier of the recorder")
1023
+ recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder")
991
1024
  },
992
1025
  async ({ recorderId }) => {
993
1026
  try {
@@ -1003,11 +1036,11 @@ function register5(server2, client) {
1003
1036
  }
1004
1037
  }
1005
1038
  );
1006
- server2.tool(
1039
+ server.tool(
1007
1040
  "generate_recorder_url",
1008
1041
  "Generate a shareable public URL for a recorder/survey.",
1009
1042
  {
1010
- recorderId: import_zod5.z.string().describe("Unique identifier of the recorder")
1043
+ recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder")
1011
1044
  },
1012
1045
  async ({ recorderId }) => {
1013
1046
  try {
@@ -1023,11 +1056,11 @@ function register5(server2, client) {
1023
1056
  }
1024
1057
  }
1025
1058
  );
1026
- server2.tool(
1059
+ server.tool(
1027
1060
  "update_recorder_settings",
1028
1061
  "Update configuration settings for a recorder (branding, permissions, etc.).",
1029
1062
  {
1030
- recorderId: import_zod5.z.string().describe("Unique identifier of the recorder"),
1063
+ recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder"),
1031
1064
  settings: import_zod5.z.record(import_zod5.z.unknown()).describe("Settings object with updated values")
1032
1065
  },
1033
1066
  async ({ recorderId, settings }) => {
@@ -1044,11 +1077,11 @@ function register5(server2, client) {
1044
1077
  }
1045
1078
  }
1046
1079
  );
1047
- server2.tool(
1080
+ server.tool(
1048
1081
  "update_recorder_questions",
1049
1082
  "Update the survey questions for a recorder.",
1050
1083
  {
1051
- recorderId: import_zod5.z.string().describe("Unique identifier of the recorder"),
1084
+ recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder"),
1052
1085
  questions: import_zod5.z.array(import_zod5.z.record(import_zod5.z.unknown())).describe("Array of question objects")
1053
1086
  },
1054
1087
  async ({ recorderId, questions }) => {
@@ -1065,11 +1098,11 @@ function register5(server2, client) {
1065
1098
  }
1066
1099
  }
1067
1100
  );
1068
- server2.tool(
1101
+ server.tool(
1069
1102
  "delete_recorder",
1070
1103
  "Permanently delete a recorder/survey. Existing recordings are preserved.",
1071
1104
  {
1072
- recorderId: import_zod5.z.string().describe("Unique identifier of the recorder to delete")
1105
+ recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder to delete")
1073
1106
  },
1074
1107
  async ({ recorderId }) => {
1075
1108
  try {
@@ -1086,20 +1119,27 @@ function register5(server2, client) {
1086
1119
  }
1087
1120
  );
1088
1121
  }
1122
+ var import_zod5;
1123
+ var init_recorder = __esm({
1124
+ "src/tools/recorder.ts"() {
1125
+ "use strict";
1126
+ import_zod5 = require("zod");
1127
+ init_client();
1128
+ }
1129
+ });
1089
1130
 
1090
1131
  // src/tools/embed.ts
1091
1132
  var embed_exports = {};
1092
1133
  __export(embed_exports, {
1093
1134
  register: () => register6
1094
1135
  });
1095
- var import_zod6 = require("zod");
1096
- function register6(server2, client) {
1136
+ function register6(server, client) {
1097
1137
  const api = client ?? speakClient;
1098
- server2.tool(
1138
+ server.tool(
1099
1139
  "create_embed",
1100
1140
  "Create an embeddable player/transcript widget for a media file.",
1101
1141
  {
1102
- mediaId: import_zod6.z.string().describe("Unique identifier of the media file"),
1142
+ mediaId: import_zod6.z.string().min(1).describe("Unique identifier of the media file"),
1103
1143
  settings: import_zod6.z.record(import_zod6.z.unknown()).optional().describe("Embed configuration settings")
1104
1144
  },
1105
1145
  async (body) => {
@@ -1116,11 +1156,11 @@ function register6(server2, client) {
1116
1156
  }
1117
1157
  }
1118
1158
  );
1119
- server2.tool(
1159
+ server.tool(
1120
1160
  "update_embed",
1121
1161
  "Update settings for an existing embed widget.",
1122
1162
  {
1123
- embedId: import_zod6.z.string().describe("Unique identifier of the embed"),
1163
+ embedId: import_zod6.z.string().min(1).describe("Unique identifier of the embed"),
1124
1164
  settings: import_zod6.z.record(import_zod6.z.unknown()).optional().describe("Updated embed settings")
1125
1165
  },
1126
1166
  async ({ embedId, ...body }) => {
@@ -1137,11 +1177,11 @@ function register6(server2, client) {
1137
1177
  }
1138
1178
  }
1139
1179
  );
1140
- server2.tool(
1180
+ server.tool(
1141
1181
  "check_embed",
1142
1182
  "Check if an embed exists for a media file and retrieve its configuration.",
1143
1183
  {
1144
- mediaId: import_zod6.z.string().describe("Unique identifier of the media file")
1184
+ mediaId: import_zod6.z.string().min(1).describe("Unique identifier of the media file")
1145
1185
  },
1146
1186
  async ({ mediaId }) => {
1147
1187
  try {
@@ -1157,11 +1197,11 @@ function register6(server2, client) {
1157
1197
  }
1158
1198
  }
1159
1199
  );
1160
- server2.tool(
1200
+ server.tool(
1161
1201
  "get_embed_iframe_url",
1162
1202
  "Get the iframe URL for embedding a media player/transcript on a webpage.",
1163
1203
  {
1164
- mediaId: import_zod6.z.string().describe("Unique identifier of the media file")
1204
+ mediaId: import_zod6.z.string().min(1).describe("Unique identifier of the media file")
1165
1205
  },
1166
1206
  async ({ mediaId }) => {
1167
1207
  try {
@@ -1180,16 +1220,23 @@ function register6(server2, client) {
1180
1220
  }
1181
1221
  );
1182
1222
  }
1223
+ var import_zod6;
1224
+ var init_embed = __esm({
1225
+ "src/tools/embed.ts"() {
1226
+ "use strict";
1227
+ import_zod6 = require("zod");
1228
+ init_client();
1229
+ }
1230
+ });
1183
1231
 
1184
1232
  // src/tools/prompt.ts
1185
1233
  var prompt_exports = {};
1186
1234
  __export(prompt_exports, {
1187
1235
  register: () => register7
1188
1236
  });
1189
- var import_zod7 = require("zod");
1190
- function register7(server2, client) {
1237
+ function register7(server, client) {
1191
1238
  const api = client ?? speakClient;
1192
- server2.tool(
1239
+ server.tool(
1193
1240
  "list_prompts",
1194
1241
  "List all available Magic Prompt templates for AI-powered questions about your media.",
1195
1242
  {},
@@ -1207,12 +1254,12 @@ function register7(server2, client) {
1207
1254
  }
1208
1255
  }
1209
1256
  );
1210
- server2.tool(
1257
+ server.tool(
1211
1258
  "ask_magic_prompt",
1212
1259
  "Ask an AI-powered question about a specific media file using Speak AI's Magic Prompt.",
1213
1260
  {
1214
- mediaId: import_zod7.z.string().describe("Unique identifier of the media file to query"),
1215
- prompt: import_zod7.z.string().describe("The question or prompt to ask about the media"),
1261
+ mediaId: import_zod7.z.string().min(1).describe("Unique identifier of the media file to query"),
1262
+ prompt: import_zod7.z.string().min(1).describe("The question or prompt to ask about the media"),
1216
1263
  promptId: import_zod7.z.string().optional().describe("ID of a predefined prompt template to use")
1217
1264
  },
1218
1265
  async (body) => {
@@ -1230,16 +1277,23 @@ function register7(server2, client) {
1230
1277
  }
1231
1278
  );
1232
1279
  }
1280
+ var import_zod7;
1281
+ var init_prompt = __esm({
1282
+ "src/tools/prompt.ts"() {
1283
+ "use strict";
1284
+ import_zod7 = require("zod");
1285
+ init_client();
1286
+ }
1287
+ });
1233
1288
 
1234
1289
  // src/tools/meeting.ts
1235
1290
  var meeting_exports = {};
1236
1291
  __export(meeting_exports, {
1237
1292
  register: () => register8
1238
1293
  });
1239
- var import_zod8 = require("zod");
1240
- function register8(server2, client) {
1294
+ function register8(server, client) {
1241
1295
  const api = client ?? speakClient;
1242
- server2.tool(
1296
+ server.tool(
1243
1297
  "list_meeting_events",
1244
1298
  "List scheduled or completed meeting assistant events with filtering and pagination.",
1245
1299
  {
@@ -1264,11 +1318,11 @@ function register8(server2, client) {
1264
1318
  }
1265
1319
  }
1266
1320
  );
1267
- server2.tool(
1321
+ server.tool(
1268
1322
  "schedule_meeting_event",
1269
1323
  "Schedule the Speak AI meeting assistant to join and record an upcoming meeting.",
1270
1324
  {
1271
- meetingUrl: import_zod8.z.string().describe("URL of the meeting to join"),
1325
+ meetingUrl: import_zod8.z.string().min(1).describe("URL of the meeting to join"),
1272
1326
  title: import_zod8.z.string().optional().describe("Display title for the event"),
1273
1327
  scheduledAt: import_zod8.z.string().optional().describe("ISO 8601 datetime for when the meeting starts")
1274
1328
  },
@@ -1289,7 +1343,7 @@ function register8(server2, client) {
1289
1343
  }
1290
1344
  }
1291
1345
  );
1292
- server2.tool(
1346
+ server.tool(
1293
1347
  "remove_assistant_from_meeting",
1294
1348
  "Remove the Speak AI assistant from an active or scheduled meeting.",
1295
1349
  {
@@ -1313,7 +1367,7 @@ function register8(server2, client) {
1313
1367
  }
1314
1368
  }
1315
1369
  );
1316
- server2.tool(
1370
+ server.tool(
1317
1371
  "delete_scheduled_assistant",
1318
1372
  "Cancel and delete a scheduled meeting assistant event.",
1319
1373
  {
@@ -1337,16 +1391,23 @@ function register8(server2, client) {
1337
1391
  }
1338
1392
  );
1339
1393
  }
1394
+ var import_zod8;
1395
+ var init_meeting = __esm({
1396
+ "src/tools/meeting.ts"() {
1397
+ "use strict";
1398
+ import_zod8 = require("zod");
1399
+ init_client();
1400
+ }
1401
+ });
1340
1402
 
1341
1403
  // src/tools/fields.ts
1342
1404
  var fields_exports = {};
1343
1405
  __export(fields_exports, {
1344
1406
  register: () => register9
1345
1407
  });
1346
- var import_zod9 = require("zod");
1347
- function register9(server2, client) {
1408
+ function register9(server, client) {
1348
1409
  const api = client ?? speakClient;
1349
- server2.tool(
1410
+ server.tool(
1350
1411
  "list_fields",
1351
1412
  "List all custom fields defined in the workspace.",
1352
1413
  {},
@@ -1364,11 +1425,11 @@ function register9(server2, client) {
1364
1425
  }
1365
1426
  }
1366
1427
  );
1367
- server2.tool(
1428
+ server.tool(
1368
1429
  "create_field",
1369
1430
  "Create a new custom field for categorizing and tagging media.",
1370
1431
  {
1371
- name: import_zod9.z.string().describe("Display name for the field"),
1432
+ name: import_zod9.z.string().min(1).describe("Display name for the field"),
1372
1433
  type: import_zod9.z.string().optional().describe("Field type (text, number, select, etc.)"),
1373
1434
  options: import_zod9.z.array(import_zod9.z.string()).optional().describe("Options for select/multi-select field types")
1374
1435
  },
@@ -1386,7 +1447,7 @@ function register9(server2, client) {
1386
1447
  }
1387
1448
  }
1388
1449
  );
1389
- server2.tool(
1450
+ server.tool(
1390
1451
  "update_multiple_fields",
1391
1452
  "Update multiple custom fields in a single batch operation.",
1392
1453
  {
@@ -1406,11 +1467,11 @@ function register9(server2, client) {
1406
1467
  }
1407
1468
  }
1408
1469
  );
1409
- server2.tool(
1470
+ server.tool(
1410
1471
  "update_field",
1411
1472
  "Update a specific custom field by ID.",
1412
1473
  {
1413
- id: import_zod9.z.string().describe("Unique identifier of the field"),
1474
+ id: import_zod9.z.string().min(1).describe("Unique identifier of the field"),
1414
1475
  name: import_zod9.z.string().optional().describe("New display name"),
1415
1476
  type: import_zod9.z.string().optional().describe("New field type"),
1416
1477
  options: import_zod9.z.array(import_zod9.z.string()).optional().describe("Updated options for select types")
@@ -1430,16 +1491,23 @@ function register9(server2, client) {
1430
1491
  }
1431
1492
  );
1432
1493
  }
1494
+ var import_zod9;
1495
+ var init_fields = __esm({
1496
+ "src/tools/fields.ts"() {
1497
+ "use strict";
1498
+ import_zod9 = require("zod");
1499
+ init_client();
1500
+ }
1501
+ });
1433
1502
 
1434
1503
  // src/tools/automations.ts
1435
1504
  var automations_exports = {};
1436
1505
  __export(automations_exports, {
1437
1506
  register: () => register10
1438
1507
  });
1439
- var import_zod10 = require("zod");
1440
- function register10(server2, client) {
1508
+ function register10(server, client) {
1441
1509
  const api = client ?? speakClient;
1442
- server2.tool(
1510
+ server.tool(
1443
1511
  "list_automations",
1444
1512
  "List all automation rules configured in the workspace.",
1445
1513
  {},
@@ -1457,11 +1525,11 @@ function register10(server2, client) {
1457
1525
  }
1458
1526
  }
1459
1527
  );
1460
- server2.tool(
1528
+ server.tool(
1461
1529
  "get_automation",
1462
1530
  "Get detailed information about a specific automation rule.",
1463
1531
  {
1464
- automationId: import_zod10.z.string().describe("Unique identifier of the automation")
1532
+ automationId: import_zod10.z.string().min(1).describe("Unique identifier of the automation")
1465
1533
  },
1466
1534
  async ({ automationId }) => {
1467
1535
  try {
@@ -1477,7 +1545,7 @@ function register10(server2, client) {
1477
1545
  }
1478
1546
  }
1479
1547
  );
1480
- server2.tool(
1548
+ server.tool(
1481
1549
  "create_automation",
1482
1550
  "Create a new automation rule for automatic media processing workflows.",
1483
1551
  {
@@ -1500,11 +1568,11 @@ function register10(server2, client) {
1500
1568
  }
1501
1569
  }
1502
1570
  );
1503
- server2.tool(
1571
+ server.tool(
1504
1572
  "update_automation",
1505
1573
  "Update an existing automation rule's configuration.",
1506
1574
  {
1507
- automationId: import_zod10.z.string().describe("Unique identifier of the automation"),
1575
+ automationId: import_zod10.z.string().min(1).describe("Unique identifier of the automation"),
1508
1576
  name: import_zod10.z.string().optional().describe("New display name"),
1509
1577
  trigger: import_zod10.z.record(import_zod10.z.unknown()).optional().describe("Updated trigger configuration"),
1510
1578
  actions: import_zod10.z.array(import_zod10.z.record(import_zod10.z.unknown())).optional().describe("Updated action configurations"),
@@ -1527,11 +1595,11 @@ function register10(server2, client) {
1527
1595
  }
1528
1596
  }
1529
1597
  );
1530
- server2.tool(
1598
+ server.tool(
1531
1599
  "toggle_automation_status",
1532
1600
  "Enable or disable an automation rule.",
1533
1601
  {
1534
- automationId: import_zod10.z.string().describe("Unique identifier of the automation"),
1602
+ automationId: import_zod10.z.string().min(1).describe("Unique identifier of the automation"),
1535
1603
  enabled: import_zod10.z.boolean().describe("Set to true to enable, false to disable")
1536
1604
  },
1537
1605
  async ({ automationId, enabled }) => {
@@ -1552,16 +1620,23 @@ function register10(server2, client) {
1552
1620
  }
1553
1621
  );
1554
1622
  }
1623
+ var import_zod10;
1624
+ var init_automations = __esm({
1625
+ "src/tools/automations.ts"() {
1626
+ "use strict";
1627
+ import_zod10 = require("zod");
1628
+ init_client();
1629
+ }
1630
+ });
1555
1631
 
1556
1632
  // src/tools/webhooks.ts
1557
1633
  var webhooks_exports = {};
1558
1634
  __export(webhooks_exports, {
1559
1635
  register: () => register11
1560
1636
  });
1561
- var import_zod11 = require("zod");
1562
- function register11(server2, client) {
1637
+ function register11(server, client) {
1563
1638
  const api = client ?? speakClient;
1564
- server2.tool(
1639
+ server.tool(
1565
1640
  "create_webhook",
1566
1641
  "Create a new webhook to receive real-time notifications when events occur in Speak AI.",
1567
1642
  {
@@ -1582,7 +1657,7 @@ function register11(server2, client) {
1582
1657
  }
1583
1658
  }
1584
1659
  );
1585
- server2.tool(
1660
+ server.tool(
1586
1661
  "list_webhooks",
1587
1662
  "List all configured webhooks in the workspace.",
1588
1663
  {},
@@ -1600,11 +1675,11 @@ function register11(server2, client) {
1600
1675
  }
1601
1676
  }
1602
1677
  );
1603
- server2.tool(
1678
+ server.tool(
1604
1679
  "update_webhook",
1605
1680
  "Update an existing webhook's URL or subscribed events.",
1606
1681
  {
1607
- webhookId: import_zod11.z.string().describe("Unique identifier of the webhook"),
1682
+ webhookId: import_zod11.z.string().min(1).describe("Unique identifier of the webhook"),
1608
1683
  url: import_zod11.z.string().url().optional().describe("New endpoint URL"),
1609
1684
  events: import_zod11.z.array(import_zod11.z.string()).optional().describe("Updated array of event types")
1610
1685
  },
@@ -1622,11 +1697,11 @@ function register11(server2, client) {
1622
1697
  }
1623
1698
  }
1624
1699
  );
1625
- server2.tool(
1700
+ server.tool(
1626
1701
  "delete_webhook",
1627
1702
  "Delete a webhook and stop receiving notifications at its endpoint.",
1628
1703
  {
1629
- webhookId: import_zod11.z.string().describe("Unique identifier of the webhook to delete")
1704
+ webhookId: import_zod11.z.string().min(1).describe("Unique identifier of the webhook to delete")
1630
1705
  },
1631
1706
  async ({ webhookId }) => {
1632
1707
  try {
@@ -1643,43 +1718,611 @@ function register11(server2, client) {
1643
1718
  }
1644
1719
  );
1645
1720
  }
1721
+ var import_zod11;
1722
+ var init_webhooks = __esm({
1723
+ "src/tools/webhooks.ts"() {
1724
+ "use strict";
1725
+ import_zod11 = require("zod");
1726
+ init_client();
1727
+ }
1728
+ });
1646
1729
 
1647
1730
  // src/tools/index.ts
1648
- var modules = [
1649
- media_exports,
1650
- text_exports,
1651
- exports_exports,
1652
- folders_exports,
1653
- recorder_exports,
1654
- embed_exports,
1655
- prompt_exports,
1656
- meeting_exports,
1657
- fields_exports,
1658
- automations_exports,
1659
- webhooks_exports
1660
- ];
1661
- function registerAllTools(server2, client) {
1731
+ var tools_exports = {};
1732
+ __export(tools_exports, {
1733
+ registerAllTools: () => registerAllTools
1734
+ });
1735
+ function registerAllTools(server, client) {
1662
1736
  for (const mod of modules) {
1663
- mod.register(server2, client);
1737
+ mod.register(server, client);
1664
1738
  }
1665
1739
  }
1740
+ var modules;
1741
+ var init_tools = __esm({
1742
+ "src/tools/index.ts"() {
1743
+ "use strict";
1744
+ init_media();
1745
+ init_text();
1746
+ init_exports();
1747
+ init_folders();
1748
+ init_recorder();
1749
+ init_embed();
1750
+ init_prompt();
1751
+ init_meeting();
1752
+ init_fields();
1753
+ init_automations();
1754
+ init_webhooks();
1755
+ modules = [
1756
+ media_exports,
1757
+ text_exports,
1758
+ exports_exports,
1759
+ folders_exports,
1760
+ recorder_exports,
1761
+ embed_exports,
1762
+ prompt_exports,
1763
+ meeting_exports,
1764
+ fields_exports,
1765
+ automations_exports,
1766
+ webhooks_exports
1767
+ ];
1768
+ }
1769
+ });
1666
1770
 
1667
- // src/index.ts
1668
- var server = new import_mcp.McpServer({
1669
- name: "speak-ai",
1670
- version: "1.0.0"
1771
+ // src/cli/config.ts
1772
+ var config_exports = {};
1773
+ __export(config_exports, {
1774
+ getConfigPath: () => getConfigPath,
1775
+ loadConfig: () => loadConfig,
1776
+ resolveApiKey: () => resolveApiKey,
1777
+ resolveBaseUrl: () => resolveBaseUrl,
1778
+ saveConfig: () => saveConfig
1671
1779
  });
1672
- registerAllTools(server);
1673
- async function main() {
1674
- const transport = new import_stdio.StdioServerTransport();
1675
- await server.connect(transport);
1676
- process.stderr.write("[speak-mcp] Server started on stdio transport\n");
1780
+ function ensureDir() {
1781
+ if (!import_fs.default.existsSync(CONFIG_DIR)) {
1782
+ import_fs.default.mkdirSync(CONFIG_DIR, { recursive: true });
1783
+ }
1784
+ }
1785
+ function loadConfig() {
1786
+ try {
1787
+ if (import_fs.default.existsSync(CONFIG_FILE)) {
1788
+ return JSON.parse(import_fs.default.readFileSync(CONFIG_FILE, "utf-8"));
1789
+ }
1790
+ } catch {
1791
+ }
1792
+ return {};
1793
+ }
1794
+ function saveConfig(config) {
1795
+ ensureDir();
1796
+ import_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", {
1797
+ mode: 384
1798
+ // Owner read/write only
1799
+ });
1800
+ }
1801
+ function resolveApiKey() {
1802
+ if (process.env.SPEAK_API_KEY) return process.env.SPEAK_API_KEY;
1803
+ const config = loadConfig();
1804
+ if (config.apiKey) {
1805
+ process.env.SPEAK_API_KEY = config.apiKey;
1806
+ return config.apiKey;
1807
+ }
1808
+ return void 0;
1809
+ }
1810
+ function resolveBaseUrl() {
1811
+ if (process.env.SPEAK_BASE_URL) return process.env.SPEAK_BASE_URL;
1812
+ const config = loadConfig();
1813
+ if (config.baseUrl) {
1814
+ process.env.SPEAK_BASE_URL = config.baseUrl;
1815
+ return config.baseUrl;
1816
+ }
1817
+ return "https://api.speakai.co";
1818
+ }
1819
+ function getConfigPath() {
1820
+ return CONFIG_FILE;
1821
+ }
1822
+ var import_fs, import_path, import_os, CONFIG_DIR, CONFIG_FILE;
1823
+ var init_config = __esm({
1824
+ "src/cli/config.ts"() {
1825
+ "use strict";
1826
+ import_fs = __toESM(require("fs"));
1827
+ import_path = __toESM(require("path"));
1828
+ import_os = __toESM(require("os"));
1829
+ CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".speakai");
1830
+ CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
1831
+ }
1832
+ });
1833
+
1834
+ // src/cli/format.ts
1835
+ function printJson(data) {
1836
+ console.log(JSON.stringify(data, null, 2));
1837
+ }
1838
+ function printTable(rows, columns) {
1839
+ if (rows.length === 0) {
1840
+ console.log("No results found.");
1841
+ return;
1842
+ }
1843
+ const widths = columns.map((col) => {
1844
+ const maxData = rows.reduce(
1845
+ (max, row) => Math.max(max, String(row[col.key] ?? "").length),
1846
+ 0
1847
+ );
1848
+ return col.width ?? Math.max(col.label.length, Math.min(maxData, 50));
1849
+ });
1850
+ const header = columns.map((col, i) => col.label.padEnd(widths[i])).join(" ");
1851
+ console.log(header);
1852
+ console.log(widths.map((w) => "\u2500".repeat(w)).join("\u2500\u2500"));
1853
+ for (const row of rows) {
1854
+ const line = columns.map((col, i) => {
1855
+ const val = String(row[col.key] ?? "\u2014");
1856
+ return val.length > widths[i] ? val.slice(0, widths[i] - 1) + "\u2026" : val.padEnd(widths[i]);
1857
+ }).join(" ");
1858
+ console.log(line);
1859
+ }
1860
+ console.log(`
1861
+ ${rows.length} result${rows.length === 1 ? "" : "s"}`);
1677
1862
  }
1678
- main().catch((err) => {
1679
- process.stderr.write(`[speak-mcp] Fatal error: ${err}
1863
+ function printError(message) {
1864
+ console.error(`Error: ${message}`);
1865
+ }
1866
+ function printSuccess(message) {
1867
+ console.log(message);
1868
+ }
1869
+ var init_format = __esm({
1870
+ "src/cli/format.ts"() {
1871
+ "use strict";
1872
+ }
1873
+ });
1874
+
1875
+ // src/cli/index.ts
1876
+ var cli_exports = {};
1877
+ __export(cli_exports, {
1878
+ createCli: () => createCli
1879
+ });
1880
+ async function getClient() {
1881
+ const { speakClient: speakClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
1882
+ return speakClient2;
1883
+ }
1884
+ function requireApiKey() {
1885
+ const key = resolveApiKey();
1886
+ resolveBaseUrl();
1887
+ if (!key) {
1888
+ printError(
1889
+ 'No API key configured. Run "speak-mcp config set-key" or set SPEAK_API_KEY.'
1890
+ );
1891
+ process.exit(1);
1892
+ }
1893
+ }
1894
+ function createCli() {
1895
+ const program = new import_commander.Command();
1896
+ program.name("speak-mcp").description(
1897
+ "Speak AI CLI & MCP Server \u2014 transcribe, analyze, and manage media from the command line"
1898
+ ).version("1.0.0");
1899
+ const config = program.command("config").description("Manage configuration");
1900
+ config.command("set-key").description("Set your Speak AI API key").argument("[key]", "API key (omit for interactive prompt)").action(async (key) => {
1901
+ if (!key) {
1902
+ const rl = (0, import_readline.createInterface)({
1903
+ input: process.stdin,
1904
+ output: process.stdout
1905
+ });
1906
+ key = await new Promise(
1907
+ (resolve) => rl.question("Enter your Speak AI API key: ", (answer) => {
1908
+ rl.close();
1909
+ resolve(answer.trim());
1910
+ })
1911
+ );
1912
+ }
1913
+ if (!key) {
1914
+ printError("No key provided.");
1915
+ process.exit(1);
1916
+ }
1917
+ const cfg = loadConfig();
1918
+ cfg.apiKey = key;
1919
+ saveConfig(cfg);
1920
+ printSuccess(`API key saved to ${getConfigPath()}`);
1921
+ });
1922
+ config.command("show").description("Show current configuration").action(() => {
1923
+ const cfg = loadConfig();
1924
+ const envKey = process.env.SPEAK_API_KEY;
1925
+ console.log(`Config file: ${getConfigPath()}`);
1926
+ console.log(
1927
+ `API key: ${cfg.apiKey ? cfg.apiKey.slice(0, 8) + "..." : "(not set)"}`
1928
+ );
1929
+ console.log(
1930
+ `Base URL: ${cfg.baseUrl ?? "https://api.speakai.co (default)"}`
1931
+ );
1932
+ if (envKey) {
1933
+ console.log(
1934
+ `Env override: SPEAK_API_KEY=${envKey.slice(0, 8)}...`
1935
+ );
1936
+ }
1937
+ });
1938
+ config.command("set-url").description("Set custom API base URL").argument("<url>", "Base URL (e.g. https://api.speakai.co)").action((url) => {
1939
+ const cfg = loadConfig();
1940
+ cfg.baseUrl = url;
1941
+ saveConfig(cfg);
1942
+ printSuccess(`Base URL set to ${url}`);
1943
+ });
1944
+ program.command("list-media").alias("ls").description("List media files").option("-t, --type <type>", "Filter by type (audio, video, text)").option("-p, --page <n>", "Page number (0-based)", "0").option("-s, --page-size <n>", "Results per page", "20").option("--sort <field>", "Sort field", "createdAt:desc").option("-f, --folder <id>", "Filter by folder ID").option("-n, --name <filter>", "Filter by name").option("--favorites", "Show only favorites").option("--json", "Output raw JSON").action(async (opts) => {
1945
+ requireApiKey();
1946
+ const client = await getClient();
1947
+ try {
1948
+ const params = {
1949
+ page: parseInt(opts.page),
1950
+ pageSize: parseInt(opts.pageSize),
1951
+ sortBy: opts.sort,
1952
+ filterMedia: 2
1953
+ // 0=Uploaded, 1=Assigned, 2=Both
1954
+ };
1955
+ if (opts.type) params.mediaType = opts.type;
1956
+ if (opts.folder) params.folderId = opts.folder;
1957
+ if (opts.name) params.filterName = opts.name;
1958
+ if (opts.favorites) params.isFavorites = true;
1959
+ const res = await client.get("/v1/media", { params });
1960
+ const data = res.data?.data;
1961
+ if (opts.json) {
1962
+ printJson(data);
1963
+ return;
1964
+ }
1965
+ console.log(`Total: ${data.totalCount} | Page ${opts.page} of ${data.pages}
1680
1966
  `);
1681
- process.exit(1);
1967
+ printTable(data.mediaList ?? [], [
1968
+ { key: "_id", label: "ID", width: 14 },
1969
+ { key: "name", label: "Name", width: 40 },
1970
+ { key: "mediaType", label: "Type", width: 6 },
1971
+ { key: "state", label: "Status", width: 12 },
1972
+ { key: "createdAt", label: "Created", width: 20 }
1973
+ ]);
1974
+ } catch (err) {
1975
+ printError(err.response?.data?.message ?? err.message);
1976
+ process.exit(1);
1977
+ }
1978
+ });
1979
+ program.command("get-transcript").alias("transcript").description("Get transcript for a media file").argument("<mediaId>", "Media file ID").option("--json", "Output raw JSON").option("--plain", "Output plain text only (no timestamps)").action(async (mediaId, opts) => {
1980
+ requireApiKey();
1981
+ const client = await getClient();
1982
+ try {
1983
+ const res = await client.get(`/v1/media/transcript/${mediaId}`);
1984
+ const data = res.data?.data;
1985
+ if (opts.json) {
1986
+ printJson(data);
1987
+ return;
1988
+ }
1989
+ if (opts.plain) {
1990
+ const segments2 = data?.transcript ?? data ?? [];
1991
+ for (const seg of segments2) {
1992
+ console.log(seg.text ?? "");
1993
+ }
1994
+ return;
1995
+ }
1996
+ const segments = data?.transcript ?? data ?? [];
1997
+ let lastSpeaker = "";
1998
+ for (const seg of segments) {
1999
+ const speaker = seg.speakerId ?? "?";
2000
+ const start = seg.instances?.[0]?.start ?? "";
2001
+ const text = seg.text ?? "";
2002
+ if (speaker !== lastSpeaker) {
2003
+ console.log(`
2004
+ [Speaker ${speaker}] ${start}`);
2005
+ lastSpeaker = speaker;
2006
+ }
2007
+ process.stdout.write(text + " ");
2008
+ }
2009
+ console.log();
2010
+ } catch (err) {
2011
+ printError(err.response?.data?.message ?? err.message);
2012
+ process.exit(1);
2013
+ }
2014
+ });
2015
+ program.command("get-insights").alias("insights").description("Get AI-generated insights for a media file").argument("<mediaId>", "Media file ID").option("--json", "Output raw JSON").action(async (mediaId, opts) => {
2016
+ requireApiKey();
2017
+ const client = await getClient();
2018
+ try {
2019
+ const res = await client.get(`/v1/media/insight/${mediaId}`);
2020
+ const data = res.data?.data;
2021
+ if (opts.json) {
2022
+ printJson(data);
2023
+ return;
2024
+ }
2025
+ if (data?.summary) {
2026
+ console.log("\u2500\u2500 Summary \u2500\u2500");
2027
+ console.log(data.summary + "\n");
2028
+ }
2029
+ const categories = [
2030
+ "keywords",
2031
+ "topics",
2032
+ "people",
2033
+ "locations",
2034
+ "brands",
2035
+ "sentiment"
2036
+ ];
2037
+ for (const cat of categories) {
2038
+ const items = data?.[cat];
2039
+ if (items && Array.isArray(items) && items.length > 0) {
2040
+ console.log(`\u2500\u2500 ${cat.charAt(0).toUpperCase() + cat.slice(1)} \u2500\u2500`);
2041
+ for (const item of items.slice(0, 20)) {
2042
+ const name = typeof item === "string" ? item : item.name ?? item.text ?? JSON.stringify(item);
2043
+ console.log(` ${name}`);
2044
+ }
2045
+ if (items.length > 20) console.log(` ... and ${items.length - 20} more`);
2046
+ console.log();
2047
+ }
2048
+ }
2049
+ if (data?.sentiment && !Array.isArray(data.sentiment)) {
2050
+ console.log("\u2500\u2500 Sentiment \u2500\u2500");
2051
+ printJson(data.sentiment);
2052
+ console.log();
2053
+ }
2054
+ } catch (err) {
2055
+ printError(err.response?.data?.message ?? err.message);
2056
+ process.exit(1);
2057
+ }
2058
+ });
2059
+ program.command("upload").description("Upload media from a URL").argument("<url>", "Publicly accessible media URL").option("-n, --name <name>", "Display name").option("-t, --type <type>", "Media type (audio or video)", "audio").option("-l, --language <lang>", "Source language (BCP-47)", "en-US").option("-f, --folder <id>", "Destination folder ID").option("--tags <tags>", "Comma-separated tags").option("--wait", "Wait for processing to complete").option("--json", "Output raw JSON").action(async (url, opts) => {
2060
+ requireApiKey();
2061
+ const client = await getClient();
2062
+ try {
2063
+ const body = {
2064
+ name: opts.name ?? url.split("/").pop()?.split("?")[0] ?? "Upload",
2065
+ url,
2066
+ mediaType: opts.type,
2067
+ sourceLanguage: opts.language
2068
+ };
2069
+ if (opts.folder) body.folderId = opts.folder;
2070
+ if (opts.tags) body.tags = opts.tags;
2071
+ const res = await client.post("/v1/media/upload", body);
2072
+ const data = res.data?.data;
2073
+ if (opts.json && !opts.wait) {
2074
+ printJson(data);
2075
+ return;
2076
+ }
2077
+ const mediaId = data?.mediaId;
2078
+ printSuccess(`Uploaded: ${mediaId} (state: ${data?.state})`);
2079
+ if (opts.wait && mediaId) {
2080
+ process.stdout.write("Processing");
2081
+ let status = data?.state;
2082
+ while (status !== "processed" && status !== "failed") {
2083
+ await new Promise((r) => setTimeout(r, 5e3));
2084
+ process.stdout.write(".");
2085
+ const statusRes = await client.get(`/v1/media/status/${mediaId}`);
2086
+ status = statusRes.data?.data?.state;
2087
+ }
2088
+ console.log();
2089
+ if (status === "processed") {
2090
+ printSuccess(`Done! Media ${mediaId} is ready.`);
2091
+ } else {
2092
+ printError(`Processing failed for ${mediaId}`);
2093
+ process.exit(1);
2094
+ }
2095
+ }
2096
+ } catch (err) {
2097
+ printError(err.response?.data?.message ?? err.message);
2098
+ process.exit(1);
2099
+ }
2100
+ });
2101
+ program.command("export").description("Export media transcript/insights").argument("<mediaId>", "Media file ID").option(
2102
+ "-f, --format <type>",
2103
+ "Export format (pdf, docx, srt, vtt, txt, csv, md)",
2104
+ "txt"
2105
+ ).option("--speakers", "Include speaker names").option("--timestamps", "Include timestamps").option("--redacted", "Apply PII redaction").option("--json", "Output raw JSON").action(async (mediaId, opts) => {
2106
+ requireApiKey();
2107
+ const client = await getClient();
2108
+ try {
2109
+ const params = {};
2110
+ if (opts.speakers) params.isSpeakerNames = true;
2111
+ if (opts.timestamps) params.isTimeStamps = true;
2112
+ if (opts.redacted) params.isRedacted = true;
2113
+ const res = await client.post(
2114
+ `/v1/media/export/${mediaId}/${opts.format}`,
2115
+ null,
2116
+ { params }
2117
+ );
2118
+ if (opts.json) {
2119
+ printJson(res.data);
2120
+ } else {
2121
+ printJson(res.data?.data ?? res.data);
2122
+ }
2123
+ } catch (err) {
2124
+ printError(err.response?.data?.message ?? err.message);
2125
+ process.exit(1);
2126
+ }
2127
+ });
2128
+ program.command("status").description("Check processing status of a media file").argument("<mediaId>", "Media file ID").option("--json", "Output raw JSON").action(async (mediaId, opts) => {
2129
+ requireApiKey();
2130
+ const client = await getClient();
2131
+ try {
2132
+ const res = await client.get(`/v1/media/status/${mediaId}`);
2133
+ const data = res.data?.data;
2134
+ if (opts.json) {
2135
+ printJson(data);
2136
+ return;
2137
+ }
2138
+ console.log(`Name: ${data?.name ?? "\u2014"}`);
2139
+ console.log(`Status: ${data?.state ?? "\u2014"}`);
2140
+ console.log(`Type: ${data?.mediaType ?? "\u2014"}`);
2141
+ const dur = data?.duration;
2142
+ const durStr = dur?.inSecond ? `${Math.round(dur.inSecond)}s` : typeof dur === "number" ? `${Math.round(dur)}s` : "\u2014";
2143
+ console.log(`Duration: ${durStr}`);
2144
+ console.log(`Created: ${data?.createdAt ?? "\u2014"}`);
2145
+ } catch (err) {
2146
+ printError(err.response?.data?.message ?? err.message);
2147
+ process.exit(1);
2148
+ }
2149
+ });
2150
+ program.command("create-text").description("Create a text note for AI analysis").argument("<name>", "Note title").option("-t, --text <text>", "Text content (or pipe via stdin)").option("-f, --folder <id>", "Folder ID").option("--tags <tags>", "Comma-separated tags").option("--json", "Output raw JSON").action(async (name, opts) => {
2151
+ requireApiKey();
2152
+ const client = await getClient();
2153
+ try {
2154
+ let text = opts.text;
2155
+ if (!text && !process.stdin.isTTY) {
2156
+ const chunks = [];
2157
+ for await (const chunk of process.stdin) {
2158
+ chunks.push(chunk);
2159
+ }
2160
+ text = Buffer.concat(chunks).toString("utf-8").trim();
2161
+ }
2162
+ if (!text) {
2163
+ printError("Provide text via --text or pipe via stdin");
2164
+ process.exit(1);
2165
+ }
2166
+ const body = { name, text, rawText: text };
2167
+ if (opts.folder) body.folderId = opts.folder;
2168
+ if (opts.tags) body.tags = opts.tags;
2169
+ const res = await client.post("/v1/text/create", body);
2170
+ const data = res.data?.data;
2171
+ if (opts.json) {
2172
+ printJson(data);
2173
+ } else {
2174
+ printSuccess(`Created text note: ${data?.mediaId ?? data?._id}`);
2175
+ }
2176
+ } catch (err) {
2177
+ printError(err.response?.data?.message ?? err.message);
2178
+ process.exit(1);
2179
+ }
2180
+ });
2181
+ program.command("list-folders").alias("folders").description("List all folders").option("--json", "Output raw JSON").action(async (opts) => {
2182
+ requireApiKey();
2183
+ const client = await getClient();
2184
+ try {
2185
+ const res = await client.get("/v1/folder", {
2186
+ params: { page: 0, pageSize: 100, sortBy: "createdAt:desc" }
2187
+ });
2188
+ const data = res.data?.data;
2189
+ if (opts.json) {
2190
+ printJson(data);
2191
+ return;
2192
+ }
2193
+ const folders = Array.isArray(data) ? data : data?.folderList ?? data?.folders ?? [];
2194
+ printTable(folders, [
2195
+ { key: "_id", label: "ID", width: 14 },
2196
+ { key: "name", label: "Name", width: 40 },
2197
+ { key: "createdAt", label: "Created", width: 20 }
2198
+ ]);
2199
+ } catch (err) {
2200
+ printError(err.response?.data?.message ?? err.message);
2201
+ process.exit(1);
2202
+ }
2203
+ });
2204
+ program.command("ask").description("Ask an AI question about a media file").argument("<mediaId>", "Media file ID").argument("<prompt>", "Your question").option("--assistant <type>", "Assistant type (general, researcher, marketer, sales, recruiter)", "general").option("--json", "Output raw JSON").action(async (mediaId, prompt, opts) => {
2205
+ requireApiKey();
2206
+ const client = await getClient();
2207
+ try {
2208
+ const res = await client.post("/v1/prompt", {
2209
+ mediaIds: [mediaId],
2210
+ prompt,
2211
+ assistantType: opts.assistant
2212
+ });
2213
+ const data = res.data?.data;
2214
+ if (opts.json) {
2215
+ printJson(data);
2216
+ } else {
2217
+ console.log(data?.answer ?? data?.message ?? JSON.stringify(data, null, 2));
2218
+ }
2219
+ } catch (err) {
2220
+ printError(err.response?.data?.message ?? err.message);
2221
+ process.exit(1);
2222
+ }
2223
+ });
2224
+ program.command("schedule-meeting").description("Schedule AI assistant to join a meeting").argument("<url>", "Meeting URL (Zoom, Meet, Teams)").option("-t, --title <title>", "Meeting title").option("-d, --date <datetime>", "Meeting date/time (ISO 8601, omit to join now)").option("-l, --language <lang>", "Meeting language", "en-US").option("--json", "Output raw JSON").action(async (url, opts) => {
2225
+ requireApiKey();
2226
+ const client = await getClient();
2227
+ try {
2228
+ const body = {
2229
+ meetingURL: url,
2230
+ title: opts.title ?? "Meeting",
2231
+ meetingLanguage: opts.language
2232
+ };
2233
+ if (opts.date) body.meetingDate = opts.date;
2234
+ const res = await client.post(
2235
+ "/v1/meeting-assistant/events/schedule",
2236
+ body
2237
+ );
2238
+ const data = res.data?.data;
2239
+ if (opts.json) {
2240
+ printJson(data);
2241
+ } else {
2242
+ printSuccess(`Meeting scheduled: ${data?._id ?? "OK"}`);
2243
+ if (!opts.date) console.log("Assistant will join immediately.");
2244
+ }
2245
+ } catch (err) {
2246
+ printError(err.response?.data?.message ?? err.message);
2247
+ process.exit(1);
2248
+ }
2249
+ });
2250
+ return program;
2251
+ }
2252
+ var import_commander, import_readline;
2253
+ var init_cli = __esm({
2254
+ "src/cli/index.ts"() {
2255
+ "use strict";
2256
+ import_commander = require("commander");
2257
+ import_readline = require("readline");
2258
+ init_config();
2259
+ init_format();
2260
+ }
2261
+ });
2262
+
2263
+ // src/index.ts
2264
+ var index_exports = {};
2265
+ __export(index_exports, {
2266
+ createSpeakClient: () => createSpeakClient,
2267
+ formatAxiosError: () => formatAxiosError,
2268
+ registerAllTools: () => registerAllTools
1682
2269
  });
2270
+ module.exports = __toCommonJS(index_exports);
2271
+ init_tools();
2272
+ init_client();
2273
+ var args = process.argv.slice(2);
2274
+ var cliCommands = [
2275
+ "config",
2276
+ "list-media",
2277
+ "ls",
2278
+ "get-transcript",
2279
+ "transcript",
2280
+ "get-insights",
2281
+ "insights",
2282
+ "upload",
2283
+ "export",
2284
+ "status",
2285
+ "create-text",
2286
+ "list-folders",
2287
+ "folders",
2288
+ "ask",
2289
+ "schedule-meeting",
2290
+ "help"
2291
+ ];
2292
+ var isCliMode = args.length > 0 && (args[0].startsWith("-") || cliCommands.includes(args[0]));
2293
+ if (isCliMode) {
2294
+ Promise.resolve().then(() => (init_config(), config_exports)).then(({ resolveApiKey: resolveApiKey2, resolveBaseUrl: resolveBaseUrl2 }) => {
2295
+ resolveApiKey2();
2296
+ resolveBaseUrl2();
2297
+ Promise.resolve().then(() => (init_cli(), cli_exports)).then(({ createCli: createCli2 }) => {
2298
+ const program = createCli2();
2299
+ program.parseAsync(process.argv).catch((err) => {
2300
+ console.error(`Error: ${err.message}`);
2301
+ process.exit(1);
2302
+ });
2303
+ });
2304
+ });
2305
+ } else {
2306
+ import("@modelcontextprotocol/sdk/server/mcp.js").then(({ McpServer }) => {
2307
+ import("@modelcontextprotocol/sdk/server/stdio.js").then(
2308
+ ({ StdioServerTransport }) => {
2309
+ Promise.resolve().then(() => (init_tools(), tools_exports)).then(({ registerAllTools: registerAllTools2 }) => {
2310
+ const server = new McpServer({
2311
+ name: "speak-ai",
2312
+ version: "1.0.0"
2313
+ });
2314
+ registerAllTools2(server);
2315
+ const transport = new StdioServerTransport();
2316
+ server.connect(transport).then(() => {
2317
+ process.stderr.write(
2318
+ "[speak-mcp] Server started on stdio transport\n"
2319
+ );
2320
+ });
2321
+ });
2322
+ }
2323
+ );
2324
+ });
2325
+ }
1683
2326
  // Annotate the CommonJS export names for ESM import in node:
1684
2327
  0 && (module.exports = {
1685
2328
  createSpeakClient,