@speakai/mcp-server 1.2.0 → 1.3.1

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 (3) hide show
  1. package/README.md +246 -79
  2. package/dist/index.js +644 -93
  3. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -119,17 +119,35 @@ function createSpeakClient(options) {
119
119
  timeout: 6e4
120
120
  });
121
121
  }
122
+ function redactValue(value, depth = 0) {
123
+ if (depth > 4) return "[truncated]";
124
+ if (typeof value === "string") {
125
+ return value.length > MAX_STRING_LEN ? value.slice(0, MAX_STRING_LEN) + "\u2026" : value;
126
+ }
127
+ if (Array.isArray(value)) {
128
+ return value.slice(0, 20).map((v) => redactValue(v, depth + 1));
129
+ }
130
+ if (value && typeof value === "object") {
131
+ const out = {};
132
+ for (const [k, v] of Object.entries(value)) {
133
+ out[k] = SENSITIVE_KEY_PATTERN.test(k) ? "[redacted]" : redactValue(v, depth + 1);
134
+ }
135
+ return out;
136
+ }
137
+ return value;
138
+ }
122
139
  function formatAxiosError(error) {
123
140
  if (import_axios.default.isAxiosError(error)) {
124
141
  const status = error.response?.status;
125
142
  const data = error.response?.data;
126
- const message = typeof data === "object" && data !== null ? JSON.stringify(data, null, 2) : String(data ?? error.message);
143
+ const safe = redactValue(data);
144
+ const message = typeof safe === "object" && safe !== null ? JSON.stringify(safe, null, 2) : String(safe ?? error.message);
127
145
  return status ? `HTTP ${status}: ${message}` : `Request failed: ${message}`;
128
146
  }
129
147
  if (error instanceof Error) return error.message;
130
148
  return String(error);
131
149
  }
132
- var import_axios, accessToken, refreshToken, tokenExpiresAt, speakClient;
150
+ var import_axios, accessToken, refreshToken, tokenExpiresAt, speakClient, SENSITIVE_KEY_PATTERN, MAX_STRING_LEN;
133
151
  var init_client = __esm({
134
152
  "src/client.ts"() {
135
153
  "use strict";
@@ -179,6 +197,8 @@ var init_client = __esm({
179
197
  return Promise.reject(error);
180
198
  }
181
199
  );
200
+ SENSITIVE_KEY_PATTERN = /(token|secret|password|cookie|authorization|jwt|apikey|api[_-]?key|bearer|signature)/i;
201
+ MAX_STRING_LEN = 500;
182
202
  }
183
203
  });
184
204
 
@@ -1090,6 +1110,13 @@ function register(server, client) {
1090
1110
  filename: import_zod.z.string().min(1).describe("Original filename including extension"),
1091
1111
  mimeType: import_zod.z.string().describe('MIME type of the file, e.g. "audio/mp4" or "video/mp4"')
1092
1112
  },
