Skip to main content
Glama

mcp-google-sheets

new-event-matching-search.ts6.71 kB
import { createTrigger, PiecePropValueSchema, Property, } from '@activepieces/pieces-framework'; import { TriggerStrategy } from '@activepieces/pieces-framework'; import { googleCalendarCommon } from '../common'; import { GoogleCalendarEvent } from '../common/types'; import { googleCalendarAuth } from '../../'; import { DedupeStrategy, Polling, pollingHelper, } from '@activepieces/pieces-common'; import { AuthenticationType, httpClient, HttpMethod, HttpRequest, } from '@activepieces/pieces-common'; interface GoogleCalendarEventList { items: GoogleCalendarEvent[]; } const polling: Polling< PiecePropValueSchema<typeof googleCalendarAuth>, { calendar_id: string | undefined; search_term: string | undefined; event_types: string[] | undefined; search_fields: string[] | undefined; } > = { strategy: DedupeStrategy.TIMEBASED, items: async ({ auth, propsValue, lastFetchEpochMS }) => { const { calendar_id, search_term, event_types, search_fields } = propsValue; if (!calendar_id || !search_term) { return []; } let minUpdated: Date; if (lastFetchEpochMS === 0) { minUpdated = new Date(); minUpdated.setDate(minUpdated.getDate() - 1); } else { minUpdated = new Date(lastFetchEpochMS); } const queryParams: Record<string, string> = { singleEvents: 'true', orderBy: 'updated', updatedMin: minUpdated.toISOString(), q: search_term, }; if (event_types && event_types.length > 0) { event_types.forEach((type) => { if (!queryParams.eventTypes) { queryParams.eventTypes = type; } else { queryParams.eventTypes += '&eventTypes=' + type; } }); } const request: HttpRequest = { method: HttpMethod.GET, url: `${googleCalendarCommon.baseUrl}/calendars/${calendar_id}/events`, authentication: { type: AuthenticationType.BEARER_TOKEN, token: auth.access_token, }, queryParams: queryParams, }; const response = await httpClient.sendRequest<GoogleCalendarEventList>( request ); const events = response.body.items; const newEvents = events.filter((event) => { const created = new Date(event.created ?? 0).getTime(); const updated = new Date(event.updated ?? 0).getTime(); const isNewEvent = updated - created < 5000; if (!isNewEvent) return false; if (search_fields && search_fields.length > 0) { const searchTermLower = search_term.toLowerCase(); return search_fields.some((field) => { switch (field) { case 'summary': return ( event.summary?.toLowerCase().includes(searchTermLower) || false ); case 'description': return ( event.description?.toLowerCase().includes(searchTermLower) || false ); case 'location': return ( event.location?.toLowerCase().includes(searchTermLower) || false ); case 'attendees': return ( event.attendees?.some( (attendee) => attendee.email?.toLowerCase().includes(searchTermLower) || attendee.displayName ?.toLowerCase() .includes(searchTermLower) ) || false ); default: return false; } }); } return true; }); return newEvents.map((event) => { return { epochMilliSeconds: new Date(event.updated!).getTime(), data: event, }; }); }, }; export const newEventMatchingSearch = createTrigger({ auth: googleCalendarAuth, name: 'new_event_matching_search', displayName: 'New Event Matching Search', description: 'Fires when a new event is created that matches a specified search term.', props: { calendar_id: googleCalendarCommon.calendarDropdown('writer'), search_term: Property.ShortText({ displayName: 'Search Term', description: 'The keyword(s) to search for in new events (searches across title, description, location, and attendees by default).', required: true, }), event_types: Property.StaticMultiSelectDropdown({ displayName: 'Event Types', description: 'Filter by specific event types (optional)', required: false, options: { options: [ { label: 'Default Events', value: 'default' }, { label: 'Birthday Events', value: 'birthday' }, { label: 'Focus Time', value: 'focusTime' }, { label: 'Out of Office', value: 'outOfOffice' }, { label: 'Working Location', value: 'workingLocation' }, { label: 'From Gmail', value: 'fromGmail' }, ], }, }), search_fields: Property.StaticMultiSelectDropdown({ displayName: 'Search In Fields', description: "Specify which fields to search in (leave empty to use Google's default search across all fields)", required: false, options: { options: [ { label: 'Event Title/Summary', value: 'summary' }, { label: 'Event Description', value: 'description' }, { label: 'Event Location', value: 'location' }, { label: 'Attendee Names/Emails', value: 'attendees' }, ], }, }), }, type: TriggerStrategy.POLLING, sampleData: { id: 'abc123def456', summary: 'Final Project Review', description: 'Review of the Q3 final project deliverables.', status: 'confirmed', created: '2025-08-14T09:05:00.000Z', updated: '2025-08-14T09:05:01.000Z', start: { dateTime: '2025-09-01T10:00:00-07:00' }, end: { dateTime: '2025-09-01T11:30:00-07:00' }, organizer: { email: 'project.manager@example.com' }, }, async onEnable(context) { await pollingHelper.onEnable(polling, { auth: context.auth, store: context.store, propsValue: context.propsValue, }); }, async onDisable(context) { await pollingHelper.onDisable(polling, { auth: context.auth, store: context.store, propsValue: context.propsValue, }); }, async run(context) { return await pollingHelper.poll(polling, { auth: context.auth, store: context.store, propsValue: context.propsValue, files: context.files, }); }, async test(context) { return await pollingHelper.test(polling, { auth: context.auth, store: context.store, propsValue: context.propsValue, files: context.files, }); }, });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server