admin_list_capabilities
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this only if asked explicitly which tools are available. Returns the catalog (name, description, side-effect class).
admin_whoami
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this only if you specifically need the signed-in admin's identity object (user id, email, company id/slug, brand, and the admin's linked ambassador account if any). The orientation already includes this info, so most questions don't need this tool.
ambassador_availability
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about WHEN an ambassador is free, reachable, or already booked — 'what's their availability', 'are they free next week', 'can I schedule them', 'how do they get notified'. Returns, per ambassador: declared weekly SHIFT availability and CHAT availability (recurring slots in their own timezone, or an always/never mode); one-time UNAVAILABILITY blocks (time off — these override everything, including 'always available'); the shifts they already have SCHEDULED within the lookahead window; a currentlyAvailable flag for shifts and for chat; and their NOTIFICATION preferences (which categories reach them by email vs push, and whether a push token is registered). Identify the ambassador by id (numeric user id), ids (BATCH — many ids in one call; prefer this over per-id fan-out), or query (name substring). To find the best time to schedule a GROUP, use availability_overlap instead — it does the cross-ambassador overlap math for you. windowDays sets the scheduled-shift lookahead (default 7). Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
ambassador_deactivate
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to set championActive=false on an ambassador. Reversible via ambassador_reactivate.
ambassador_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Permanently delete an ambassador (or cancel a pending invite). Two-phase: first call returns a preview + confirmation token; call again with confirm.token. Irreversible — to merely make an ambassador inactive, use ambassador_deactivate instead.
ambassador_invite
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Invite one or more people to become ambassadors, by email — each is sent an invitation to onboard (the Recruit / Invite Ambassadors action). notifyWhenOnboarded pings you when an invitee finishes onboarding.
ambassador_leaderboard
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Rank ambassadors over a time window — shifts, hours worked, and reach (people reached). basis: 'worked' (default) counts only shifts the ambassador actually worked — productivity ('top ambassadors this month', 'who worked the most hours'). basis: 'assigned' counts every shift assigned to them in the window regardless of status (future scheduled shifts included; cancelled excluded) — their total workload / how many chances they have had. For 'who has had the FEWEST shifts' / spreading opportunities fairly, use order: 'asc' with includeZeroActivity: true (so ambassadors with no shifts appear, count 0) and usually basis: 'assigned'. Aggregates in one call — do NOT fan out over shift_query and tally yourself. Defaults to the last 30 days. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
ambassador_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Search WORKERS (ambassadors) within the tenant. WHEN: user asks about specific workers by name/status/id, or wants an ambassador count or status breakdown. NOT WHEN: the name they mention matches the tenant (auto-scoped, never a record). NOT WHEN: they ask about admin/portal users → use colleague_query. NOT WHEN: they ask about leads/prospects → use prospect_query. NOT WHEN: they ask WHEN a worker is free / what they're booked for / how they're notified → use ambassador_availability. Defaults: no args → count + byStatus + recent. id → that ambassador or null. query → substring across firstName/lastName/email. Each record includes profile voice-note presence (hasProfileVoiceNote, URL, duration) and topicTags, which are the topics the ambassador is qualified/interested to talk about for prospect matching. Use hasVoiceNote for 'who has a voice note' and topic for 'who is qualified to talk about X'. Status semantics: active = championActive && completedPassword; inactive = !championActive; pending = invited but not yet onboarded. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
ambassador_reactivate
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to set championActive=true on an ambassador. Reversal of ambassador_deactivate.
ambassador_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to update an ambassador's profile fields. Cannot change company affiliation or auth fields.
application_settings_get
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to read the CURRENT VALUES of shift/task/invoice operational rules, social-media attribution channels/hashtags for ambassador post analytics, scheduled-report cadence, or rule/policy-level feature toggles for this tenant. Application Settings → Social Media does not control the prospect widget's Content tab feed; use widget_content_diagnostics for that. This returns stored settings, not a feature catalogue — for 'how do I…' / 'where do I configure…' questions about the portal, use product_help_search instead. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
application_settings_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Update this tenant's operational settings (the values application_settings_get reads back): who can join, shift clocking/approval/cancellation rules, the default hourly rate, invoice config, social-media attribution hashtag tracking for ambassador post analytics, scheduled reports, and feature on/off toggles. Pass only the fields you want to change; omitted fields are left untouched. Reversible. These social-media fields do not control the widget Content tab feed. For branding and prospect-nurturing settings use widget_settings_update.
asset_activity
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for the full USAGE HISTORY of ONE physical asset — every logged event (Used in Activation, Changed Location, Changed Owner, Altered or Repaired, Shipped / In Transit, Damaged or Expired, Lost or Missing): when it happened, who carried it out, and the posting it was used for. Identify the asset by id or query (name substring). Returns the event timeline newest-first, counts by event type, and usageCount. To rank MANY assets by usage, use physical_asset_query and sort on its usageCount. For the immutable audit trail of event create/edit/delete actions, use physical_asset_audit_trail. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
availability_overlap
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to find the BEST TIME to schedule a GROUP of ambassadors — 'when can the most of them meet', 'best 3-hour window next week for a team event'. Give it the ambassador ids to consider, an event duration and a date window; it computes — server-side — every candidate start time and ranks them by how many ambassadors are concurrently free, accounting for each one's weekly availability (in their own timezone), their time-off blocks, and shifts they're already booked for. Returns ranked windows, each with the available + unavailable ambassador names. Pick the in-scope ambassador set yourself first (e.g. by location/program) — this tool does the scheduling math, not the guest-list selection. Do NOT compute overlaps by hand from per-ambassador ambassador_availability calls; that is exactly what this replaces. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
chat_guidelines_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Read the tenant's current Chat Guidelines exactly as the admin portal defines them. Use this for 'what are the chat guidelines', 'conversation guidelines', or ambassador/prospect chat moderation guidance. The admin portal stores this as the auto-generated Chat Guidelines resource (resource.chatGuidelines=true) and syncs its custom description to the tenant school settings. Returns the custom guidelines plus the always-enforced baseline rules shown in the portal. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
chat_guidelines_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Update the tenant's custom Chat Guidelines, mirroring the admin portal's edit field on Moderation → Chat Guidelines. This edits the auto-generated Chat Guidelines resource description; the backend then syncs the same text to tenant settings for moderation.
colleague_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Search COLLEAGUES (fellow admins — people who log into the portal alongside the signed-in user) within the tenant. WHEN: user asks 'who else has access', 'list our admins', 'who's on our team', or wants the admin headcount. NOT WHEN: the name they mention matches the tenant (auto-scoped, never a record). NOT WHEN: they ask about workers → use ambassador_query. NOT WHEN: they ask about leads → use prospect_query. Defaults: no args → all colleagues + count. id → that colleague. query → name/email substring. isYou: true flags the signed-in admin. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
ct_auth_status
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Show current tenant/auth context and coarse tool capability counts.
ct_prime
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Load the CampusThreads MCP operating guide. Use at the start of broad or multi-step CampusThreads work.
ct_schema
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Discover CampusThreads portal entities, fields, types, allowed values, operations, and writable fields before using ct_read/ct_write.
ct_skills_list
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] List CampusThreads MCP workflow skills available to guide multi-step work.
ct_skills_read
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Read one CampusThreads MCP workflow skill before executing a multi-step workflow.
ct_write
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Generic schema-driven write with strict validation and dry-run previews. Defaults to dryRun:true. Currently supports company_settings; use existing domain mutations for other entities until their schema write contracts are added.
dashboard_overview
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY broad org-wide question — 'how are we doing', 'what needs my attention', 'give me a summary'. Returns ambassador status, shift status incl. needsAttention count, prospect count, prospect-thread backlog — all in one call. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
dashboard_triage
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for 'what needs my attention', 'what's outstanding', 'what should I do today', 'anything I'm behind on' — it returns one actionable digest fused across shifts, prospect threads and tasks: shifts proposed by ambassadors / pending approval / awaiting a report / with cancellation requests / unfilled and starting soon, prospect threads needing a response or help, and overdue tasks. For read-only METRICS and leaderboards use dashboard_overview instead. For shift-only action item questions ('when it comes to shifts', 'shift queue', 'what shift work is on me'), set area: 'shifts' so the result excludes unrelated thread/task sections and avoids extra queries. Each section returns items up to detailLimit; if count is higher than items.length, say more exist and ask before drilling in. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
group_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Create a new ambassador group with an explicit (manual) member list. Dynamic criteria-based groups (by country, program, ambassador type, tags, etc.) must be created in the portal — this tool creates manual-selection groups only.
group_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about ambassador groups (the way the tenant clusters ambassadors). No args → count, totalMemberships, recent. With id → single group. Filters: query (name substring). Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
group_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Rename a group or replace its member list. The member list is REPLACED wholesale — pass the full intended set of ambassador ids, not a delta. Only manual-selection groups should have their members edited this way.
internal_thread_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Start a new INTERNAL thread — a discussion among the named ambassadors (plus you). Pass the ambassador record ids to include as contributors and, optionally, a title (up to 50 characters). After creating, post into it with thread_send_message.
internal_thread_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for internal admin↔ambassador chat threads, including posting conversations that are automatically created for a specific posting so ambassadors/admins can discuss that shift opportunity. Returned source: 'posting' means an auto-created posting conversation; postingId is for internal tool joins only and must not be shown to the user. Describe these as 'posting conversations' or 'the conversation for <posting title>', never as IDs, variables, or system-generated shells. No args → count, byStatus (active = msg in last 7d / quiet), recent. With id → single thread. Filters: status, source, postingId, ambassadorId, query (thread name). Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
invoice_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Generate an invoice for an ambassador for a pay period — the equivalent of the ambassador detail → Invoices → Add Invoice action. The total amount, hours and shift count are COMPUTED by the backend from the ambassador's shifts worked between startDate and endDate; you do not supply them. By default the period must contain at least one qualifying shift — pass allowEmpty:true to issue a zero-shift invoice anyway. The invoice is shared to the ambassador's app.
invoice_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about invoices (records of ambassador earnings). No args → count, totalSum (per currency), top-earners-by-amount, recent. Single: id (one invoice). Batch: ids: [...]. Filters: ambassadorId (numeric user id) OR ambassadorIds: [...] (many), generatedAfter/generatedBefore (ISO datetime — 'past year', 'this month'). ALWAYS prefer the batched form over per-ambassador drilldown. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
location_activity
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about who has VISITED a location and when — 'who's been to <venue>', 'has anyone worked at X', 'when was the last activation at Y', 'how many visits has <location> had'. Returns every recorded visit to ONE location: the ambassador (resolved name), the date, the posting + shift it belonged to, plus reach, duration and rating — with per-ambassador and per-posting rollups. Identify the location by id (from location_query) or query (label/address substring). A location with zero visits returns an empty list — nobody has worked there yet. Optional after/before (ISO datetime) restrict the visit window. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
location_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Create one or more locations (venues). Always pass a locations array — one element or many; many are written in a single batched commit, so prefer one bulk call over repeated single calls. Provide lat/lng for a location to appear on the portal Map.
location_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Permanently delete a location. Two-phase: first call returns a preview + confirmation token; call again with confirm.token to delete. Irreversible.
location_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about locations (venues where shifts happen). No args → count, byType breakdown, recent. With id → single location. Filters: type (storage_site/administrative_site/activation_site/transitional_site), subType (e.g. University/Coffee Shop), query (label or address). Each location carries visitCount / lastVisited / totalReach — read these to see at a glance which venues have had activity (visitCount 0 = nobody has worked there). For the who/when detail behind those numbers, use location_activity. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
location_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Update a location (venue) — label, type, address, coordinates, tags. Pass only the fields you want changed.
media_content_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to inspect/open media from the tenant Media page in bulk. Returns MCP image content blocks for images, and resource links for videos/documents/other files. Use key/keys from media_query or filter by query/mediaType. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
media_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for the tenant Media page / Media Library grid. No args → count, byType (image/video/document/other), recent. Filters: key, mediaType, mime substring, query (filename). To inspect multiple images/videos/files, use media_content_query after this; it returns actual image blocks for images and resource links for videos/files. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
media_upload
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Upload a file into the tenant's media library. The MCP fetches the file at sourceUrl and uploads it to storage; returns the stored media (id, url, mime). Use this when you need a hosted URL for a logo, cover photo, or attachment.
message_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Read MESSAGES (chat content) from one or many threads. Use this after prospect_thread_query / internal_thread_query narrows you to thread IDs of interest — those tools only return thread METADATA (counts, status, participants); message bodies live here. Single: threadId. Batch: threadIds: [...] (one call, many threads — PREFER this over fanning out). Each returned message carries threadId, content, senderId, senderName, fromAmbassadorSide (true = ambassador/admin authored, false = prospect), time, replyToMessageId; these property names are for your internal reasoning only and must not be repeated to the user. sinceTime (ISO datetime) returns only newer messages — efficient for 'what's new since X'. limitPerThread caps per-thread (default 50). Threads outside the tenant are silently skipped. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
physical_asset_audit_trail
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for the AUDIT TRAIL of ONE physical asset — the immutable log shown in the portal's Audit Trail tab, stored separately from normal asset activity events. It shows whether asset events were created, edited, or deleted, who performed the action, when the audit entry was created, and the event details captured at that point. Identify the asset by id or query (name substring). For operational usage history only, use asset_activity. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
physical_asset_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Create one or more physical assets (banners, devices, kits, etc.). Always pass an assets array — one element or many; many are written in a single batched commit, so prefer one bulk call. Each asset may be placed at a location (locationLabel/address); assigning an asset to an ambassador owner is done afterwards in the portal. An optional customID becomes the asset's permanent id (no slashes, cannot be changed later).
physical_asset_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Permanently delete a physical asset. Two-phase: first call returns a preview + confirmation token; call again with confirm.token to delete. Irreversible.
physical_asset_image_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this when the user asks what a physical asset photo/image shows, or asks to inspect asset images. Fetches the same signed image that the admin portal displays, downloads it server-side, and returns MCP image content blocks plus temporary view links for visual inspection. Identify assets by id, ids, or query (name substring). Matching assets that share the same stored image are deduplicated, so bulk size variants return one image block when they use one photo. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
physical_asset_image_upload
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Upload or replace the photo for ONE existing physical asset, following the same process as the admin portal: one image only, image/* files only, 10 MB upload limit, HEIC/HEIF converted to JPEG at quality 0.8 before storage, signed upload through the backend, then the asset record is saved with the new photo metadata. Pass imageBase64 (raw base64 or data URI) or sourceUrl, plus a filename when possible.
physical_asset_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about physical assets (banners, cameras, kits, etc.). No args → count, byStatus (in_review/in_transit/in_storage/in_activation/in_possession), recent. With id → single asset. Filters: status, type, ownerAmbassadorId (the ambassador's record id), query. portalStatusLabel matches the admin portal status badge, rawStatus is the stored Firestore label, and currentHolder mirrors the portal's owner/location display. For 'who is assigned/currently owns this asset' use the owner fields; for physical state use portalStatusLabel + currentHolder. Each asset carries usageCount (times Used in Activation) and lastUsedAt — sort by usageCount to answer 'which assets are used the most'. For one asset's full event timeline use asset_activity. For seeing or describing the asset photo/image itself, use physical_asset_image_query. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
physical_asset_review
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Review an ambassador-submitted asset (one with status 'In Review'). approve: true accepts it → status becomes In Storage and the reviewer is recorded; approve: false rejects the submission → the asset is deleted.
physical_asset_set_status
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Set a physical asset's status directly — e.g. mark it Unavailable (disposed) or move it to In Storage. For transitions that should leave a history entry (shipped, owner change, used in an activation) prefer logging an asset event in the portal.
physical_asset_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Update a physical asset's editable fields — name, type, category, function, cost, description, notes, and its current location. Pass only the fields you want changed.
posting_cancel
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to cancel a posting. Cancellation notifies assigned ambassadors and removes linked calendar events. Two-phase: preview first, then confirm with token.
posting_cancel_recurring_series
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Cancel every future, active occurrence in a recurring posting series while preserving past and already-completed shift records. Use this when an admin says to cancel a recurring series, all upcoming shifts, or all future occurrences. Two-phase: preview first, then confirm with token.
posting_create_draft
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to create a new posting in draft state. Use posting_publish after to make it active.
posting_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to permanently delete a posting. Two-phase: preview, then confirm with token. Irreversible.
posting_publish
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to publish an autosaved draft posting so ambassadors can pick up its shifts. Matches the admin portal: creates a fresh published posting from the draft payload, then deletes the draft row so the backend create lifecycle runs for shifts, recurrence, notifications, and calendars.
posting_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about postings (job posts that become shifts). No args → count (true total), byStatus, recent (newest-created first). With id → single posting. Returned postings include opening fill status: totalOpenings, filledCount, and openCount, so you do NOT need a follow-up shift_query just to check whether a posting is fully staffed. For audit/history questions — who signed up, who was assigned or unassigned, why an opening became unfilled, cancellation request history, or what changed over time — use shift_audit_trail after identifying the posting. Filters: status (draft/active/cancelled), query (substring across workType/summary/address — so a place name like 'Hamilton' or 'Upper James' matches), startsAfter/startsBefore (ISO datetime — filter by the posting's scheduled time). Drafts match the admin portal rule: publishedAt: null, not the legacy status enum. truncated: true in the result means more postings matched than were fetched. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
posting_restore
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to restore a cancelled posting back to active. Prefer the admin portal edit/restore flow when the admin needs to review time, assets, assignments, or conflicts before restoring. Restoring keeps the normal status enum as active, stamps restoredAt/restoredBy, clears cancellation reason/by, notifies assigned ambassadors, and restores calendar/thread side effects. Two-phase: preview first, then confirm with token.
posting_set_openings
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Change how many openings (slots for ambassadors) a posting has — raising it adds unfilled openings, lowering it removes them. The 'add/remove opening' control in the event drawer.
posting_update_draft
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to update fields on a draft posting before publishing.
product_help_search
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Answers questions about HOW THE CAMPUSTHREADS ADMIN PORTAL WORKS — how to perform a task, where to find a screen/tab/setting/button, what a control does, and visual/spatial UI guidance such as which sidebar item, tab, right-side drawer, top control row, button label, icon, or color a user should look for. This is the product documentation for the software itself. ALWAYS use this for 'how do I…', 'where is…', 'how do I configure…', 'can the portal…' questions, including 'where do I click?', 'what color is the button?', and 'where on the page is it?'. Do NOT answer those by inspecting data tools: widget_settings_get, application_settings_get and the *_query tools return one tenant's DATA, not the software's capabilities — a field being absent from those tools does NOT mean the feature doesn't exist. This corpus is tenant-agnostic (the portal works the same for every tenant) and is not scoped to your company.
recruitment_intake_metrics_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for live performance questions about ONE recruitment intake's Metrics section: 'how is this intake doing?', 'how many applicants started/submitted/were selected?', 'what is the intake conversion rate?', 'where are applicants coming from?', 'what weekly hours did applicants commit to?', or 'which schools are represented?'. It returns the same derived metrics shown after opening a Recruitment intake and clicking Metrics, with optional all-time / 7 / 30 / 90 day ranges. Pass an intake id or title when known; no args returns recent intake candidates, or computes metrics if the tenant only has one intake. For where-to-click or what-the-section-means questions, use product_help_search; for raw application fields not summarized here, use portal_record_query or ct_read after this tool.
recruitment_referral_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for live questions about recruitment intake referral links: named source links, ambassador personal links, which links are active, which ambassadors have links, and how many applications each link started/submitted/selected. Filters: intake id or query, type (named/ambassador/any), active (active/inactive/any), and sourceQuery for link or ambassador name. Results deep-link to the parent Recruitment intake drawer. For overall intake performance charts use recruitment_intake_metrics_query; for where-to-click instructions use product_help_search. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
resource_create_draft
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to create a new resource in draft state. Use resource_publish after to make it visible to ambassadors.
resource_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to permanently delete a resource. Two-phase: preview, then confirm with token. Irreversible.
resource_file_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to inspect/open the uploaded file on a resource. Mirrors the portal's View file action. Returns an MCP image block when the resource file is an image; returns a resource link for PDFs, videos, documents, and other files. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
resource_file_upload
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Upload or replace the file attached to one existing resource, following the same process as the admin portal: max file size 100 MB, HEIC/HEIF images converted to JPEG at quality 0.8, signed upload through the backend, then the resource draft metadata is saved.
resource_nudge
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Send a reminder notification to an audience of ambassadors about a resource (announcement / document / email / training module) — the bulk equivalent of the portal's 'Nudge Remaining Target Ambassadors'. Above 10 recipients this is two-phase: call once for a preview + confirmation_token, then again with confirm.token to send. Mirrors the portal: ambassadors who have already completed the resource are dropped from the audience automatically, so only those still outstanding are nudged.
resource_publish
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to publish a draft resource so ambassadors can see it. A resource marked public can also become available through the public AI chatbot.
resource_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about resources (announcements, documents, emails, training modules, links). No args → count, byStatus, recent. With id → single resource. Filters: status (draft/published), resourceType, query (name). Each returned item carries a commentCount field — use it to identify which resources actually have comments BEFORE calling comment_query. Then batch the survivors into a single comment_query call (pass resourceIds: [...]), don't fan out one call per resource. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
resource_unpublish
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to move a published resource back to draft state. Reversible via resource_publish.
resource_update_draft
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to update fields on a draft resource.
reward_cheer_on
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Send a motivational 'cheer on' nudge to ambassadors about a reward — encourages them toward earning it. By default cheers everyone the reward targets; pass ambassadorIds (ambassador record ids) to cheer a specific subset.
reward_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Create a gamification reward (the structured form of Rewards → Add Reward). Supports metric threshold/ranking conditions and completion of selected tasks, events, training modules, or announcements. Completion rewards may target the required items' collaborators and groups. Rewards can grant a monetary amount, points, or both, and end on a date / when N ambassadors win / never. Recurring-round rewards are not supported here — create those in the portal. The reward is created active and ambassadors are notified.
reward_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Permanently delete a reward. Two-phase: the first call returns a preview + confirmation token; call again with confirm.token to delete. Irreversible.
reward_evaluate_now
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Trigger an immediate evaluation of the tenant's rewards — recomputes which ambassadors have met each reward's criteria right now, instead of waiting for the scheduled run.
reward_notify_available
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Notify the ambassadors a reward targets that it is available to earn — sends each the 'a reward is available' notification.
reward_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about rewards (gamification). No args → count, byStatus (ongoing/done), recent. With id → single reward. Filters: status, type, query. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
reward_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Update an existing reward's safe administrative fields: notes, rarity, monetary value, and points value. For an ongoing fixed-date reward, endAt may only extend its existing deadline. Reward name, criteria, required items, targets, start time, end mode, winner limits, and recurring schedules are immutable after creation.
shift_assign_ambassador
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Assign an ambassador to ONE available opening on a posting (the 'Assign' action in the event drawer) — creates the shift record that fills that opening. A posting has a fixed number of openings (totalOpenings); each existing shift record is one ALREADY-FILLED opening (regardless of its status). This refuses the assignment when every opening is already filled — to swap an ambassador in, shift_unassign one first. An ambassador can hold at most one opening per posting; re-assigning one who is already on it is refused. ambassadorUserId is the ambassador's numeric id (from ambassador_query).
shift_audit_trail
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this as the FIRST tool for the audit/history of ONE shift opening or posting. Always call this when the user provides a shift/posting id and asks what happened, or asks why a shift changed, why an opening became unfilled, or why expected ambassador signups/assignments are missing. Do not call shift_query first when the question already includes the shift/posting id and is about history. Use this even if they say 'this shift' and the id must come from portal context. Examples: 'what happened to this shift?', 'I thought ambassadors signed up', 'who assigned/unassigned someone?', 'why did this become unfilled?', cancellation requests/denials, hours approval/rejection, report created/updated, nudges, and request-more-info actions. This reads the same immutable Audit Log shown in the Shifts event drawer. Use shift_query first only when you need to identify the shift or read current state; use this when the user asks how state changed over time. Pass shiftId for one opening, or postingId for the whole event/posting when the opening was deleted or the user is asking about signups across the posting. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
shift_flexed_start_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for flexed-start / Flexed Shift questions, e.g. 'Which shifts have had a flexed start in the past quarter?' This is a one-call optimized query against the shift opening fields the admin portal uses for the orange swap-arrows Flexed icon. Do NOT answer flexed-start questions by searching product docs, checking ct_schema, or pulling broad shift_query results and comparing clock-in times manually. A flexed start means the opening has personalStartTime / a portal 'Flexed: start-end' value; it is not merely a clock-in that differs from the scheduled start. Returns scheduled vs flexed start/end times, early/late/same direction, ambassador/posting identity, and clock-in offsets for context. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
shift_location_tracking_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Fetch the GPS tracking trace shown in the admin portal's post-shift report map. Use this when the user asks about GPS location points, movement path, map coverage, tracking gaps, check-in/check-out coordinates, or whether the ambassador stayed on site. This is separate from visitedLocations: visitedLocations are route/report stops, while this tool returns the actual GPS check-in tracking metadata and ordered location points. Also use this for product-level questions about how shift GPS tracking works; the response includes trackingMechanics based on the current ambassador app implementation. Answer in admin-facing language; do not mention Firestore paths, document ids, or implementation field names. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
shift_nudge
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Nudge the assigned ambassador(s) about a shift — the 'Nudge for Report' / 'Request More Info' action in the shift drawer. Reminds them to submit (or add detail to) the post-shift report; pass moreInfo to ask for something specific. Accepts a shiftIds array — one or many; many are nudged in a single batched write. The shift id is the the shift's id from shift_query.
shift_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] ANY question about shifts (scheduled work units AND their post-shift reports). For flexed-start / Flexed Shift questions, use shift_flexed_start_query instead; it reads the portal's personalStartTime fields directly and avoids a broad shift scan. For audit/history questions — what happened to a shift, who signed up, who assigned or unassigned an ambassador, why an opening became unfilled, cancellation request history, or report/approval audit events — do not use shift_query as the first tool when the user already gives a shift/posting id; use shift_audit_trail directly. Use shift_query only if you must identify which shift/posting the user means before reading its audit trail. For reviewing ONE worked shift in detail — what the ambassador did, where they went, whether GPS/attachments/report look suspicious, or whether to approve/dispute — use shift_report_review first instead of manually chaining shift/location/GPS/attachment tools. A shift's scheduling/clock/payment details and the ambassador's submitted post-shift report are returned together as ONE complete record per shift; you never need to look at either part separately. Each returned item carries: human-readable ambassadorName (plus ambassadorId record id and ambassadorUserId numeric id for cross-tool pivots), postingTitle (+ postingId), effective startTime/endTime, original scheduledStartTime/scheduledEndTime, flexed personalStartTime/personalEndTime, hasFlexedStart/flexedStartOffsetMins, clockedInAt/clockedOutAt, amountEarnedCAD/paymentStatus/paymentDate, reportText/reportAttachmentCount/reportAttachments/reach, computed durationMins (worked span, else scheduled), lastSeen/updatedAt/unreadByAdmin. For route or multi-stop report questions, read visitedLocations as the ambassador's claimed/reported stops: each stop may include travel minutes before the stop, minutes spent at the stop, reach, rating, notes, and attachment count. If those per-stop time fields are null/missing, say the report did not record travel or time-per-stop; do not infer it from map pins or location totals. Report attachments are separate from the report text. If the user asks to inspect/open those files, call shift_report_attachment_query; media_query cannot fetch shift report attachments. GPS check-in tracking is separate from route stop reports. For small/single results, gpsTrackingSummary tells you whether actual phone GPS points exist. If the user asks where the ambassador went specifically, exact locations, GPS/location points, map coverage, movement path, check-in/check-out coordinates, tracking gaps, or whether the reported route is suspicious, you MUST call shift_location_tracking_query for that shift before answering. No args → count, byStatus breakdown, recent. Single: id. Batched: ids: [...]. Filters: status, ambassadorId/ambassadorIds, postingId/postingIds, time-range startAfter/startBefore, unreadByAdmin: true|false. Status semantics: pending_approval = report submitted, but reported hours have not been approved/resolved yet. awaiting_report = shift completed, no report yet. filled_completed = reported hours are approved/resolved, matching the admin portal's Completed opening state; paymentStatus may still be Awaiting Approval because payment is separate. filled_scheduled = future shift, ambassador assigned. Phrasings: 'reports I need to approve' → status: pending_approval. 'reports I haven't read yet' → status: pending_approval, unreadByAdmin: true. ALWAYS prefer the batched/filter forms over per-shift drilldown. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
shift_report_attachment_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Fetch temporary links for one shift's post-shift report attachments. Use this only when shift_query shows reportAttachmentCount > 0 and the user asks about the attached files, photos, receipts, or wants the attachments checked/opened. These are shift-specific S3 objects, not general Media Library records, so media_query is not the right tool. Return product-level answers: refer to 'attachment 1', 'the first photo', etc.; do not show raw file keys, object names, S3 bucket details, or implementation field names. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
shift_report_review
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this as the FIRST tool for reviewing ONE worked shift or post-shift report: 'what did they do', 'where did they go specifically', 'is anything suspicious', 'should I approve this', 'show me the report/attachments/GPS for this shift'. It returns the portal-style review packet in one call: shift/timesheet details, claimed route stops with saved location names/addresses, actual phone GPS tracking points, report attachments, and review findings. This replaces the common multi-call sequence shift_query → location_query → shift_location_tracking_query → shift_report_attachment_query. Use shift_query for broad lists; use this for one shift you are about to explain, investigate, approve, dispute, or nudge. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
shift_resolve_cancellation_request
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Resolve an ambassador's request to cancel a shift. approve: true grants it — the shift assignment is removed (the opening reopens); approve: false denies it — the ambassador stays assigned and the request is cleared.
shift_resolve_timesheet
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Resolve a worked shift's timesheet — the admin action in the Timesheet drawer. outcome: 'approve' accepts the worked clock times exactly like the admin portal's Approve Reported Hours action (sets approved + resolved times; it does not mark payment paid/approved); outcome: 'dispute' records a disagreement with the times (disputeReason required); outcome: 'absent' marks the ambassador a no-show. approve/dispute need startTime + endTime (the actual ISO clock-in/out). Returns the updated shift.
shift_unassign
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Remove a shift assignment — unassigns the ambassador / cancels that single opening (the 'Unassign' / 'Cancel opening' action). Reversible by assigning again. To act on an ambassador's own cancellation REQUEST, use shift_resolve_cancellation_request.
tag_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Create a topic tag for the tenant — tags label conversation topics / ambassador interests. The new tag is owned by this company (not a platform-common tag).
tag_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Delete a topic tag owned by this tenant. Platform-common tags cannot be deleted.
tag_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about topic tags. No args → count + breakdown of company-owned vs platform-common. With id → single tag. Filters: query (name substring), includeCommon (default true). Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
task_approve
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Approve a task that an assigned ambassador has submitted for review. This moves the task from Review to Done and records the approving admin.
task_create
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to create a new task on the kanban board.
task_delete
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to archive a task — like the portal's Delete, it moves the task to the Archive board (it is not removed from the board view). Archived tasks are automatically purged after a 30-day grace period. Two-phase: first call returns a preview + token; call again with confirm.token to archive.
task_move_column
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to move an active task between the To Do and In Progress columns. Ambassadors submit completed tasks for review; admins use task_approve after review rather than moving a task directly to Done.
task_nudge
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Send a reminder notification to every collaborator on a task (the portal's 'Nudge all collaborators'). The task's existing collaborator set is used as-is — no audience to pick.
task_query
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this for ANY question about kanban tasks. No args → count, byStatus (to_do/in_progress/review/done), recent. With id → single task. Filters: status (column), priority (Low/Medium/High), dueAfter/dueBefore, query (name substring), createdBy (numeric user id, for 'tasks I created'). Each returned item carries a commentCount field — use it to filter to tasks that have comments BEFORE calling comment_query. Then batch the survivors into a single comment_query call (pass taskIds: [...]), don't fan out one call per task. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
task_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to update fields on an existing task. To move a task to a different column use task_move_column instead.
thread_answer_suggestion
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Answer a message's suggestion request — when the chatbot asked an admin how to respond, this records the suggested reply. Omit suggestion (or pass empty) to simply mark the request resolved without one. Clears the message's pending-suggestion flag.
thread_edit_message
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Edit an existing message in a thread (the portal's edit-message action). Can change the content (an admin edit is treated as clean — clears any moderation flag), the message it is replyToMessageId replying to (pass null to detach), and/or its reaction emoji (pass null to remove). Provide at least one of the three.
thread_send_message
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Send a message into a thread — a prospect conversation OR an internal thread (the admin reply box). The message posts as the thread's assigned ambassador, which is how the portal attributes admin replies so the recipient sees a consistent sender. Optionally reply to a specific message with replyToMessageId. This notifies the recipient.
thread_set_contributors
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Set the contributor (participant) list of a thread — pass the FULL intended set of ambassador record ids; it replaces the current list. Newly added contributors get an addedDate stamp.
thread_set_message_deleted
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Hide or restore a message in a thread. deleted: true removes it from the conversation (the portal's delete-message action); deleted: false restores it. Soft and reversible.
widget_content_diagnostics
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this when a social post/photo/video is not appearing in the prospect widget's Content tab, or when the Content tab is missing. One-call diagnostic for Widget Customization → Content: reads source Instagram/TikTok accounts, hashtag filters, title, and contentTag/Elfsight feed id from Firestore schools/{slug}.widgetConfig. This is separate from Application Settings → Social Media, which is only ambassador post attribution/dashboard analytics. Prefer this over application_settings_get for widget content feed issues. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
widget_embed_diagnostics
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this when the user says the embedded prospect widget does not show up, is blank, or is blocked on their website. One-call diagnostic: returns the Security whitelist shown in the admin portal, the runtime domain list the widget checks, domain-match results for an optional URL/domain, external-thread disabled state, and the expected embed snippet. Prefer this over product_help_search + widget_settings_get for live troubleshooting. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
widget_settings_get
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Use this to read the CURRENT VALUES visible in Widget Customization: popcard appearance, ambassador-profile display, AI bot toggles, widget Content tab source settings, Security / Whitelisted Domains, prospect-nurturing config, branding, and tenant feature toggles. Widget Content settings are separate from Application Settings → Social Media attribution hashtags. This joins the Strapi company settings with the Firestore school widgetConfig because the admin portal reads both. For widget embed troubleshooting, prefer widget_embed_diagnostics. For social post/photo/video issues in the widget Content tab, prefer widget_content_diagnostics. For 'how do I…' / 'where do I configure…' questions about the portal, use product_help_search instead. Routing: prefer this optimized tool for the workflow it describes. If its result omits a field visible in the admin portal, or source-level detail is needed, call ct_read for supported generic entities or portal_record_query for an exact record before saying the MCP cannot access it.
widget_settings_update
ChatGPT[Tenant: Lumo (slug=lumo-demo). Every tool is auto-scoped here — never search FOR this name as a record.] Update this tenant's branding and prospect-nurturing settings (the values widget_settings_get reads back). Pass only the fields you want to change; omitted fields are left untouched. Reversible — set a field again to change it back. For Application Settings social-media attribution tracking, scheduled reports, shift/invoice rules and other operational settings use application_settings_update.