Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions server/src/addie/mcp/meeting-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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,
Expand All @@ -624,6 +631,7 @@ export function createMeetingToolHandlers(
durationMinutes,
timezone,
createdByUserId: getUserId(),
inviteMode,
});

let response = `✅ Scheduled: **${title}**\n\n`;
Expand All @@ -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({
Expand Down
25 changes: 18 additions & 7 deletions server/src/services/meeting-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down
Loading