From 7c54062c77ad31ffbd1ea09e189b2d62653474c2 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Thu, 15 Jan 2026 14:19:50 -0500 Subject: [PATCH] feat: Add invite_mode to meeting scheduling Added invite_mode parameter to control who gets invited to meetings: - all_members (default): Invite everyone in the working group - topic_subscribers: Only invite members subscribed to the meeting's topics - none: Create meeting without invites (opt-in mode) This allows scheduling meetings where people can self-join rather than being automatically invited. Co-Authored-By: Claude Opus 4.5 --- server/src/addie/mcp/meeting-tools.ts | 16 ++++++++++++++-- server/src/services/meeting-service.ts | 25 ++++++++++++++++++------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/server/src/addie/mcp/meeting-tools.ts b/server/src/addie/mcp/meeting-tools.ts index d835cda9b1..c4046fbc72 100644 --- a/server/src/addie/mcp/meeting-tools.ts +++ b/server/src/addie/mcp/meeting-tools.ts @@ -259,7 +259,12 @@ Example prompts this handles: topic_slugs: { type: 'array', items: { type: 'string' }, - description: 'Topic tags for this meeting (only members subscribed to these topics will be invited)', + description: 'Topic tags for this meeting (used with invite_mode: topic_subscribers)', + }, + invite_mode: { + type: 'string', + enum: ['all_members', 'topic_subscribers', 'none'], + description: 'Who to invite: all_members (default - invite everyone in the working group), topic_subscribers (only those subscribed to the topics), or none (opt-in - create meeting but let people join themselves)', }, recurrence: { type: 'object', @@ -613,6 +618,8 @@ export function createMeetingToolHandlers( } // One-time meeting + const inviteMode = input.invite_mode as 'all_members' | 'topic_subscribers' | 'none' | undefined; + try { const result = await meetingService.scheduleMeeting({ workingGroupId: workingGroup.id, @@ -624,6 +631,7 @@ export function createMeetingToolHandlers( durationMinutes, timezone, createdByUserId: getUserId(), + inviteMode, }); let response = `✅ Scheduled: **${title}**\n\n`; @@ -638,8 +646,12 @@ export function createMeetingToolHandlers( if (result.errors.length > 0) { response += `\n⚠️ Some integrations had issues:\n`; response += result.errors.map(e => `• ${e}`).join('\n'); + } else if (inviteMode === 'none') { + response += `\n📋 Meeting created as **opt-in** - no invites sent. Members can join using the Zoom link.`; + } else if (inviteMode === 'topic_subscribers') { + response += `\n📧 Calendar invites sent to topic subscribers.`; } else { - response += `\n📧 Calendar invites have been sent to working group members.`; + response += `\n📧 Calendar invites sent to working group members.`; } logger.info({ diff --git a/server/src/services/meeting-service.ts b/server/src/services/meeting-service.ts index 15c7130cea..71cd02af07 100644 --- a/server/src/services/meeting-service.ts +++ b/server/src/services/meeting-service.ts @@ -49,6 +49,8 @@ export interface ScheduleMeetingOptions { createZoomMeeting?: boolean; sendCalendarInvites?: boolean; announceInSlack?: boolean; + // Control who gets invited: 'all_members', 'topic_subscribers', or 'none' (opt-in) + inviteMode?: 'all_members' | 'topic_subscribers' | 'none'; } export interface ScheduleMeetingResult { @@ -135,13 +137,22 @@ export async function scheduleMeeting(options: ScheduleMeetingOptions): Promise< meeting.zoom_passcode = zoomMeeting.password; } - // Invite working group members to the meeting - const invitedCount = await meetingsDb.addAttendeesFromGroup( - meeting.id, - options.workingGroupId, - options.topicSlugs - ); - logger.info({ meetingId: meeting.id, invitedCount }, 'Invited members to meeting'); + // Invite working group members to the meeting based on inviteMode + let invitedCount = 0; + const inviteMode = options.inviteMode || 'all_members'; + + if (inviteMode !== 'none') { + // 'all_members' passes undefined topicSlugs, 'topic_subscribers' passes the actual topics + const topicFilter = inviteMode === 'topic_subscribers' ? options.topicSlugs : undefined; + invitedCount = await meetingsDb.addAttendeesFromGroup( + meeting.id, + options.workingGroupId, + topicFilter + ); + logger.info({ meetingId: meeting.id, invitedCount, inviteMode }, 'Invited members to meeting'); + } else { + logger.info({ meetingId: meeting.id, inviteMode }, 'Skipped invites - opt-in mode'); + } // Create Google Calendar event with invites let calendarEvent: calendar.CalendarEvent | undefined;