@speakai/mcp-server 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -272,7 +272,7 @@ Get a Speak AI API key at [app.speakai.co/developers/apikeys](https://app.speaka
272
272
 
273
273
  The `@speakai/mcp-server` npm package provides:
274
274
 
275
- - A CLI (`speakai-mcp`) for scripting and pipelines (28 commands).
275
+ - A CLI (`speakai-mcp`) for scripting and pipelines (30 commands).
276
276
  - A stdio-mode MCP server for clients that don't support remote HTTP transport.
277
277
  - An auto-setup wizard that detects installed MCP clients and configures them.
278
278
 
@@ -638,7 +638,7 @@ Parameters: days (optional, default: 7), folder (optional)
638
638
 
639
639
  **Example:** "Use the meeting-brief prompt with days=14 to cover the last two weeks"
640
640
 
641
- ### CLI (28 Commands)
641
+ ### CLI (30 Commands)
642
642
 
643
643
  Install globally and configure once:
644
644
 
@@ -703,7 +703,9 @@ npx @speakai/mcp-server config set-key
703
703
  |---|---|
704
704
  | `stats` | Show workspace media statistics |
705
705
  | `languages` | List supported transcription languages |
706
+ | `list-meeting-events` | List scheduled/completed meeting events (`--platform`, `--status`, `--sort`) |
706
707
  | `schedule-meeting <url>` | Schedule AI assistant to join a meeting |
708
+ | `live-transcript` | Fetch new sentences from an in-progress meeting (`--event-id` or `--media-id`, `--since-end-in-sec`) |
707
709
  | `create-text <name>` | Create a text note (`--text` or pipe via stdin) |
708
710
 
709
711
  #### CLI options
package/dist/index.js CHANGED
@@ -3185,7 +3185,7 @@ function register8(server, client) {
3185
3185
  "list_meeting_events",
3186
3186
  "List scheduled or completed meeting assistant events with filtering and pagination.",
3187
3187
  {
3188
- platformType: import_zod9.z.string().optional().describe("Filter by platform (e.g. zoom, teams, meet)"),
3188
+ platformType: import_zod9.z.string().optional().describe("Filter by platform. Allowed values: zoom, googleMeet, microsoftTeams, webex. Comma-separate for multiple. Must match these exact strings \u2014 server validates strictly."),
3189
3189
  meetingStatus: import_zod9.z.string().optional().describe("Filter by status (e.g. scheduled, completed, cancelled)"),
3190
3190
  page: import_zod9.z.number().int().min(0).optional().describe("Page number (0-based, default: 0)"),
3191
3191
  pageSize: import_zod9.z.number().int().min(1).max(500).optional().describe("Results per page (default: 20, max: 500)")
@@ -3312,7 +3312,7 @@ function register8(server, client) {
3312
3312
  registerSpeakTool(
3313
3313
  server,
3314
3314
  "get_live_meeting_transcript",
3315
- "Pull the transcript for an in-progress (or just-ended) meeting and receive only the sentences added since your last call. Pass meetingAssistantEventId from list_meeting_events (preferred) or mediaId directly. Pass sinceEndInSec from the previous response's nextCursor to skip already-seen sentences; omit it on the first call. Returns newSentences, nextCursor (pass back on the next call), isLive (true while the bot is recording), and meetingStatus. Works while the meeting is live and after it ends.",
3315
+ "Fetch new sentences from an in-progress or just-ended meeting transcript. Identify the meeting via meetingAssistantEventId (preferred) or mediaId. Pass back the previous response's nextCursor as sinceEndInSec to receive only what's been added since.",
3316
3316
  {
3317
3317
  meetingAssistantEventId: import_zod9.z.string().optional().describe("Meeting assistant event id from list_meeting_events. Either this or mediaId is required."),
3318
3318
  mediaId: import_zod9.z.string().optional().describe("Media id of the live meeting. Either this or meetingAssistantEventId is required."),
@@ -3338,7 +3338,7 @@ function register8(server, client) {
3338
3338
  let meetingName;
3339
3339
  if (meetingAssistantEventId) {
3340
3340
  const eventsRes = await api.get("/v1/meeting-assistant/events", {
3341
- params: { pageSize: 500 }
3341
+ params: { pageSize: 50, sortBy: "startTime:desc" }
3342
3342
  });
3343
3343
  const events = eventsRes.data?.data?.events ?? eventsRes.data?.events ?? [];
3344
3344
  const event = events.find((e) => e.meetingAssistantEventId === meetingAssistantEventId);
@@ -5464,6 +5464,38 @@ function createCli() {
5464
5464
  process.exit(1);
5465
5465
  }
5466
5466
  });
5467
+ program.command("list-meeting-events").description("List scheduled or completed meeting assistant events").option("-P, --platform <type>", "Filter by platform: zoom, googleMeet, microsoftTeams, webex (comma-separate for multiple)").option("-S, --status <status>", "Filter by meeting status (comma-separate for multiple)").option("-p, --page <n>", "Page number (0-based)", "0").option("-s, --page-size <n>", "Results per page", "20").option("--sort <field>", "Sort field", "startTime:desc").option("--json", "Output raw JSON").action(async (opts) => {
5468
+ requireApiKey();
5469
+ const client = await getClient();
5470
+ try {
5471
+ const params = {
5472
+ page: parseInt(opts.page),
5473
+ pageSize: parseInt(opts.pageSize),
5474
+ sortBy: opts.sort
5475
+ };
5476
+ if (opts.platform) params.platformType = opts.platform;
5477
+ if (opts.status) params.meetingStatus = opts.status;
5478
+ const res = await client.get("/v1/meeting-assistant/events", { params });
5479
+ const data = res.data?.data;
5480
+ if (opts.json) {
5481
+ printJson(data);
5482
+ return;
5483
+ }
5484
+ const events = data?.events ?? [];
5485
+ console.log(`Total: ${data?.totalCount ?? events.length}
5486
+ `);
5487
+ printTable(events, [
5488
+ { key: "meetingAssistantEventId", label: "Event ID", width: 24 },
5489
+ { key: "title", label: "Title", width: 32 },
5490
+ { key: "platform", label: "Platform", width: 16 },
5491
+ { key: "currentStatus", label: "Status", width: 18 },
5492
+ { key: "startTime", label: "Start", width: 20 }
5493
+ ]);
5494
+ } catch (err) {
5495
+ printError(err.response?.data?.message ?? err.message);
5496
+ process.exit(1);
5497
+ }
5498
+ });
5467
5499
  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) => {
5468
5500
  requireApiKey();
5469
5501
  const client = await getClient();
@@ -5490,6 +5522,66 @@ function createCli() {
5490
5522
  process.exit(1);
5491
5523
  }
5492
5524
  });
5525
+ program.command("live-transcript").description("Fetch new sentences from an in-progress or just-ended meeting").option("-e, --event-id <id>", "Meeting assistant event id (use `speakai-mcp list-meeting-events` to find it)").option("-m, --media-id <id>", "Media id (alternative to --event-id)").option("-s, --since-end-in-sec <seconds>", "nextCursor from previous call; omit on first call", parseFloat).option("--json", "Output raw JSON").action(async (opts) => {
5526
+ requireApiKey();
5527
+ const client = await getClient();
5528
+ if (!opts.eventId && !opts.mediaId) {
5529
+ printError("Provide --event-id or --media-id");
5530
+ process.exit(1);
5531
+ }
5532
+ try {
5533
+ let resolvedMediaId = opts.mediaId;
5534
+ let meetingStatus = null;
5535
+ let meetingName;
5536
+ if (opts.eventId) {
5537
+ const eventsRes = await client.get("/v1/meeting-assistant/events", {
5538
+ params: { pageSize: 50, sortBy: "startTime:desc" }
5539
+ });
5540
+ const events = eventsRes.data?.data?.events ?? eventsRes.data?.events ?? [];
5541
+ const event = events.find((e) => e.meetingAssistantEventId === opts.eventId);
5542
+ if (!event) {
5543
+ printError(`Meeting event not found: ${opts.eventId}`);
5544
+ process.exit(1);
5545
+ }
5546
+ meetingStatus = event.currentStatus ?? null;
5547
+ meetingName = event.title;
5548
+ const mediaRef = event.mediaId;
5549
+ resolvedMediaId = typeof mediaRef === "string" ? mediaRef : mediaRef?.mediaId;
5550
+ if (!resolvedMediaId) {
5551
+ printError("Meeting has no linked media yet \u2014 bot has not joined or started recording.");
5552
+ process.exit(1);
5553
+ }
5554
+ }
5555
+ const transcriptRes = await client.get(`/v1/media/transcript/${resolvedMediaId}`, {
5556
+ params: Number.isFinite(opts.sinceEndInSec) ? { sinceEndInSec: opts.sinceEndInSec } : void 0
5557
+ });
5558
+ const data = transcriptRes.data?.data ?? transcriptRes.data ?? {};
5559
+ const sentences = data?.insight?.transcript ?? [];
5560
+ const maxEnd = sentences.reduce((m, s) => Math.max(m, s.instances?.[0]?.endInSec ?? 0), 0);
5561
+ const nextCursor = sentences.length > 0 ? maxEnd : opts.sinceEndInSec ?? 0;
5562
+ const payload = {
5563
+ mediaId: resolvedMediaId,
5564
+ name: data?.name ?? meetingName ?? null,
5565
+ meetingStatus,
5566
+ isLive: meetingStatus === "inCallRecording",
5567
+ newSentences: sentences,
5568
+ nextCursor
5569
+ };
5570
+ if (opts.json) {
5571
+ printJson(payload);
5572
+ } else {
5573
+ console.log(`Meeting: ${payload.name ?? resolvedMediaId}`);
5574
+ console.log(`Status: ${payload.meetingStatus ?? "unknown"} (isLive=${payload.isLive})`);
5575
+ console.log(`New sentences: ${sentences.length} \u2022 nextCursor: ${nextCursor}`);
5576
+ for (const s of sentences) {
5577
+ console.log(` [${s.speakerId ?? "?"}] ${s.text ?? ""}`);
5578
+ }
5579
+ }
5580
+ } catch (err) {
5581
+ printError(err.response?.data?.message ?? err.message);
5582
+ process.exit(1);
5583
+ }
5584
+ });
5493
5585
  return program;
5494
5586
  }
5495
5587
  var import_commander, import_readline;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@speakai/mcp-server",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "mcpName": "io.github.speakai/mcp-server",
5
5
  "description": "Official Speak AI MCP Server — capture meetings, search thousands of recordings, run async voice and video surveys, create clips, and automate workflows from your AI assistant.",
6
6
  "homepage": "https://mcp.speakai.co",