1113
+ {
1114
+ title: "Get Signed Upload URL",
1115
+ readOnlyHint: true,
1116
+ destructiveHint: false,
1117
+ idempotentHint: false,
1118
+ openWorldHint: true
1119
+ },
1093
1120
  async ({ isVideo, filename, mimeType }) => {
1094
1121
  try {
1095
1122
  const result = await api.get("/v1/media/upload/signedurl", {
@@ -1127,6 +1154,13 @@ function register(server, client) {
1127
1154
  })
1128
1155
  ).optional().describe("Custom field values to attach to the media")
1129
1156
  },
1157
+ {
1158
+ title: "Upload Media from URL",
1159
+ readOnlyHint: false,
1160
+ destructiveHint: false,
1161
+ idempotentHint: false,
1162
+ openWorldHint: true
1163
+ },
1130
1164
  async (body) => {
1131
1165
  try {
1132
1166
  const result = await api.post("/v1/media/upload", body);
@@ -1170,6 +1204,13 @@ function register(server, client) {
1170
1204
  "Additional data to include with each media item. Without this, only metadata is returned. Use 'transcription' to include full transcripts inline, 'speakers' for speaker details, 'keywords' for extracted keywords, etc. Avoids N+1 API calls when you need data for multiple files."
1171
1205
  )
1172
1206
  },
1207
+ {
1208
+ title: "List Media Files",
1209
+ readOnlyHint: true,
1210
+ destructiveHint: false,
1211
+ idempotentHint: true,
1212
+ openWorldHint: true
1213
+ },
1173
1214
  async ({ include, ...params }) => {
1174
1215
  try {
1175
1216
  const queryParams = { ...params };
@@ -1196,6 +1237,13 @@ function register(server, client) {
1196
1237
  {
1197
1238
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
1198
1239
  },
1240
+ {
1241
+ title: "Get Media Insights",
1242
+ readOnlyHint: true,
1243
+ destructiveHint: false,
1244
+ idempotentHint: true,
1245
+ openWorldHint: true
1246
+ },
1199
1247
  async ({ mediaId }) => {
1200
1248
  try {
1201
1249
  const result = await api.get(`/v1/media/insight/${mediaId}`);
@@ -1218,6 +1266,13 @@ function register(server, client) {
1218
1266
  {
1219
1267
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
1220
1268
  },
1269
+ {
1270
+ title: "Get Transcript",
1271
+ readOnlyHint: true,
1272
+ destructiveHint: false,
1273
+ idempotentHint: true,
1274
+ openWorldHint: true
1275
+ },
1221
1276
  async ({ mediaId }) => {
1222
1277
  try {
1223
1278
  const result = await api.get(`/v1/media/transcript/${mediaId}`);
@@ -1246,6 +1301,13 @@ function register(server, client) {
1246
1301
  })
1247
1302
  ).describe("Array of speaker ID to name mappings")
1248
1303
  },
1304
+ {
1305
+ title: "Rename Transcript Speakers",
1306
+ readOnlyHint: false,
1307
+ destructiveHint: true,
1308
+ idempotentHint: true,
1309
+ openWorldHint: true
1310
+ },
1249
1311
  async ({ mediaId, speakers }) => {
1250
1312
  try {
1251
1313
  const result = await api.put(
@@ -1271,6 +1333,13 @@ function register(server, client) {
1271
1333
  {
1272
1334
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
1273
1335
  },
1336
+ {
1337
+ title: "Get Media Status",
1338
+ readOnlyHint: true,
1339
+ destructiveHint: false,
1340
+ idempotentHint: true,
1341
+ openWorldHint: true
1342
+ },
1274
1343
  async ({ mediaId }) => {
1275
1344
  try {
1276
1345
  const result = await api.get(`/v1/media/status/${mediaId}`);
@@ -1300,6 +1369,13 @@ function register(server, client) {
1300
1369
  remark: import_zod.z.string().optional().describe("Internal remark or note"),
1301
1370
  manageBy: import_zod.z.string().optional().describe("User ID to assign management of this media to")
1302
1371
  },
1372
+ {
1373
+ title: "Update Media Metadata",
1374
+ readOnlyHint: false,
1375
+ destructiveHint: false,
1376
+ idempotentHint: true,
1377
+ openWorldHint: true
1378
+ },
1303
1379
  async ({ mediaId, ...body }) => {
1304
1380
  try {
1305
1381
  const result = await api.put(`/v1/media/${mediaId}`, body);
@@ -1322,6 +1398,13 @@ function register(server, client) {
1322
1398
  {
1323
1399
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file to delete")
1324
1400
  },
1401
+ {
1402
+ title: "Delete Media File",
1403
+ readOnlyHint: false,
1404
+ destructiveHint: true,
1405
+ idempotentHint: true,
1406
+ openWorldHint: true
1407
+ },
1325
1408
  async ({ mediaId }) => {
1326
1409
  try {
1327
1410
  const result = await api.delete(`/v1/media/${mediaId}`);
@@ -1344,6 +1427,13 @@ function register(server, client) {
1344
1427
  {
1345
1428
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
1346
1429
  },
1430
+ {
1431
+ title: "Get Captions",
1432
+ readOnlyHint: true,
1433
+ destructiveHint: false,
1434
+ idempotentHint: true,
1435
+ openWorldHint: true
1436
+ },
1347
1437
  async ({ mediaId }) => {
1348
1438
  try {
1349
1439
  const result = await api.get(`/v1/media/caption/${mediaId}`);
@@ -1364,6 +1454,13 @@ function register(server, client) {
1364
1454
  "list_supported_languages",
1365
1455
  "List all languages supported for transcription. Use the language codes when uploading media with a specific sourceLanguage.",
1366
1456
  {},
1457
+ {
1458
+ title: "List Supported Languages",
1459
+ readOnlyHint: true,
1460
+ destructiveHint: false,
1461
+ idempotentHint: true,
1462
+ openWorldHint: true
1463
+ },
1367
1464
  async () => {
1368
1465
  try {
1369
1466
  const result = await api.get("/v1/media/supportedLanguages");
@@ -1384,6 +1481,13 @@ function register(server, client) {
1384
1481
  "get_media_statistics",
1385
1482
  "Get workspace-level media statistics \u2014 total counts, processing status breakdown, storage usage, etc.",
1386
1483
  {},
1484
+ {
1485
+ title: "Get Media Statistics",
1486
+ readOnlyHint: true,
1487
+ destructiveHint: false,
1488
+ idempotentHint: true,
1489
+ openWorldHint: true
1490
+ },
1387
1491
  async () => {
1388
1492
  try {
1389
1493
  const result = await api.get("/v1/media/statistics");
@@ -1406,6 +1510,13 @@ function register(server, client) {
1406
1510
  {
1407
1511
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file")
1408
1512
  },
1513
+ {
1514
+ title: "Toggle Media Favorite",
1515
+ readOnlyHint: false,
1516
+ destructiveHint: false,
1517
+ idempotentHint: true,
1518
+ openWorldHint: true
1519
+ },
1409
1520
  async (body) => {
1410
1521
  try {
1411
1522
  const result = await api.post("/v1/media/favorites", body);
@@ -1428,6 +1539,13 @@ function register(server, client) {
1428
1539
  {
1429
1540
  mediaId: import_zod.z.string().min(1).describe("Unique identifier of the media file to re-analyze")
1430
1541
  },
1542
+ {
1543
+ title: "Re-analyze Media",
1544
+ readOnlyHint: false,
1545
+ destructiveHint: false,
1546
+ idempotentHint: false,
1547
+ openWorldHint: true
1548
+ },
1431
1549
  async ({ mediaId }) => {
1432
1550
  try {
1433
1551
  const result = await api.post(`/v1/media/reanalyze/${mediaId}`, {});
@@ -1456,6 +1574,13 @@ function register(server, client) {
1456
1574
  })
1457
1575
  ).describe("Array of speaker ID to name mappings to apply to all specified media files")
1458
1576
  },
1577
+ {
1578
+ title: "Bulk Rename Speakers Across Files",
1579
+ readOnlyHint: false,
1580
+ destructiveHint: true,
1581
+ idempotentHint: true,
1582
+ openWorldHint: true
1583
+ },
1459
1584
  async ({ mediaIds, speakers }) => {
1460
1585
  const results = [];
1461
1586
  for (const mediaId of mediaIds) {
@@ -1490,6 +1615,13 @@ function register(server, client) {
1490
1615
  folderId: import_zod.z.string().min(1).describe("Target folder ID to move media into"),
1491
1616
  mediaIds: import_zod.z.array(import_zod.z.string().min(1)).min(1).describe("Array of media IDs to move")
1492
1617
  },
1618
+ {
1619
+ title: "Bulk Move Media Files",
1620
+ readOnlyHint: false,
1621
+ destructiveHint: true,
1622
+ idempotentHint: false,
1623
+ openWorldHint: true
1624
+ },
1493
1625
  async (body) => {
1494
1626
  try {
1495
1627
  const result = await api.put("/v1/media/move", body);
@@ -1541,6 +1673,13 @@ function register2(server, client) {
1541
1673
  })
1542
1674
  ).optional().describe("Custom field values to attach to the text note")
1543
1675
  },
1676
+ {
1677
+ title: "Create Text Note",
1678
+ readOnlyHint: false,
1679
+ destructiveHint: false,
1680
+ idempotentHint: false,
1681
+ openWorldHint: true
1682
+ },
1544
1683
  async (body) => {
1545
1684
  try {
1546
1685
  const result = await api.post("/v1/text/create", body);
@@ -1563,6 +1702,13 @@ function register2(server, client) {
1563
1702
  {
1564
1703
  mediaId: import_zod2.z.string().min(1).describe("Unique identifier of the text note")
1565
1704
  },
1705
+ {
1706
+ title: "Get Text Note Insights",
1707
+ readOnlyHint: true,
1708
+ destructiveHint: false,
1709
+ idempotentHint: true,
1710
+ openWorldHint: true
1711
+ },
1566
1712
  async ({ mediaId }) => {
1567
1713
  try {
1568
1714
  const result = await api.get(`/v1/text/insight/${mediaId}`);
@@ -1585,6 +1731,13 @@ function register2(server, client) {
1585
1731
  {
1586
1732
  mediaId: import_zod2.z.string().describe("Unique identifier of the text note to reanalyze")
1587
1733
  },
1734
+ {
1735
+ title: "Re-analyze Text Note",
1736
+ readOnlyHint: false,
1737
+ destructiveHint: false,
1738
+ idempotentHint: false,
1739
+ openWorldHint: true
1740
+ },
1588
1741
  async ({ mediaId }) => {
1589
1742
  try {
1590
1743
  const result = await api.get(`/v1/text/reanalyze/${mediaId}`);
@@ -1612,6 +1765,13 @@ function register2(server, client) {
1612
1765
  folderId: import_zod2.z.string().optional().describe("Move to a different folder"),
1613
1766
  tags: import_zod2.z.string().optional().describe("Updated comma-separated tags")
1614
1767
  },
1768
+ {
1769
+ title: "Update Text Note",
1770
+ readOnlyHint: false,
1771
+ destructiveHint: true,
1772
+ idempotentHint: true,
1773
+ openWorldHint: true
1774
+ },
1615
1775
  async ({ mediaId, ...body }) => {
1616
1776
  try {
1617
1777
  const result = await api.put(
@@ -1661,6 +1821,13 @@ function register3(server, client) {
1661
1821
  isRedacted: import_zod3.z.boolean().optional().describe("Apply PII redaction to export"),
1662
1822
  redactedCategories: import_zod3.z.array(import_zod3.z.string()).optional().describe("Specific categories to redact")
1663
1823
  },
1824
+ {
1825
+ title: "Export Media Transcript",
1826
+ readOnlyHint: true,
1827
+ destructiveHint: false,
1828
+ idempotentHint: true,
1829
+ openWorldHint: true
1830
+ },
1664
1831
  async ({ mediaId, fileType, ...body }) => {
1665
1832
  try {
1666
1833
  const result = await api.post(
@@ -1694,6 +1861,13 @@ function register3(server, client) {
1694
1861
  isMerged: import_zod3.z.boolean().optional().describe("Merge all exports into a single file"),
1695
1862
  folderId: import_zod3.z.string().optional().describe("Folder ID for the merged export")
1696
1863
  },
1864
+ {
1865
+ title: "Export Multiple Media Files",
1866
+ readOnlyHint: true,
1867
+ destructiveHint: false,
1868
+ idempotentHint: true,
1869
+ openWorldHint: true
1870
+ },
1697
1871
  async (body) => {
1698
1872
  try {
1699
1873
  const result = await api.post(
@@ -1734,6 +1908,13 @@ function register4(server, client) {
1734
1908
  "get_all_folder_views",
1735
1909
  "Retrieve all saved views across all folders.",
1736
1910
  {},
1911
+ {
1912
+ title: "Get All Folder Views",
1913
+ readOnlyHint: true,
1914
+ destructiveHint: false,
1915
+ idempotentHint: true,
1916
+ openWorldHint: true
1917
+ },
1737
1918
  async () => {
1738
1919
  try {
1739
1920
  const result = await api.get("/v1/folders/views");
@@ -1756,6 +1937,13 @@ function register4(server, client) {
1756
1937
  {
1757
1938
  folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder")
1758
1939
  },
1940
+ {
1941
+ title: "Get Folder Views",
1942
+ readOnlyHint: true,
1943
+ destructiveHint: false,
1944
+ idempotentHint: true,
1945
+ openWorldHint: true
1946
+ },
1759
1947
  async ({ folderId }) => {
1760
1948
  try {
1761
1949
  const result = await api.get(`/v1/folders/${folderId}/views`);
@@ -1780,6 +1968,13 @@ function register4(server, client) {
1780
1968
  name: import_zod4.z.string().optional().describe("Display name for the view"),
1781
1969
  filters: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("Filter configuration object")
1782
1970
  },
1971
+ {
1972
+ title: "Create Folder View",
1973
+ readOnlyHint: false,
1974
+ destructiveHint: false,
1975
+ idempotentHint: false,
1976
+ openWorldHint: true
1977
+ },
1783
1978
  async ({ folderId, ...body }) => {
1784
1979
  try {
1785
1980
  const result = await api.post(
@@ -1808,6 +2003,13 @@ function register4(server, client) {
1808
2003
  name: import_zod4.z.string().optional().describe("New display name for the view"),
1809
2004
  filters: import_zod4.z.record(import_zod4.z.unknown()).optional().describe("Updated filter configuration")
1810
2005
  },
2006
+ {
2007
+ title: "Update Folder View",
2008
+ readOnlyHint: false,
2009
+ destructiveHint: false,
2010
+ idempotentHint: true,
2011
+ openWorldHint: true
2012
+ },
1811
2013
  async ({ folderId, viewId, ...body }) => {
1812
2014
  try {
1813
2015
  const result = await api.put(
@@ -1833,6 +2035,13 @@ function register4(server, client) {
1833
2035
  {
1834
2036
  viewId: import_zod4.z.string().min(1).describe("Unique identifier of the view to clone")
1835
2037
  },
2038
+ {
2039
+ title: "Clone Folder View",
2040
+ readOnlyHint: false,
2041
+ destructiveHint: false,
2042
+ idempotentHint: false,
2043
+ openWorldHint: true
2044
+ },
1836
2045
  async (body) => {
1837
2046
  try {
1838
2047
  const result = await api.post("/v1/folders/views/clone", body);
@@ -1857,6 +2066,13 @@ function register4(server, client) {
1857
2066
  pageSize: import_zod4.z.number().int().min(1).max(500).optional().describe("Results per page (default: 20, max: 500)"),
1858
2067
  sortBy: import_zod4.z.string().optional().describe('Sort field and direction, e.g. "createdAt:desc"')
1859
2068
  },
2069
+ {
2070
+ title: "List Folders",
2071
+ readOnlyHint: true,
2072
+ destructiveHint: false,
2073
+ idempotentHint: true,
2074
+ openWorldHint: true
2075
+ },
1860
2076
  async (params) => {
1861
2077
  try {
1862
2078
  const result = await api.get("/v1/folder", { params });
@@ -1879,6 +2095,13 @@ function register4(server, client) {
1879
2095
  {
1880
2096
  folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder")
1881
2097
  },
2098
+ {
2099
+ title: "Get Folder Info",
2100
+ readOnlyHint: true,
2101
+ destructiveHint: false,
2102
+ idempotentHint: true,
2103
+ openWorldHint: true
2104
+ },
1882
2105
  async ({ folderId }) => {
1883
2106
  try {
1884
2107
  const result = await api.get(`/v1/folder/${folderId}`);
@@ -1902,6 +2125,13 @@ function register4(server, client) {
1902
2125
  name: import_zod4.z.string().min(1).describe("Display name for the new folder"),
1903
2126
  parentFolderId: import_zod4.z.string().optional().describe("ID of the parent folder for nesting")
1904
2127
  },
2128
+ {
2129
+ title: "Create Folder",
2130
+ readOnlyHint: false,
2131
+ destructiveHint: false,
2132
+ idempotentHint: false,
2133
+ openWorldHint: true
2134
+ },
1905
2135
  async (body) => {
1906
2136
  try {
1907
2137
  const result = await api.post("/v1/folder", body);
@@ -1924,6 +2154,13 @@ function register4(server, client) {
1924
2154
  {
1925
2155
  folderId: import_zod4.z.string().min(1).describe("ID of the folder to clone")
1926
2156
  },
2157
+ {
2158
+ title: "Clone Folder",
2159
+ readOnlyHint: false,
2160
+ destructiveHint: false,
2161
+ idempotentHint: false,
2162
+ openWorldHint: true
2163
+ },
1927
2164
  async (body) => {
1928
2165
  try {
1929
2166
  const result = await api.post("/v1/folder/clone", body);
@@ -1947,6 +2184,13 @@ function register4(server, client) {
1947
2184
  folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder"),
1948
2185
  name: import_zod4.z.string().optional().describe("New display name for the folder")
1949
2186
  },
2187
+ {
2188
+ title: "Update Folder",
2189
+ readOnlyHint: false,
2190
+ destructiveHint: false,
2191
+ idempotentHint: true,
2192
+ openWorldHint: true
2193
+ },
1950
2194
  async ({ folderId, ...body }) => {
1951
2195
  try {
1952
2196
  const result = await api.put(`/v1/folder/${folderId}`, body);
@@ -1969,6 +2213,13 @@ function register4(server, client) {
1969
2213
  {
1970
2214
  folderId: import_zod4.z.string().min(1).describe("Unique identifier of the folder to delete")
1971
2215
  },
2216
+ {
2217
+ title: "Delete Folder",
2218
+ readOnlyHint: false,
2219
+ destructiveHint: true,
2220
+ idempotentHint: true,
2221
+ openWorldHint: true
2222
+ },
1972
2223
  async ({ folderId }) => {
1973
2224
  try {
1974
2225
  const result = await api.delete(`/v1/folder/${folderId}`);
@@ -2008,6 +2259,13 @@ function register5(server, client) {
2008
2259
  {
2009
2260
  token: import_zod5.z.string().min(1).describe("Unique token identifying the recorder")
2010
2261
  },
2262
+ {
2263
+ title: "Check Recorder Status",
2264
+ readOnlyHint: true,
2265
+ destructiveHint: false,
2266
+ idempotentHint: true,
2267
+ openWorldHint: true
2268
+ },
2011
2269
  async ({ token }) => {
2012
2270
  try {
2013
2271
  const result = await api.get(`/v1/recorder/status/${token}`);
@@ -2030,6 +2288,13 @@ function register5(server, client) {
2030
2288
  folderId: import_zod5.z.string().optional().describe("Folder to store recordings in"),
2031
2289
  settings: import_zod5.z.record(import_zod5.z.unknown()).optional().describe("Recorder configuration settings")
2032
2290
  },
2291
+ {
2292
+ title: "Create Recorder",
2293
+ readOnlyHint: false,
2294
+ destructiveHint: false,
2295
+ idempotentHint: false,
2296
+ openWorldHint: true
2297
+ },
2033
2298
  async (body) => {
2034
2299
  try {
2035
2300
  const result = await api.post("/v1/recorder/create", body);
@@ -2052,6 +2317,13 @@ function register5(server, client) {
2052
2317
  pageSize: import_zod5.z.number().int().min(1).max(500).optional().describe("Results per page (default: 20, max: 500)"),
2053
2318
  sortBy: import_zod5.z.string().optional().describe('Sort field, e.g. "createdAt:desc"')
2054
2319
  },
2320
+ {
2321
+ title: "List Recorders",
2322
+ readOnlyHint: true,
2323
+ destructiveHint: false,
2324
+ idempotentHint: true,
2325
+ openWorldHint: true
2326
+ },
2055
2327
  async (params) => {
2056
2328
  try {
2057
2329
  const result = await api.get("/v1/recorder", { params });
@@ -2072,6 +2344,13 @@ function register5(server, client) {
2072
2344
  {
2073
2345
  recorderId: import_zod5.z.string().min(1).describe("ID of the recorder to clone")
2074
2346
  },
2347
+ {
2348
+ title: "Clone Recorder",
2349
+ readOnlyHint: false,
2350
+ destructiveHint: false,
2351
+ idempotentHint: false,
2352
+ openWorldHint: true
2353
+ },
2075
2354
  async (body) => {
2076
2355
  try {
2077
2356
  const result = await api.post("/v1/recorder/clone", body);
@@ -2092,6 +2371,13 @@ function register5(server, client) {
2092
2371
  {
2093
2372
  recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder")
2094
2373
  },
2374
+ {
2375
+ title: "Get Recorder Info",
2376
+ readOnlyHint: true,
2377
+ destructiveHint: false,
2378
+ idempotentHint: true,
2379
+ openWorldHint: true
2380
+ },
2095
2381
  async ({ recorderId }) => {
2096
2382
  try {
2097
2383
  const result = await api.get(`/v1/recorder/${recorderId}`);
@@ -2112,6 +2398,13 @@ function register5(server, client) {
2112
2398
  {
2113
2399
  recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder")
2114
2400
  },
2401
+ {
2402
+ title: "Get Recorder Submissions",
2403
+ readOnlyHint: true,
2404
+ destructiveHint: false,
2405
+ idempotentHint: true,
2406
+ openWorldHint: true
2407
+ },
2115
2408
  async ({ recorderId }) => {
2116
2409
  try {
2117
2410
  const result = await api.get(`/v1/recorder/recordings/${recorderId}`);
@@ -2132,6 +2425,13 @@ function register5(server, client) {
2132
2425
  {
2133
2426
  recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder")
2134
2427
  },
2428
+ {
2429
+ title: "Generate Recorder Share URL",
2430
+ readOnlyHint: true,
2431
+ destructiveHint: false,
2432
+ idempotentHint: true,
2433
+ openWorldHint: true
2434
+ },
2135
2435
  async ({ recorderId }) => {
2136
2436
  try {
2137
2437
  const result = await api.get(`/v1/recorder/url/${recorderId}`);
@@ -2153,6 +2453,13 @@ function register5(server, client) {
2153
2453
  recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder"),
2154
2454
  settings: import_zod5.z.record(import_zod5.z.unknown()).describe("Settings object with updated values")
2155
2455
  },
2456
+ {
2457
+ title: "Update Recorder Settings",
2458
+ readOnlyHint: false,
2459
+ destructiveHint: false,
2460
+ idempotentHint: true,
2461
+ openWorldHint: true
2462
+ },
2156
2463
  async ({ recorderId, settings }) => {
2157
2464
  try {
2158
2465
  const result = await api.put(`/v1/recorder/settings/${recorderId}`, settings);
@@ -2174,6 +2481,13 @@ function register5(server, client) {
2174
2481
  recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder"),
2175
2482
  questions: import_zod5.z.array(import_zod5.z.record(import_zod5.z.unknown())).describe("Array of question objects")
2176
2483
  },
2484
+ {
2485
+ title: "Update Recorder Questions",
2486
+ readOnlyHint: false,
2487
+ destructiveHint: true,
2488
+ idempotentHint: true,
2489
+ openWorldHint: true
2490
+ },
2177
2491
  async ({ recorderId, questions }) => {
2178
2492
  try {
2179
2493
  const result = await api.put(`/v1/recorder/questions/${recorderId}`, { questions });
@@ -2194,6 +2508,13 @@ function register5(server, client) {
2194
2508
  {
2195
2509
  recorderId: import_zod5.z.string().min(1).describe("Unique identifier of the recorder to delete")
2196
2510
  },
2511
+ {
2512
+ title: "Delete Recorder",
2513
+ readOnlyHint: false,
2514
+ destructiveHint: true,
2515
+ idempotentHint: true,
2516
+ openWorldHint: true
2517
+ },
2197
2518
  async ({ recorderId }) => {
2198
2519
  try {
2199
2520
  const result = await api.delete(`/v1/recorder/${recorderId}`);
@@ -2232,6 +2553,13 @@ function register6(server, client) {
2232
2553
  mediaId: import_zod6.z.string().min(1).describe("Unique identifier of the media file"),
2233
2554
  settings: import_zod6.z.record(import_zod6.z.unknown()).optional().describe("Embed configuration settings")
2234
2555
  },
2556
+ {
2557
+ title: "Create Embed Widget",
2558
+ readOnlyHint: false,
2559
+ destructiveHint: false,
2560
+ idempotentHint: false,
2561
+ openWorldHint: true
2562
+ },
2235
2563
  async (body) => {
2236
2564
  try {
2237
2565
  const result = await api.post("/v1/embed", body);
@@ -2253,6 +2581,13 @@ function register6(server, client) {
2253
2581
  embedId: import_zod6.z.string().min(1).describe("Unique identifier of the embed"),
2254
2582
  settings: import_zod6.z.record(import_zod6.z.unknown()).optional().describe("Updated embed settings")
2255
2583
  },
2584
+ {
2585
+ title: "Update Embed Widget",
2586
+ readOnlyHint: false,
2587
+ destructiveHint: false,
2588
+ idempotentHint: true,
2589
+ openWorldHint: true
2590
+ },
2256
2591
  async ({ embedId, ...body }) => {
2257
2592
  try {
2258
2593
  const result = await api.put(`/v1/embed/${embedId}`, body);
@@ -2273,6 +2608,13 @@ function register6(server, client) {
2273
2608
  {
2274
2609
  mediaId: import_zod6.z.string().min(1).describe("Unique identifier of the media file")
2275
2610
  },
2611
+ {
2612
+ title: "Check Embed Exists",
2613
+ readOnlyHint: true,
2614
+ destructiveHint: false,
2615
+ idempotentHint: true,
2616
+ openWorldHint: true
2617
+ },
2276
2618
  async ({ mediaId }) => {
2277
2619
  try {
2278
2620
  const result = await api.get(`/v1/embed/${mediaId}`);
@@ -2293,6 +2635,13 @@ function register6(server, client) {
2293
2635
  {
2294
2636
  mediaId: import_zod6.z.string().min(1).describe("Unique identifier of the media file")
2295
2637
  },
2638
+ {
2639
+ title: "Get Embed Iframe URL",
2640
+ readOnlyHint: true,
2641
+ destructiveHint: false,
2642
+ idempotentHint: true,
2643
+ openWorldHint: true
2644
+ },
2296
2645
  async ({ mediaId }) => {
2297
2646
  try {
2298
2647
  const result = await api.get("/v1/embed/iframe", {
@@ -2350,6 +2699,13 @@ function register7(server, client) {
2350
2699
  endDate: import_zod7.z.string().optional().describe("End date for date range filter (ISO 8601, e.g., '2025-03-31')"),
2351
2700
  isIndividualPrompt: import_zod7.z.boolean().optional().describe("When true, processes each media file separately instead of combining context. Useful for comparing responses across files.")
2352
2701
  },
2702
+ {
2703
+ title: "Ask AI About Your Recordings",
2704
+ readOnlyHint: true,
2705
+ destructiveHint: false,
2706
+ idempotentHint: false,
2707
+ openWorldHint: true
2708
+ },
2353
2709
  async (params) => {
2354
2710
  try {
2355
2711
  const result = await api.post("/v1/prompt", params);
@@ -2371,6 +2727,13 @@ function register7(server, client) {
2371
2727
  promptId: import_zod7.z.string().min(1).describe("ID of the conversation containing the failed message"),
2372
2728
  messageId: import_zod7.z.string().min(1).describe("ID of the specific message to retry")
2373
2729
  },
2730
+ {
2731
+ title: "Retry AI Question",
2732
+ readOnlyHint: true,
2733
+ destructiveHint: false,
2734
+ idempotentHint: false,
2735
+ openWorldHint: true
2736
+ },
2374
2737
  async (body) => {
2375
2738
  try {
2376
2739
  const result = await api.post("/v1/prompt/retry", body);
@@ -2391,6 +2754,13 @@ function register7(server, client) {
2391
2754
  {
2392
2755
  limit: import_zod7.z.number().int().positive().optional().describe("Number of recent conversations to return (default: 10)")
2393
2756
  },
2757
+ {
2758
+ title: "Get Chat History",
2759
+ readOnlyHint: true,
2760
+ destructiveHint: false,
2761
+ idempotentHint: true,
2762
+ openWorldHint: true
2763
+ },
2394
2764
  async ({ limit }) => {
2395
2765
  try {
2396
2766
  const result = await api.get("/v1/prompt/history", {
@@ -2418,6 +2788,13 @@ function register7(server, client) {
2418
2788
  page: import_zod7.z.number().int().min(0).optional().describe("Page number for pagination (0-based, default: 0)"),
2419
2789
  pageSize: import_zod7.z.number().int().min(1).max(500).optional().describe("Results per page (default: 25, max: 500)")
2420
2790
  },
2791
+ {
2792
+ title: "Get Chat Messages",
2793
+ readOnlyHint: true,
2794
+ destructiveHint: false,
2795
+ idempotentHint: true,
2796
+ openWorldHint: true
2797
+ },
2421
2798
  async (params) => {
2422
2799
  try {
2423
2800
  const result = await api.get("/v1/prompt/messages", { params });
@@ -2438,6 +2815,13 @@ function register7(server, client) {
2438
2815
  {
2439
2816
  promptId: import_zod7.z.string().min(1).describe("ID of the message to delete")
2440
2817
  },
2818
+ {
2819
+ title: "Delete Chat Message",
2820
+ readOnlyHint: false,
2821
+ destructiveHint: true,
2822
+ idempotentHint: true,
2823
+ openWorldHint: true
2824
+ },
2441
2825
  async ({ promptId }) => {
2442
2826
  try {
2443
2827
  const result = await api.delete(`/v1/prompt/message/${promptId}`);
@@ -2456,6 +2840,13 @@ function register7(server, client) {
2456
2840
  "list_prompts",
2457
2841
  "List all available Magic Prompt templates. Use template IDs with ask_magic_prompt's assistantTemplateId parameter when using assistantType 'custom'.",
2458
2842
  {},
2843
+ {
2844
+ title: "List Prompt Templates",
2845
+ readOnlyHint: true,
2846
+ destructiveHint: false,
2847
+ idempotentHint: true,
2848
+ openWorldHint: true
2849
+ },
2459
2850
  async () => {
2460
2851
  try {
2461
2852
  const result = await api.get("/v1/prompt");
@@ -2474,6 +2865,13 @@ function register7(server, client) {
2474
2865
  "get_favorite_prompts",
2475
2866
  "Get all prompts and answers that have been marked as favorites. Useful for finding saved insights and important AI-generated analysis.",
2476
2867
  {},
2868
+ {
2869
+ title: "Get Favorite Prompts",
2870
+ readOnlyHint: true,
2871
+ destructiveHint: false,
2872
+ idempotentHint: true,
2873
+ openWorldHint: true
2874
+ },
2477
2875
  async () => {
2478
2876
  try {
2479
2877
  const result = await api.get("/v1/prompt/favorites");
@@ -2496,6 +2894,13 @@ function register7(server, client) {
2496
2894
  messageId: import_zod7.z.string().min(1).describe("ID of the specific message to favorite/unfavorite"),
2497
2895
  isFavorite: import_zod7.z.boolean().describe("true to mark as favorite, false to remove")
2498
2896
  },
2897
+ {
2898
+ title: "Toggle Prompt Favorite",
2899
+ readOnlyHint: false,
2900
+ destructiveHint: false,
2901
+ idempotentHint: true,
2902
+ openWorldHint: true
2903
+ },
2499
2904
  async (body) => {
2500
2905
  try {
2501
2906
  const result = await api.post("/v1/prompt/favorites", body);
@@ -2517,6 +2922,13 @@ function register7(server, client) {
2517
2922
  promptId: import_zod7.z.string().min(1).describe("ID of the conversation to rename"),
2518
2923
  title: import_zod7.z.string().min(1).describe("New title for the conversation")
2519
2924
  },
2925
+ {
2926
+ title: "Rename Chat",
2927
+ readOnlyHint: false,
2928
+ destructiveHint: false,
2929
+ idempotentHint: true,
2930
+ openWorldHint: true
2931
+ },
2520
2932
  async ({ promptId, title }) => {
2521
2933
  try {
2522
2934
  const result = await api.put(`/v1/prompt/${promptId}`, { title });
@@ -2540,6 +2952,13 @@ function register7(server, client) {
2540
2952
  score: import_zod7.z.number().describe("Feedback score: 1 for thumbs up, -1 for thumbs down"),
2541
2953
  reason: import_zod7.z.string().optional().describe("Optional explanation for the feedback")
2542
2954
  },
2955
+ {
2956
+ title: "Submit Chat Feedback",
2957
+ readOnlyHint: false,
2958
+ destructiveHint: false,
2959
+ idempotentHint: false,
2960
+ openWorldHint: true
2961
+ },
2543
2962
  async (body) => {
2544
2963
  try {
2545
2964
  const result = await api.post("/v1/prompt/feedback", body);
@@ -2561,6 +2980,13 @@ function register7(server, client) {
2561
2980
  startDate: import_zod7.z.string().optional().describe("Start date for stats (ISO 8601)"),
2562
2981
  endDate: import_zod7.z.string().optional().describe("End date for stats (ISO 8601)")
2563
2982
  },
2983
+ {
2984
+ title: "Get Chat Statistics",
2985
+ readOnlyHint: true,
2986
+ destructiveHint: false,
2987
+ idempotentHint: true,
2988
+ openWorldHint: true
2989
+ },
2564
2990
  async (params) => {
2565
2991
  try {
2566
2992
  const result = await api.get("/v1/prompt/statistics", { params });
@@ -2581,6 +3007,13 @@ function register7(server, client) {
2581
3007
  {
2582
3008
  promptId: import_zod7.z.string().min(1).describe("ID of the conversation to export")
2583
3009
  },
3010
+ {
3011
+ title: "Export Chat Answer",
3012
+ readOnlyHint: true,
3013
+ destructiveHint: false,
3014
+ idempotentHint: true,
3015
+ openWorldHint: true
3016
+ },
2584
3017
  async (body) => {
2585
3018
  try {
2586
3019
  const result = await api.post("/v1/prompt/export", body);
@@ -2622,6 +3055,13 @@ function register8(server, client) {
2622
3055
  page: import_zod8.z.number().int().min(0).optional().describe("Page number (0-based, default: 0)"),
2623
3056
  pageSize: import_zod8.z.number().int().min(1).max(500).optional().describe("Results per page (default: 20, max: 500)")
2624
3057
  },
3058
+ {
3059
+ title: "List Meeting Events",
3060
+ readOnlyHint: true,
3061
+ destructiveHint: false,
3062
+ idempotentHint: true,
3063
+ openWorldHint: true
3064
+ },
2625
3065
  async (params) => {
2626
3066
  try {
2627
3067
  const result = await api.get("/v1/meeting-assistant/events", {
@@ -2646,6 +3086,13 @@ function register8(server, client) {
2646
3086
  title: import_zod8.z.string().optional().describe("Display title for the event"),
2647
3087
  scheduledAt: import_zod8.z.string().optional().describe("ISO 8601 datetime for when the meeting starts")
2648
3088
  },
3089
+ {
3090
+ title: "Schedule AI Meeting Assistant",
3091
+ readOnlyHint: false,
3092
+ destructiveHint: false,
3093
+ idempotentHint: false,
3094
+ openWorldHint: true
3095
+ },
2649
3096
  async (body) => {
2650
3097
  try {
2651
3098
  const result = await api.post(
@@ -2669,6 +3116,13 @@ function register8(server, client) {
2669
3116
  {
2670
3117
  meetingAssistantEventId: import_zod8.z.string().describe("Unique identifier of the meeting assistant event")
2671
3118
  },
3119
+ {
3120
+ title: "Remove Assistant from Meeting",
3121
+ readOnlyHint: false,
3122
+ destructiveHint: false,
3123
+ idempotentHint: true,
3124
+ openWorldHint: true
3125
+ },
2672
3126
  async ({ meetingAssistantEventId }) => {
2673
3127
  try {
2674
3128
  const result = await api.put(
@@ -2693,6 +3147,13 @@ function register8(server, client) {
2693
3147
  {
2694
3148
  meetingAssistantEventId: import_zod8.z.string().describe("Unique identifier of the meeting assistant event to cancel")
2695
3149
  },
3150
+ {
3151
+ title: "Cancel Scheduled Meeting Assistant",
3152
+ readOnlyHint: false,
3153
+ destructiveHint: true,
3154
+ idempotentHint: true,
3155
+ openWorldHint: true
3156
+ },
2696
3157
  async ({ meetingAssistantEventId }) => {
2697
3158
  try {
2698
3159
  const result = await api.delete(
@@ -2731,6 +3192,13 @@ function register9(server, client) {
2731
3192
  "list_fields",
2732
3193
  "List all custom fields defined in the workspace.",
2733
3194
  {},
3195
+ {
3196
+ title: "List Custom Fields",
3197
+ readOnlyHint: true,
3198
+ destructiveHint: false,
3199
+ idempotentHint: true,
3200
+ openWorldHint: true
3201
+ },
2734
3202
  async () => {
2735
3203
  try {
2736
3204
  const result = await api.get("/v1/fields");
@@ -2753,6 +3221,13 @@ function register9(server, client) {
2753
3221
  type: import_zod9.z.string().optional().describe("Field type (text, number, select, etc.)"),
2754
3222
  options: import_zod9.z.array(import_zod9.z.string()).optional().describe("Options for select/multi-select field types")
2755
3223
  },
3224
+ {
3225
+ title: "Create Custom Field",
3226
+ readOnlyHint: false,
3227
+ destructiveHint: false,
3228
+ idempotentHint: false,
3229
+ openWorldHint: true
3230
+ },
2756
3231
  async (body) => {
2757
3232
  try {
2758
3233
  const result = await api.post("/v1/fields", body);
@@ -2773,6 +3248,13 @@ function register9(server, client) {
2773
3248
  {
2774
3249
  fields: import_zod9.z.array(import_zod9.z.record(import_zod9.z.unknown())).describe("Array of field objects to update")
2775
3250
  },
3251
+ {
3252
+ title: "Bulk Update Custom Fields",
3253
+ readOnlyHint: false,
3254
+ destructiveHint: false,
3255
+ idempotentHint: true,
3256
+ openWorldHint: true
3257
+ },
2776
3258
  async ({ fields }) => {
2777
3259
  try {
2778
3260
  const result = await api.post("/v1/fields/multi", { fields });
@@ -2796,6 +3278,13 @@ function register9(server, client) {
2796
3278
  type: import_zod9.z.string().optional().describe("New field type"),
2797
3279
  options: import_zod9.z.array(import_zod9.z.string()).optional().describe("Updated options for select types")
2798
3280
  },
3281
+ {
3282
+ title: "Update Custom Field",
3283
+ readOnlyHint: false,
3284
+ destructiveHint: false,
3285
+ idempotentHint: true,
3286
+ openWorldHint: true
3287
+ },
2799
3288
  async ({ id, ...body }) => {
2800
3289
  try {
2801
3290
  const result = await api.put(`/v1/fields/${id}`, body);
@@ -2831,6 +3320,13 @@ function register10(server, client) {
2831
3320
  "list_automations",
2832
3321
  "List all automation rules configured in the workspace.",
2833
3322
  {},
3323
+ {
3324
+ title: "List Automations",
3325
+ readOnlyHint: true,
3326
+ destructiveHint: false,
3327
+ idempotentHint: true,
3328
+ openWorldHint: true
3329
+ },
2834
3330
  async () => {
2835
3331
  try {
2836
3332
  const result = await api.get("/v1/automations");
@@ -2851,6 +3347,13 @@ function register10(server, client) {
2851
3347
  {
2852
3348
  automationId: import_zod10.z.string().min(1).describe("Unique identifier of the automation")
2853
3349
  },
3350
+ {
3351
+ title: "Get Automation Details",
3352
+ readOnlyHint: true,
3353
+ destructiveHint: false,
3354
+ idempotentHint: true,
3355
+ openWorldHint: true
3356
+ },
2854
3357
  async ({ automationId }) => {
2855
3358
  try {
2856
3359
  const result = await api.get(`/v1/automations/${automationId}`);
@@ -2874,6 +3377,13 @@ function register10(server, client) {
2874
3377
  actions: import_zod10.z.array(import_zod10.z.record(import_zod10.z.unknown())).optional().describe("Array of action configurations"),
2875
3378
  config: import_zod10.z.record(import_zod10.z.unknown()).optional().describe("Full automation configuration object")
2876
3379
  },
3380
+ {
3381
+ title: "Create Automation",
3382
+ readOnlyHint: false,
3383
+ destructiveHint: false,
3384
+ idempotentHint: false,
3385
+ openWorldHint: true
3386
+ },
2877
3387
  async (body) => {
2878
3388
  try {
2879
3389
  const result = await api.post("/v1/automations/", body);
@@ -2898,6 +3408,13 @@ function register10(server, client) {
2898
3408
  actions: import_zod10.z.array(import_zod10.z.record(import_zod10.z.unknown())).optional().describe("Updated action configurations"),
2899
3409
  config: import_zod10.z.record(import_zod10.z.unknown()).optional().describe("Full updated configuration object")
2900
3410
  },
3411
+ {
3412
+ title: "Update Automation",
3413
+ readOnlyHint: false,
3414
+ destructiveHint: false,
3415
+ idempotentHint: true,
3416
+ openWorldHint: true
3417
+ },
2901
3418
  async ({ automationId, ...body }) => {
2902
3419
  try {
2903
3420
  const result = await api.put(
@@ -2922,6 +3439,13 @@ function register10(server, client) {
2922
3439
  automationId: import_zod10.z.string().min(1).describe("Unique identifier of the automation"),
2923
3440
  enabled: import_zod10.z.boolean().describe("Set to true to enable, false to disable")
2924
3441
  },
3442
+ {
3443
+ title: "Enable or Disable Automation",
3444
+ readOnlyHint: false,
3445
+ destructiveHint: false,
3446
+ idempotentHint: true,
3447
+ openWorldHint: true
3448
+ },
2925
3449
  async ({ automationId, enabled }) => {
2926
3450
  try {
2927
3451
  const result = await api.put(
@@ -2963,6 +3487,13 @@ function register11(server, client) {
2963
3487
  url: import_zod11.z.string().url().describe("HTTPS endpoint URL to receive webhook payloads"),
2964
3488
  events: import_zod11.z.array(import_zod11.z.string()).optional().describe("Array of event types to subscribe to")
2965
3489
  },
3490
+ {
3491
+ title: "Create Webhook",
3492
+ readOnlyHint: false,
3493
+ destructiveHint: false,
3494
+ idempotentHint: false,
3495
+ openWorldHint: true
3496
+ },
2966
3497
  async (body) => {
2967
3498
  try {
2968
3499
  const result = await api.post("/v1/webhook", body);
@@ -2981,6 +3512,13 @@ function register11(server, client) {
2981
3512
  "list_webhooks",
2982
3513
  "List all configured webhooks in the workspace.",
2983
3514
  {},
3515
+ {
3516
+ title: "List Webhooks",
3517
+ readOnlyHint: true,
3518
+ destructiveHint: false,
3519
+ idempotentHint: true,
3520
+ openWorldHint: true
3521
+ },
2984
3522
  async () => {
2985
3523
  try {
2986
3524
  const result = await api.get("/v1/webhook");
@@ -3003,6 +3541,13 @@ function register11(server, client) {
3003
3541
  url: import_zod11.z.string().url().optional().describe("New endpoint URL"),
3004
3542
  events: import_zod11.z.array(import_zod11.z.string()).optional().describe("Updated array of event types")
3005
3543
  },
3544
+ {
3545
+ title: "Update Webhook",
3546
+ readOnlyHint: false,
3547
+ destructiveHint: false,
3548
+ idempotentHint: true,
3549
+ openWorldHint: true
3550
+ },
3006
3551
  async ({ webhookId, ...body }) => {
3007
3552
  try {
3008
3553
  const result = await api.put(`/v1/webhook/${webhookId}`, body);
@@ -3023,6 +3568,13 @@ function register11(server, client) {
3023
3568
  {
3024
3569
  webhookId: import_zod11.z.string().min(1).describe("Unique identifier of the webhook to delete")
3025
3570
  },
3571
+ {
3572
+ title: "Delete Webhook",
3573
+ readOnlyHint: false,
3574
+ destructiveHint: true,
3575
+ idempotentHint: true,
3576
+ openWorldHint: true
3577
+ },
3026
3578
  async ({ webhookId }) => {
3027
3579
  try {
3028
3580
  const result = await api.delete(`/v1/webhook/${webhookId}`);
@@ -3076,6 +3628,13 @@ function register12(server, client) {
3076
3628
  })
3077
3629
  ).optional().describe("Advanced filters for narrowing search results by tags, speakers, media type, sentiment, folder, etc.")
3078
3630
  },
3631
+ {
3632
+ title: "Search Media Library",
3633
+ readOnlyHint: true,
3634
+ destructiveHint: false,
3635
+ idempotentHint: true,
3636
+ openWorldHint: true
3637
+ },
3079
3638
  async (params) => {
3080
3639
  try {
3081
3640
  const result = await api.post("/v1/analytics/search", params);
@@ -3130,6 +3689,13 @@ function register13(server, client) {
3130
3689
  tags: import_zod13.z.array(import_zod13.z.string()).optional().describe("Tags for the clip"),
3131
3690
  mergeStrategy: import_zod13.z.enum(["CONCATENATE"]).optional().describe("How to merge multiple segments (default: CONCATENATE)")
3132
3691
  },
3692
+ {
3693
+ title: "Create Highlight Clip",
3694
+ readOnlyHint: false,
3695
+ destructiveHint: false,
3696
+ idempotentHint: false,
3697
+ openWorldHint: true
3698
+ },
3133
3699
  async (body) => {
3134
3700
  try {
3135
3701
  const result = await api.post("/v1/clips", body);
@@ -3152,6 +3718,13 @@ function register13(server, client) {
3152
3718
  folderId: import_zod13.z.string().optional().describe("Filter clips by folder ID"),
3153
3719
  mediaIds: import_zod13.z.array(import_zod13.z.string()).optional().describe("Filter clips by source media file IDs")
3154
3720
  },
3721
+ {
3722
+ title: "List Clips",
3723
+ readOnlyHint: true,
3724
+ destructiveHint: false,
3725
+ idempotentHint: true,
3726
+ openWorldHint: true
3727
+ },
3155
3728
  async ({ clipId, ...params }) => {
3156
3729
  try {
3157
3730
  const url = clipId ? `/v1/clips/${clipId}` : "/v1/clips";
@@ -3176,6 +3749,13 @@ function register13(server, client) {
3176
3749
  description: import_zod13.z.string().optional().describe("New description"),
3177
3750
  tags: import_zod13.z.array(import_zod13.z.string()).optional().describe("New tags")
3178
3751
  },
3752
+ {
3753
+ title: "Update Clip",
3754
+ readOnlyHint: false,
3755
+ destructiveHint: false,
3756
+ idempotentHint: true,
3757
+ openWorldHint: true
3758
+ },
3179
3759
  async ({ clipId, ...body }) => {
3180
3760
  try {
3181
3761
  const result = await api.put(`/v1/clips/${clipId}`, body);
@@ -3196,6 +3776,13 @@ function register13(server, client) {
3196
3776
  {
3197
3777
  clipId: import_zod13.z.string().min(1).describe("ID of the clip to delete")
3198
3778
  },
3779
+ {
3780
+ title: "Delete Clip",
3781
+ readOnlyHint: false,
3782
+ destructiveHint: true,
3783
+ idempotentHint: true,
3784
+ openWorldHint: true
3785
+ },
3199
3786
  async ({ clipId }) => {
3200
3787
  try {
3201
3788
  const result = await api.delete(`/v1/clips/${clipId}`);
@@ -3264,12 +3851,7 @@ function register14(server, client) {
3264
3851
  const api = client ?? speakClient;
3265
3852
  server.tool(
3266
3853
  "upload_and_analyze",
3267
- [
3268
- "Upload media from a URL, wait for processing to complete, then return the transcript and AI insights \u2014 all in one call.",
3269
- "This is a convenience tool that combines upload_media + polling get_media_status + get_transcript + get_media_insights.",
3270
- "Processing typically takes 1-3 minutes for audio under 60 minutes.",
3271
- "Use this when you want the full analysis result without managing the polling loop yourself."
3272
- ].join(" "),
3854
+ "Upload media and return media_id immediately. After this returns, poll get_media_status until state is 'processed' (typically 1-3 min for under 60min audio), then call get_media_insights for AI summaries. This async pattern is required for remote MCP transports \u2014 long blocking calls die at proxy idle timeouts.",
3273
3855
  {
3274
3856
  url: import_zod14.z.string().describe("Publicly accessible URL of the media file"),
3275
3857
  name: import_zod14.z.string().optional().describe("Display name for the media (defaults to filename from URL)"),
@@ -3278,6 +3860,13 @@ function register14(server, client) {
3278
3860
  folderId: import_zod14.z.string().optional().describe("Folder ID to place the media in"),
3279
3861
  tags: import_zod14.z.string().optional().describe("Comma-separated tags")
3280
3862
  },
3863
+ {
3864
+ title: "Upload and Analyze Media",
3865
+ readOnlyHint: false,
3866
+ destructiveHint: false,
3867
+ idempotentHint: false,
3868
+ openWorldHint: true
3869
+ },
3281
3870
  async (params) => {
3282
3871
  try {
3283
3872
  const uploadBody = {
@@ -3290,6 +3879,7 @@ function register14(server, client) {
3290
3879
  if (params.tags) uploadBody.tags = params.tags;
3291
3880
  const uploadRes = await api.post("/v1/media/upload", uploadBody);
3292
3881
  const mediaId = uploadRes.data?.data?.mediaId;
3882
+ const state = uploadRes.data?.data?.state ?? "pending";
3293
3883
  if (!mediaId) {
3294
3884
  return {
3295
3885
  content: [{ type: "text", text: `Error: Upload succeeded but no mediaId returned.
@@ -3297,35 +3887,15 @@ ${JSON.stringify(uploadRes.data, null, 2)}` }],
3297
3887
  isError: true
3298
3888
  };
3299
3889
  }
3300
- let state = uploadRes.data?.data?.state;
3301
- let attempts = 0;
3302
- while (state !== MediaState.PROCESSED && state !== MediaState.FAILED && attempts < MAX_POLL_ATTEMPTS) {
3303
- await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
3304
- const statusRes = await api.get(`/v1/media/status/${mediaId}`);
3305
- state = statusRes.data?.data?.state;
3306
- attempts++;
3307
- }
3308
- if (state === MediaState.FAILED) {
3309
- return {
3310
- content: [{ type: "text", text: `Error: Processing failed for media ${mediaId}` }],
3311
- isError: true
3312
- };
3313
- }
3314
- if (state !== MediaState.PROCESSED) {
3315
- return {
3316
- content: [{ type: "text", text: `Timeout: Media ${mediaId} is still processing (state: ${state}). Use get_media_status to check later.` }],
3317
- isError: true
3318
- };
3319
- }
3320
- const [transcriptRes, insightsRes] = await Promise.all([
3321
- api.get(`/v1/media/transcript/${mediaId}`),
3322
- api.get(`/v1/media/insight/${mediaId}`)
3323
- ]);
3324
3890
  const result = {
3325
3891
  mediaId,
3326
- state: "processed",
3327
- transcript: transcriptRes.data?.data,
3328
- insights: insightsRes.data?.data
3892
+ state,
3893
+ message: "Upload accepted. Processing has started in the background.",
3894
+ nextSteps: [
3895
+ `1. Poll get_media_status with mediaId="${mediaId}" every 10-30 seconds.`,
3896
+ `2. When state is "processed" (typically 1-3 min for audio under 60 min), call get_media_insights for the AI summary and get_transcript for the full transcript.`,
3897
+ `3. If state becomes "failed", processing did not complete \u2014 surface the error to the user.`
3898
+ ]
3329
3899
  };
3330
3900
  return {
3331
3901
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
@@ -3354,6 +3924,13 @@ ${JSON.stringify(uploadRes.data, null, 2)}` }],
3354
3924
  folderId: import_zod14.z.string().optional().describe("Folder ID to place the media in"),
3355
3925
  tags: import_zod14.z.string().optional().describe("Comma-separated tags")
3356
3926
  },
3927
+ {
3928
+ title: "Upload Local File",
3929
+ readOnlyHint: false,
3930
+ destructiveHint: false,
3931
+ idempotentHint: false,
3932
+ openWorldHint: true
3933
+ },
3357
3934
  async (params) => {
3358
3935
  try {
3359
3936
  const filePath = params.filePath;
@@ -3426,7 +4003,7 @@ ${JSON.stringify(signedRes.data, null, 2)}` }],
3426
4003
  }
3427
4004
  );
3428
4005
  }
3429
- var import_zod14, fs, path2, POLL_INTERVAL_MS, MAX_POLL_ATTEMPTS;
4006
+ var import_zod14, fs, path2;
3430
4007
  var init_workflows = __esm({
3431
4008
  "src/tools/workflows.ts"() {
3432
4009
  "use strict";
@@ -3436,8 +4013,6 @@ var init_workflows = __esm({
3436
4013
  fs = __toESM(require("fs"));
3437
4014
  path2 = __toESM(require("path"));
3438
4015
  init_media_utils();
3439
- POLL_INTERVAL_MS = 5e3;
3440
- MAX_POLL_ATTEMPTS = 120;
3441
4016
  }
3442
4017
  });
3443
4018
 
@@ -3493,6 +4068,21 @@ var resources_exports = {};
3493
4068
  __export(resources_exports, {
3494
4069
  registerResources: () => registerResources
3495
4070
  });
4071
+ function asJsonContent(uri, data) {
4072
+ return {
4073
+ contents: [
4074
+ {
4075
+ uri,
4076
+ mimeType: "application/json",
4077
+ text: JSON.stringify(data, null, 2)
4078
+ }
4079
+ ]
4080
+ };
4081
+ }
4082
+ function reportError(label, err) {
4083
+ const detail = formatAxiosError(err);
4084
+ throw new Error(`Speak AI resource '${label}' failed: ${detail}`);
4085
+ }
3496
4086
  function registerResources(server, client) {
3497
4087
  const api = client ?? speakClient;
3498
4088
  server.resource(
@@ -3504,17 +4094,9 @@ function registerResources(server, client) {
3504
4094
  const result = await api.get("/v1/media", {
3505
4095
  params: { page: 0, pageSize: 50, sortBy: "createdAt:desc", filterMedia: 2 }
3506
4096
  });
3507
- return {
3508
- contents: [
3509
- {
3510
- uri: "speakai://media",
3511
- mimeType: "application/json",
3512
- text: JSON.stringify(result.data?.data, null, 2)
3513
- }
3514
- ]
3515
- };
3516
- } catch {
3517
- return { contents: [] };
4097
+ return asJsonContent("speakai://media", result.data?.data);
4098
+ } catch (err) {
4099
+ reportError("media-library", err);
3518
4100
  }
3519
4101
  }
3520
4102
  );
@@ -3527,17 +4109,9 @@ function registerResources(server, client) {
3527
4109
  const result = await api.get("/v1/folder", {
3528
4110
  params: { page: 0, pageSize: 100, sortBy: "createdAt:desc" }
3529
4111
  });
3530
- return {
3531
- contents: [
3532
- {
3533
- uri: "speakai://folders",
3534
- mimeType: "application/json",
3535
- text: JSON.stringify(result.data?.data, null, 2)
3536
- }
3537
- ]
3538
- };
3539
- } catch {
3540
- return { contents: [] };
4112
+ return asJsonContent("speakai://folders", result.data?.data);
4113
+ } catch (err) {
4114
+ reportError("folders", err);
3541
4115
  }
3542
4116
  }
3543
4117
  );
@@ -3548,17 +4122,9 @@ function registerResources(server, client) {
3548
4122
  async () => {
3549
4123
  try {
3550
4124
  const result = await api.get("/v1/media/supportedLanguages");
3551
- return {
3552
- contents: [
3553
- {
3554
- uri: "speakai://languages",
3555
- mimeType: "application/json",
3556
- text: JSON.stringify(result.data?.data, null, 2)
3557
- }
3558
- ]
3559
- };
3560
- } catch {
3561
- return { contents: [] };
4125
+ return asJsonContent("speakai://languages", result.data?.data);
4126
+ } catch (err) {
4127
+ reportError("supported-languages", err);
3562
4128
  }
3563
4129
  }
3564
4130
  );
@@ -3569,17 +4135,9 @@ function registerResources(server, client) {
3569
4135
  async (uri, { mediaId }) => {
3570
4136
  try {
3571
4137
  const result = await api.get(`/v1/media/transcript/${mediaId}`);
3572
- return {
3573
- contents: [
3574
- {
3575
- uri: uri.href,
3576
- mimeType: "application/json",
3577
- text: JSON.stringify(result.data?.data, null, 2)
3578
- }
3579
- ]
3580
- };
3581
- } catch {
3582
- return { contents: [] };
4138
+ return asJsonContent(uri.href, result.data?.data);
4139
+ } catch (err) {
4140
+ reportError(`transcript(${mediaId})`, err);
3583
4141
  }
3584
4142
  }
3585
4143
  );
@@ -3590,17 +4148,9 @@ function registerResources(server, client) {
3590
4148
  async (uri, { mediaId }) => {
3591
4149
  try {
3592
4150
  const result = await api.get(`/v1/media/insight/${mediaId}`);
3593
- return {
3594
- contents: [
3595
- {
3596
- uri: uri.href,
3597
- mimeType: "application/json",
3598
- text: JSON.stringify(result.data?.data, null, 2)
3599
- }
3600
- ]
3601
- };
3602
- } catch {
3603
- return { contents: [] };
4151
+ return asJsonContent(uri.href, result.data?.data);
4152
+ } catch (err) {
4153
+ reportError(`insights(${mediaId})`, err);
3604
4154
  }
3605
4155
  }
3606
4156
  );
@@ -3611,6 +4161,7 @@ var init_resources = __esm({
3611
4161
  "use strict";
3612
4162
  import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
3613
4163
  init_client();
4164
+ init_client();
3614
4165
  }
3615
4166
  });
3616
4167