get_action_items
Extract action items from Fathom meeting recordings to track tasks and follow-ups. Specify a recording ID or check recent meetings for pending items.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| recording_id | No | Get action items from a specific meeting | |
| include_completed | No | Include completed action items (default: true) | |
| limit | No | Number of recent meetings to check if no recording_id (default: 10) |
Implementation Reference
- src/index.ts:273-326 (handler)Main handler logic: Fetches meetings using Fathom client (specific or recent), extracts and filters action items, formats output as markdown using helpers.async ({ recording_id, include_completed, limit }) => { const meetingLimit = limit || 10; console.error(recording_id ? `Getting action items for ${recording_id}...` : `Getting action items from recent meetings...`); if (recording_id) { const response = await fathom.listMeetings({ include_action_items: true }); const meeting = response.items.find(m => m.recording_id === recording_id); if (!meeting) { return { content: [{ type: 'text', text: `Meeting with recording ID ${recording_id} not found.` }], isError: true, }; } let items = meeting.action_items || []; if (include_completed === false) { items = items.filter(i => !i.completed); } const title = meeting.title || meeting.meeting_title || `Meeting ${meeting.recording_id}`; const markdown = `## Action Items from: ${title}\n\n${formatActionItems(items)}`; return { content: [{ type: 'text', text: markdown }], }; } else { const response = await fathom.listMeetings({ include_action_items: true }); const meetings = response.items.slice(0, meetingLimit); const sections: string[] = []; for (const meeting of meetings) { let items = meeting.action_items || []; if (items.length === 0) continue; if (include_completed === false) { items = items.filter(i => !i.completed); } if (items.length === 0) continue; const title = meeting.title || meeting.meeting_title || `Meeting ${meeting.recording_id}`; const date = formatDate(meeting.recording_start_time); sections.push(`### ${title}\n_${date}_\n\n${formatActionItems(items)}`); } const markdown = sections.length > 0 ? `# Action Items from Recent Meetings\n\n${sections.join('\n\n')}` : 'No action items found in recent meetings.'; return { content: [{ type: 'text', text: markdown }], }; } }
- src/index.ts:268-272 (schema)Zod schema defining input parameters for the tool.{ recording_id: z.number().optional().describe('Get action items from a specific meeting'), include_completed: z.boolean().optional().describe('Include completed action items (default: true)'), limit: z.number().optional().describe('Number of recent meetings to check if no recording_id (default: 10)'), },
- src/index.ts:266-327 (registration)Registration of the 'get_action_items' tool with schema and handler using server.tool().server.tool( 'get_action_items', { recording_id: z.number().optional().describe('Get action items from a specific meeting'), include_completed: z.boolean().optional().describe('Include completed action items (default: true)'), limit: z.number().optional().describe('Number of recent meetings to check if no recording_id (default: 10)'), }, async ({ recording_id, include_completed, limit }) => { const meetingLimit = limit || 10; console.error(recording_id ? `Getting action items for ${recording_id}...` : `Getting action items from recent meetings...`); if (recording_id) { const response = await fathom.listMeetings({ include_action_items: true }); const meeting = response.items.find(m => m.recording_id === recording_id); if (!meeting) { return { content: [{ type: 'text', text: `Meeting with recording ID ${recording_id} not found.` }], isError: true, }; } let items = meeting.action_items || []; if (include_completed === false) { items = items.filter(i => !i.completed); } const title = meeting.title || meeting.meeting_title || `Meeting ${meeting.recording_id}`; const markdown = `## Action Items from: ${title}\n\n${formatActionItems(items)}`; return { content: [{ type: 'text', text: markdown }], }; } else { const response = await fathom.listMeetings({ include_action_items: true }); const meetings = response.items.slice(0, meetingLimit); const sections: string[] = []; for (const meeting of meetings) { let items = meeting.action_items || []; if (items.length === 0) continue; if (include_completed === false) { items = items.filter(i => !i.completed); } if (items.length === 0) continue; const title = meeting.title || meeting.meeting_title || `Meeting ${meeting.recording_id}`; const date = formatDate(meeting.recording_start_time); sections.push(`### ${title}\n_${date}_\n\n${formatActionItems(items)}`); } const markdown = sections.length > 0 ? `# Action Items from Recent Meetings\n\n${sections.join('\n\n')}` : 'No action items found in recent meetings.'; return { content: [{ type: 'text', text: markdown }], }; } } );
- src/formatters.ts:122-133 (helper)Helper to format action items as markdown checklist with status, assignee, and timestamp.export function formatActionItems(actionItems: ActionItem[] | null | undefined): string { if (!actionItems || actionItems.length === 0) { return '_No action items_'; } return actionItems.map(item => { const status = item.completed ? '[x]' : '[ ]'; const assignee = item.assignee ? ` _(assigned to ${item.assignee.name})_` : ''; const timestamp = item.recording_timestamp ? ` at ${item.recording_timestamp}` : ''; return `- ${status} ${item.description}${assignee}${timestamp}`; }).join('\n'); }
- src/formatters.ts:66-76 (helper)Helper to format ISO date to readable date string used in meeting headers.export function formatDate(isoDate: string): string { const date = new Date(isoDate); return date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', }); }